package cmd import ( "encoding/json" "testing" "time" abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" "github.com/SAP/jenkins-library/pkg/abaputils" "github.com/SAP/jenkins-library/pkg/mock" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/stretchr/testify/assert" ) type abapEnvironmentBuildMockUtils struct { *mock.ExecMockRunner *abapbuild.MockClient } func newAbapEnvironmentBuildTestsUtils() abapEnvironmentBuildUtils { mC := abapbuild.GetBuildMockClientToRun2Times() utils := abapEnvironmentBuildMockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, MockClient: &mC, } return &utils } func (mB abapEnvironmentBuildMockUtils) PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) { } func (mB abapEnvironmentBuildMockUtils) GetAbapCommunicationArrangementInfo(options abaputils.AbapEnvironmentOptions, oDataURL string) (abaputils.ConnectionDetailsHTTP, error) { var cd abaputils.ConnectionDetailsHTTP cd.URL = "/sap/opu/odata/BUILD/CORE_SRV" return cd, nil } func (mB abapEnvironmentBuildMockUtils) publish() { } func (mB abapEnvironmentBuildMockUtils) GetPollIntervall() time.Duration { return 1 * time.Microsecond } func (mB abapEnvironmentBuildMockUtils) getMaxRuntime() time.Duration { return 1 * time.Second } func (mB abapEnvironmentBuildMockUtils) getPollingInterval() time.Duration { return 1 * time.Microsecond } func TestRunAbapEnvironmentBuild(t *testing.T) { t.Parallel() t.Run("happy path", func(t *testing.T) { t.Parallel() // init cpe := abapEnvironmentBuildCommonPipelineEnvironment{} config := abapEnvironmentBuildOptions{} config.AddonDescriptor = addonDescriptor config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` config.DownloadAllResultFiles = true config.PublishAllDownloadedResultFiles = true utils := newAbapEnvironmentBuildTestsUtils() // test err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe) // assert finalValues := `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"AunitValue1"},{"value_id":"MyId2","value":"AunitValue2"},{"value_id":"BUILD_FRAMEWORK_MODE","value":"P"}]` assert.NoError(t, err) assert.Equal(t, finalValues, cpe.abap.buildValues) }) t.Run("happy path, download only one", func(t *testing.T) { t.Parallel() // init cpe := abapEnvironmentBuildCommonPipelineEnvironment{} config := abapEnvironmentBuildOptions{} config.AddonDescriptor = addonDescriptor config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` config.DownloadResultFilenames = []string{"SAR_XML"} config.PublishResultFilenames = []string{"SAR_XML"} utils := newAbapEnvironmentBuildTestsUtils() // test err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe) // assert assert.NoError(t, err) }) t.Run("happy path, use AddonDescriptor", func(t *testing.T) { t.Parallel() // init expectedValueList := []abapbuild.Value{} recordedValueList := []abapbuild.Value{} cpe := abapEnvironmentBuildCommonPipelineEnvironment{} config := abapEnvironmentBuildOptions{} config.AddonDescriptor = addonDescriptor config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"}]` //config.ConditionOnAddonDescriptor = `[{"field":"PackageType","operator":"!=","value":"AOI"}]` //The mock client returns MyId1 & and MyId2 therefore we rename it to these values so that we can remove it from the output config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"MyId1"},{"use":"Status","renameTo":"MyId2"}]` utils := newAbapEnvironmentBuildTestsUtils() // test err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe) // assert finalValues := `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"BUILD_FRAMEWORK_MODE","value":"P"}]` json.Unmarshal([]byte(finalValues), expectedValueList) json.Unmarshal([]byte(cpe.abap.buildValues), recordedValueList) assert.NoError(t, err) assert.ElementsMatch(t, expectedValueList, recordedValueList) }) t.Run("error path, try to publish file, which was not downloaded", func(t *testing.T) { t.Parallel() // init cpe := abapEnvironmentBuildCommonPipelineEnvironment{} config := abapEnvironmentBuildOptions{} config.AddonDescriptor = addonDescriptor config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` config.DownloadResultFilenames = []string{"DELIVERY_LOGS.ZIP"} config.PublishResultFilenames = []string{"SAR_XML"} utils := newAbapEnvironmentBuildTestsUtils() // test err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe) // assert assert.Error(t, err) }) t.Run("error path, try to download file which does not exist", func(t *testing.T) { t.Parallel() // init cpe := abapEnvironmentBuildCommonPipelineEnvironment{} config := abapEnvironmentBuildOptions{} config.AddonDescriptor = addonDescriptor config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` config.DownloadResultFilenames = []string{"DOES_NOT_EXIST"} config.PublishAllDownloadedResultFiles = true utils := newAbapEnvironmentBuildTestsUtils() // test err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe) // assert assert.Error(t, err) }) } func TestGenerateValues(t *testing.T) { t.Run("happy path", func(t *testing.T) { // init config := abapEnvironmentBuildOptions{} config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` config.CpeValues = `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"PACKAGES","value":"CPE_PACKAGE"},{"value_id":"MyId2","value":"Value2"}]` // test values, err := generateValuesOnlyFromConfig(&config) // assert assert.NoError(t, err) assert.Equal(t, 3, len(values)) //values generated by map -> therefore we can not just iterate over the generated values and check them, as they are in random order checkMap := map[string]string{ "PACKAGES": "/BUILD/AUNIT_DUMMY_TESTS", "MyId1": "Value1", "MyId2": "Value2", } for _, value := range values { checkValue, present := checkMap[value.ValueID] assert.True(t, present) assert.Equal(t, checkValue, value.Value) } }) t.Run("happy path, use addonDescriptor", func(t *testing.T) { // init config := abapEnvironmentBuildOptions{} config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` config.CpeValues = `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"PACKAGES","value":"CPE_PACKAGE"},{"value_id": "Status","value":"R"},{"value_id":"MyId2","value":"Value2"}]` config.AddonDescriptor = addonDescriptor config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test valuesAddonDescriptor, err := evaluateAddonDescriptor(&config) values0, err := generateValuesWithAddonDescriptor(&config, valuesAddonDescriptor[0]) // assert assert.NoError(t, err) assert.Equal(t, 5, len(values0)) //values generated by map -> therefore we can not just iterate over the generated values and check them, as they are in random order checkMap := map[string]string{ "PACKAGES": "/BUILD/AUNIT_DUMMY_TESTS", "MyId1": "Value1", "MyId2": "Value2", "SWC": "/ITAPC1/I_CURRENCY", "Status": "P", } for _, value := range values0 { checkValue, present := checkMap[value.ValueID] assert.True(t, present) assert.Equal(t, checkValue, value.Value) } }) t.Run("error path, use addonDescriptor already in config", func(t *testing.T) { // init config := abapEnvironmentBuildOptions{} config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"},{"value_id":"Branch","value":"configBranch"}]` config.CpeValues = `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"PACKAGES","value":"CPE_PACKAGE"},{"value_id": "Status","value":"R"},{"value_id":"MyId2","value":"Value2"}]` config.AddonDescriptor = addonDescriptor config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"},{"use":"Branch","renameTo":"Branch"}]` // test valuesAddonDescriptor, err := evaluateAddonDescriptor(&config) values0, err := generateValuesWithAddonDescriptor(&config, valuesAddonDescriptor[0]) // assert assert.Error(t, err) assert.Equal(t, 0, len(values0)) }) t.Run("error path - duplicate in config", func(t *testing.T) { // init config := abapEnvironmentBuildOptions{} config.Values = `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"},{"value_id":"MyId1","value":"Value1"}]` // test values, err := generateValuesOnlyFromConfig(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("error path - bad formating in config.Values", func(t *testing.T) { // init config := abapEnvironmentBuildOptions{} config.Values = `[{"task_id":"PACKAGES","task":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"MyId1","value":"Value1"}]` // test _, err := generateValuesOnlyFromConfig(&config) // assert assert.Error(t, err) }) } func TestEvaluateAddonDescriptor(t *testing.T) { //global init config := abapEnvironmentBuildOptions{} config.AddonDescriptor = addonDescriptor t.Run("Find one", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"field":"Name","operator":"==","value":"/ITAPC1/I_CURRENCY"},{"field":"Status","operator":"!=","value":"R"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.NoError(t, err) assert.Equal(t, 1, len(values)) assert.Equal(t, 2, len(values[0])) }) t.Run("Find both", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"field":"PackageType","operator":"==","value":"AOI"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.NoError(t, err) assert.Equal(t, 2, len(values)) assert.Equal(t, 2, len(values[0])) assert.Equal(t, 2, len(values[1])) }) t.Run("Find none", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"field":"PackageType","operator":"!=","value":"AOI"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.NoError(t, err) assert.Equal(t, 0, len(values)) }) t.Run("No condition", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.NoError(t, err) assert.Equal(t, 2, len(values)) assert.Equal(t, 2, len(values[0])) assert.Equal(t, 2, len(values[1])) }) t.Run("No UseFields", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `` config.UseFieldsOfAddonDescriptor = `` // test values, err := evaluateAddonDescriptor(&config) // assert assert.NoError(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Wrong fieldname", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"fieldxxx":"Name","operator":"==","value":"/ITAPC1/I_CURRENCY"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Wrong value fieldname", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"field":"Name","operator":"==","valuexxxx":"/ITAPC1/I_CURRENCY"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Field which does not exist", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"field":"DoesNotExist","operator":"==","valuexxxx":"/ITAPC1/I_CURRENCY"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Wrong operator", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `[{"field":"Name","operator":"()","value":"/ITAPC1/I_CURRENCY"}]` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Test UseFieldsOfAddonDescriptor: Bad formatting use", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `` config.UseFieldsOfAddonDescriptor = `[{"usexxx":"Name","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Test UseFieldsOfAddonDescriptor: Bad formatting as", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `` config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"SWC"},{"use":"Status","asxxx":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) t.Run("Test UseFieldsOfAddonDescriptor: use which does not exist", func(t *testing.T) { // init config.ConditionOnAddonDescriptor = `` config.UseFieldsOfAddonDescriptor = `[{"use":"DoesNotExist","renameTo":"SWC"},{"use":"Status","renameTo":"Status"}]` // test values, err := evaluateAddonDescriptor(&config) // assert assert.Error(t, err) assert.Equal(t, 0, len(values)) }) } var addonDescriptor = `{ "addonProduct":"/ITAPC1/I_CURRENCZPRODUCT", "addonVersion":"1.0.0", "addonVersionAAK":"0001", "AddonSpsLevel":"0000", "AddonPatchLevel":"0000", "TargetVectorID":"", "repositories":[ { "name":"/ITAPC1/I_CURRENCY", "tag":"", "branch":"v1.0.0", "commitID":"1cb96a82", "version":"1.0.0", "versionAAK":"0001", "PackageName":"SAPK-004AAINITAPC1", "PackageType":"AOI", "SpLevel":"0000", "PatchLevel":"0000", "PredecessorCommitID":"", "Status":"P", "Namespace":"/ITAPC1/", "SarXMLFilePath":"", "languages":null, "InBuildScope":false }, { "name":"/ITAPC1/I_FLIGHT", "tag":"", "branch":"v2.0.0", "commitID":"5b87c03", "version":"2.0.0", "versionAAK":"0001", "PackageName":"SAPK-005AAINITAPC2", "PackageType":"AOI", "SpLevel":"0000", "PatchLevel":"0000", "PredecessorCommitID":"", "Status":"R", "Namespace":"/ITAPC1/", "SarXMLFilePath":"", "languages":null, "InBuildScope":false } ] }`