1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-10-30 23:57:50 +02:00

chore: cleanup reporting & some incorrect file usage in tests (#3943)

* chore: cleanup reporting & some incorrect file usage in tests

* cleanup interface

* chore: remove comment

* preserve error handling

* Rename FileUtils.go to fileUtils.go

* clean up formatting

* chore: address static check findings

* fix brittle test

* chore: cleanup formatting
This commit is contained in:
Oliver Nocon
2022-08-09 10:57:02 +02:00
committed by GitHub
parent 9f8064d733
commit a46f796bcd
38 changed files with 407 additions and 374 deletions

View File

@@ -16,19 +16,19 @@ import (
func abapAddonAssemblyKitCheckPV(config abapAddonAssemblyKitCheckPVOptions, telemetryData *telemetry.CustomData, cpe *abapAddonAssemblyKitCheckPVCommonPipelineEnvironment) {
utils := aakaas.NewAakBundle()
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
if err := runAbapAddonAssemblyKitCheckPV(&config, telemetryData, &utils, cpe); err != nil {
if err := runAbapAddonAssemblyKitCheckPV(&config, telemetryData, utils, cpe); err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapAddonAssemblyKitCheckPV(config *abapAddonAssemblyKitCheckPVOptions, telemetryData *telemetry.CustomData, utils *aakaas.AakUtils, cpe *abapAddonAssemblyKitCheckPVCommonPipelineEnvironment) error {
func runAbapAddonAssemblyKitCheckPV(config *abapAddonAssemblyKitCheckPVOptions, telemetryData *telemetry.CustomData, utils aakaas.AakUtils, cpe *abapAddonAssemblyKitCheckPVCommonPipelineEnvironment) error {
conn := new(abapbuild.Connector)
if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, *utils); err != nil {
if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, utils); err != nil {
return err
}
log.Entry().Infof("Reading Product Version Information from addonDescriptor (aka addon.yml) file: %s", config.AddonDescriptorFileName)
addonDescriptor, err := (*utils).ReadAddonDescriptor(config.AddonDescriptorFileName)
addonDescriptor, err := utils.ReadAddonDescriptor(config.AddonDescriptorFileName)
if err != nil {
return err
}
@@ -57,8 +57,10 @@ func runAbapAddonAssemblyKitCheckPV(config *abapAddonAssemblyKitCheckPVOptions,
var filesToPublish []piperutils.Path
log.Entry().Infof("Add %s to be published", config.AddonDescriptorFileName)
filesToPublish = append(filesToPublish, piperutils.Path{Target: config.AddonDescriptorFileName, Name: "AddonDescriptor", Mandatory: true})
log.Entry().Infof("Publsihing %v files", len(filesToPublish))
piperutils.PersistReportsAndLinks("abapAddonAssemblyKitCheckPV", "", filesToPublish, nil)
log.Entry().Infof("Publishing %v files", len(filesToPublish))
if err := piperutils.PersistReportsAndLinks("abapAddonAssemblyKitCheckPV", "", utils, filesToPublish, nil); err != nil {
log.Entry().WithError(err).Error("failed to persist report information")
}
return nil
}

View File

@@ -21,7 +21,7 @@ func TestCheckPVStep(t *testing.T) {
config.Password = "dummyPassword"
t.Run("step success", func(t *testing.T) {
config.AddonDescriptorFileName = "success"
err := runAbapAddonAssemblyKitCheckPV(&config, nil, &utils, &cpe)
err := runAbapAddonAssemblyKitCheckPV(&config, nil, utils, &cpe)
assert.NoError(t, err, "Did not expect error")
var addonDescriptorFinal abaputils.AddonDescriptor
err = json.Unmarshal([]byte(cpe.abap.addonDescriptor), &addonDescriptorFinal)
@@ -32,7 +32,7 @@ func TestCheckPVStep(t *testing.T) {
})
t.Run("step error - in ReadAddonDescriptor", func(t *testing.T) {
config.AddonDescriptorFileName = "failing"
err := runAbapAddonAssemblyKitCheckPV(&config, nil, &utils, &cpe)
err := runAbapAddonAssemblyKitCheckPV(&config, nil, utils, &cpe)
assert.Error(t, err, "Did expect error")
assert.Equal(t, err.Error(), "error in ReadAddonDescriptor")
})
@@ -40,7 +40,7 @@ func TestCheckPVStep(t *testing.T) {
config.AddonDescriptorFileName = "success"
bundle.SetBody("ErrorBody")
bundle.SetError("error during validation")
err := runAbapAddonAssemblyKitCheckPV(&config, nil, &utils, &cpe)
err := runAbapAddonAssemblyKitCheckPV(&config, nil, utils, &cpe)
assert.Error(t, err, "Did expect error")
})
}

View File

@@ -32,13 +32,14 @@ func abapEnvironmentAssemblePackages(config abapEnvironmentAssemblePackagesOptio
}
client := piperhttp.Client{}
err := runAbapEnvironmentAssemblePackages(&config, telemetryData, &autils, &client, cpe)
utils := piperutils.Files{}
err := runAbapEnvironmentAssemblePackages(&config, telemetryData, &autils, &utils, &client, cpe)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapEnvironmentAssemblePackages(config *abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client abapbuild.HTTPSendLoader, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) error {
func runAbapEnvironmentAssemblePackages(config *abapEnvironmentAssemblePackagesOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, utils piperutils.FileUtils, client abapbuild.HTTPSendLoader, cpe *abapEnvironmentAssemblePackagesCommonPipelineEnvironment) error {
connBuild := new(abapbuild.Connector)
if errConBuild := initAssemblePackagesConnection(connBuild, config, com, client); errConBuild != nil {
return errConBuild
@@ -71,7 +72,7 @@ func runAbapEnvironmentAssemblePackages(config *abapEnvironmentAssemblePackagesO
}
log.Entry().Infof("Publishing %v files", len(filesToPublish))
piperutils.PersistReportsAndLinks("abapEnvironmentAssemblePackages", "", filesToPublish, nil)
piperutils.PersistReportsAndLinks("abapEnvironmentAssemblePackages", "", utils, filesToPublish, nil)
var reposBackToCPE []abaputils.Repository
for _, b := range builds {

View File

@@ -7,6 +7,7 @@ import (
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
"github.com/SAP/jenkins-library/pkg/abaputils"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/stretchr/testify/assert"
)
@@ -83,26 +84,24 @@ func TestStep(t *testing.T) {
cpe := &abapEnvironmentAssemblePackagesCommonPipelineEnvironment{}
t.Run("abapEnvironmentAssemblePackages: nothing to do", func(t *testing.T) {
config := &abapEnvironmentAssemblePackagesOptions{
AddonDescriptor: cpeAbapAddonDescriptorPackageLocked,
MaxRuntimeInMinutes: 1,
PollIntervalsInMilliseconds: 1,
}
err := runAbapEnvironmentAssemblePackages(config, nil, autils, &client, cpe)
err := runAbapEnvironmentAssemblePackages(config, nil, autils, &mock.FilesMock{}, &client, cpe)
assert.NoError(t, err)
assert.Contains(t, cpe.abap.addonDescriptor, `"InBuildScope":false`)
})
t.Run("abapEnvironmentAssemblePackages: build", func(t *testing.T) {
config := &abapEnvironmentAssemblePackagesOptions{
AddonDescriptor: cpeAbapAddonDescriptorPackageReserved,
MaxRuntimeInMinutes: 1,
PollIntervalsInMilliseconds: 1,
}
err := runAbapEnvironmentAssemblePackages(config, nil, autils, &client, cpe)
err := runAbapEnvironmentAssemblePackages(config, nil, autils, &mock.FilesMock{}, &client, cpe)
assert.NoError(t, err)
assert.Contains(t, cpe.abap.addonDescriptor, `SAPK-001AAINITAPC1.SAR`)
assert.Contains(t, cpe.abap.addonDescriptor, `"InBuildScope":true`)

View File

@@ -5,7 +5,6 @@ import (
"net/url"
"reflect"
"strings"
"time"
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
@@ -21,8 +20,8 @@ import (
type abapEnvironmentBuildUtils interface {
command.ExecRunner
abaputils.Communication
abapbuild.Publish
abapbuild.HTTPSendLoader
piperutils.FileUtils
getMaxRuntime() time.Duration
getPollingInterval() time.Duration
publish()
@@ -32,6 +31,7 @@ type abapEnvironmentBuildUtilsBundle struct {
*command.Command
*piperhttp.Client
*abaputils.AbapUtils
*piperutils.Files
maxRuntime time.Duration
pollingInterval time.Duration
storePublish publish
@@ -44,14 +44,14 @@ type publish struct {
links []piperutils.Path
}
func (p *publish) publish() {
func (p *publish) publish(utils piperutils.FileUtils) {
if p.stepName != "" {
abapbuild.PersistReportsAndLinks(p.stepName, p.workspace, p.reports, p.links)
piperutils.PersistReportsAndLinks(p.stepName, p.workspace, utils, p.reports, p.links)
}
}
func (aEBUB *abapEnvironmentBuildUtilsBundle) publish() {
aEBUB.storePublish.publish()
aEBUB.storePublish.publish(aEBUB)
}
func (aEBUB *abapEnvironmentBuildUtilsBundle) getMaxRuntime() time.Duration {
@@ -63,7 +63,7 @@ func (aEBUB *abapEnvironmentBuildUtilsBundle) getPollingInterval() time.Duration
}
func (aEBUB *abapEnvironmentBuildUtilsBundle) PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
//abapbuild.PersistReportsAndLinks(stepName, workspace, reports, links)
// abapbuild.PersistReportsAndLinks(stepName, workspace, reports, links)
if aEBUB.storePublish.stepName == "" {
aEBUB.storePublish.stepName = stepName
aEBUB.storePublish.workspace = workspace
@@ -94,13 +94,12 @@ func newAbapEnvironmentBuildUtils(maxRuntime time.Duration, pollingInterval time
func abapEnvironmentBuild(config abapEnvironmentBuildOptions, telemetryData *telemetry.CustomData, cpe *abapEnvironmentBuildCommonPipelineEnvironment) {
utils := newAbapEnvironmentBuildUtils(time.Duration(config.MaxRuntimeInMinutes), time.Duration(config.PollingIntervalInSeconds))
if err := runAbapEnvironmentBuild(&config, telemetryData, &utils, cpe); err != nil {
if err := runAbapEnvironmentBuild(&config, telemetryData, utils, cpe); err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapEnvironmentBuild(config *abapEnvironmentBuildOptions, telemetryData *telemetry.CustomData, utils *abapEnvironmentBuildUtils, cpe *abapEnvironmentBuildCommonPipelineEnvironment) error {
func runAbapEnvironmentBuild(config *abapEnvironmentBuildOptions, telemetryData *telemetry.CustomData, utils abapEnvironmentBuildUtils, cpe *abapEnvironmentBuildCommonPipelineEnvironment) error {
conn := new(abapbuild.Connector)
if err := initConnection(conn, config, utils); err != nil {
return errors.Wrap(err, "Connector initialization for communication with the ABAP system failed")
@@ -112,8 +111,8 @@ func runAbapEnvironmentBuild(config *abapEnvironmentBuildOptions, telemetryData
}
finalValues, err := runBuilds(conn, config, utils, valuesList)
//files should be published, even if an error occured
(*utils).publish()
// files should be published, even if an error occured
utils.publish()
if err != nil {
return err
}
@@ -125,9 +124,9 @@ func runAbapEnvironmentBuild(config *abapEnvironmentBuildOptions, telemetryData
return nil
}
func runBuilds(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils *abapEnvironmentBuildUtils, valuesList [][]abapbuild.Value) ([]abapbuild.Value, error) {
func runBuilds(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils abapEnvironmentBuildUtils, valuesList [][]abapbuild.Value) ([]abapbuild.Value, error) {
var finalValues []abapbuild.Value
//No addonDescriptor involved
// No addonDescriptor involved
if len(valuesList) == 0 {
values, err := generateValuesOnlyFromConfig(config)
if err != nil {
@@ -138,7 +137,7 @@ func runBuilds(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, u
return finalValues, errors.Wrap(err, "Error during execution of build framework")
}
} else {
//Run several times for each repository in the addonDescriptor
// Run several times for each repository in the addonDescriptor
var errstrings []string
vE := valuesEvaluator{}
vE.m = make(map[string]string)
@@ -156,7 +155,7 @@ func runBuilds(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, u
errstrings = append(errstrings, err.Error())
}
finalValuesForOneBuild = removeAddonDescriptorValues(finalValuesForOneBuild, values)
//This means: probably values are duplicated, but the first one wins -> perhaps change this in the future if needed
// This means: probably values are duplicated, but the first one wins -> perhaps change this in the future if needed
if err := vE.appendValuesIfNotPresent(finalValuesForOneBuild, false); err != nil {
errstrings = append(errstrings, err.Error())
}
@@ -170,7 +169,7 @@ func runBuilds(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, u
return finalValues, nil
}
func initConnection(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils *abapEnvironmentBuildUtils) error {
func initConnection(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils abapEnvironmentBuildUtils) error {
var connConfig abapbuild.ConnectorConfiguration
connConfig.CfAPIEndpoint = config.CfAPIEndpoint
connConfig.CfOrg = config.CfOrg
@@ -187,17 +186,17 @@ func initConnection(conn *abapbuild.Connector, config *abapEnvironmentBuildOptio
connConfig.Parameters.Add("sap-client", config.AbapSourceClient)
}
if err := conn.InitBuildFramework(connConfig, *utils, *utils); err != nil {
if err := conn.InitBuildFramework(connConfig, utils, utils); err != nil {
return err
}
conn.MaxRuntime = (*utils).getMaxRuntime()
conn.PollingInterval = (*utils).getPollingInterval()
conn.MaxRuntime = utils.getMaxRuntime()
conn.PollingInterval = utils.getPollingInterval()
return nil
}
// ***********************************Run Build***************************************************************
func runBuild(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils *abapEnvironmentBuildUtils, values []abapbuild.Value) ([]abapbuild.Value, error) {
func runBuild(conn *abapbuild.Connector, config *abapEnvironmentBuildOptions, utils abapEnvironmentBuildUtils, values []abapbuild.Value) ([]abapbuild.Value, error) {
var finalValues []abapbuild.Value
var inputValues abapbuild.Values
inputValues.Values = values
@@ -272,11 +271,11 @@ func (b *myBuild) Download() error {
return nil
}
func (b *myBuild) Publish(utils *abapEnvironmentBuildUtils) error {
func (b *myBuild) Publish(utils abapEnvironmentBuildUtils) error {
if b.PublishAllDownloadedResultFiles {
b.PublishAllDownloadedResults("abapEnvironmentBuild", *utils)
b.PublishAllDownloadedResults("abapEnvironmentBuild", utils)
} else {
if err := b.PublishDownloadedResults("abapEnvironmentBuild", b.PublishResultFilenames, *utils); err != nil {
if err := b.PublishDownloadedResults("abapEnvironmentBuild", b.PublishResultFilenames, utils); err != nil {
return errors.Wrapf(err, "Error during the publish of the result files %s", b.PublishResultFilenames)
}
}
@@ -330,15 +329,15 @@ func removeAddonDescriptorValues(finalValuesFromBuild []abapbuild.Value, valuesF
func generateValuesWithAddonDescriptor(config *abapEnvironmentBuildOptions, repoValues []abapbuild.Value) ([]abapbuild.Value, error) {
var values []abapbuild.Value
vE := valuesEvaluator{}
//values from config
// values from config
if err := vE.initialize(config.Values); err != nil {
return values, err
}
//values from addondescriptor
// values from addondescriptor
if err := vE.appendValuesIfNotPresent(repoValues, true); err != nil {
return values, err
}
//values from commonepipelineEnvironment
// values from commonepipelineEnvironment
if err := vE.appendStringValuesIfNotPresent(config.CpeValues, false); err != nil {
return values, err
}

View File

@@ -15,6 +15,7 @@ import (
type abapEnvironmentBuildMockUtils struct {
*mock.ExecMockRunner
*abapbuild.MockClient
*mock.FilesMock
}
func newAbapEnvironmentBuildTestsUtils() abapEnvironmentBuildUtils {
@@ -22,6 +23,7 @@ func newAbapEnvironmentBuildTestsUtils() abapEnvironmentBuildUtils {
utils := abapEnvironmentBuildMockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
MockClient: &mC,
FilesMock: &mock.FilesMock{},
}
return &utils
}
@@ -31,6 +33,7 @@ func newAbapEnvironmentBuildTestsUtilsWithClient() abapEnvironmentBuildUtils {
utils := abapEnvironmentBuildMockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
MockClient: &mC,
FilesMock: &mock.FilesMock{},
}
return &utils
}
@@ -70,7 +73,7 @@ func TestRunAbapEnvironmentBuild(t *testing.T) {
config.PublishAllDownloadedResultFiles = true
utils := newAbapEnvironmentBuildTestsUtils()
// test
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
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)
@@ -87,7 +90,7 @@ func TestRunAbapEnvironmentBuild(t *testing.T) {
config.AbapSourceClient = "001"
utils := newAbapEnvironmentBuildTestsUtilsWithClient()
// test
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
err := runAbapEnvironmentBuild(&config, nil, utils, &cpe)
// assert
finalValues := `[{"value_id":"PHASE","value":"AUNIT"},{"value_id":"SUN","value":"SUMMER"}]`
assert.NoError(t, err)
@@ -105,7 +108,7 @@ func TestRunAbapEnvironmentBuild(t *testing.T) {
config.PublishResultFilenames = []string{"SAR_XML"}
utils := newAbapEnvironmentBuildTestsUtils()
// test
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
err := runAbapEnvironmentBuild(&config, nil, utils, &cpe)
// assert
assert.NoError(t, err)
})
@@ -124,7 +127,7 @@ func TestRunAbapEnvironmentBuild(t *testing.T) {
config.UseFieldsOfAddonDescriptor = `[{"use":"Name","renameTo":"MyId1"},{"use":"Status","renameTo":"MyId2"}]`
utils := newAbapEnvironmentBuildTestsUtils()
// test
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
err := runAbapEnvironmentBuild(&config, nil, utils, &cpe)
// assert
finalValues := `[{"value_id":"PACKAGES","value":"/BUILD/AUNIT_DUMMY_TESTS"},{"value_id":"BUILD_FRAMEWORK_MODE","value":"P"}]`
err = json.Unmarshal([]byte(finalValues), &expectedValueList)
@@ -146,7 +149,7 @@ func TestRunAbapEnvironmentBuild(t *testing.T) {
config.PublishResultFilenames = []string{"SAR_XML"}
utils := newAbapEnvironmentBuildTestsUtils()
// test
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
err := runAbapEnvironmentBuild(&config, nil, utils, &cpe)
// assert
assert.Error(t, err)
})
@@ -162,7 +165,7 @@ func TestRunAbapEnvironmentBuild(t *testing.T) {
config.PublishAllDownloadedResultFiles = true
utils := newAbapEnvironmentBuildTestsUtils()
// test
err := runAbapEnvironmentBuild(&config, nil, &utils, &cpe)
err := runAbapEnvironmentBuild(&config, nil, utils, &cpe)
// assert
assert.Error(t, err)
})

View File

@@ -2,8 +2,8 @@ package cmd
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/SAP/jenkins-library/pkg/abaputils"
@@ -53,7 +53,6 @@ func TestFetchXcsrfTokenFromHead(t *testing.T) {
func TestCheckATCSystemConfigurationFile(t *testing.T) {
t.Parallel()
t.Run("Check ATC Configuration File - empty", func(t *testing.T) {
errExpected := "pushing ATC System Configuration failed. Reason: Configured Filelocation is empty (File: atcSystemConfig.json)"
var parsedConfigurationJsonExpected parsedConfigJsonWithExpand
var atcSystemConfiguartionJsonFileExpected []byte
@@ -71,7 +70,6 @@ func TestHandleHttpResponse(t *testing.T) {
t.Parallel()
t.Run("failiure case: HandleHttpResponse", func(t *testing.T) {
bodyText := `
--B772E21DAA42B9571C778276B829D6C20
Content-Type: multipart/mixed; boundary=B772E21DAA42B9571C778276B829D6C21
@@ -139,13 +137,12 @@ cache-control: no-cache, no-store, must-revalidate
}
resp.Header.Set("Content-type", "multipart/mixed")
err = HandleHttpResponse(resp, err, "Unit Test", con)
//inner error expected
// inner error expected
errExpected := "Outer Response Code: 200 - but at least one Inner response returned StatusCode 4* or 5*. Please check Log for details."
assert.Equal(t, errExpected, err.Error())
})
t.Run("success case: HandleHttpResponse", func(t *testing.T) {
bodyText := `
--B772E21DAA42B9571C778276B829D6C20
Content-Type: multipart/mixed; boundary=B772E21DAA42B9571C778276B829D6C21
@@ -221,7 +218,6 @@ func TestBuildATCSystemConfigBatchRequest(t *testing.T) {
t.Parallel()
t.Run("success case: BuildATCSystemConfigBatch - Config Base & 1 Priority", func(t *testing.T) {
batchATCSystemConfigFileExpected := `
--request-separator
Content-Type: multipart/mixed;boundary=changeset
@@ -250,7 +246,7 @@ Content-Type: application/json
--request-separator--`
//no Configuration name supplied
// no Configuration name supplied
atcSystemConfigFileString := `{
"conf_name": "UNITTEST_PIPERSTEP",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -280,11 +276,9 @@ Content-Type: application/json
t.Fatal("Failed to Build ATC System Config Batch")
}
assert.Equal(t, batchATCSystemConfigFileExpected, batchATCSystemConfigFile)
})
t.Run("success case: BuildATCSystemConfigBatch - Config Base & 2 Priorities", func(t *testing.T) {
batchATCSystemConfigFileExpected := `
--request-separator
Content-Type: multipart/mixed;boundary=changeset
@@ -323,7 +317,7 @@ Content-Type: application/json
--request-separator--`
//no Configuration name supplied
// no Configuration name supplied
atcSystemConfigFileString := `{
"conf_name": "UNITTEST_PIPERSTEP",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -358,11 +352,9 @@ Content-Type: application/json
t.Fatal("Failed to Build ATC System Config Batch Request")
}
assert.Equal(t, batchATCSystemConfigFileExpected, batchATCSystemConfigFile)
})
t.Run("success case: BuildATCSystemConfigBatch - Config Base only (no existing _priorities)", func(t *testing.T) {
batchATCSystemConfigFileExpected := `
--request-separator
Content-Type: multipart/mixed;boundary=changeset
@@ -381,7 +373,7 @@ Content-Type: application/json
--request-separator--`
//no Configuration name supplied
// no Configuration name supplied
atcSystemConfigFileString := `{
"conf_name": "UNITTEST_PIPERSTEP",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -403,11 +395,9 @@ Content-Type: application/json
t.Fatal("Failed to Build ATC System Config Batch")
}
assert.Equal(t, batchATCSystemConfigFileExpected, batchATCSystemConfigFile)
})
t.Run("success case: BuildATCSystemConfigBatch - Config Base only (empty expand _priorities)", func(t *testing.T) {
batchATCSystemConfigFileExpected := `
--request-separator
Content-Type: multipart/mixed;boundary=changeset
@@ -426,7 +416,7 @@ Content-Type: application/json
--request-separator--`
//no Configuration name supplied
// no Configuration name supplied
atcSystemConfigFileString := `{
"conf_name": "UNITTEST_PIPERSTEP",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -450,14 +440,12 @@ Content-Type: application/json
t.Fatal("Failed to Build ATC System Config Batch")
}
assert.Equal(t, batchATCSystemConfigFileExpected, batchATCSystemConfigFile)
})
t.Run("failure case: BuildATCSystemConfigBatch", func(t *testing.T) {
batchATCSystemConfigFileExpected := ``
//no Configuration name supplied
// no Configuration name supplied
atcSystemConfigFileString := `{
"conf_name": "UNITTEST_PIPERSTEP",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -487,14 +475,14 @@ Content-Type: application/json
t.Fatal("Failed to Build ATC System Config Batch")
}
assert.NotEqual(t, batchATCSystemConfigFileExpected, batchATCSystemConfigFile)
})
}
func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
t.Parallel()
t.Run("run Step Failure - ATC System Configuration File empty", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
autils := abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
@@ -511,19 +499,12 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
}
dir := t.TempDir()
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
}()
config := abapEnvironmentPushATCSystemConfigOptions{AtcSystemConfigFilePath: "atcSystemConfig.json"}
config := abapEnvironmentPushATCSystemConfigOptions{AtcSystemConfigFilePath: filepath.Join(dir, "atcSystemConfig.json")}
atcSystemConfigFileString := ``
err := ioutil.WriteFile(config.AtcSystemConfigFilePath, []byte(atcSystemConfigFileString), 0644)
err := os.WriteFile(config.AtcSystemConfigFilePath, []byte(atcSystemConfigFileString), 0o644)
if err != nil {
t.Fatal("Failed to write File: " + config.AtcSystemConfigFilePath)
}
@@ -535,7 +516,7 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
})
t.Run("run Step Failure - ATC System Configuration invalid", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
autils := abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
@@ -552,17 +533,10 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
}
dir := t.TempDir()
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
}()
config := abapEnvironmentPushATCSystemConfigOptions{AtcSystemConfigFilePath: filepath.Join(dir, "atcSystemConfig.json")}
config := abapEnvironmentPushATCSystemConfigOptions{AtcSystemConfigFilePath: "atcSystemConfig.json"}
//no Configuration name supplied
// no Configuration name supplied
atcSystemConfigFileString := `{
"conf_name": "",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -585,7 +559,7 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
]
}
`
err := ioutil.WriteFile(config.AtcSystemConfigFilePath, []byte(atcSystemConfigFileString), 0644)
err := os.WriteFile(config.AtcSystemConfigFilePath, []byte(atcSystemConfigFileString), 0o644)
if err != nil {
t.Fatal("Failed to write File: " + config.AtcSystemConfigFilePath)
}
@@ -597,7 +571,7 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
})
t.Run("run Step Successful - Push ATC System Configuration", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
autils := abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
@@ -614,17 +588,10 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
}
dir := t.TempDir()
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
}()
config := abapEnvironmentPushATCSystemConfigOptions{AtcSystemConfigFilePath: filepath.Join(dir, "atcSystemConfig.json")}
config := abapEnvironmentPushATCSystemConfigOptions{AtcSystemConfigFilePath: "atcSystemConfig.json"}
//valid ATC System Configuration File
// valid ATC System Configuration File
atcSystemConfigFileString := `{
"conf_name": "UNITTEST_PIPERSTEP",
"checkvariant": "SAP_CLOUD_PLATFORM_ATC_DEFAULT",
@@ -647,7 +614,7 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
]
}
`
err := ioutil.WriteFile(config.AtcSystemConfigFilePath, []byte(atcSystemConfigFileString), 0644)
err := os.WriteFile(config.AtcSystemConfigFilePath, []byte(atcSystemConfigFileString), 0o644)
if err != nil {
t.Fatal("Failed to write File: " + config.AtcSystemConfigFilePath)
}
@@ -657,7 +624,7 @@ func TestRunAbapEnvironmentPushATCSystemConfig(t *testing.T) {
})
t.Run("run Step Failure - ATC System Configuration File does not exist", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
autils := abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"

View File

@@ -36,6 +36,7 @@ func abapEnvironmentRunATCCheck(options abapEnvironmentRunATCCheckOptions, telem
var err error
client := piperhttp.Client{}
fileUtils := piperutils.Files{}
cookieJar, _ := cookiejar.New(nil)
clientOptions := piperhttp.ClientOptions{
CookieJar: cookieJar,
@@ -62,7 +63,7 @@ func abapEnvironmentRunATCCheck(options abapEnvironmentRunATCCheckOptions, telem
resp, err = triggerATCRun(options, details, &client)
}
if err == nil {
err = fetchAndPersistATCResults(resp, details, &client, options.AtcResultsFileName, options.GenerateHTML)
err = fetchAndPersistATCResults(resp, details, &client, &fileUtils, options.AtcResultsFileName, options.GenerateHTML)
}
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
@@ -71,7 +72,7 @@ func abapEnvironmentRunATCCheck(options abapEnvironmentRunATCCheckOptions, telem
log.Entry().Info("ATC 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")
}
func fetchAndPersistATCResults(resp *http.Response, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, atcResultFileName string, generateHTML bool) error {
func fetchAndPersistATCResults(resp *http.Response, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, utils piperutils.FileUtils, atcResultFileName string, generateHTML bool) error {
var err error
abapEndpoint := details.URL
location := resp.Header.Get("Location")
@@ -88,7 +89,7 @@ func fetchAndPersistATCResults(resp *http.Response, details abaputils.Connection
}
if err == nil {
defer resp.Body.Close()
err = logAndPersistATCResult(body, atcResultFileName, generateHTML)
err = logAndPersistATCResult(utils, body, atcResultFileName, generateHTML)
}
if err != nil {
return fmt.Errorf("Handling ATC result failed: %w", err)
@@ -202,7 +203,7 @@ func getATCObjectSet(ATCConfig ATCConfiguration) (objectSet string, err error) {
return objectSet, nil
}
func logAndPersistATCResult(body []byte, atcResultFileName string, generateHTML bool) error {
func logAndPersistATCResult(utils piperutils.FileUtils, body []byte, atcResultFileName string, generateHTML bool) error {
if len(body) == 0 {
return fmt.Errorf("Parsing ATC result failed: %w", errors.New("Body is empty, can't parse empty body"))
}
@@ -241,7 +242,7 @@ func logAndPersistATCResult(body []byte, atcResultFileName string, generateHTML
reports = append(reports, piperutils.Path{Target: atcResultFileName, Name: "ATC Results HTML file", Mandatory: true})
}
}
piperutils.PersistReportsAndLinks("abapEnvironmentRunATCCheck", "", reports, nil)
piperutils.PersistReportsAndLinks("abapEnvironmentRunATCCheck", "", utils, reports, nil)
}
if err != nil {
return fmt.Errorf("Writing results failed: %w", err)

View File

@@ -23,7 +23,7 @@ func TestHostConfig(t *testing.T) {
}
execRunner := &mock.ExecMockRunner{}
var autils = abaputils.AbapUtils{
autils := abaputils.AbapUtils{
Exec: execRunner,
}
var con abaputils.ConnectionDetailsHTTP
@@ -37,7 +37,7 @@ func TestHostConfig(t *testing.T) {
}
})
t.Run("No host/ServiceKey configuration", func(t *testing.T) {
//Testing without CfOrg parameter
// Testing without CfOrg parameter
config := abaputils.AbapEnvironmentOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfSpace: "testSpace",
@@ -51,7 +51,7 @@ func TestHostConfig(t *testing.T) {
}
execRunner := &mock.ExecMockRunner{}
var autils = abaputils.AbapUtils{
autils := abaputils.AbapUtils{
Exec: execRunner,
}
@@ -76,7 +76,7 @@ func TestHostConfig(t *testing.T) {
AbapEnvOptions: config,
}
execRunner := &mock.ExecMockRunner{}
var autils = abaputils.AbapUtils{
autils := abaputils.AbapUtils{
Exec: execRunner,
}
var con abaputils.ConnectionDetailsHTTP
@@ -242,7 +242,7 @@ func TestParseATCResult(t *testing.T) {
</file>
</checkstyle>`
body := []byte(bodyString)
err := logAndPersistATCResult(body, "ATCResults.xml", false)
err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false)
assert.Equal(t, nil, err)
})
t.Run("succes case: test parsing empty XML result", func(t *testing.T) {
@@ -257,14 +257,14 @@ func TestParseATCResult(t *testing.T) {
<checkstyle>
</checkstyle>`
body := []byte(bodyString)
err := logAndPersistATCResult(body, "ATCResults.xml", false)
err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.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 := logAndPersistATCResult(body, "ATCResults.xml", false)
err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false)
assert.EqualError(t, err, "Parsing ATC result failed: Body is empty, can't parse empty body")
})
t.Run("failure case: html response", func(t *testing.T) {
@@ -277,7 +277,7 @@ func TestParseATCResult(t *testing.T) {
}()
bodyString := `<html><head><title>HTMLTestResponse</title</head></html>`
body := []byte(bodyString)
err := logAndPersistATCResult(body, "ATCResults.xml", false)
err := logAndPersistATCResult(&mock.FilesMock{}, body, "ATCResults.xml", false)
assert.EqualError(t, err, "The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system")
})
}
@@ -294,7 +294,6 @@ func TestBuildATCCheckBody(t *testing.T) {
assert.Equal(t, nil, err)
})
t.Run("success case: Test build body with example yaml config", func(t *testing.T) {
expectedObjectSet := "<obj:objectSet><obj:softwarecomponents><obj:softwarecomponent value=\"testSoftwareComponent\"/><obj:softwarecomponent value=\"testSoftwareComponent2\"/></obj:softwarecomponents><obj:packages><obj:package value=\"testPackage\" includeSubpackages=\"true\"/><obj:package value=\"testPackage2\" includeSubpackages=\"false\"/></obj:packages></obj:objectSet>"
config := ATCConfiguration{
@@ -319,7 +318,6 @@ func TestBuildATCCheckBody(t *testing.T) {
assert.Equal(t, nil, err)
})
t.Run("failure case: Test build body with example yaml config with only packages and no software components", func(t *testing.T) {
expectedObjectSet := `<obj:objectSet><obj:packages><obj:package value="testPackage" includeSubpackages="true"/><obj:package value="testPackage2" includeSubpackages="false"/></obj:packages></obj:objectSet>`
var err error
@@ -342,7 +340,6 @@ func TestBuildATCCheckBody(t *testing.T) {
assert.Equal(t, nil, err)
})
t.Run("success case: Test build body with example yaml config with no packages and only software components", func(t *testing.T) {
expectedObjectSet := `<obj:objectSet><obj:softwarecomponents><obj:softwarecomponent value="testSoftwareComponent"/><obj:softwarecomponent value="testSoftwareComponent2"/></obj:softwarecomponents></obj:objectSet>`
config := ATCConfiguration{
@@ -365,7 +362,7 @@ func TestBuildATCCheckBody(t *testing.T) {
}
func TestGenerateHTMLDocument(t *testing.T) {
//Failure case is not needed --> all failing cases would be depended on parsedXML *Result which is covered in TestParseATCResult
// Failure case is not needed --> all failing cases would be depended on parsedXML *Result which is covered in TestParseATCResult
t.Run("success case: html response", func(t *testing.T) {
expectedResult := "<!DOCTYPE html><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>ATC Results</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><style>table,th,td {border: 1px solid black;border-collapse:collapse;}th,td{padding: 5px;text-align:left;font-size:medium;}</style></head><body><h1 style=\"text-align:left;font-size:large\">ATC Results</h1><table style=\"width:100%\"><tr><th>Severity</th><th>File</th><th>Message</th><th>Line</th><th>Checked by</th></tr><tr style=\"background-color: rgba(227,85,0)\"><td>error</td><td>testFile2</td><td>testMessage</td><td style=\"text-align:center\">1</td><td>sourceTester</td></tr><tr style=\"background-color: rgba(255,175,0, 0.75)\"><td>warning</td><td>testFile</td><td>testMessage2</td><td style=\"text-align:center\">2</td><td>sourceTester</td></tr><tr style=\"background-color: rgba(255,175,0, 0.2)\"><td>info</td><td>testFile</td><td>testMessage1</td><td style=\"text-align:center\">1</td><td>sourceTester</td></tr></table></body></html>"
@@ -393,9 +390,7 @@ func TestGenerateHTMLDocument(t *testing.T) {
}
func TestResolveConfiguration(t *testing.T) {
t.Run("resolve atcConfig-yml with ATC Set", func(t *testing.T) {
expectedBodyString := "<?xml version=\"1.0\" encoding=\"UTF-8\"?><atc:runparameters xmlns:atc=\"http://www.sap.com/adt/atc\" xmlns:obj=\"http://www.sap.com/adt/objectset\" checkVariant=\"MY_TEST\" configuration=\"MY_CONFIG\"><obj:objectSet><obj:softwarecomponents><obj:softwarecomponent value=\"Z_TEST\"/><obj:softwarecomponent value=\"/DMO/SWC\"/></obj:softwarecomponents><obj:packages><obj:package value=\"Z_TEST\" includeSubpackages=\"false\"/><obj:package value=\"Z_TEST_TREE\" includeSubpackages=\"true\"/></obj:packages></obj:objectSet></atc:runparameters>"
config := abapEnvironmentRunATCCheckOptions{
AtcConfig: "atc.yml",
@@ -421,17 +416,15 @@ atcobjects:
- name: /DMO/SWC
`
err := ioutil.WriteFile(config.AtcConfig, []byte(yamlBody), 0644)
err := ioutil.WriteFile(config.AtcConfig, []byte(yamlBody), 0o644)
if assert.Equal(t, err, nil) {
bodyString, err := buildATCRequestBody(config)
assert.Equal(t, nil, err)
assert.Equal(t, expectedBodyString, bodyString)
}
})
t.Run("resolve atcConfig-yml with OSL", func(t *testing.T) {
config := abapEnvironmentRunATCCheckOptions{
AtcConfig: "atc.yml",
}
@@ -459,7 +452,7 @@ objectset:
`
expectedBodyString := "<?xml version=\"1.0\" encoding=\"UTF-8\"?><atc:runparameters xmlns:atc=\"http://www.sap.com/adt/atc\" xmlns:obj=\"http://www.sap.com/adt/objectset\" checkVariant=\"MY_TEST\" configuration=\"MY_CONFIG\"><osl:objectSet xsi:type=\"multiPropertySet\" xmlns:osl=\"http://www.sap.com/api/osl\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><osl:package name=\"Z_TEST\"/><osl:package name=\"Z_TEST_TREE\" includeSubpackages=\"true\"/><osl:softwareComponent name=\"Z_TEST\"/><osl:softwareComponent name=\"/DMO/SWC\"/></osl:objectSet></atc:runparameters>"
err := ioutil.WriteFile(config.AtcConfig, []byte(yamlBody), 0644)
err := ioutil.WriteFile(config.AtcConfig, []byte(yamlBody), 0o644)
if assert.Equal(t, err, nil) {
bodyString, err := buildATCRequestBody(config)
assert.Equal(t, nil, err)
@@ -468,7 +461,6 @@ objectset:
})
t.Run("resolve repo-yml", func(t *testing.T) {
expectedBodyString := "<?xml version=\"1.0\" encoding=\"UTF-8\"?><atc:runparameters xmlns:atc=\"http://www.sap.com/adt/atc\" xmlns:obj=\"http://www.sap.com/adt/objectset\" checkVariant=\"ABAP_CLOUD_DEVELOPMENT_DEFAULT\"><obj:objectSet><obj:softwarecomponents><obj:softwarecomponent value=\"Z_TEST\"/><obj:softwarecomponent value=\"/DMO/SWC\"/></obj:softwarecomponents></obj:objectSet></atc:runparameters>"
config := abapEnvironmentRunATCCheckOptions{
Repositories: "repo.yml",
@@ -487,17 +479,15 @@ objectset:
- name: /DMO/SWC
`
err := ioutil.WriteFile(config.Repositories, []byte(yamlBody), 0644)
err := ioutil.WriteFile(config.Repositories, []byte(yamlBody), 0o644)
if assert.Equal(t, err, nil) {
bodyString, err := buildATCRequestBody(config)
assert.Equal(t, nil, err)
assert.Equal(t, expectedBodyString, bodyString)
}
})
t.Run("Missing config files", func(t *testing.T) {
config := abapEnvironmentRunATCCheckOptions{
AtcConfig: "atc.yml",
}
@@ -505,16 +495,13 @@ objectset:
bodyString, err := buildATCRequestBody(config)
assert.Equal(t, "Could not find atc.yml", err.Error())
assert.Equal(t, "", bodyString)
})
t.Run("Config file not specified", func(t *testing.T) {
config := abapEnvironmentRunATCCheckOptions{}
bodyString, err := buildATCRequestBody(config)
assert.Equal(t, "No configuration provided - please provide either an ATC configuration file or a repository configuration file", err.Error())
assert.Equal(t, "", bodyString)
})
}

View File

@@ -34,15 +34,16 @@ func abapEnvironmentRunAUnitTest(config abapEnvironmentRunAUnitTestOptions, tele
}
client := piperhttp.Client{}
utils := piperutils.Files{}
// 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)
err := runAbapEnvironmentRunAUnitTest(&config, telemetryData, &autils, &client, &utils)
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 {
func runAbapEnvironmentRunAUnitTest(config *abapEnvironmentRunAUnitTestOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender, utils piperutils.FileUtils) error {
var details abaputils.ConnectionDetailsHTTP
subOptions := convertAUnitOptions(config)
details, err := com.GetAbapCommunicationArrangementInfo(subOptions, "")
@@ -62,7 +63,7 @@ func runAbapEnvironmentRunAUnitTest(config *abapEnvironmentRunAUnitTestOptions,
resp, err = triggerAUnitrun(*config, details, client)
}
if err == nil {
err = fetchAndPersistAUnitResults(resp, details, client, config.AUnitResultsFileName, config.GenerateHTML)
err = fetchAndPersistAUnitResults(resp, details, client, utils, config.AUnitResultsFileName, config.GenerateHTML)
}
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
@@ -134,7 +135,7 @@ func convertAUnitOptions(options *abapEnvironmentRunAUnitTestOptions) abaputils.
return subOptions
}
func fetchAndPersistAUnitResults(resp *http.Response, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, aunitResultFileName string, generateHTML bool) error {
func fetchAndPersistAUnitResults(resp *http.Response, details abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, utils piperutils.FileUtils, aunitResultFileName string, generateHTML bool) error {
var err error
abapEndpoint := details.URL
location := resp.Header.Get("Location")
@@ -151,7 +152,7 @@ func fetchAndPersistAUnitResults(resp *http.Response, details abaputils.Connecti
}
if err == nil {
defer resp.Body.Close()
err = persistAUnitResult(body, aunitResultFileName, generateHTML)
err = persistAUnitResult(utils, body, aunitResultFileName, generateHTML)
}
if err != nil {
return fmt.Errorf("Handling AUnit result failed: %w", err)
@@ -344,7 +345,7 @@ func getAUnitResults(requestType string, details abaputils.ConnectionDetailsHTTP
return req, err
}
func persistAUnitResult(body []byte, aunitResultFileName string, generateHTML bool) (err error) {
func persistAUnitResult(utils piperutils.FileUtils, body []byte, aunitResultFileName string, generateHTML bool) (err error) {
if len(body) == 0 {
return fmt.Errorf("Parsing AUnit result failed: %w", errors.New("Body is empty, can't parse empty body"))
}
@@ -396,7 +397,7 @@ func persistAUnitResult(body []byte, aunitResultFileName string, generateHTML bo
}
//Persist findings afterwards
reports = append(reports, piperutils.Path{Target: aunitResultFileName, Name: "AUnit Results", Mandatory: true})
piperutils.PersistReportsAndLinks("abapEnvironmentRunAUnitTest", "", reports, nil)
piperutils.PersistReportsAndLinks("abapEnvironmentRunAUnitTest", "", utils, reports, nil)
return nil
}

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,6 @@ import (
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"math"
"os"
"path/filepath"
@@ -36,6 +35,7 @@ type checkmarxExecuteScanUtils interface {
Stat(name string) (os.FileInfo, error)
Open(name string) (*os.File, error)
WriteFile(filename string, data []byte, perm os.FileMode) error
MkdirAll(path string, perm os.FileMode) error
PathMatch(pattern, name string) (bool, error)
GetWorkspace() string
GetIssueService() *github.IssuesService
@@ -57,7 +57,11 @@ func (c *checkmarxExecuteScanUtilsBundle) GetWorkspace() string {
}
func (c *checkmarxExecuteScanUtilsBundle) WriteFile(filename string, data []byte, perm os.FileMode) error {
return ioutil.WriteFile(filename, data, perm)
return os.WriteFile(filename, data, perm)
}
func (c *checkmarxExecuteScanUtilsBundle) MkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
func (c *checkmarxExecuteScanUtilsBundle) FileInfoHeader(fi os.FileInfo) (*zip.FileHeader, error) {
@@ -367,7 +371,7 @@ func verifyCxProjectCompliance(ctx context.Context, config checkmarxExecuteScanO
}
// create toolrecord
toolRecordFileName, err := createToolRecordCx(utils.GetWorkspace(), config, results)
toolRecordFileName, err := createToolRecordCx(utils, utils.GetWorkspace(), config, results)
if err != nil {
// do not fail until the framework is well established
log.Entry().Warning("TR_CHECKMARX: Failed to create toolrecord file ...", err)
@@ -417,7 +421,7 @@ func verifyCxProjectCompliance(ctx context.Context, config checkmarxExecuteScanO
}
}
piperutils.PersistReportsAndLinks("checkmarxExecuteScan", utils.GetWorkspace(), reports, links)
piperutils.PersistReportsAndLinks("checkmarxExecuteScan", utils.GetWorkspace(), utils, reports, links)
reportToInflux(results, influx)
if insecure {
@@ -962,8 +966,8 @@ func isFileNotMatchingPattern(patterns []string, path string, info os.FileInfo,
return true, nil
}
func createToolRecordCx(workspace string, config checkmarxExecuteScanOptions, results map[string]interface{}) (string, error) {
record := toolrecord.New(workspace, "checkmarx", config.ServerURL)
func createToolRecordCx(utils checkmarxExecuteScanUtils, workspace string, config checkmarxExecuteScanOptions, results map[string]interface{}) (string, error) {
record := toolrecord.New(utils, workspace, "checkmarx", config.ServerURL)
// Todo TeamId - see run_scan()
// record.AddKeyData("team", XXX, resultMap["Team"], "")
// Project

View File

@@ -321,6 +321,10 @@ func (c *checkmarxExecuteScanUtilsMock) WriteFile(filename string, data []byte,
return ioutil.WriteFile(filename, data, perm)
}
func (c *checkmarxExecuteScanUtilsMock) MkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
func (c *checkmarxExecuteScanUtilsMock) FileInfoHeader(fi os.FileInfo) (*zip.FileHeader, error) {
if c.errorOnFileInfoHeader {
return nil, fmt.Errorf("error on FileInfoHeader")

View File

@@ -16,7 +16,7 @@ import (
type codeqlExecuteScanUtils interface {
command.ExecRunner
FileExists(filename string) (bool, error)
piperutils.FileUtils
}
type RepoInfo struct {
@@ -226,7 +226,7 @@ func runCodeqlExecuteScan(config *codeqlExecuteScanOptions, telemetryData *telem
reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/codeqlReport.csv", config.ModulePath)})
piperutils.PersistReportsAndLinks("codeqlExecuteScan", "./", reports, nil)
piperutils.PersistReportsAndLinks("codeqlExecuteScan", "./", utils, reports, nil)
err = uploadResults(config, utils)
if err != nil {

View File

@@ -198,7 +198,7 @@ func runDetect(ctx context.Context, config detectExecuteScanOptions, utils detec
}
}
// create Toolrecord file
toolRecordFileName, toolRecordErr := createToolRecordDetect("./", config, blackduckSystem)
toolRecordFileName, toolRecordErr := createToolRecordDetect(utils, "./", config, blackduckSystem)
if toolRecordErr != nil {
// do not fail until the framework is well established
log.Entry().Warning("TR_DETECT: Failed to create toolrecord file "+toolRecordFileName, err)
@@ -538,7 +538,7 @@ func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOpt
}
paths = append(paths, policyReportPaths...)
piperutils.PersistReportsAndLinks("detectExecuteScan", "", paths, nil)
piperutils.PersistReportsAndLinks("detectExecuteScan", "", utils, paths, nil)
if err != nil {
errorsOccured = append(errorsOccured, fmt.Sprint(err))
}
@@ -719,8 +719,8 @@ func isActivePolicyViolation(status string) bool {
}
// create toolrecord file for detectExecute
func createToolRecordDetect(workspace string, config detectExecuteScanOptions, sys *blackduckSystem) (string, error) {
record := toolrecord.New(workspace, "detectExecute", config.ServerURL)
func createToolRecordDetect(utils detectUtils, workspace string, config detectExecuteScanOptions, sys *blackduckSystem) (string, error) {
record := toolrecord.New(utils, workspace, "detectExecute", config.ServerURL)
project, err := sys.Client.GetProject(config.ProjectName)
if err != nil {
return "", fmt.Errorf("TR_DETECT: GetProject failed %v", err)

View File

@@ -57,6 +57,7 @@ type pullRequestService interface {
type fortifyUtils interface {
maven.Utils
gradle.Utils
piperutils.FileUtils
SetDir(d string)
GetArtifact(buildTool, buildDescriptorFile string, options *versioning.Options) (versioning.Artifact, error)
@@ -122,7 +123,7 @@ func fortifyExecuteScan(config fortifyExecuteScanOptions, telemetryData *telemet
influx.step_data.fields.fortify = false
reports, err := runFortifyScan(ctx, config, sys, utils, telemetryData, influx, auditStatus)
piperutils.PersistReportsAndLinks("fortifyExecuteScan", config.ModulePath, reports, nil)
piperutils.PersistReportsAndLinks("fortifyExecuteScan", config.ModulePath, utils, reports, nil)
if err != nil {
log.Entry().WithError(err).Fatal("Fortify scan and check failed")
}
@@ -229,7 +230,7 @@ func runFortifyScan(ctx context.Context, config fortifyExecuteScanOptions, sys f
// create toolrecord file
// tbd - how to handle verifyOnly
toolRecordFileName, err := createToolRecordFortify("./", config, project.ID, fortifyProjectName, projectVersion.ID, fortifyProjectVersion)
toolRecordFileName, err := createToolRecordFortify(utils, "./", config, project.ID, fortifyProjectName, projectVersion.ID, fortifyProjectVersion)
if err != nil {
// do not fail until the framework is well established
log.Entry().Warning("TR_FORTIFY: Failed to create toolrecord file ...", err)
@@ -1211,8 +1212,8 @@ func getSeparator() string {
return ":"
}
func createToolRecordFortify(workspace string, config fortifyExecuteScanOptions, projectID int64, projectName string, projectVersionID int64, projectVersion string) (string, error) {
record := toolrecord.New(workspace, "fortify", config.ServerURL)
func createToolRecordFortify(utils fortifyUtils, workspace string, config fortifyExecuteScanOptions, projectID int64, projectName string, projectVersionID int64, projectVersion string) (string, error) {
record := toolrecord.New(utils, workspace, "fortify", config.ServerURL)
// Project
err := record.AddKeyData("project",
strconv.FormatInt(projectID, 10),

View File

@@ -784,7 +784,7 @@ func (f filesMock) TempDir(dir string, pattern string) (name string, err error)
if f.failOnCreation {
return "", errors.New("error appeared")
}
return piperutils.Files{}.TempDir(dir, pattern)
return piperutils.Files{}.TempDir("", pattern)
}
func (f *filesMock) RemoveAll(path string) error {

View File

@@ -22,6 +22,7 @@ const hadolintCommand = "hadolint"
type HadolintPiperFileUtils interface {
FileExists(filename string) (bool, error)
FileWrite(filename string, data []byte, perm os.FileMode) error
WriteFile(filename string, data []byte, perm os.FileMode) error
}
// HadolintClient abstracts http.Client
@@ -114,7 +115,7 @@ func runHadolint(config hadolintExecuteOptions, utils hadolintUtils) error {
}
//TODO: mock away in tests
// persist report information
piperutils.PersistReportsAndLinks("hadolintExecute", "./", []piperutils.Path{{Target: config.ReportFile}}, []piperutils.Path{})
piperutils.PersistReportsAndLinks("hadolintExecute", "./", utils, []piperutils.Path{{Target: config.ReportFile}}, []piperutils.Path{})
return nil
}

View File

@@ -21,7 +21,9 @@ func TestRunHadolintExecute(t *testing.T) {
}
fileMock.
On("FileExists", config.ConfigurationFile).Return(false, nil)
On("FileExists", config.ConfigurationFile).Return(false, nil).
On("WriteFile", "hadolintExecute_reports.json", mock.Anything, mock.Anything).Return(nil).
On("WriteFile", "hadolintExecute_links.json", mock.Anything, mock.Anything).Return(nil)
// test
err := runHadolint(config, hadolintUtils{
@@ -62,7 +64,11 @@ func TestRunHadolintExecute(t *testing.T) {
// checks if config exists before downloading
On("FileExists", config.ConfigurationFile).Return(false, nil).Once().
// checks again but config is now downloaded
On("FileExists", config.ConfigurationFile).Return(true, nil)
On("FileExists", config.ConfigurationFile).Return(true, nil).
On("WriteFile", "hadolintExecute_reports.json", mock.Anything, mock.Anything).Return(nil).
On("WriteFile", "hadolintExecute_links.json", mock.Anything, mock.Anything).Return(nil)
//m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" }))
// test
err := runHadolint(config, hadolintUtils{
HadolintPiperFileUtils: fileMock,

View File

@@ -98,7 +98,7 @@ func runMalwareScan(config *malwareExecuteScanOptions, telemetryData *telemetry.
log.Entry().Infof("* Signatures: %s", scannerInfo.SignatureTimestamp)
log.Entry().Infof("***************************************")
if _, err = createToolRecordMalwareScan("./", config, scannerInfo); err != nil {
if _, err = createToolRecordMalwareScan(utils, "./", config, scannerInfo); err != nil {
return err
}
@@ -187,8 +187,8 @@ func validateHash(remoteHash, fileName string, utils malwareScanUtils) error {
}
// create toolrecord file for malwarescan
func createToolRecordMalwareScan(workspace string, config *malwareExecuteScanOptions, scanner *malwarescan.Info) (string, error) {
record := toolrecord.New(workspace, "malwarescan", config.Host)
func createToolRecordMalwareScan(utils malwareScanUtils, workspace string, config *malwareExecuteScanOptions, scanner *malwarescan.Info) (string, error) {
record := toolrecord.New(utils, workspace, "malwarescan", config.Host)
record.SetOverallDisplayData("Malware Scanner", "")
if err := record.AddKeyData("engineVersion", scanner.EngineVersion, "Engine Version", ""); err != nil {

View File

@@ -268,7 +268,7 @@ func executeProtecodeScan(influx *protecodeExecuteScanInflux, client protecode.P
}
// create toolrecord file
toolRecordFileName, err := createToolRecordProtecode("./", config, productID, webuiURL)
toolRecordFileName, err := createToolRecordProtecode(utils, "./", config, productID, webuiURL)
if err != nil {
// do not fail until the framework is well established
log.Entry().Warning("TR_PROTECODE: Failed to create toolrecord file ...", err)
@@ -276,7 +276,7 @@ func executeProtecodeScan(influx *protecodeExecuteScanInflux, client protecode.P
reports = append(reports, piperutils.Path{Target: toolRecordFileName})
}
piperutils.PersistReportsAndLinks("protecodeExecuteScan", "", reports, links)
piperutils.PersistReportsAndLinks("protecodeExecuteScan", "", utils, reports, links)
if config.FailOnSevereVulnerabilities && protecode.HasSevereVulnerabilities(result.Result, config.ExcludeCVEs) {
log.SetErrorCategory(log.ErrorCompliance)
@@ -418,8 +418,8 @@ func getProcessedVersion(config *protecodeExecuteScanOptions) string {
// create toolrecord file for protecode
// todo: check if group and product names can be retrieved
func createToolRecordProtecode(workspace string, config *protecodeExecuteScanOptions, productID int, webuiURL string) (string, error) {
record := toolrecord.New(workspace, "protecode", config.ServerURL)
func createToolRecordProtecode(utils protecodeUtils, workspace string, config *protecodeExecuteScanOptions, productID int, webuiURL string) (string, error) {
record := toolrecord.New(utils, workspace, "protecode", config.ServerURL)
groupURL := config.ServerURL + "/#/groups/" + config.Group
err := record.AddKeyData("group",
config.Group,

View File

@@ -18,9 +18,7 @@ import (
keytool "github.com/SAP/jenkins-library/pkg/java"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/orchestrator"
FileUtils "github.com/SAP/jenkins-library/pkg/piperutils"
SliceUtils "github.com/SAP/jenkins-library/pkg/piperutils"
StepResults "github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/piperutils"
SonarUtils "github.com/SAP/jenkins-library/pkg/sonar"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/versioning"
@@ -45,8 +43,8 @@ var (
sonar sonarSettings
execLookPath = exec.LookPath
fileUtilsExists = FileUtils.FileExists
fileUtilsUnzip = FileUtils.Unzip
fileUtilsExists = piperutils.FileExists
fileUtilsUnzip = piperutils.Unzip
osRename = os.Rename
osStat = os.Stat
doublestarGlob = doublestar.Glob
@@ -95,7 +93,8 @@ func sonarExecuteScan(config sonarExecuteScanOptions, _ *telemetry.CustomData, i
}
influx.step_data.fields.sonar = false
if err := runSonar(config, downloadClient, &runner, apiClient, influx); err != nil {
fileUtils := piperutils.Files{}
if err := runSonar(config, downloadClient, &runner, apiClient, &fileUtils, influx); err != nil {
if log.GetErrorCategory() == log.ErrorUndefined && runner.GetExitCode() == 2 {
// see https://github.com/SonarSource/sonar-scanner-cli/blob/adb67d645c3bcb9b46f29dea06ba082ebec9ba7a/src/main/java/org/sonarsource/scanner/cli/Exit.java#L25
log.SetErrorCategory(log.ErrorConfiguration)
@@ -105,7 +104,7 @@ func sonarExecuteScan(config sonarExecuteScanOptions, _ *telemetry.CustomData, i
influx.step_data.fields.sonar = true
}
func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runner command.ExecRunner, apiClient SonarUtils.Sender, influx *sonarExecuteScanInflux) error {
func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runner command.ExecRunner, apiClient SonarUtils.Sender, utils piperutils.FileUtils, influx *sonarExecuteScanInflux) error {
// Set config based on orchestrator-specific environment variables
detectParametersFromCI(&config)
@@ -168,7 +167,7 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne
sonar.options = append(sonar.options, config.Options...)
}
sonar.options = SliceUtils.PrefixIfNeeded(SliceUtils.Trim(sonar.options), "-D")
sonar.options = piperutils.PrefixIfNeeded(piperutils.Trim(sonar.options), "-D")
log.Entry().
WithField("command", sonar.binary).
@@ -194,13 +193,13 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne
return nil
}
// write links JSON
links := []StepResults.Path{
links := []piperutils.Path{
{
Target: taskReport.DashboardURL,
Name: "Sonar Web UI",
},
}
StepResults.PersistReportsAndLinks("sonarExecuteScan", sonar.workingDir, nil, links)
piperutils.PersistReportsAndLinks("sonarExecuteScan", sonar.workingDir, utils, nil, links)
if len(config.Token) == 0 {
log.Entry().Warn("no measurements are fetched due to missing credentials")
@@ -278,7 +277,7 @@ func runSonar(config sonarExecuteScanOptions, client piperhttp.Downloader, runne
// isInOptions returns true, if the given property is already provided in config.Options.
func isInOptions(config sonarExecuteScanOptions, property string) bool {
property = strings.TrimSuffix(property, "=")
return SliceUtils.ContainsStringPart(config.Options, property)
return piperutils.ContainsStringPart(config.Options, property)
}
func addJavaBinaries() {

View File

@@ -17,11 +17,11 @@ import (
piperHttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/mock"
FileUtils "github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/piperutils"
SonarUtils "github.com/SAP/jenkins-library/pkg/sonar"
)
//TODO: extract to mock package
// TODO: extract to mock package
type mockDownloader struct {
shouldFail bool
requestedURL []string
@@ -92,8 +92,8 @@ func mockGlob(matchesForPatterns map[string][]string) func(pattern string) ([]st
}
func createTaskReportFile(t *testing.T, workingDir string) {
require.NoError(t, os.MkdirAll(filepath.Join(workingDir, ".scannerwork"), 0755))
require.NoError(t, ioutil.WriteFile(filepath.Join(workingDir, ".scannerwork", "report-task.txt"), []byte(taskReportContent), 0755))
require.NoError(t, os.MkdirAll(filepath.Join(workingDir, ".scannerwork"), 0o755))
require.NoError(t, ioutil.WriteFile(filepath.Join(workingDir, ".scannerwork", "report-task.txt"), []byte(taskReportContent), 0o755))
require.FileExists(t, filepath.Join(workingDir, ".scannerwork", "report-task.txt"))
}
@@ -175,7 +175,7 @@ func TestRunSonar(t *testing.T) {
}
fileUtilsExists = mockFileUtilsExists(true)
// test
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &sonarExecuteScanInflux{})
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &mock.FilesMock{}, &sonarExecuteScanInflux{})
// assert
assert.NoError(t, err)
assert.Contains(t, sonar.options, "-Dsonar.projectVersion=1")
@@ -183,8 +183,6 @@ func TestRunSonar(t *testing.T) {
assert.Contains(t, sonar.environment, "SONAR_HOST_URL="+sonarServerURL)
assert.Contains(t, sonar.environment, "SONAR_TOKEN=secret-ABC")
assert.Contains(t, sonar.environment, "SONAR_SCANNER_OPTS=-Djavax.net.ssl.trustStore="+filepath.Join(getWorkingDir(), ".certificates", "cacerts")+" -Djavax.net.ssl.trustStorePassword=changeit")
assert.FileExists(t, filepath.Join(sonar.workingDir, "sonarExecuteScan_reports.json"))
assert.FileExists(t, filepath.Join(sonar.workingDir, "sonarExecuteScan_links.json"))
})
t.Run("with custom options", func(t *testing.T) {
// init
@@ -203,10 +201,10 @@ func TestRunSonar(t *testing.T) {
}
fileUtilsExists = mockFileUtilsExists(true)
defer func() {
fileUtilsExists = FileUtils.FileExists
fileUtilsExists = piperutils.FileExists
}()
// test
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &sonarExecuteScanInflux{})
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &mock.FilesMock{}, &sonarExecuteScanInflux{})
// assert
assert.NoError(t, err)
assert.Contains(t, sonar.options, "-Dsonar.projectKey=piper")
@@ -235,7 +233,7 @@ func TestRunSonar(t *testing.T) {
osStat = mockOsStat(existsMap)
defer func() {
fileUtilsExists = FileUtils.FileExists
fileUtilsExists = piperutils.FileExists
doublestarGlob = doublestar.Glob
osStat = os.Stat
}()
@@ -244,7 +242,7 @@ func TestRunSonar(t *testing.T) {
PullRequestProvider: "GitHub",
}
// test
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &sonarExecuteScanInflux{})
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &mock.FilesMock{}, &sonarExecuteScanInflux{})
// assert
assert.NoError(t, err)
assert.Contains(t, sonar.options, fmt.Sprintf("-Dsonar.java.binaries=%s,%s,%s",
@@ -274,7 +272,7 @@ func TestRunSonar(t *testing.T) {
osStat = mockOsStat(existsMap)
defer func() {
fileUtilsExists = FileUtils.FileExists
fileUtilsExists = piperutils.FileExists
doublestarGlob = doublestar.Glob
osStat = os.Stat
}()
@@ -284,7 +282,7 @@ func TestRunSonar(t *testing.T) {
PullRequestProvider: "GitHub",
}
// test
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &sonarExecuteScanInflux{})
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &mock.FilesMock{}, &sonarExecuteScanInflux{})
// assert
assert.NoError(t, err)
assert.NotContains(t, sonar.options, fmt.Sprintf("-Dsonar.java.binaries=%s",
@@ -313,10 +311,10 @@ func TestRunSonar(t *testing.T) {
defer func() { GeneralConfig.Verbose = false }()
fileUtilsExists = mockFileUtilsExists(true)
defer func() {
fileUtilsExists = FileUtils.FileExists
fileUtilsExists = piperutils.FileExists
}()
// test
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &sonarExecuteScanInflux{})
err := runSonar(options, &mockDownloadClient, &mockRunner, apiClient, &mock.FilesMock{}, &sonarExecuteScanInflux{})
// assert
assert.NoError(t, err)
assert.Contains(t, sonar.options, "-Dsonar.projectKey=mock-project-key")
@@ -430,7 +428,7 @@ func TestSonarLoadScanner(t *testing.T) {
osRename = mockOsRename(t, "sonar-scanner-4.6.2.2472-linux", ".sonar-scanner")
defer func() {
execLookPath = exec.LookPath
fileUtilsUnzip = FileUtils.Unzip
fileUtilsUnzip = piperutils.Unzip
osRename = os.Rename
}()
// test
@@ -455,7 +453,7 @@ func TestSonarLoadCertificates(t *testing.T) {
options: []string{},
}
fileUtilsExists = mockFileUtilsExists(true)
defer func() { fileUtilsExists = FileUtils.FileExists }()
defer func() { fileUtilsExists = piperutils.FileExists }()
// test
err := loadCertificates([]string{}, &mockClient, &mockRunner)
// assert

View File

@@ -226,7 +226,7 @@ func runWhitesourceScan(ctx context.Context, config *ScanOptions, scan *ws.Scan,
log.Entry().Info("-----------------------------------------------------")
paths, err := checkAndReportScanResults(ctx, config, scan, utils, sys, influx)
piperutils.PersistReportsAndLinks("whitesourceExecuteScan", "", paths, nil)
piperutils.PersistReportsAndLinks("whitesourceExecuteScan", "", utils, paths, nil)
persistScannedProjects(config, scan, commonPipelineEnvironment)
if err != nil {
return errors.Wrapf(err, "failed to check and report scan results")
@@ -273,7 +273,7 @@ func checkAndReportScanResults(ctx context.Context, config *ScanOptions, scan *w
// create toolrecord file
// tbd - how to handle verifyOnly
toolRecordFileName, err := createToolRecordWhitesource("./", config, scan)
toolRecordFileName, err := createToolRecordWhitesource(utils, "./", config, scan)
if err != nil {
// do not fail until the framework is well established
log.Entry().Warning("TR_WHITESOURCE: Failed to create toolrecord file ...", err)
@@ -750,7 +750,7 @@ func newVulnerabilityExcelReport(alerts []ws.Alert, config *ScanOptions, utils w
return err
}
filePath := piperutils.Path{Name: "aggregated-vulnerabilities", Target: fileName}
piperutils.PersistReportsAndLinks("whitesourceExecuteScan", "", []piperutils.Path{filePath}, nil)
piperutils.PersistReportsAndLinks("whitesourceExecuteScan", "", utils, []piperutils.Path{filePath}, nil)
return nil
}
@@ -812,7 +812,7 @@ func newLibraryCSVReport(libraries map[string][]ws.Library, config *ScanOptions,
return errors.Wrapf(err, "failed to write file: %s", fileName)
}
filePath := piperutils.Path{Name: "aggregated-libraries", Target: fileName}
piperutils.PersistReportsAndLinks("whitesourceExecuteScan", "", []piperutils.Path{filePath}, nil)
piperutils.PersistReportsAndLinks("whitesourceExecuteScan", "", utils, []piperutils.Path{filePath}, nil)
return nil
}
@@ -830,8 +830,8 @@ func persistScannedProjects(config *ScanOptions, scan *ws.Scan, commonPipelineEn
// create toolrecord file for whitesource
//
func createToolRecordWhitesource(workspace string, config *whitesourceExecuteScanOptions, scan *ws.Scan) (string, error) {
record := toolrecord.New(workspace, "whitesource", config.ServiceURL)
func createToolRecordWhitesource(utils whitesourceUtils, workspace string, config *whitesourceExecuteScanOptions, scan *ws.Scan) (string, error) {
record := toolrecord.New(utils, workspace, "whitesource", config.ServiceURL)
wsUiRoot := "https://saas.whitesourcesoftware.com"
productURL := wsUiRoot + "/Wss/WSS.html#!product;token=" + config.ProductToken
err := record.AddKeyData("product",

View File

@@ -8,7 +8,6 @@ import (
"time"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/reporting"
"github.com/SAP/jenkins-library/pkg/versioning"
@@ -663,7 +662,8 @@ func TestAggregateVersionWideLibraries(t *testing.T) {
contents, _ := utils.FileRead(resource)
asString := string(contents)
assert.Equal(t, "Library Name, Project Name\nmock-library, mock-project\n", asString)
assert.NotEmpty(t, piperenv.GetParameter("", "whitesourceExecuteScan_reports.json"))
c, _ := utils.ReadFile("/whitesourceExecuteScan_reports.json")
assert.NotEmpty(t, c)
}
})
}
@@ -692,7 +692,8 @@ func TestAggregateVersionWideVulnerabilities(t *testing.T) {
sheetContents, err := utils.FileRead(reportSheet)
assert.NoError(t, err)
assert.NotEmpty(t, sheetContents)
assert.NotEmpty(t, piperenv.GetParameter("", "whitesourceExecuteScan_reports.json"))
c, _ := utils.ReadFile("whitesourceExecuteScan_reports.json")
assert.NotEmpty(t, c)
})
}

View File

@@ -8,11 +8,13 @@ import (
"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"
)
type AakUtils interface {
command.ExecRunner
abapbuild.HTTPSendLoader
piperutils.FileUtils
ReadAddonDescriptor(FileName string) (abaputils.AddonDescriptor, error)
GetMaxRuntime() time.Duration
GetPollingInterval() time.Duration
@@ -21,6 +23,7 @@ type AakUtils interface {
type AakBundle struct {
*command.Command
*piperhttp.Client
*piperutils.Files
maxRuntime time.Duration
pollingInterval time.Duration
}

View File

@@ -9,12 +9,14 @@ import (
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/pkg/errors"
)
type AakBundleMock struct {
*mock.ExecMockRunner
*abaputils.ClientMock
*mock.FilesMock
maxRuntime time.Duration
}
@@ -23,6 +25,7 @@ func NewAakBundleMock() *AakBundleMock {
ExecMockRunner: &mock.ExecMockRunner{},
ClientMock: &abaputils.ClientMock{},
maxRuntime: 1 * time.Second,
FilesMock: &mock.FilesMock{},
}
return &utils
}
@@ -100,6 +103,7 @@ func (bundle *AakBundleMock) ReadAddonDescriptor(FileName string) (abaputils.Add
type AakBundleMockNewMC struct {
*mock.ExecMockRunner
*abapbuild.MockClient
*piperutils.Files
maxRuntime time.Duration
}

View File

@@ -440,7 +440,7 @@ func (b *Build) DownloadResults(filenames []string, basePath string, filenamePre
}
// PublishAllDownloadedResults : publishes all build artefacts which were downloaded before
func (b *Build) PublishAllDownloadedResults(stepname string, publish Publish) {
func (b *Build) PublishAllDownloadedResults(stepname string, utils piperutils.FileUtils) {
var filesToPublish []piperutils.Path
for i_task := range b.Tasks {
for i_result := range b.Tasks[i_task].Results {
@@ -451,12 +451,14 @@ func (b *Build) PublishAllDownloadedResults(stepname string, publish Publish) {
}
}
if len(filesToPublish) > 0 {
publish.PersistReportsAndLinks(stepname, "", filesToPublish, nil)
if err := piperutils.PersistReportsAndLinks(stepname, "", utils, filesToPublish, nil); err != nil {
log.Entry().WithError(err).Error("failed to persist reports")
}
}
}
// PublishDownloadedResults : Publishes build artefacts specified in filenames
func (b *Build) PublishDownloadedResults(stepname string, filenames []string, publish Publish) error {
func (b *Build) PublishDownloadedResults(stepname string, filenames []string, utils piperutils.FileUtils) error {
var filesToPublish []piperutils.Path
for i := range filenames {
result, err := b.GetResult(filenames[i])
@@ -472,7 +474,9 @@ func (b *Build) PublishDownloadedResults(stepname string, filenames []string, pu
}
}
if len(filesToPublish) > 0 {
publish.PersistReportsAndLinks(stepname, "", filesToPublish, nil)
if err := piperutils.PersistReportsAndLinks(stepname, "", utils, filesToPublish, nil); err != nil {
log.Entry().WithError(err).Error("failed to persist reports")
}
}
return nil
}
@@ -594,12 +598,3 @@ func unmarshalTasks(body []byte, connector Connector) ([]task, error) {
}
return tasks, nil
}
// *****************publish *******************************
type Publish interface {
PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path)
}
func PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
piperutils.PersistReportsAndLinks(stepName, workspace, reports, links)
}

View File

@@ -34,8 +34,7 @@ func (c *ClMock) SetOptions(opts piperhttp.ClientOptions) {}
// SendRequest : BF Send Fake request
func (c *ClMock) SendRequest(method string, url string, bdy io.Reader, hdr http.Header, cookies []*http.Cookie) (*http.Response, error) {
if method == "GET" || method == "POST" {
var body []byte
body = []byte(fakeResponse(method, url))
body := []byte(fakeResponse(method, url))
return &http.Response{
StatusCode: c.StatusCode,
Body: ioutil.NopCloser(bytes.NewReader(body)),

View File

@@ -7,18 +7,10 @@ import (
"time"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/stretchr/testify/assert"
)
type mockPublish struct {
reports []piperutils.Path
}
func (mP *mockPublish) PersistReportsAndLinks(stepName, workspace string, reports, links []piperutils.Path) {
mP.reports = reports
}
func testSetup(client piperhttp.Sender, buildID string) Build {
conn := new(Connector)
conn.Client = client
@@ -370,36 +362,26 @@ func TestPublishAllDownloadedResults(t *testing.T) {
t.Run("Something was downloaded", func(t *testing.T) {
//arrange
build := GetMockBuildTestDownloadPublish()
mP := mockPublish{}
files := mock.FilesMock{}
build.Tasks[1].Results[0].SavedFilename = "File1"
build.Tasks[1].Results[0].DownloadPath = "Dir1/File1"
build.Tasks[1].Results[2].SavedFilename = "File3"
build.Tasks[1].Results[2].DownloadPath = "File3"
//act
build.PublishAllDownloadedResults("MyStep", &mP)
build.PublishAllDownloadedResults("MyStep", &files)
//assert
publishedFiles := []piperutils.Path{
{
Target: "Dir1/File1",
Name: "File1",
Mandatory: true,
},
{
Target: "File3",
Name: "File3",
Mandatory: true,
},
}
assert.Equal(t, publishedFiles, mP.reports)
assert.True(t, files.HasFile("/MyStep_reports.json"))
assert.True(t, files.HasFile("/MyStep_links.json"))
})
t.Run("Nothing was downloaded", func(t *testing.T) {
//arrange
build := GetMockBuildTestDownloadPublish()
mP := mockPublish{}
files := mock.FilesMock{}
//act
build.PublishAllDownloadedResults("MyStep", &mP)
build.PublishAllDownloadedResults("MyStep", &files)
//assert
assert.Equal(t, 0, len(mP.reports))
assert.False(t, files.HasFile("/MyStep_reports.json"))
assert.False(t, files.HasFile("/MyStep_links.json"))
})
}
@@ -408,37 +390,28 @@ func TestPublishDownloadedResults(t *testing.T) {
t.Run("Publish downloaded files", func(t *testing.T) {
//arrange
build := GetMockBuildTestDownloadPublish()
mP := mockPublish{}
files := mock.FilesMock{}
build.Tasks[1].Results[0].SavedFilename = "SuperFile_File1"
build.Tasks[1].Results[0].DownloadPath = "Dir1/SuperFile_File1"
build.Tasks[1].Results[2].SavedFilename = "File3"
build.Tasks[1].Results[2].DownloadPath = "File3"
//act
err := build.PublishDownloadedResults("MyStep", filenames, &mP)
err := build.PublishDownloadedResults("MyStep", filenames, &files)
//assert
assert.NoError(t, err)
publishedFiles := []piperutils.Path{
{
Target: "Dir1/SuperFile_File1",
Name: "SuperFile_File1",
Mandatory: true,
},
{
Target: "File3",
Name: "File3",
Mandatory: true,
},
}
assert.Equal(t, publishedFiles, mP.reports)
assert.True(t, files.HasFile("/MyStep_reports.json"))
assert.True(t, files.HasFile("/MyStep_links.json"))
})
t.Run("Try to publish file which was not downloaded", func(t *testing.T) {
//arrange
build := GetMockBuildTestDownloadPublish()
mP := mockPublish{}
files := mock.FilesMock{}
build.Tasks[1].Results[0].SavedFilename = "SuperFile_File1"
build.Tasks[1].Results[0].DownloadPath = "Dir1/SuperFile_File1"
//act
err := build.PublishDownloadedResults("MyStep", filenames, &mP)
err := build.PublishDownloadedResults("MyStep", filenames, &files)
//assert
assert.Error(t, err)
})

View File

@@ -92,12 +92,22 @@ func TestCreateJSONReport(t *testing.T) {
assert.Equal(t, 5, reportingData.InformationTotal)
assert.Equal(t, 0, reportingData.InformationAudited)
assert.Equal(t, 2, len(*reportingData.LowPerQuery))
assert.Equal(t, "Low_Query_Name_1", (*reportingData.LowPerQuery)[0].QueryName)
assert.Equal(t, 0, (*reportingData.LowPerQuery)[0].Audited)
assert.Equal(t, 4, (*reportingData.LowPerQuery)[0].Total)
assert.Equal(t, "Low_Query_Name_2", (*reportingData.LowPerQuery)[1].QueryName)
assert.Equal(t, 5, (*reportingData.LowPerQuery)[1].Audited)
assert.Equal(t, 5, (*reportingData.LowPerQuery)[1].Total)
if (*reportingData.LowPerQuery)[0].QueryName == "Low_Query_Name_1" {
assert.Equal(t, "Low_Query_Name_1", (*reportingData.LowPerQuery)[0].QueryName)
assert.Equal(t, 0, (*reportingData.LowPerQuery)[0].Audited)
assert.Equal(t, 4, (*reportingData.LowPerQuery)[0].Total)
assert.Equal(t, "Low_Query_Name_2", (*reportingData.LowPerQuery)[1].QueryName)
assert.Equal(t, 5, (*reportingData.LowPerQuery)[1].Audited)
assert.Equal(t, 5, (*reportingData.LowPerQuery)[1].Total)
} else {
assert.Equal(t, "Low_Query_Name_1", (*reportingData.LowPerQuery)[1].QueryName)
assert.Equal(t, 0, (*reportingData.LowPerQuery)[1].Audited)
assert.Equal(t, 4, (*reportingData.LowPerQuery)[1].Total)
assert.Equal(t, "Low_Query_Name_2", (*reportingData.LowPerQuery)[0].QueryName)
assert.Equal(t, 5, (*reportingData.LowPerQuery)[0].Audited)
assert.Equal(t, 5, (*reportingData.LowPerQuery)[0].Total)
}
}
func TestJsonReportWithNoLowVulnData(t *testing.T) {

View File

@@ -47,3 +47,16 @@ func (_m *HadolintPiperFileUtils) FileWrite(filename string, data []byte, perm o
return r0
}
func (_m *HadolintPiperFileUtils) WriteFile(filename string, data []byte, perm os.FileMode) error {
ret := _m.Called(filename, data, perm)
var r0 error
if rf, ok := ret.Get(0).(func(string, []byte, os.FileMode) error); ok {
r0 = rf(filename, data, perm)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@@ -20,8 +20,8 @@ import (
var dirContent []byte
const (
defaultFileMode os.FileMode = 0644
defaultDirMode os.FileMode = 0755
defaultFileMode os.FileMode = 0o644
defaultDirMode os.FileMode = 0o755
)
type fileInfoMock struct {
@@ -50,7 +50,7 @@ func (p *fileProperties) isDir() bool {
return p.content == &dirContent
}
//FilesMock implements the functions from piperutils.Files with an in-memory file system.
// FilesMock implements the functions from piperutils.Files with an in-memory file system.
type FilesMock struct {
files map[string]*fileProperties
writtenFiles []string
@@ -274,6 +274,11 @@ func (f *FilesMock) FileRead(path string) ([]byte, error) {
return *props.content, nil
}
// ReadFile can be used as replacement for os.ReadFile in a compatible manner
func (f *FilesMock) ReadFile(name string) ([]byte, error) {
return f.FileRead(name)
}
// FileWrite just forwards to AddFile(), i.e. the content is associated with the given path.
func (f *FilesMock) FileWrite(path string, content []byte, mode os.FileMode) error {
if f.FileWriteError != nil {
@@ -288,6 +293,11 @@ func (f *FilesMock) FileWrite(path string, content []byte, mode os.FileMode) err
return nil
}
// WriteFile can be used as replacement for os.WriteFile in a compatible manner
func (f *FilesMock) WriteFile(filename string, data []byte, perm os.FileMode) error {
return f.FileWrite(filename, data, perm)
}
// RemoveAll is a proxy for FileRemove
func (f *FilesMock) RemoveAll(path string) error {
return f.FileRemove(path)
@@ -378,7 +388,7 @@ func (f *FilesMock) TempDir(baseDir string, pattern string) (string, error) {
tmpDir = fmt.Sprintf("%s/%stest", baseDir, pattern)
}
err := f.MkdirAll(tmpDir, 0755)
err := f.MkdirAll(tmpDir, 0o755)
if err != nil {
return "", err
}
@@ -621,5 +631,5 @@ func (f *FilesMock) Open(name string) (io.ReadWriteCloser, error) {
}
func (f *FilesMock) Create(name string) (io.ReadWriteCloser, error) {
return f.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
return f.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
}

View File

@@ -26,7 +26,9 @@ type FileUtils interface {
Copy(src, dest string) (int64, error)
Move(src, dest string) error
FileRead(path string) ([]byte, error)
ReadFile(path string) ([]byte, error)
FileWrite(path string, content []byte, perm os.FileMode) error
WriteFile(path string, content []byte, perm os.FileMode) error
FileRemove(path string) error
MkdirAll(path string, perm os.FileMode) error
Chmod(path string, mode os.FileMode) error
@@ -44,15 +46,14 @@ type FileUtils interface {
}
// Files ...
type Files struct {
}
type Files struct{}
// TempDir creates a temporary directory
func (f Files) TempDir(dir, pattern string) (name string, err error) {
if len(dir) == 0 {
// lazy init system temp dir in case it doesn't exist
if exists, _ := f.DirExists(os.TempDir()); !exists {
f.MkdirAll(os.TempDir(), 0666)
f.MkdirAll(os.TempDir(), 0o666)
}
}
@@ -94,9 +95,7 @@ func (f Files) DirExists(path string) (bool, error) {
// Copy ...
func (f Files) Copy(src, dst string) (int64, error) {
exists, err := f.FileExists(src)
if err != nil {
return 0, err
}
@@ -126,6 +125,7 @@ func (f Files) Copy(src, dst string) (int64, error) {
return nBytes, err
}
// Move will move files from src to dst
func (f Files) Move(src, dst string) error {
if exists, err := f.FileExists(src); err != nil {
return err
@@ -140,7 +140,7 @@ func (f Files) Move(src, dst string) error {
return f.FileRemove(src)
}
//Chmod is a wrapper for os.Chmod().
// Chmod is a wrapper for os.Chmod().
func (f Files) Chmod(path string, mode os.FileMode) error {
return os.Chmod(path, mode)
}
@@ -170,7 +170,6 @@ func (f Files) Chmod(path string, mode os.FileMode) error {
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
func Unzip(src, dest string) ([]string, error) {
var filenames []string
r, err := zip.OpenReader(src)
@@ -236,18 +235,15 @@ func Unzip(src, dest string) ([]string, error) {
// stripComponentLevel = 2 -> parentFolder/childFolder/someFile.Txt -> someFile.Txt
// when stripCompenent in 0 the untar will retain the original tar folder structure
// when stripCompmenet is greater than 0 the expectation is all files must be under that level folder and if not there is a hard check and failure condition
func Untar(src string, dest string, stripComponentLevel int) error {
file, err := os.Open(src)
defer file.Close()
if err != nil {
return fmt.Errorf("unable to open src: %v", err)
}
defer file.Close()
if b, err := isFileGzipped(src); err == nil && b {
zr, err := gzip.NewReader(file)
if err != nil {
return fmt.Errorf("requires gzip-compressed body: %v", err)
}
@@ -301,7 +297,7 @@ func untar(r io.Reader, dir string, level int) (err error) {
// write will fail with the same error.
dir := filepath.Dir(abs)
if !madeDir[dir] {
if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {
if err := os.MkdirAll(filepath.Dir(abs), 0o755); err != nil {
return err
}
madeDir[dir] = true
@@ -321,7 +317,7 @@ func untar(r io.Reader, dir string, level int) (err error) {
return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size)
}
case mode.IsDir():
if err := os.MkdirAll(abs, 0755); err != nil {
if err := os.MkdirAll(abs, 0o755); err != nil {
return err
}
madeDir[abs] = true
@@ -367,14 +363,24 @@ func Copy(src, dst string) (int64, error) {
return Files{}.Copy(src, dst)
}
// FileRead is a wrapper for ioutil.ReadFile().
// FileRead is a wrapper for os.ReadFile().
func (f Files) FileRead(path string) ([]byte, error) {
return ioutil.ReadFile(path)
return os.ReadFile(path)
}
// FileWrite is a wrapper for ioutil.WriteFile().
// ReadFile is a wrapper for os.ReadFile() using the same name and syntax.
func (f Files) ReadFile(path string) ([]byte, error) {
return f.FileRead(path)
}
// FileWrite is a wrapper for os.WriteFile().
func (f Files) FileWrite(path string, content []byte, perm os.FileMode) error {
return ioutil.WriteFile(path, content, perm)
return os.WriteFile(path, content, perm)
}
// WriteFile is a wrapper for os.ReadFile() using the same name and syntax.
func (f Files) WriteFile(path string, content []byte, perm os.FileMode) error {
return f.FileWrite(path, content, perm)
}
// FileRemove is a wrapper for os.Remove().

View File

@@ -3,9 +3,10 @@ package piperutils
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperenv"
)
// Path - struct to serialize paths and some metadata back to the invoker
@@ -16,8 +17,12 @@ type Path struct {
Scope string `json:"scope"`
}
type fileWriter interface {
WriteFile(filename string, data []byte, perm os.FileMode) error
}
// PersistReportsAndLinks stores the report paths and links in JSON format in the workspace for processing outside
func PersistReportsAndLinks(stepName, workspace string, reports, links []Path) {
func PersistReportsAndLinks(stepName, workspace string, files fileWriter, reports, links []Path) error {
if reports == nil {
reports = []Path{}
}
@@ -32,19 +37,25 @@ func PersistReportsAndLinks(stepName, workspace string, reports, links []Path) {
break
}
}
reportList, err := json.Marshal(&reports)
if err != nil {
if hasMandatoryReport {
log.Entry().Fatalln("Failed to marshall reports.json data for archiving")
return fmt.Errorf("failed to marshall reports.json data for archiving: %w", err)
}
log.Entry().Errorln("Failed to marshall reports.json data for archiving")
}
piperenv.SetParameter(workspace, fmt.Sprintf("%v_reports.json", stepName), string(reportList))
if err := files.WriteFile(filepath.Join(workspace, fmt.Sprintf("%v_reports.json", stepName)), reportList, 0666); err != nil {
return fmt.Errorf("failed to write reports.json: %w", err)
}
linkList, err := json.Marshal(&links)
if err != nil {
log.Entry().Errorln("Failed to marshall links.json data for archiving")
} else {
piperenv.SetParameter(workspace, fmt.Sprintf("%v_links.json", stepName), string(linkList))
return fmt.Errorf("failed to marshall links.json data for archiving: %w", err)
}
if err := files.WriteFile(filepath.Join(workspace, fmt.Sprintf("%v_links.json", stepName)), linkList, 0666); err != nil {
return fmt.Errorf("failed to write links.json: %w", err)
}
return nil
}

View File

@@ -2,7 +2,8 @@ package piperutils
import (
"encoding/json"
"io/ioutil"
"fmt"
"os"
"path/filepath"
"testing"
@@ -10,33 +11,56 @@ import (
"github.com/stretchr/testify/require"
)
type fileMock struct {
fileMap map[string][]byte
writeErrors map[string]error
}
func (f *fileMock) WriteFile(filename string, data []byte, perm os.FileMode) error {
if f.writeErrors != nil && f.writeErrors[filename] != nil {
return f.writeErrors[filename]
}
f.fileMap[filename] = data
return nil
}
func (f *fileMock) ReadFile(name string) ([]byte, error) {
return f.fileMap[name], nil
}
func (f *fileMock) FileExists(name string) bool {
return f.fileMap[name] != nil
}
func TestPersistReportAndLinks(t *testing.T) {
t.Run("default", func(t *testing.T) {
workspace := t.TempDir()
workspace := ""
t.Run("success - default", func(t *testing.T) {
files := fileMock{fileMap: map[string][]byte{}}
reports := []Path{{Target: "testFile1.json", Mandatory: true}, {Target: "testFile2.json"}}
links := []Path{{Target: "https://1234568.com/test", Name: "Weblink"}}
PersistReportsAndLinks("checkmarxExecuteScan", workspace, reports, links)
err := PersistReportsAndLinks("checkmarxExecuteScan", workspace, &files, reports, links)
assert.NoError(t, err)
reportsJSONPath := filepath.Join(workspace, "checkmarxExecuteScan_reports.json")
assert.FileExists(t, reportsJSONPath)
assert.True(t, files.FileExists(reportsJSONPath))
linksJSONPath := filepath.Join(workspace, "checkmarxExecuteScan_links.json")
assert.FileExists(t, linksJSONPath)
assert.True(t, files.FileExists(linksJSONPath))
var reportsLoaded []Path
var linksLoaded []Path
reportsFileData, err := ioutil.ReadFile(reportsJSONPath)
reportsFileData, err := files.ReadFile(reportsJSONPath)
reportsDataString := string(reportsFileData)
println(reportsDataString)
assert.NoError(t, err, "No error expected but got one")
linksFileData, err := ioutil.ReadFile(linksJSONPath)
linksFileData, err := files.ReadFile(linksJSONPath)
linksDataString := string(linksFileData)
println(linksDataString)
assert.NoError(t, err, "No error expected but got one")
json.Unmarshal(reportsFileData, &reportsLoaded)
json.Unmarshal(linksFileData, &linksLoaded)
_ = json.Unmarshal(reportsFileData, &reportsLoaded)
_ = json.Unmarshal(linksFileData, &linksLoaded)
assert.Equal(t, 2, len(reportsLoaded), "wrong number of reports")
assert.Equal(t, 1, len(linksLoaded), "wrong number of links")
@@ -49,9 +73,8 @@ func TestPersistReportAndLinks(t *testing.T) {
assert.Equal(t, "Weblink", linksLoaded[0].Name, "name value on link 1 has wrong value")
})
t.Run("empty list", func(t *testing.T) {
// init
workspace := t.TempDir()
t.Run("success - empty list", func(t *testing.T) {
files := fileMock{fileMap: map[string][]byte{}}
reportsJSONPath := filepath.Join(workspace, "sonarExecuteScan_reports.json")
linksJSONPath := filepath.Join(workspace, "sonarExecuteScan_links.json")
@@ -62,13 +85,42 @@ func TestPersistReportAndLinks(t *testing.T) {
require.Empty(t, links)
// test
PersistReportsAndLinks("sonarExecuteScan", workspace, reports, links)
err := PersistReportsAndLinks("sonarExecuteScan", workspace, &files, reports, links)
// assert
assert.NoError(t, err)
for _, reportFile := range []string{reportsJSONPath, linksJSONPath} {
assert.FileExists(t, reportFile)
reportsFileData, err := ioutil.ReadFile(reportFile)
assert.True(t, files.FileExists(reportFile))
reportsFileData, err := files.ReadFile(reportFile)
require.NoError(t, err, "No error expected but got one")
assert.Equal(t, "[]", string(reportsFileData))
}
})
t.Run("failure - write reports", func(t *testing.T) {
stepName := "checkmarxExecuteScan"
files := fileMock{
fileMap: map[string][]byte{},
writeErrors: map[string]error{filepath.Join(workspace, fmt.Sprintf("%v_reports.json", stepName)): fmt.Errorf("write error")},
}
reports := []Path{{Target: "testFile1.json"}, {Target: "testFile2.json"}}
links := []Path{{Target: "https://1234568.com/test", Name: "Weblink"}}
err := PersistReportsAndLinks(stepName, workspace, &files, reports, links)
assert.EqualError(t, err, "failed to write reports.json: write error")
})
t.Run("failure - write links", func(t *testing.T) {
stepName := "checkmarxExecuteScan"
files := fileMock{
fileMap: map[string][]byte{},
writeErrors: map[string]error{filepath.Join(workspace, fmt.Sprintf("%v_links.json", stepName)): fmt.Errorf("write error")},
}
reports := []Path{{Target: "testFile1.json"}, {Target: "testFile2.json"}}
links := []Path{{Target: "https://1234568.com/test", Name: "Weblink"}}
err := PersistReportsAndLinks(stepName, workspace, &files, reports, links)
assert.EqualError(t, err, "failed to write links.json: write error")
})
}

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io/fs"
"os"
"path/filepath"
"time"
@@ -31,6 +31,8 @@ type Toolrecord struct {
DisplayName string
DisplayURL string
fileUtils fileWriteUtils
// detailed keydata - needs tool-specific parsing
Keys []keydataset
@@ -42,9 +44,15 @@ type Toolrecord struct {
reportFileName string
}
type fileWriteUtils interface {
MkdirAll(path string, perm fs.FileMode) error
WriteFile(name string, data []byte, perm fs.FileMode) error
}
// New - initialize a new toolrecord
func New(workspace, toolName, toolInstance string) *Toolrecord {
func New(fileUtils fileWriteUtils, workspace, toolName, toolInstance string) *Toolrecord {
tr := Toolrecord{}
tr.fileUtils = fileUtils
tr.RecordVersion = 1
tr.ToolName = toolName
@@ -108,7 +116,7 @@ func (tr *Toolrecord) Persist() error {
}
// create workspace/toolrecord
dirPath := filepath.Join(tr.workspace, "toolruns")
err := os.MkdirAll(dirPath, os.ModePerm)
err := tr.fileUtils.MkdirAll(dirPath, os.ModePerm)
if err != nil {
return fmt.Errorf("TR_PERSIST: %v", err)
}
@@ -126,14 +134,14 @@ func (tr *Toolrecord) Persist() error {
if len(file) == 0 {
return fmt.Errorf("TR_PERSIST: empty json content")
}
err = ioutil.WriteFile(tr.GetFileName(), file, 0644)
err = tr.fileUtils.WriteFile(tr.GetFileName(), file, 0o644)
if err != nil {
return fmt.Errorf("TR_PERSIST: %v", err)
}
return nil
}
// default aggregation for overall displayName and URL
// GenerateDefaultDisplayData - default aggregation for overall displayName and URL
// can be overriden by calling SetOverallDisplayData
func (tr *Toolrecord) GenerateDefaultDisplayData() {
displayName := ""
@@ -156,7 +164,7 @@ func (tr *Toolrecord) GenerateDefaultDisplayData() {
tr.DisplayURL = displayURL
}
// Override the default generation for DisplayName & DisplayURL
// SetOverallDisplayData - override the default generation for DisplayName & DisplayURL
func (tr *Toolrecord) SetOverallDisplayData(newName, newURL string) {
tr.DisplayName = newName
tr.DisplayURL = newURL

View File

@@ -3,6 +3,7 @@ package toolrecord_test
import (
"testing"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/toolrecord"
"github.com/stretchr/testify/assert"
)
@@ -11,11 +12,12 @@ func TestToolRecord(t *testing.T) {
workspace := t.TempDir()
t.Run("Check toolrecord", func(t *testing.T) {
tr := toolrecord.New(workspace, "dummyTool", "dummyInstance")
fileMock := mock.FilesMock{}
tr := toolrecord.New(&fileMock, workspace, "dummyTool", "dummyInstance")
tr.AddKeyData("Organization", "dummyOrgId", "dummyOrgName", "dummyOrgUrl")
tr.AddKeyData("Project", "dummyProjectId", "dummyProjName", "dummyProjUrl")
tr.AddKeyData("ScanId", "dummyScanId", "dummyScanName", "dummyScanUrl")
_ = tr.AddKeyData("Organization", "dummyOrgId", "dummyOrgName", "dummyOrgUrl")
_ = tr.AddKeyData("Project", "dummyProjectId", "dummyProjName", "dummyProjUrl")
_ = tr.AddKeyData("ScanId", "dummyScanId", "dummyScanName", "dummyScanUrl")
context := map[string]interface{}{
"demo": "data",
"anything": struct {
@@ -23,15 +25,15 @@ func TestToolRecord(t *testing.T) {
i1 int
}{"goes", 42},
}
tr.AddContext("DemoContext", context)
_ = tr.AddContext("DemoContext", context)
context2 := "a string"
tr.AddContext("Context2", context2)
_ = tr.AddContext("Context2", context2)
var context3 [2]string
context3[0] = "c3_1"
context3[1] = "c3_2"
tr.AddContext("Context3", context3)
_ = tr.AddContext("Context3", context3)
err := tr.Persist()
assert.Nil(t, err, "internal error %s")
assert.FileExists(t, tr.GetFileName(), "toolrecord not persisted %s")
assert.True(t, fileMock.HasFile(tr.GetFileName()), "toolrecord not persisted %s")
})
}