mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-02-15 14:04:04 +02:00
AUnit step (#3075)
* Add AUnit step * Add Groovy File * Update metadata * Add groovy test config * Add Unit tests * Add Documentation * Docu fixes * change docu * change docu * change logging level & remove sleep * change docu * change docu * Update documentation/docs/steps/abapEnvironmentRunAUnitTest.md Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>
This commit is contained in:
parent
cacdb2b867
commit
09f5c0a524
566
cmd/abapEnvironmentRunAUnitTest.go
Normal file
566
cmd/abapEnvironmentRunAUnitTest.go
Normal file
@ -0,0 +1,566 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/abaputils"
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type abapEnvironmentRunAUnitTestUtils interface {
|
||||
command.ExecRunner
|
||||
|
||||
FileExists(filename string) (bool, error)
|
||||
|
||||
// Add more methods here, or embed additional interfaces, or remove/replace as required.
|
||||
// The abapEnvironmentRunAUnitTestUtils interface should be descriptive of your runtime dependencies,
|
||||
// i.e. include everything you need to be able to mock in tests.
|
||||
// Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies.
|
||||
}
|
||||
|
||||
type abapEnvironmentRunAUnitTestUtilsBundle struct {
|
||||
*command.Command
|
||||
*piperutils.Files
|
||||
|
||||
// Embed more structs as necessary to implement methods or interfaces you add to abapEnvironmentRunAUnitTestUtils.
|
||||
// Structs embedded in this way must each have a unique set of methods attached.
|
||||
// If there is no struct which implements the method you need, attach the method to
|
||||
// abapEnvironmentRunAUnitTestUtilsBundle and forward to the implementation of the dependency.
|
||||
}
|
||||
|
||||
func newAbapEnvironmentRunAUnitTestUtils() abapEnvironmentRunAUnitTestUtils {
|
||||
utils := abapEnvironmentRunAUnitTestUtilsBundle{
|
||||
Command: &command.Command{},
|
||||
Files: &piperutils.Files{},
|
||||
}
|
||||
// Reroute command output to logging framework
|
||||
utils.Stdout(log.Writer())
|
||||
utils.Stderr(log.Writer())
|
||||
return &utils
|
||||
}
|
||||
|
||||
func abapEnvironmentRunAUnitTest(config abapEnvironmentRunAUnitTestOptions, telemetryData *telemetry.CustomData) {
|
||||
|
||||
// for command execution use Command
|
||||
c := command.Command{}
|
||||
// reroute command output to logging framework
|
||||
c.Stdout(log.Writer())
|
||||
c.Stderr(log.Writer())
|
||||
|
||||
var autils = abaputils.AbapUtils{
|
||||
Exec: &c,
|
||||
}
|
||||
|
||||
client := piperhttp.Client{}
|
||||
|
||||
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
|
||||
err := runAbapEnvironmentRunAUnitTest(&config, telemetryData, &autils, &client)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("step execution failed")
|
||||
}
|
||||
}
|
||||
|
||||
func runAbapEnvironmentRunAUnitTest(config *abapEnvironmentRunAUnitTestOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) error {
|
||||
var details abaputils.ConnectionDetailsHTTP
|
||||
subOptions := convertAUnitOptions(config)
|
||||
details, err := com.GetAbapCommunicationArrangementInfo(subOptions, "")
|
||||
var resp *http.Response
|
||||
cookieJar, _ := cookiejar.New(nil)
|
||||
//Fetch Xcrsf-Token
|
||||
if err == nil {
|
||||
credentialsOptions := piperhttp.ClientOptions{
|
||||
Username: details.User,
|
||||
Password: details.Password,
|
||||
CookieJar: cookieJar,
|
||||
}
|
||||
client.SetOptions(credentialsOptions)
|
||||
details.XCsrfToken, err = fetchAUnitXcsrfToken("GET", details, nil, client)
|
||||
}
|
||||
if err == nil {
|
||||
resp, err = triggerAUnitrun(*config, details, client)
|
||||
}
|
||||
if err == nil {
|
||||
err = handleAUnitResults(resp, details, client, config.AUnitResultsFileName)
|
||||
}
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("step execution failed")
|
||||
}
|
||||
log.Entry().Info("AUnit test run completed successfully. If there are any results from the respective run they will be listed in the logs above as well as being saved in the output .xml file")
|
||||
return nil
|
||||
}
|
||||
|
||||
func triggerAUnitrun(config abapEnvironmentRunAUnitTestOptions, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (*http.Response, error) {
|
||||
var aUnitConfigYamlFile []byte
|
||||
abapEndpoint := details.URL
|
||||
filelocation, err := filepath.Glob(config.AUnitConfig)
|
||||
//Parse YAML AUnit run configuration as body for AUnit run trigger
|
||||
if err == nil {
|
||||
filename, err := filepath.Abs(filelocation[0])
|
||||
if err == nil {
|
||||
aUnitConfigYamlFile, err = ioutil.ReadFile(filename)
|
||||
}
|
||||
}
|
||||
var AUnitConfig AUnitConfig
|
||||
if err == nil {
|
||||
var result []byte
|
||||
result, err = yaml.YAMLToJSON(aUnitConfigYamlFile)
|
||||
json.Unmarshal(result, &AUnitConfig)
|
||||
}
|
||||
var metadataString, optionsString, objectSetString string
|
||||
if err == nil {
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(AUnitConfig)
|
||||
}
|
||||
|
||||
//Trigger AUnit run
|
||||
var resp *http.Response
|
||||
var bodyString = `<?xml version="1.0" encoding="UTF-8"?>` + metadataString + optionsString + objectSetString + `</aunit:run>`
|
||||
var body = []byte(bodyString)
|
||||
if err == nil {
|
||||
log.Entry().Debugf("Request Body: %s", bodyString)
|
||||
details.URL = abapEndpoint + "/sap/bc/adt/api/abapunit/runs"
|
||||
resp, err = runAUnit("POST", details, body, client)
|
||||
}
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("Triggering AUnit test run failed: %w", err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func convertAUnitOptions(options *abapEnvironmentRunAUnitTestOptions) abaputils.AbapEnvironmentOptions {
|
||||
subOptions := abaputils.AbapEnvironmentOptions{}
|
||||
|
||||
subOptions.CfAPIEndpoint = options.CfAPIEndpoint
|
||||
subOptions.CfServiceInstance = options.CfServiceInstance
|
||||
subOptions.CfServiceKeyName = options.CfServiceKeyName
|
||||
subOptions.CfOrg = options.CfOrg
|
||||
subOptions.CfSpace = options.CfSpace
|
||||
subOptions.Host = options.Host
|
||||
subOptions.Password = options.Password
|
||||
subOptions.Username = options.Username
|
||||
|
||||
return subOptions
|
||||
}
|
||||
|
||||
func handleAUnitResults(resp *http.Response, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, aunitResultFileName string) error {
|
||||
var err error
|
||||
var abapEndpoint string
|
||||
abapEndpoint = details.URL
|
||||
location := resp.Header.Get("Location")
|
||||
details.URL = abapEndpoint + location
|
||||
location, err = pollAUnitRun(details, nil, client)
|
||||
if err == nil {
|
||||
details.URL = abapEndpoint + location
|
||||
resp, err = getResultAUnitRun("GET", details, nil, client)
|
||||
}
|
||||
//Parse response
|
||||
var body []byte
|
||||
if err == nil {
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
err = parseAUnitResult(body, aunitResultFileName)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Handling AUnit result failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildAUnitTestBody(AUnitConfig AUnitConfig) (metadataString string, optionsString string, objectSetString string, err error) {
|
||||
|
||||
//Checks before building the XML body
|
||||
if AUnitConfig.Title == "" {
|
||||
return "", "", "", fmt.Errorf("Error while parsing AUnit test run config. No title for the AUnit run has been provided. Please configure an appropriate title for the respective test run")
|
||||
} else if AUnitConfig.Context == "" {
|
||||
return "", "", "", fmt.Errorf("Error while parsing AUnit test run config. No context for the AUnit run has been provided. Please configure an appropriate context for the respective test run")
|
||||
} else if reflect.DeepEqual(AUnitOptions{}, AUnitConfig.Options) {
|
||||
return "", "", "", fmt.Errorf("Error while parsing AUnit test run config. No options have been provided. Please configure the options for the respective test run")
|
||||
} else if reflect.DeepEqual(ObjectSet{}, AUnitConfig.ObjectSet) {
|
||||
return "", "", "", fmt.Errorf("Error while parsing AUnit test run object set config. No object set has been provided. Please configure the objects you want to be checked for the respective test run")
|
||||
} else if len(AUnitConfig.ObjectSet) == 0 {
|
||||
return "", "", "", fmt.Errorf("Error while parsing AUnit test run object set config. No object set has been provided. Please configure the set of objects you want to be checked for the respective test run")
|
||||
}
|
||||
|
||||
//Build metadata string
|
||||
metadataString += `<aunit:run title="` + AUnitConfig.Title + `" context="` + AUnitConfig.Context + `" xmlns:aunit="http://www.sap.com/adt/api/aunit">`
|
||||
|
||||
//Build Options
|
||||
optionsString += buildAUnitOptionsString(AUnitConfig)
|
||||
|
||||
//Build Object Set
|
||||
objectSetString += buildAUnitObjectSetString(AUnitConfig)
|
||||
|
||||
return metadataString, optionsString, objectSetString, nil
|
||||
}
|
||||
|
||||
func runAUnit(requestType string, details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (*http.Response, error) {
|
||||
|
||||
log.Entry().WithField("ABAP endpoint: ", details.URL).Info("Triggering AUnit run")
|
||||
|
||||
header := make(map[string][]string)
|
||||
header["X-Csrf-Token"] = []string{details.XCsrfToken}
|
||||
header["Content-Type"] = []string{"application/vnd.sap.adt.api.abapunit.run.v1+xml; charset=utf-8;"}
|
||||
|
||||
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
|
||||
if err != nil {
|
||||
return req, fmt.Errorf("Triggering AUnit run failed: %w", err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
return req, err
|
||||
}
|
||||
|
||||
func buildAUnitOptionsString(AUnitConfig AUnitConfig) (optionsString string) {
|
||||
|
||||
optionsString += `<aunit:options>`
|
||||
if AUnitConfig.Options.Measurements != "" {
|
||||
optionsString += `<aunit:measurements type="` + AUnitConfig.Options.Measurements + `"/>`
|
||||
}
|
||||
optionsString += `<aunit:scope`
|
||||
if AUnitConfig.Options.Scope.OwnTests != nil {
|
||||
optionsString += ` ownTests="` + fmt.Sprintf("%v", *AUnitConfig.Options.Scope.OwnTests) + `"`
|
||||
}
|
||||
if AUnitConfig.Options.Scope.ForeignTests != nil {
|
||||
optionsString += ` foreignTests="` + fmt.Sprintf("%v", *AUnitConfig.Options.Scope.ForeignTests) + `"`
|
||||
}
|
||||
optionsString += `/><aunit:riskLevel`
|
||||
if AUnitConfig.Options.RiskLevel.Harmless != nil {
|
||||
optionsString += ` harmless="` + fmt.Sprintf("%v", *AUnitConfig.Options.RiskLevel.Harmless) + `"`
|
||||
}
|
||||
if AUnitConfig.Options.RiskLevel.Dangerous != nil {
|
||||
optionsString += ` dangerous="` + fmt.Sprintf("%v", *AUnitConfig.Options.RiskLevel.Dangerous) + `"`
|
||||
}
|
||||
if AUnitConfig.Options.RiskLevel.Critical != nil {
|
||||
optionsString += ` critical="` + fmt.Sprintf("%v", *AUnitConfig.Options.RiskLevel.Critical) + `"`
|
||||
}
|
||||
optionsString += `/><aunit:duration`
|
||||
if AUnitConfig.Options.Duration.Short != nil {
|
||||
optionsString += ` short="` + fmt.Sprintf("%v", *AUnitConfig.Options.Duration.Short) + `"`
|
||||
}
|
||||
if AUnitConfig.Options.Duration.Medium != nil {
|
||||
optionsString += ` medium="` + fmt.Sprintf("%v", *AUnitConfig.Options.Duration.Medium) + `"`
|
||||
}
|
||||
if AUnitConfig.Options.Duration.Long != nil {
|
||||
optionsString += ` long="` + fmt.Sprintf("%v", *AUnitConfig.Options.Duration.Long) + `"`
|
||||
}
|
||||
optionsString += `/></aunit:options>`
|
||||
return optionsString
|
||||
}
|
||||
|
||||
func buildAUnitObjectSetString(AUnitConfig AUnitConfig) (objectSetString string) {
|
||||
|
||||
//Build ObjectSets {
|
||||
for _, s := range AUnitConfig.ObjectSet {
|
||||
//Write object set
|
||||
objectSetString += `<osl:objectSet xsi:type="` + s.Type + `" xmlns:osl="http://www.sap.com/api/osl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">`
|
||||
for _, t := range s.Set {
|
||||
objectSetString += `<osl:set xsi:type="` + t.Type + `">`
|
||||
for _, packageSet := range t.PackageSet {
|
||||
objectSetString += `<osl:package name="` + packageSet.Name + `" includeSubpackages="` + fmt.Sprintf("%v", *packageSet.IncludeSubpackages) + `"/>`
|
||||
}
|
||||
for _, flatObjectSet := range t.FlatObjectSet {
|
||||
objectSetString += `<osl:package name="` + flatObjectSet.Name + `" includeSubpackages="` + fmt.Sprintf("%v", *&flatObjectSet.Type) + `"/>`
|
||||
}
|
||||
objectSetString += `</osl:set>`
|
||||
}
|
||||
|
||||
objectSetString += `</osl:objectSet>`
|
||||
}
|
||||
return objectSetString
|
||||
}
|
||||
|
||||
func fetchAUnitXcsrfToken(requestType string, details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (string, error) {
|
||||
|
||||
log.Entry().WithField("ABAP Endpoint: ", details.URL).Debug("Fetching Xcrsf-Token")
|
||||
|
||||
details.URL += "/sap/bc/adt/api/abapunit/runs/00000000000000000000000000000000"
|
||||
details.XCsrfToken = "fetch"
|
||||
header := make(map[string][]string)
|
||||
header["X-Csrf-Token"] = []string{details.XCsrfToken}
|
||||
header["Accept"] = []string{"application/vnd.sap.adt.api.abapunit.run-status.v1+xml"}
|
||||
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Fetching Xcsrf-Token failed: %w", err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
|
||||
token := req.Header.Get("X-Csrf-Token")
|
||||
return token, err
|
||||
}
|
||||
|
||||
func pollAUnitRun(details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (string, error) {
|
||||
|
||||
log.Entry().WithField("ABAP endpoint", details.URL).Info("Polling AUnit run status")
|
||||
|
||||
for {
|
||||
resp, err := getHTTPResponseAUnitRun("GET", details, nil, client)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Getting HTTP response failed: %w", err)
|
||||
}
|
||||
bodyText, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Reading response body failed: %w", err)
|
||||
}
|
||||
x := new(AUnitRun)
|
||||
xml.Unmarshal(bodyText, &x)
|
||||
|
||||
log.Entry().Infof("Current polling status: %s", x.Progress.Status)
|
||||
if x.Progress.Status == "Not Created" {
|
||||
return "", err
|
||||
}
|
||||
if x.Progress.Status == "Completed" || x.Progress.Status == "FINISHED" {
|
||||
return x.Link.Href, err
|
||||
}
|
||||
if x.Progress.Status == "" {
|
||||
return "", fmt.Errorf("Could not get any response from AUnit poll: %w", errors.New("Status from AUnit run is empty. Either it's not an ABAP system or AUnit run hasn't started"))
|
||||
}
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func getHTTPResponseAUnitRun(requestType string, details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (*http.Response, error) {
|
||||
|
||||
log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Polling AUnit run status")
|
||||
|
||||
header := make(map[string][]string)
|
||||
header["Accept"] = []string{"application/vnd.sap.adt.api.abapunit.run-status.v1+xml"}
|
||||
|
||||
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
|
||||
if err != nil {
|
||||
return req, fmt.Errorf("Getting AUnit run status failed: %w", err)
|
||||
}
|
||||
return req, err
|
||||
}
|
||||
|
||||
func getResultAUnitRun(requestType string, details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (*http.Response, error) {
|
||||
|
||||
log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Getting AUnit results")
|
||||
|
||||
header := make(map[string][]string)
|
||||
header["x-csrf-token"] = []string{details.XCsrfToken}
|
||||
header["Accept"] = []string{"application/vnd.sap.adt.api.junit.run-result.v1+xml"}
|
||||
|
||||
req, err := client.SendRequest(requestType, details.URL, bytes.NewBuffer(body), header, nil)
|
||||
if err != nil {
|
||||
return req, fmt.Errorf("Getting AUnit run results failed: %w", err)
|
||||
}
|
||||
return req, err
|
||||
}
|
||||
|
||||
func parseAUnitResult(body []byte, aunitResultFileName string) (err error) {
|
||||
if len(body) == 0 {
|
||||
return fmt.Errorf("Parsing AUnit result failed: %w", errors.New("Body is empty, can't parse empty body"))
|
||||
}
|
||||
|
||||
responseBody := string(body)
|
||||
log.Entry().Debugf("Response body: %s", responseBody)
|
||||
|
||||
//Optional checks before writing the Results
|
||||
parsedXML := new(AUnitResult)
|
||||
xml.Unmarshal([]byte(body), &parsedXML)
|
||||
if len(parsedXML.Testsuite.Testcase) == 0 {
|
||||
log.Entry().Info("There were no AUnit findings from this run")
|
||||
return nil
|
||||
}
|
||||
|
||||
//Write Results
|
||||
err = ioutil.WriteFile(aunitResultFileName, body, 0644)
|
||||
if err == nil {
|
||||
log.Entry().Infof("Writing %s file was successful. Please find the results from the respective AUnit run in the %s file or in below logs", aunitResultFileName, aunitResultFileName)
|
||||
//Logging of findings
|
||||
log.Entry().Infof(`Here are the results for the AUnit test run '%s' executed by User %s on System %s in Client %s at %s. The AUnit run took %s seconds and contains %s tests with %s failures, %s errors, %s skipped and %s assert findings`, parsedXML.Title, parsedXML.System, parsedXML.ExecutedBy, parsedXML.Client, parsedXML.Timestamp, parsedXML.Time, parsedXML.Tests, parsedXML.Failures, parsedXML.Errors, parsedXML.Skipped, parsedXML.Asserts)
|
||||
for _, s := range parsedXML.Testsuite.Testcase {
|
||||
//Log Info for testcase
|
||||
for _, failure := range s.Failure {
|
||||
log.Entry().Debugf("%s, %s: %s found by %s", failure.Type, failure.Message, failure.Message, s.Classname)
|
||||
}
|
||||
|
||||
for _, skipped := range s.Skipped {
|
||||
log.Entry().Debugf("The following test has been skipped: %s: %s", skipped.Message, skipped.Text)
|
||||
}
|
||||
}
|
||||
//Persist findings afterwards
|
||||
var reports []piperutils.Path
|
||||
reports = append(reports, piperutils.Path{Target: aunitResultFileName, Name: "AUnit Results", Mandatory: true})
|
||||
piperutils.PersistReportsAndLinks("abapEnvironmentRunAUnitTest", "", reports, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Writing results failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// Object Set Structure
|
||||
//
|
||||
|
||||
//AUnitConfig object for parsing yaml config of software components and packages
|
||||
type AUnitConfig struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Context string `json:"context,omitempty"`
|
||||
Options AUnitOptions `json:"options,omitempty"`
|
||||
ObjectSet []ObjectSet `json:"objectset,omitempty"`
|
||||
}
|
||||
|
||||
//AUnitOptions in form of packages and software components to be checked
|
||||
type AUnitOptions struct {
|
||||
Measurements string `json:"measurements,omitempty"`
|
||||
Scope Scope `json:"scope,omitempty"`
|
||||
RiskLevel RiskLevel `json:"risklevel,omitempty"`
|
||||
Duration Duration `json:"duration,omitempty"`
|
||||
}
|
||||
|
||||
//Scope in form of packages and software components to be checked
|
||||
type Scope struct {
|
||||
OwnTests *bool `json:"owntests,omitempty"`
|
||||
ForeignTests *bool `json:"foreigntests,omitempty"`
|
||||
}
|
||||
|
||||
//RiskLevel in form of packages and software components to be checked
|
||||
type RiskLevel struct {
|
||||
Harmless *bool `json:"harmless,omitempty"`
|
||||
Dangerous *bool `json:"dangerous,omitempty"`
|
||||
Critical *bool `json:"critical,omitempty"`
|
||||
}
|
||||
|
||||
//Duration in form of packages and software components to be checked
|
||||
type Duration struct {
|
||||
Short *bool `json:"short,omitempty"`
|
||||
Medium *bool `json:"medium,omitempty"`
|
||||
Long *bool `json:"long,omitempty"`
|
||||
}
|
||||
|
||||
//ObjectSet in form of packages and software components to be checked
|
||||
type ObjectSet struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Set []Set `json:"set,omitempty"`
|
||||
}
|
||||
|
||||
//Set in form of packages and software components to be checked
|
||||
type Set struct {
|
||||
//Set []Set `json:"set,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
PackageSet []AUnitPackage `json:"package,omitempty"`
|
||||
FlatObjectSet []AUnitObject `json:"object,omitempty"`
|
||||
/*FlatSet []FlatObjectSet `json:"flatobjectset,omitempty"`
|
||||
ObjectTypeSet []ObjectTypeSet `json:"objecttypeset,omitempty"`
|
||||
ComponentSet []ComponentSet `json:"componentset,omitempty"`
|
||||
TransportSet []TransportSet `json:"transportset,omitempty"`*/
|
||||
}
|
||||
|
||||
//AUnitPackage in form of packages and software components to be checked
|
||||
type AUnitPackage struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
IncludeSubpackages *bool `json:"includesubpackages,omitempty"`
|
||||
}
|
||||
|
||||
//AUnitObject in form of packages and software components to be checked
|
||||
type AUnitObject struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
//
|
||||
// AUnit Run Structure
|
||||
//
|
||||
|
||||
//AUnitRun Object for parsing XML
|
||||
type AUnitRun struct {
|
||||
XMLName xml.Name `xml:"run"`
|
||||
Title string `xml:"title,attr"`
|
||||
Context string `xml:"context,attr"`
|
||||
Progress Progress `xml:"progress"`
|
||||
ExecutedBy ExecutedBy `xml:"executedBy"`
|
||||
Time Time `xml:"time"`
|
||||
Link AUnitLink `xml:"link"`
|
||||
}
|
||||
|
||||
//Progress of AUnit run
|
||||
type Progress struct {
|
||||
Status string `xml:"status,attr"`
|
||||
Percentage string `xml:"percentage,attr"`
|
||||
}
|
||||
|
||||
//ExecutedBy User
|
||||
type ExecutedBy struct {
|
||||
User string `xml:"user,attr"`
|
||||
}
|
||||
|
||||
//Time run was started and finished
|
||||
type Time struct {
|
||||
Started string `xml:"started,attr"`
|
||||
Ended string `xml:"ended,attr"`
|
||||
}
|
||||
|
||||
//AUnitLink containing result locations
|
||||
type AUnitLink struct {
|
||||
Href string `xml:"href,attr"`
|
||||
Rel string `xml:"rel,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
}
|
||||
|
||||
//
|
||||
// AUnit Result Structure
|
||||
//
|
||||
|
||||
type AUnitResult struct {
|
||||
XMLName xml.Name `xml:"testsuites"`
|
||||
Title string `xml:"title,attr"`
|
||||
System string `xml:"system,attr"`
|
||||
Client string `xml:"client,attr"`
|
||||
ExecutedBy string `xml:"executedBy,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
Timestamp string `xml:"timestamp,attr"`
|
||||
Failures string `xml:"failures,attr"`
|
||||
Errors string `xml:"errors,attr"`
|
||||
Skipped string `xml:"skipped,attr"`
|
||||
Asserts string `xml:"asserts,attr"`
|
||||
Tests string `xml:"tests,attr"`
|
||||
Testsuite struct {
|
||||
Tests string `xml:"tests,attr"`
|
||||
Asserts string `xml:"asserts,attr"`
|
||||
Skipped string `xml:"skipped,attr"`
|
||||
Errors string `xml:"errors,attr"`
|
||||
Failures string `xml:"failures,attr"`
|
||||
Timestamp string `xml:"timestamp,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
Hostname string `xml:"hostname,attr"`
|
||||
Package string `xml:"package,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
Testcase []struct {
|
||||
Asserts string `xml:"asserts,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
Classname string `xml:"classname,attr"`
|
||||
Error []struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type,attr"`
|
||||
Message string `xml:"message,attr"`
|
||||
} `xml:"error"`
|
||||
Failure []struct {
|
||||
Text string `xml:",chardata"`
|
||||
Type string `xml:"type,attr"`
|
||||
Message string `xml:"message,attr"`
|
||||
} `xml:"failure"`
|
||||
Skipped []struct {
|
||||
Text string `xml:",chardata"`
|
||||
Message string `xml:"message,attr"`
|
||||
} `xml:"skipped"`
|
||||
} `xml:"testcase"`
|
||||
} `xml:"testsuite"`
|
||||
}
|
254
cmd/abapEnvironmentRunAUnitTest_generated.go
Normal file
254
cmd/abapEnvironmentRunAUnitTest_generated.go
Normal file
@ -0,0 +1,254 @@
|
||||
// Code generated by piper's step-generator. DO NOT EDIT.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/splunk"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type abapEnvironmentRunAUnitTestOptions struct {
|
||||
AUnitConfig string `json:"aUnitConfig,omitempty"`
|
||||
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
|
||||
CfOrg string `json:"cfOrg,omitempty"`
|
||||
CfServiceInstance string `json:"cfServiceInstance,omitempty"`
|
||||
CfServiceKeyName string `json:"cfServiceKeyName,omitempty"`
|
||||
CfSpace string `json:"cfSpace,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
AUnitResultsFileName string `json:"aUnitResultsFileName,omitempty"`
|
||||
}
|
||||
|
||||
// AbapEnvironmentRunAUnitTestCommand Runs an AUnit Test
|
||||
func AbapEnvironmentRunAUnitTestCommand() *cobra.Command {
|
||||
const STEP_NAME = "abapEnvironmentRunAUnitTest"
|
||||
|
||||
metadata := abapEnvironmentRunAUnitTestMetadata()
|
||||
var stepConfig abapEnvironmentRunAUnitTestOptions
|
||||
var startTime time.Time
|
||||
var logCollector *log.CollectorHook
|
||||
|
||||
var createAbapEnvironmentRunAUnitTestCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "Runs an AUnit Test",
|
||||
Long: `This step is for triggering an [AUnit](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/cdd19e3a5c49458291ec65d8d86e2b9a.html) test run on an SAP BTP ABAP Environment system.
|
||||
Please provide either of the following options:
|
||||
|
||||
* The host and credentials of the BTP ABAP Environment system itself. The credentials must be configured for the Communication Scenario SAP_COM_0735.
|
||||
* The Cloud Foundry parameters (API endpoint, organization, space), credentials, the service instance for the ABAP service and the service key for the Communication Scenario SAP_COM_0735.
|
||||
* Only provide one of those options with the respective credentials. If all values are provided, the direct communication (via host) has priority.
|
||||
|
||||
Regardless of the option you chose, please make sure to provide the object set containing the objects that you want to be checked analog to the examples listed on this page.`,
|
||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||
startTime = time.Now()
|
||||
log.SetStepName(STEP_NAME)
|
||||
log.SetVerbose(GeneralConfig.Verbose)
|
||||
|
||||
GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens)
|
||||
|
||||
path, _ := os.Getwd()
|
||||
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
|
||||
log.RegisterHook(fatalHook)
|
||||
|
||||
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
log.RegisterSecret(stepConfig.Username)
|
||||
log.RegisterSecret(stepConfig.Password)
|
||||
|
||||
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
|
||||
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
|
||||
log.RegisterHook(&sentryHook)
|
||||
}
|
||||
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
|
||||
log.RegisterHook(logCollector)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
telemetryData := telemetry.CustomData{}
|
||||
telemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
config.RemoveVaultSecretFiles()
|
||||
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
telemetryData.ErrorCategory = log.GetErrorCategory().String()
|
||||
telemetry.Send(&telemetryData)
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunk.Send(&telemetryData, logCollector)
|
||||
}
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
|
||||
splunk.Initialize(GeneralConfig.CorrelationID,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Dsn,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Token,
|
||||
GeneralConfig.HookConfig.SplunkConfig.Index,
|
||||
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
|
||||
}
|
||||
abapEnvironmentRunAUnitTest(stepConfig, &telemetryData)
|
||||
telemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addAbapEnvironmentRunAUnitTestFlags(createAbapEnvironmentRunAUnitTestCmd, &stepConfig)
|
||||
return createAbapEnvironmentRunAUnitTestCmd
|
||||
}
|
||||
|
||||
func addAbapEnvironmentRunAUnitTestFlags(cmd *cobra.Command, stepConfig *abapEnvironmentRunAUnitTestOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.AUnitConfig, "aUnitConfig", os.Getenv("PIPER_aUnitConfig"), "Path to a YAML configuration file for the object set to be checked during the AUnit test run")
|
||||
cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API endpoint")
|
||||
cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "Cloud Foundry org")
|
||||
cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Parameter of ServiceInstance Name to delete Cloud Foundry Service")
|
||||
cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Parameter of Cloud Foundry Service Key to be created")
|
||||
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry Space")
|
||||
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0735")
|
||||
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0735")
|
||||
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system")
|
||||
cmd.Flags().StringVar(&stepConfig.AUnitResultsFileName, "aUnitResultsFileName", `AUnitResults.xml`, "Specifies output file name for the results from the AUnit run.")
|
||||
|
||||
cmd.MarkFlagRequired("aUnitConfig")
|
||||
cmd.MarkFlagRequired("username")
|
||||
cmd.MarkFlagRequired("password")
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func abapEnvironmentRunAUnitTestMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "abapEnvironmentRunAUnitTest",
|
||||
Aliases: []config.Alias{},
|
||||
Description: "Runs an AUnit Test",
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Secrets: []config.StepSecrets{
|
||||
{Name: "abapCredentialsId", Description: "Jenkins credentials ID containing user and password to authenticate to the BTP ABAP Environment system or the Cloud Foundry API", Type: "jenkins", Aliases: []config.Alias{{Name: "cfCredentialsId", Deprecated: false}}},
|
||||
},
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "aUnitConfig",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_aUnitConfig"),
|
||||
},
|
||||
{
|
||||
Name: "cfApiEndpoint",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/apiEndpoint"}},
|
||||
Default: os.Getenv("PIPER_cfApiEndpoint"),
|
||||
},
|
||||
{
|
||||
Name: "cfOrg",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/org"}},
|
||||
Default: os.Getenv("PIPER_cfOrg"),
|
||||
},
|
||||
{
|
||||
Name: "cfServiceInstance",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/serviceInstance"}},
|
||||
Default: os.Getenv("PIPER_cfServiceInstance"),
|
||||
},
|
||||
{
|
||||
Name: "cfServiceKeyName",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}},
|
||||
Default: os.Getenv("PIPER_cfServiceKeyName"),
|
||||
},
|
||||
{
|
||||
Name: "cfSpace",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "cloudFoundry/space"}},
|
||||
Default: os.Getenv("PIPER_cfSpace"),
|
||||
},
|
||||
{
|
||||
Name: "username",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "abapCredentialsId",
|
||||
Param: "username",
|
||||
Type: "secret",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_username"),
|
||||
},
|
||||
{
|
||||
Name: "password",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "abapCredentialsId",
|
||||
Param: "password",
|
||||
Type: "secret",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS2"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_password"),
|
||||
},
|
||||
{
|
||||
Name: "host",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_host"),
|
||||
},
|
||||
{
|
||||
Name: "aUnitResultsFileName",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: `AUnitResults.xml`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []config.Container{
|
||||
{Name: "cf", Image: "ppiper/cf-cli:7"},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
17
cmd/abapEnvironmentRunAUnitTest_generated_test.go
Normal file
17
cmd/abapEnvironmentRunAUnitTest_generated_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAbapEnvironmentRunAUnitTestCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCmd := AbapEnvironmentRunAUnitTestCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procedure
|
||||
assert.Equal(t, "abapEnvironmentRunAUnitTest", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
437
cmd/abapEnvironmentRunAUnitTest_test.go
Normal file
437
cmd/abapEnvironmentRunAUnitTest_test.go
Normal file
@ -0,0 +1,437 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/abaputils"
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type abapEnvironmentRunAUnitTestMockUtils struct {
|
||||
*mock.ExecMockRunner
|
||||
*mock.FilesMock
|
||||
}
|
||||
|
||||
func newAbapEnvironmentRunAUnitTestTestsUtils() abapEnvironmentRunAUnitTestMockUtils {
|
||||
utils := abapEnvironmentRunAUnitTestMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
return utils
|
||||
}
|
||||
|
||||
func TestBuildAUnitTestBody(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Test AUnit test run body with no data", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expectedmetadataString := ""
|
||||
expectedoptionsString := ""
|
||||
expectedobjectSetString := ""
|
||||
|
||||
var err error
|
||||
var config AUnitConfig
|
||||
var metadataString, optionsString, objectSetString string
|
||||
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(config)
|
||||
|
||||
assert.Equal(t, expectedmetadataString, metadataString)
|
||||
assert.Equal(t, expectedoptionsString, optionsString)
|
||||
assert.Equal(t, expectedobjectSetString, objectSetString)
|
||||
assert.EqualError(t, err, "Error while parsing AUnit test run config. No title for the AUnit run has been provided. Please configure an appropriate title for the respective test run")
|
||||
})
|
||||
|
||||
t.Run("Test AUnit test run body with example yaml config", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expectedmetadataString := `<aunit:run title="Test Title" context="Test Context" xmlns:aunit="http://www.sap.com/adt/api/aunit">`
|
||||
expectedoptionsString := `<aunit:options><aunit:measurements type="none"/><aunit:scope ownTests="false" foreignTests="false"/><aunit:riskLevel harmless="false" dangerous="false" critical="false"/><aunit:duration short="false" medium="false" long="false"/></aunit:options>`
|
||||
expectedobjectSetString := `<osl:objectSet xsi:type="testSet" xmlns:osl="http://www.sap.com/api/osl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><osl:set xsi:type="testSet"><osl:package name="TestPackage" includeSubpackages="false"/><osl:package name="TestObject" includeSubpackages="CLAS"/></osl:set></osl:objectSet>`
|
||||
|
||||
var err error
|
||||
var config AUnitConfig
|
||||
|
||||
config = AUnitConfig{
|
||||
Title: "Test Title",
|
||||
Context: "Test Context",
|
||||
Options: AUnitOptions{
|
||||
Measurements: "none",
|
||||
Scope: Scope{
|
||||
OwnTests: new(bool),
|
||||
ForeignTests: new(bool),
|
||||
},
|
||||
RiskLevel: RiskLevel{
|
||||
Harmless: new(bool),
|
||||
Dangerous: new(bool),
|
||||
Critical: new(bool),
|
||||
},
|
||||
Duration: Duration{
|
||||
Short: new(bool),
|
||||
Medium: new(bool),
|
||||
Long: new(bool),
|
||||
},
|
||||
},
|
||||
ObjectSet: []ObjectSet{{
|
||||
Type: "testSet",
|
||||
Set: []Set{{
|
||||
Type: "testSet",
|
||||
PackageSet: []AUnitPackage{{
|
||||
Name: "TestPackage",
|
||||
IncludeSubpackages: new(bool),
|
||||
}},
|
||||
FlatObjectSet: []AUnitObject{{
|
||||
Name: "TestObject",
|
||||
Type: "CLAS",
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
|
||||
var metadataString, optionsString, objectSetString string
|
||||
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(config)
|
||||
|
||||
assert.Equal(t, expectedmetadataString, metadataString)
|
||||
assert.Equal(t, expectedoptionsString, optionsString)
|
||||
assert.Equal(t, expectedobjectSetString, objectSetString)
|
||||
assert.Equal(t, nil, err)
|
||||
//assert.EqualError(t, err, "Error while parsing AUnit test run config. No title for the AUnit run has been provided. Please configure an appropriate title for the respective test run")
|
||||
})
|
||||
|
||||
t.Run("Test AUnit test run body with example yaml config fail: no Title", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expectedmetadataString := ""
|
||||
expectedoptionsString := ""
|
||||
expectedobjectSetString := ""
|
||||
|
||||
var err error
|
||||
var config AUnitConfig
|
||||
|
||||
config = AUnitConfig{}
|
||||
|
||||
var metadataString, optionsString, objectSetString string
|
||||
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(config)
|
||||
|
||||
assert.Equal(t, expectedmetadataString, metadataString)
|
||||
assert.Equal(t, expectedoptionsString, optionsString)
|
||||
assert.Equal(t, expectedobjectSetString, objectSetString)
|
||||
assert.EqualError(t, err, "Error while parsing AUnit test run config. No title for the AUnit run has been provided. Please configure an appropriate title for the respective test run")
|
||||
})
|
||||
|
||||
t.Run("Test AUnit test run body with example yaml config fail: no Context", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expectedmetadataString := ""
|
||||
expectedoptionsString := ""
|
||||
expectedobjectSetString := ""
|
||||
|
||||
var err error
|
||||
var config AUnitConfig
|
||||
|
||||
config = AUnitConfig{Title: "Test"}
|
||||
|
||||
var metadataString, optionsString, objectSetString string
|
||||
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(config)
|
||||
|
||||
assert.Equal(t, expectedmetadataString, metadataString)
|
||||
assert.Equal(t, expectedoptionsString, optionsString)
|
||||
assert.Equal(t, expectedobjectSetString, objectSetString)
|
||||
assert.EqualError(t, err, "Error while parsing AUnit test run config. No context for the AUnit run has been provided. Please configure an appropriate context for the respective test run")
|
||||
})
|
||||
|
||||
t.Run("Test AUnit test run body with example yaml config fail: no Options", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expectedmetadataString := ""
|
||||
expectedoptionsString := ""
|
||||
expectedobjectSetString := ""
|
||||
|
||||
var err error
|
||||
var config AUnitConfig
|
||||
|
||||
config = AUnitConfig{Title: "Test", Context: "Test"}
|
||||
|
||||
var metadataString, optionsString, objectSetString string
|
||||
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(config)
|
||||
|
||||
assert.Equal(t, expectedmetadataString, metadataString)
|
||||
assert.Equal(t, expectedoptionsString, optionsString)
|
||||
assert.Equal(t, expectedobjectSetString, objectSetString)
|
||||
assert.EqualError(t, err, "Error while parsing AUnit test run config. No options have been provided. Please configure the options for the respective test run")
|
||||
})
|
||||
|
||||
t.Run("Test AUnit test run body with example yaml config fail: no ObjectSet", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
expectedmetadataString := ""
|
||||
expectedoptionsString := ""
|
||||
expectedobjectSetString := ""
|
||||
|
||||
var err error
|
||||
var config AUnitConfig
|
||||
|
||||
config = AUnitConfig{Title: "Test", Context: "Test", Options: AUnitOptions{Measurements: "Test"}}
|
||||
|
||||
var metadataString, optionsString, objectSetString string
|
||||
|
||||
metadataString, optionsString, objectSetString, err = buildAUnitTestBody(config)
|
||||
|
||||
assert.Equal(t, expectedmetadataString, metadataString)
|
||||
assert.Equal(t, expectedoptionsString, optionsString)
|
||||
assert.Equal(t, expectedobjectSetString, objectSetString)
|
||||
assert.EqualError(t, err, "Error while parsing AUnit test run object set config. No object set has been provided. Please configure the set of objects you want to be checked for the respective test run")
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseAUnitResult(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("succes case: test parsing example XML result", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir, err := ioutil.TempDir("", "test get result AUnit test run")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create temporary directory")
|
||||
}
|
||||
oldCWD, _ := os.Getwd()
|
||||
_ = os.Chdir(dir)
|
||||
// clean up tmp dir
|
||||
defer func() {
|
||||
_ = os.Chdir(oldCWD)
|
||||
_ = os.RemoveAll(dir)
|
||||
}()
|
||||
bodyString := `<?xml version="1.0" encoding="utf-8"?><testsuites title="My AUnit run" system="TST" client="100" executedBy="TESTUSER" time="000.000" timestamp="2021-01-01T00:00:00Z" failures="2" errors="2" skipped="0" asserts="0" tests="2"><testsuite name="" tests="2" failures="2" errors="0" skipped="0" asserts="0" package="testpackage" timestamp="2021-01-01T00:00:00ZZ" time="0.000" hostname="test"><testcase classname="test" name="execute" time="0.000" asserts="2"><failure message="testMessage1" type="Assert Failure">Test1</failure><failure message="testMessage2" type="Assert Failure">Test2</failure></testcase></testsuite></testsuites>`
|
||||
body := []byte(bodyString)
|
||||
err = parseAUnitResult(body, "AUnitResults.xml")
|
||||
assert.Equal(t, nil, err)
|
||||
})
|
||||
|
||||
t.Run("succes case: test parsing empty AUnit run XML result", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir, err := ioutil.TempDir("", "test get result AUnit test run")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create temporary directory")
|
||||
}
|
||||
oldCWD, _ := os.Getwd()
|
||||
_ = os.Chdir(dir)
|
||||
// clean up tmp dir
|
||||
defer func() {
|
||||
_ = os.Chdir(oldCWD)
|
||||
_ = os.RemoveAll(dir)
|
||||
}()
|
||||
bodyString := `<?xml version="1.0" encoding="UTF-8"?>`
|
||||
body := []byte(bodyString)
|
||||
err = parseAUnitResult(body, "AUnitResults.xml")
|
||||
assert.Equal(t, nil, err)
|
||||
})
|
||||
|
||||
t.Run("failure case: parsing empty xml", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var bodyString string
|
||||
body := []byte(bodyString)
|
||||
|
||||
err := parseAUnitResult(body, "AUnitResults.xml")
|
||||
assert.EqualError(t, err, "Parsing AUnit result failed: Body is empty, can't parse empty body")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetResultAUnitRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Get HTTP Response from AUnit test run Test", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `AUnit test result body`,
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
resp, err := getResultAUnitRun("GET", con, []byte(client.Body), client)
|
||||
defer resp.Body.Close()
|
||||
if assert.Equal(t, nil, err) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(resp.Body)
|
||||
newStr := buf.String()
|
||||
assert.Equal(t, "AUnit test result body", newStr)
|
||||
assert.Equal(t, int64(0), resp.ContentLength)
|
||||
assert.Equal(t, []string([]string(nil)), resp.Header["X-Crsf-Token"])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Get HTTP Response from AUnit test run Test Failure", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `AUnit test result body`,
|
||||
BodyList: []string{},
|
||||
StatusCode: 400,
|
||||
Error: fmt.Errorf("%w", errors.New("Test fail")),
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
resp, err := getResultAUnitRun("GET", con, []byte(client.Body), client)
|
||||
defer resp.Body.Close()
|
||||
if assert.EqualError(t, err, "Getting AUnit run results failed: Test fail") {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(resp.Body)
|
||||
newStr := buf.String()
|
||||
assert.Equal(t, "AUnit test result body", newStr)
|
||||
assert.Equal(t, int64(0), resp.ContentLength)
|
||||
assert.Equal(t, 400, resp.StatusCode)
|
||||
assert.Equal(t, []string([]string(nil)), resp.Header["X-Crsf-Token"])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunAbapEnvironmentRunAUnitTest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
/*
|
||||
t.Parallel()
|
||||
// init
|
||||
config := abapEnvironmentRunAUnitTestOptions{}
|
||||
|
||||
utils := newAbapEnvironmentRunAUnitTestTestsUtils()
|
||||
utils.AddFile("file.txt", []byte("dummy content"))
|
||||
|
||||
// test
|
||||
err := runAbapEnvironmentRunAUnitTest(&config, nil, nil, utils)
|
||||
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
*/
|
||||
})
|
||||
|
||||
t.Run("FetchXcsrfToken Test", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tokenExpected := "myToken"
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `Xcsrf Token test`,
|
||||
Token: tokenExpected,
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
token, error := fetchAUnitXcsrfToken("GET", con, []byte(client.Body), client)
|
||||
if assert.Equal(t, nil, error) {
|
||||
assert.Equal(t, tokenExpected, token)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("failure case: fetch token", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tokenExpected := ""
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `Xcsrf Token test`,
|
||||
Token: "",
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
token, error := fetchAUnitXcsrfToken("GET", con, []byte(client.Body), client)
|
||||
if assert.Equal(t, nil, error) {
|
||||
assert.Equal(t, tokenExpected, token)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("AUnit test run Poll Test", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tokenExpected := "myToken"
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `<?xml version="1.0" encoding="utf-8"?><aunit:run xmlns:aunit="http://www.sap.com/adt/api/aunit"><aunit:progress status="FINISHED"/><aunit:time/><atom:link href="/sap/bc/adt/api/abapunit/results/test" rel="http://www.sap.com/adt/relations/api/abapunit/run-result" type="application/vnd.sap.adt.api.junit.run-result.v1+xml" title="JUnit Run Result" xmlns:atom="http://www.w3.org/2005/Atom"/></aunit:run>`,
|
||||
Token: tokenExpected,
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
resp, err := pollAUnitRun(con, []byte(client.Body), client)
|
||||
if assert.Equal(t, nil, err) {
|
||||
assert.Equal(t, "/sap/bc/adt/api/abapunit/results/test", resp)
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("AUnit test run Poll Test Fail", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tokenExpected := "myToken"
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `<?xml version="1.0" encoding="utf-8"?><aunit:run xmlns:aunit="http://www.sap.com/adt/api/aunit"><aunit:progress status="Not Created"/><aunit:time/><atom:link href="/sap/bc/adt/api/abapunit/results/test" rel="http://www.sap.com/adt/relations/api/abapunit/run-result" type="application/vnd.sap.adt.api.junit.run-result.v1+xml" title="JUnit Run Result" xmlns:atom="http://www.w3.org/2005/Atom"/></aunit:run>`,
|
||||
Token: tokenExpected,
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
resp, err := pollAUnitRun(con, []byte(client.Body), client)
|
||||
if assert.Equal(t, nil, err) {
|
||||
assert.Equal(t, "", resp)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Get HTTP Response from AUnit test run Test", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := &abaputils.ClientMock{
|
||||
Body: `HTTP response test`,
|
||||
}
|
||||
|
||||
con := abaputils.ConnectionDetailsHTTP{
|
||||
User: "Test",
|
||||
Password: "Test",
|
||||
URL: "https://api.endpoint.com/Entity/",
|
||||
}
|
||||
fmt.Println("Body:" + string([]byte(client.Body)))
|
||||
resp, err := getHTTPResponseAUnitRun("GET", con, []byte(client.Body), client)
|
||||
defer resp.Body.Close()
|
||||
if assert.Equal(t, nil, err) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(resp.Body)
|
||||
newStr := buf.String()
|
||||
assert.Equal(t, "HTTP response test", newStr)
|
||||
assert.Equal(t, int64(0), resp.ContentLength)
|
||||
assert.Equal(t, []string([]string(nil)), resp.Header["X-Crsf-Token"])
|
||||
}
|
||||
})
|
||||
}
|
@ -21,6 +21,7 @@ func GetAllStepMetadata() map[string]config.StepData {
|
||||
"abapEnvironmentCreateSystem": abapEnvironmentCreateSystemMetadata(),
|
||||
"abapEnvironmentPullGitRepo": abapEnvironmentPullGitRepoMetadata(),
|
||||
"abapEnvironmentRunATCCheck": abapEnvironmentRunATCCheckMetadata(),
|
||||
"abapEnvironmentRunAUnitTest": abapEnvironmentRunAUnitTestMetadata(),
|
||||
"batsExecuteTests": batsExecuteTestsMetadata(),
|
||||
"checkChangeInDevelopment": checkChangeInDevelopmentMetadata(),
|
||||
"checkmarxExecuteScan": checkmarxExecuteScanMetadata(),
|
||||
|
@ -163,6 +163,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(WritePipelineEnv())
|
||||
rootCmd.AddCommand(ReadPipelineEnv())
|
||||
rootCmd.AddCommand(InfluxWriteDataCommand())
|
||||
rootCmd.AddCommand(AbapEnvironmentRunAUnitTestCommand())
|
||||
rootCmd.AddCommand(CheckStepActiveCommand())
|
||||
|
||||
addRootFlags(rootCmd)
|
||||
|
144
documentation/docs/steps/abapEnvironmentRunAUnitTest.md
Normal file
144
documentation/docs/steps/abapEnvironmentRunAUnitTest.md
Normal file
@ -0,0 +1,144 @@
|
||||
# ${docGenStepName}
|
||||
|
||||
## ${docGenDescription}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* A SAP BTP, ABAP environment system is available. On this system, a [Communication User](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/0377adea0401467f939827242c1f4014.html), a [Communication System](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/1bfe32ae08074b7186e375ab425fb114.html) and a [Communication Arrangement](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/a0771f6765f54e1c8193ad8582a32edb.html) is setup for the Communication Scenario “SAP BTP, ABAP Environment - Software Component Test Integration (SAP_COM_0735)“. This can be done manually through the respective applications on the SAP BTP, ABAP environment system or through creating a Service Key for the system on Cloud Foundry with the parameters {“scenario_id”: “SAP_COM_0735", “type”: “basic”}. In a pipeline, you can do this with the step [cloudFoundryCreateServiceKey](https://sap.github.io/jenkins-library/steps/cloudFoundryCreateServiceKey/).
|
||||
* You can either provide the ABAP endpoint configuration to directly trigger an AUnit run on the ABAP system or optionally provide the Cloud Foundry parameters with your credentials to read a Service Key of a SAP BTP, ABAP environment system in Cloud Foundry that contains all the details of the ABAP endpoint to trigger an AUnit run.
|
||||
* Regardless if you chose an ABAP endpoint directly or reading a Cloud Foundry Service Key, you have to provide the object set containing the objects you want to be checked in an AUnit run in a .yml or .yaml file. This file must be stored in the same folder as the Jenkinsfile defining the pipeline.
|
||||
* Make sure that the objects contained in the object set are present in the configured system in order to run the check. Please make sure that you have created or pulled the respective software components and/or packages including the test classes and objects in the SAP BTP, ABAP environment system, that should be checked.
|
||||
|
||||
## ${docGenParameters}
|
||||
|
||||
## ${docGenConfiguration}
|
||||
|
||||
## ${docJenkinsPluginDependencies}
|
||||
|
||||
## Examples
|
||||
|
||||
### AUnit test run via direct ABAP endpoint configuration in Jenkinsfile
|
||||
|
||||
This example triggers an AUnit test run directly on the ABAP endpoint.
|
||||
|
||||
In order to trigger the AUnit test run you have to pass the username and password for authentication to the ABAP endpoint via parameters as well as the ABAP endpoint/host. You can store the credentials in Jenkins and use the abapCredentialsId parameter to authenticate to the ABAP endpoint/host.
|
||||
|
||||
This must be configured as following:
|
||||
|
||||
```groovy
|
||||
abapEnvironmentRunAUnitTest(
|
||||
abapCredentialsId: 'abapCredentialsId',
|
||||
host: 'https://myABAPendpoint.com',
|
||||
aUnitConfig: 'aUnitConfig.yml',
|
||||
script: this,
|
||||
)
|
||||
```
|
||||
|
||||
To trigger the AUnit test run an AUnit config file `aUnitConfig.yml` will be needed. Check the section 'AUnit config file example' for more information.
|
||||
|
||||
### AUnit test run via Cloud Foundry Service Key example in Jenkinsfile
|
||||
|
||||
The following example triggers an AUnit test run via reading the Service Key of an ABAP instance in Cloud Foundry.
|
||||
|
||||
You can store the credentials in Jenkins and use the cfCredentialsId parameter to authenticate to Cloud Foundry.
|
||||
The username and password to authenticate to ABAP system will then be read from the Cloud Foundry Service Key that is bound to the ABAP instance.
|
||||
|
||||
This can be done accordingly:
|
||||
|
||||
```groovy
|
||||
abapEnvironmentRunAUnitTest(
|
||||
cfApiEndpoint : 'https://test.server.com',
|
||||
cfOrg : 'cfOrg',
|
||||
cfSpace: 'cfSpace',
|
||||
cfServiceInstance: 'myServiceInstance',
|
||||
cfServiceKeyName: 'myServiceKey',
|
||||
abapCredentialsId: 'cfCredentialsId',
|
||||
aUnitConfig: 'aUnitConfig.yml',
|
||||
script: this,
|
||||
)
|
||||
```
|
||||
|
||||
To trigger the AUnit test run an AUnit config file `aUnitConfig.yml` will be needed. Check the section 'AUnit config file example' for more information.
|
||||
|
||||
### AUnit test run via direct ABAP endpoint configuration in Jenkinsfile
|
||||
|
||||
This example triggers an AUnit run directly on the ABAP endpoint.
|
||||
|
||||
In order to trigger the AUnit run you have to pass the username and password for authentication to the ABAP endpoint via parameters as well as the ABAP endpoint/host. You can store the credentials in Jenkins and use the abapCredentialsId parameter to authenticate to the ABAP endpoint/host.
|
||||
|
||||
This must be configured as following:
|
||||
|
||||
```groovy
|
||||
abapEnvironmentRunAUnitTest(
|
||||
abapCredentialsId: 'abapCredentialsId',
|
||||
host: 'https://myABAPendpoint.com',
|
||||
aUnitConfig: 'aUnitConfig.yml',
|
||||
script: this,
|
||||
)
|
||||
```
|
||||
|
||||
To trigger the AUnit run an AUnit config file `aUnitConfig.yml` will be needed. Check section 'AUnit config file example' for more information.
|
||||
|
||||
### AUnit config file example
|
||||
|
||||
The following section contains an example of an `aUnitConfig.yml` file.
|
||||
This file must be stored in the same Git folder where the `Jenkinsfile` is stored to run the pipeline. This repository containing the `Jenkinsfile` must be taken as a SCM in the Jenkins pipeline to run the pipeline.
|
||||
|
||||
You can specify an object set containing the objects that should be checked. These can be for example packages, classes or transport requests containing test classes that can be executed. This must be in the same format as below example for a `aUnitConfig.yml` file.
|
||||
Note that if you specify a package inside a packageSet to be checked for each package that has to be checked you can configure if you want the subpackages to be included in checks or not.
|
||||
|
||||
See below example for an `aUnitConfig.yml` file containing a package to be checked:
|
||||
|
||||
```yaml
|
||||
title: My AUnit run
|
||||
context: My unit tests
|
||||
options:
|
||||
measurements: none
|
||||
scope:
|
||||
owntests: true
|
||||
foreigntests: true
|
||||
riskLevel:
|
||||
harmless: true
|
||||
dangerous: true
|
||||
critical: true
|
||||
duration:
|
||||
short: true
|
||||
medium: true
|
||||
long: true
|
||||
objectset:
|
||||
- type: unionSet
|
||||
set:
|
||||
- type: packageSet
|
||||
package:
|
||||
- name: my_package
|
||||
includesubpackages: false
|
||||
```
|
||||
|
||||
The following example of an `aUnitConfig.yml` file containing one class and one interface to be checked:
|
||||
|
||||
```yaml
|
||||
title: My AUnit run
|
||||
context: My unit tests
|
||||
options:
|
||||
measurements: none
|
||||
scope:
|
||||
owntests: true
|
||||
foreigntests: true
|
||||
riskLevel:
|
||||
harmless: true
|
||||
dangerous: true
|
||||
critical: true
|
||||
duration:
|
||||
short: true
|
||||
medium: true
|
||||
long: true
|
||||
objectset:
|
||||
- type: unionSet
|
||||
set:
|
||||
- type: flatObjectSet
|
||||
object:
|
||||
- name: my_class
|
||||
type: CLAS
|
||||
- name: my_interface
|
||||
type: INTF
|
||||
```
|
133
resources/metadata/abapEnvironmentRunAUnitTest.yaml
Normal file
133
resources/metadata/abapEnvironmentRunAUnitTest.yaml
Normal file
@ -0,0 +1,133 @@
|
||||
metadata:
|
||||
name: abapEnvironmentRunAUnitTest
|
||||
description: Runs an AUnit Test
|
||||
longDescription: |
|
||||
This step is for triggering an [AUnit](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/cdd19e3a5c49458291ec65d8d86e2b9a.html) test run on an SAP BTP ABAP Environment system.
|
||||
Please provide either of the following options:
|
||||
|
||||
* The host and credentials of the BTP ABAP Environment system itself. The credentials must be configured for the Communication Scenario SAP_COM_0735.
|
||||
* The Cloud Foundry parameters (API endpoint, organization, space), credentials, the service instance for the ABAP service and the service key for the Communication Scenario SAP_COM_0735.
|
||||
* Only provide one of those options with the respective credentials. If all values are provided, the direct communication (via host) has priority.
|
||||
|
||||
Regardless of the option you chose, please make sure to provide the object set containing the objects that you want to be checked analog to the examples listed on this page.
|
||||
spec:
|
||||
inputs:
|
||||
secrets:
|
||||
- name: abapCredentialsId
|
||||
aliases:
|
||||
- name: cfCredentialsId
|
||||
description: Jenkins credentials ID containing user and password to authenticate to the BTP ABAP Environment system or the Cloud Foundry API
|
||||
type: jenkins
|
||||
params:
|
||||
- name: aUnitConfig
|
||||
type: string
|
||||
description: Path to a YAML configuration file for the object set to be checked during the AUnit test run
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
mandatory: true
|
||||
- name: cfApiEndpoint
|
||||
type: string
|
||||
description: Cloud Foundry API endpoint
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/apiEndpoint
|
||||
- name: cfOrg
|
||||
type: string
|
||||
description: Cloud Foundry org
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/org
|
||||
- name: cfServiceInstance
|
||||
type: string
|
||||
description: Parameter of ServiceInstance Name to delete Cloud Foundry Service
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/serviceInstance
|
||||
- name: cfServiceKeyName
|
||||
type: string
|
||||
description: Parameter of Cloud Foundry Service Key to be created
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/serviceKey
|
||||
- name: cloudFoundry/serviceKeyName
|
||||
- name: cfServiceKey
|
||||
- name: cfSpace
|
||||
type: string
|
||||
description: Cloud Foundry Space
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
aliases:
|
||||
- name: cloudFoundry/space
|
||||
- name: username
|
||||
type: string
|
||||
description: User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0735
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
mandatory: true
|
||||
secret: true
|
||||
resourceRef:
|
||||
- name: abapCredentialsId
|
||||
type: secret
|
||||
param: username
|
||||
- name: password
|
||||
type: string
|
||||
description: Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0735
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS2
|
||||
mandatory: true
|
||||
secret: true
|
||||
resourceRef:
|
||||
- name: abapCredentialsId
|
||||
type: secret
|
||||
param: password
|
||||
- name: host
|
||||
type: string
|
||||
description: Specifies the host address of the SAP BTP ABAP Environment system
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- GENERAL
|
||||
mandatory: false
|
||||
- name: aUnitResultsFileName
|
||||
type: string
|
||||
description: Specifies output file name for the results from the AUnit run.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
mandatory: false
|
||||
default: "AUnitResults.xml"
|
||||
containers:
|
||||
- name: cf
|
||||
image: ppiper/cf-cli:7
|
@ -120,6 +120,7 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
'abapEnvironmentPullGitRepo', //implementing new golang pattern without fields
|
||||
'abapEnvironmentPipeline', // special step (infrastructure)
|
||||
'abapEnvironmentRunATCCheck', //implementing new golang pattern without fields
|
||||
'abapEnvironmentRunAUnitTest', //implementing new golang pattern without fields
|
||||
'abapEnvironmentCreateSystem', //implementing new golang pattern without fields
|
||||
'artifactPrepareVersion',
|
||||
'cloudFoundryCreateService', //implementing new golang pattern without fields
|
||||
|
11
vars/abapEnvironmentRunAUnitTest.groovy
Normal file
11
vars/abapEnvironmentRunAUnitTest.groovy
Normal file
@ -0,0 +1,11 @@
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
@Field String METADATA_FILE = 'metadata/abapEnvironmentRunAUnitTest.yaml'
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
List credentials = [
|
||||
[type: 'usernamePassword', id: 'abapCredentialsId', env: ['PIPER_username', 'PIPER_password']]
|
||||
]
|
||||
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, true, false, true)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user