//go:build unit // +build unit package cmd import ( "bytes" "encoding/xml" "errors" "fmt" "os" "testing" "github.com/SAP/jenkins-library/pkg/abaputils" "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" ) func TestBuildAUnitRequestBody(t *testing.T) { t.Parallel() t.Run("Test AUnit test run body with no data", func(t *testing.T) { t.Parallel() var config abapEnvironmentRunAUnitTestOptions bodyString, err := buildAUnitRequestBody(config) expectedBodyString := "" assert.Equal(t, expectedBodyString, bodyString) assert.EqualError(t, err, "No configuration provided - please provide either an AUnit configuration file or a repository configuration file") }) t.Run("Test AUnit test run body with example yaml config of not supported Object Sets", func(t *testing.T) { t.Parallel() expectedoptionsString := `` expectedobjectSetString := `` 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: abaputils.ObjectSet{ Type: "testSet", Set: []abaputils.Set{ { Type: "testSet", Set: []abaputils.Set{ { Type: "testAUnitFlatObjectSet", FlatObjectSet: []abaputils.FlatObjectSet{ { Name: "TestCLAS", Type: "CLAS", }, { Name: "TestINTF", Type: "INTF", }, }, }, { Type: "testAUnitObjectTypeSet", ObjectTypeSet: []abaputils.ObjectTypeSet{ { Name: "TestObjectType", }, }, }, }, }, }, }, } objectSetString := abaputils.BuildOSLString(config.ObjectSet) optionsString := buildAUnitOptionsString(config) assert.Equal(t, expectedoptionsString, optionsString) assert.Equal(t, expectedobjectSetString, objectSetString) }) t.Run("Test AUnit test run body with example yaml config of only Multi Property Set", func(t *testing.T) { t.Parallel() expectedoptionsString := `` expectedobjectSetString := `` 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: abaputils.ObjectSet{ Type: "multiPropertySet", MultiPropertySet: abaputils.MultiPropertySet{ SoftwareComponents: []abaputils.SoftwareComponents{ { Name: "testComponent1", }, { Name: "testComponent2", }, }, }, }, } objectSetString := abaputils.BuildOSLString(config.ObjectSet) optionsString := buildAUnitOptionsString(config) assert.Equal(t, expectedoptionsString, optionsString) assert.Equal(t, expectedobjectSetString, objectSetString) }) t.Run("Test AUnit test run body with example yaml config of only Multi Property Set but empty type", func(t *testing.T) { t.Parallel() expectedoptionsString := `` expectedobjectSetString := `` 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: abaputils.ObjectSet{ Type: "", MultiPropertySet: abaputils.MultiPropertySet{ SoftwareComponents: []abaputils.SoftwareComponents{ { Name: "testComponent1", }, { Name: "testComponent2", }, }, }, }, } objectSetString := abaputils.BuildOSLString(config.ObjectSet) optionsString := buildAUnitOptionsString(config) assert.Equal(t, expectedoptionsString, optionsString) assert.Equal(t, expectedobjectSetString, objectSetString) }) t.Run("Test AUnit test run body with example yaml config of only Multi Property Set with scomps & packages on top level", func(t *testing.T) { t.Parallel() expectedoptionsString := `` expectedobjectSetString := `` 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: abaputils.ObjectSet{ PackageNames: []abaputils.Package{{ Name: "testPackage1", }, { Name: "testPackage2", }}, SoftwareComponents: []abaputils.SoftwareComponents{{ Name: "testComponent1", }, { Name: "testComponent2", }}, }, } objectSetString := abaputils.BuildOSLString(config.ObjectSet) optionsString := buildAUnitOptionsString(config) assert.Equal(t, expectedoptionsString, optionsString) assert.Equal(t, expectedobjectSetString, objectSetString) }) t.Run("Test AUnit test run body with example yaml config: no Options", func(t *testing.T) { t.Parallel() expectedoptionsString := `` config := AUnitConfig{ Title: "Test", Context: "Test", ObjectSet: abaputils.ObjectSet{ PackageNames: []abaputils.Package{{ Name: "testPackage1", }}, SoftwareComponents: []abaputils.SoftwareComponents{{ Name: "testComponent1", }}, }, } optionsString := buildAUnitOptionsString(config) assert.Equal(t, expectedoptionsString, optionsString) }) t.Run("Config with repository-yml", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ AUnitResultsFileName: "aUnitResults.xml", Repositories: "repositories.yml", } dir := t.TempDir() oldCWD, _ := os.Getwd() _ = os.Chdir(dir) // clean up tmp dir defer func() { _ = os.Chdir(oldCWD) }() repositories := `repositories: - name: /DMO/REPO branch: main ` expectedBodyString := "" err := os.WriteFile(config.Repositories, []byte(repositories), 0o644) if assert.Equal(t, err, nil) { bodyString, err := buildAUnitRequestBody(config) assert.Equal(t, nil, err) assert.Equal(t, expectedBodyString, bodyString) } }) t.Run("Config with aunitconfig-yml", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ AUnitResultsFileName: "aUnitResults.xml", AUnitConfig: "aunit.yml", } dir := t.TempDir() oldCWD, _ := os.Getwd() _ = os.Chdir(dir) // clean up tmp dir defer func() { _ = os.Chdir(oldCWD) }() yamlBody := `title: My AUnit run objectset: packages: - name: Z_TEST softwarecomponents: - name: Z_TEST - name: /DMO/SWC ` expectedBodyString := "" err := os.WriteFile(config.AUnitConfig, []byte(yamlBody), 0o644) if assert.Equal(t, err, nil) { bodyString, err := buildAUnitRequestBody(config) assert.Equal(t, nil, err) assert.Equal(t, expectedBodyString, bodyString) } }) t.Run("Config with aunitconfig-yml mps", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ AUnitResultsFileName: "aUnitResults.xml", AUnitConfig: "aunit.yml", } dir := t.TempDir() oldCWD, _ := os.Getwd() _ = os.Chdir(dir) // clean up tmp dir defer func() { _ = os.Chdir(oldCWD) }() yamlBody := `title: My AUnit run objectset: type: multiPropertySet multipropertyset: packages: - name: Z_TEST softwarecomponents: - name: Z_TEST - name: /DMO/SWC ` expectedBodyString := "" err := os.WriteFile(config.AUnitConfig, []byte(yamlBody), 0o644) if assert.Equal(t, err, nil) { bodyString, err := buildAUnitRequestBody(config) assert.Equal(t, nil, err) assert.Equal(t, expectedBodyString, bodyString) } }) t.Run("No AUnit config file - expect no panic", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ AUnitConfig: "aunit.yml", } _, err := buildAUnitRequestBody(config) assert.Equal(t, "Could not find aunit.yml", err.Error()) }) t.Run("No Repo config file - expect no panic", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ Repositories: "repo.yml", } _, err := buildAUnitRequestBody(config) assert.Equal(t, "Could not find repo.yml", err.Error()) }) } func TestTriggerAUnitrun(t *testing.T) { t.Run("succes case: test parsing example yaml config", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ AUnitConfig: "aUnitConfig.yml", AUnitResultsFileName: "aUnitResults.xml", } client := &abaputils.ClientMock{ Body: `AUnit test result body`, StatusCode: 200, } con := abaputils.ConnectionDetailsHTTP{ User: "Test", Password: "Test", URL: "https://api.endpoint.com/Entity/", } dir := t.TempDir() oldCWD, _ := os.Getwd() _ = os.Chdir(dir) // clean up tmp dir defer func() { _ = os.Chdir(oldCWD) }() yamlBody := `title: My AUnit run context: AIE integration tests options: measurements: none scope: owntests: true foreigntests: true riskLevel: harmless: true dangerous: true critical: true duration: short: true medium: true long: true objectset: packages: - name: Z_TEST softwarecomponents: - name: Z_TEST ` err := os.WriteFile(config.AUnitConfig, []byte(yamlBody), 0o644) if assert.Equal(t, err, nil) { _, err := triggerAUnitrun(config, con, client) assert.Equal(t, nil, err) } }) t.Run("succes case: test parsing example yaml config", func(t *testing.T) { config := abapEnvironmentRunAUnitTestOptions{ AUnitConfig: "aUnitConfig.yml", AUnitResultsFileName: "aUnitResults.xml", } client := &abaputils.ClientMock{ Body: `AUnit test result body`, } con := abaputils.ConnectionDetailsHTTP{ User: "Test", Password: "Test", URL: "https://api.endpoint.com/Entity/", } dir := t.TempDir() oldCWD, _ := os.Getwd() _ = os.Chdir(dir) // clean up tmp dir defer func() { _ = os.Chdir(oldCWD) }() yamlBody := `title: My AUnit run context: AIE integration 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: componentSet component: - name: Z_TEST_SC ` err := os.WriteFile(config.AUnitConfig, []byte(yamlBody), 0o644) if assert.Equal(t, err, nil) { _, err := triggerAUnitrun(config, con, client) assert.Equal(t, nil, err) } }) } func TestParseAUnitResult(t *testing.T) { t.Parallel() t.Run("succes case: test parsing example XML result", func(t *testing.T) { bodyString := `Test1Test2` body := []byte(bodyString) err := persistAUnitResult(&mock.FilesMock{}, body, "AUnitResults.xml", false) assert.Equal(t, nil, err) }) t.Run("succes case: test parsing empty AUnit run XML result", func(t *testing.T) { bodyString := `` body := []byte(bodyString) err := persistAUnitResult(&mock.FilesMock{}, body, "AUnitResults.xml", false) assert.Equal(t, nil, err) }) t.Run("failure case: parsing empty xml", func(t *testing.T) { var bodyString string body := []byte(bodyString) err := persistAUnitResult(&mock.FilesMock{}, body, "AUnitResults.xml", false) 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 := getAUnitResults("GET", con, []byte(client.Body), client) assert.NoError(t, err) defer resp.Body.Close() if assert.Equal(t, nil, err) { buf := new(bytes.Buffer) _, err = buf.ReadFrom(resp.Body) assert.NoError(t, err) 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 := getAUnitResults("GET", con, []byte(client.Body), client) assert.EqualError(t, err, "Getting AUnit run results failed: Test fail") defer resp.Body.Close() buf := new(bytes.Buffer) _, err = buf.ReadFrom(resp.Body) assert.NoError(t, err) 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("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: ``, 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: ``, 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) assert.NoError(t, err) defer resp.Body.Close() if assert.Equal(t, nil, err) { buf := new(bytes.Buffer) _, err = buf.ReadFrom(resp.Body) assert.NoError(t, err) 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"]) } }) } func TestGenerateHTMLDocumentAUnit(t *testing.T) { t.Run("Test empty XML Result", func(t *testing.T) { expectedString := `AUnit Results

AUnit Results

Run titleSystemClientExecutedByDurationsTimestamp
FailuresErrorsSkippedAssertsTests

SeverityFileMessageTypeText
There are no AUnit findings to be displayed
` result := AUnitResult{} resultString := generateHTMLDocumentAUnit(&result) assert.Equal(t, expectedString, resultString) }) t.Run("Test AUnit XML Result", func(t *testing.T) { expectedString := `AUnit Results

AUnit Results

Run titleTest titleSystemTest systemClient000ExecutedByCC00000Duration0.15sTimestamp2021-00-00T00:00:00Z
Failures4Errors4Skipped4Asserts12Tests12

SeverityFileMessageTypeText
Testcase: my_test for class ZCL_my_test
FailureZCL_my_testtestMessageAssert ErrortestError
FailureZCL_my_testtestMessage2Assert Error2testError2
FailureZCL_my_testtestMessageAssert FailuretestFailure
FailureZCL_my_testtestMessage2Assert Failure2testFailure2
FailureZCL_my_testtestSkipped-testSkipped
FailureZCL_my_testtestSkipped2-testSkipped2
Testcase: my_test2 for class ZCL_my_test2
FailureZCL_my_test2testMessage3Assert Error3testError3
FailureZCL_my_test2testMessage4Assert Error4testError4
FailureZCL_my_test2testMessage5Assert Failure5testFailure5
FailureZCL_my_test2testMessage6Assert Failure6testFailure6
FailureZCL_my_test2testSkipped7-testSkipped7
FailureZCL_my_test2testSkipped8-testSkipped8
` result := AUnitResult{ XMLName: xml.Name{Space: "testSpace", Local: "testLocal"}, Title: "Test title", System: "Test system", Client: "000", ExecutedBy: "CC00000", Time: "0.15", Timestamp: "2021-00-00T00:00:00Z", Failures: "4", Errors: "4", Skipped: "4", Asserts: "12", Tests: "12", 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"` }{ Tests: "6", Asserts: "4", Skipped: "2", Errors: "2", Failures: "2", Timestamp: "2021-00-00T00:00:00Z", Time: "0.15", Hostname: "0xb", Package: "testPackage", Name: "ZCL_testPackage", 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\"" }{{ Asserts: "4", Time: "0.15", Name: "my_test", Classname: "ZCL_my_test", Error: []struct { Text string "xml:\",chardata\"" Type string "xml:\"type,attr\"" Message string "xml:\"message,attr\"" }{{ Text: "testError", Type: "Assert Error", Message: "testMessage", }, { Text: "testError2", Type: "Assert Error2", Message: "testMessage2", }}, Failure: []struct { Text string "xml:\",chardata\"" Type string "xml:\"type,attr\"" Message string "xml:\"message,attr\"" }{{ Text: "testFailure", Type: "Assert Failure", Message: "testMessage", }, { Text: "testFailure2", Type: "Assert Failure2", Message: "testMessage2", }}, Skipped: []struct { Text string "xml:\",chardata\"" Message string "xml:\"message,attr\"" }{{ Text: "testSkipped", Message: "testSkipped", }, { Text: "testSkipped2", Message: "testSkipped2", }}, }, { Asserts: "4", Time: "0.15", Name: "my_test2", Classname: "ZCL_my_test2", Error: []struct { Text string "xml:\",chardata\"" Type string "xml:\"type,attr\"" Message string "xml:\"message,attr\"" }{{ Text: "testError3", Type: "Assert Error3", Message: "testMessage3", }, { Text: "testError4", Type: "Assert Error4", Message: "testMessage4", }}, Failure: []struct { Text string "xml:\",chardata\"" Type string "xml:\"type,attr\"" Message string "xml:\"message,attr\"" }{{ Text: "testFailure5", Type: "Assert Failure5", Message: "testMessage5", }, { Text: "testFailure6", Type: "Assert Failure6", Message: "testMessage6", }}, Skipped: []struct { Text string "xml:\",chardata\"" Message string "xml:\"message,attr\"" }{{ Text: "testSkipped7", Message: "testSkipped7", }, { Text: "testSkipped8", Message: "testSkipped8", }}, }}, }, } resultString := generateHTMLDocumentAUnit(&result) fmt.Println(resultString) assert.Equal(t, expectedString, resultString) }) }