2020-09-18 11:54:45 +02:00
package cmd
import (
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/versioning"
ws "github.com/SAP/jenkins-library/pkg/whitesource"
"github.com/stretchr/testify/assert"
"path/filepath"
"testing"
"time"
)
type whitesourceCoordinatesMock struct {
GroupID string
ArtifactID string
Version string
}
type whitesourceUtilsMock struct {
2020-10-20 09:49:26 +02:00
* ws . ScanUtilsMock
2020-09-29 12:44:31 +02:00
coordinates whitesourceCoordinatesMock
usedBuildTool string
usedBuildDescriptorFile string
usedOptions versioning . Options
2020-09-18 11:54:45 +02:00
}
2020-09-29 12:44:31 +02:00
func ( w * whitesourceUtilsMock ) GetArtifactCoordinates ( buildTool , buildDescriptorFile string ,
options * versioning . Options ) ( versioning . Coordinates , error ) {
w . usedBuildTool = buildTool
w . usedBuildDescriptorFile = buildDescriptorFile
w . usedOptions = * options
2020-09-18 11:54:45 +02:00
return w . coordinates , nil
}
2020-09-29 12:44:31 +02:00
const wsTimeNow = "2010-05-10 00:15:42"
func ( w * whitesourceUtilsMock ) Now ( ) time . Time {
now , _ := time . Parse ( "2006-01-02 15:04:05" , wsTimeNow )
return now
}
2020-09-18 11:54:45 +02:00
func newWhitesourceUtilsMock ( ) * whitesourceUtilsMock {
return & whitesourceUtilsMock {
2020-10-20 09:49:26 +02:00
ScanUtilsMock : & ws . ScanUtilsMock {
FilesMock : & mock . FilesMock { } ,
ExecMockRunner : & mock . ExecMockRunner { } ,
} ,
2020-09-18 11:54:45 +02:00
coordinates : whitesourceCoordinatesMock {
GroupID : "mock-group-id" ,
ArtifactID : "mock-artifact-id" ,
Version : "1.0.42" ,
} ,
}
}
func TestResolveProjectIdentifiers ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
t . Parallel ( )
2020-09-18 11:54:45 +02:00
t . Run ( "happy path" , func ( t * testing . T ) {
// init
config := ScanOptions {
2020-09-29 12:44:31 +02:00
BuildTool : "mta" ,
BuildDescriptorFile : "my-mta.yml" ,
VersioningModel : "major" ,
ProductName : "mock-product" ,
M2Path : "m2/path" ,
ProjectSettingsFile : "project-settings.xml" ,
GlobalSettingsFile : "global-settings.xml" ,
2020-09-18 11:54:45 +02:00
}
utilsMock := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( & config )
2020-09-18 11:54:45 +02:00
// test
2020-09-29 12:44:31 +02:00
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
2020-09-18 11:54:45 +02:00
// assert
if assert . NoError ( t , err ) {
2020-10-20 09:49:26 +02:00
assert . Equal ( t , "mock-group-id-mock-artifact-id" , scan . AggregateProjectName )
2020-09-18 11:54:45 +02:00
assert . Equal ( t , "1" , config . ProductVersion )
assert . Equal ( t , "mock-product-token" , config . ProductToken )
2020-09-29 12:44:31 +02:00
assert . Equal ( t , "mta" , utilsMock . usedBuildTool )
assert . Equal ( t , "my-mta.yml" , utilsMock . usedBuildDescriptorFile )
assert . Equal ( t , "project-settings.xml" , utilsMock . usedOptions . ProjectSettingsFile )
assert . Equal ( t , "global-settings.xml" , utilsMock . usedOptions . GlobalSettingsFile )
assert . Equal ( t , "m2/path" , utilsMock . usedOptions . M2Path )
}
} )
t . Run ( "retrieves token for configured project name" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildTool : "mta" ,
BuildDescriptorFile : "my-mta.yml" ,
VersioningModel : "major" ,
ProductName : "mock-product" ,
2020-10-20 09:49:26 +02:00
ProjectName : "mock-project" ,
2020-09-29 12:44:31 +02:00
}
utilsMock := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( & config )
// test
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
// assert
if assert . NoError ( t , err ) {
2020-10-20 09:49:26 +02:00
assert . Equal ( t , "mock-project" , scan . AggregateProjectName )
2020-09-29 12:44:31 +02:00
assert . Equal ( t , "1" , config . ProductVersion )
assert . Equal ( t , "mock-product-token" , config . ProductToken )
assert . Equal ( t , "mta" , utilsMock . usedBuildTool )
assert . Equal ( t , "my-mta.yml" , utilsMock . usedBuildDescriptorFile )
assert . Equal ( t , "mock-project-token" , config . ProjectToken )
2020-09-18 11:54:45 +02:00
}
} )
t . Run ( "product not found" , func ( t * testing . T ) {
// init
config := ScanOptions {
2020-09-29 12:44:31 +02:00
BuildTool : "mta" ,
2020-09-18 11:54:45 +02:00
VersioningModel : "major" ,
ProductName : "does-not-exist" ,
}
utilsMock := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( & config )
2020-09-18 11:54:45 +02:00
// test
2020-09-29 12:44:31 +02:00
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
2020-09-18 11:54:45 +02:00
// assert
assert . EqualError ( t , err , "no product with name 'does-not-exist' found in Whitesource" )
} )
2020-10-29 10:21:01 +02:00
t . Run ( "product not found, created from pipeline" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildTool : "mta" ,
CreateProductFromPipeline : true ,
EmailAddressesOfInitialProductAdmins : [ ] string { "user1@domain.org" , "user2@domain.org" } ,
VersioningModel : "major" ,
ProductName : "created-by-pipeline" ,
}
utilsMock := newWhitesourceUtilsMock ( )
systemMock := ws . NewSystemMock ( "ignored" )
scan := newWhitesourceScan ( & config )
// test
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
// assert
assert . NoError ( t , err )
assert . Len ( t , systemMock . Products , 2 )
assert . Equal ( t , "created-by-pipeline" , systemMock . Products [ 1 ] . Name )
assert . Equal ( t , "mock-product-token-1" , config . ProductToken )
} )
2020-09-18 11:54:45 +02:00
}
func TestBlockUntilProjectIsUpdated ( t * testing . T ) {
t . Parallel ( )
t . Run ( "already new enough" , func ( t * testing . T ) {
// init
nowString := "2010-05-30 00:15:00 +0100"
2020-10-29 10:21:01 +02:00
now , err := time . Parse ( ws . DateTimeLayout , nowString )
2020-09-18 11:54:45 +02:00
if err != nil {
t . Fatalf ( err . Error ( ) )
}
lastUpdatedDate := "2010-05-30 00:15:01 +0100"
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( lastUpdatedDate )
2020-09-18 11:54:45 +02:00
// test
2020-10-20 09:49:26 +02:00
err = blockUntilProjectIsUpdated ( systemMock . Projects [ 0 ] . Token , systemMock , now , 2 * time . Second , 1 * time . Second , 2 * time . Second )
2020-09-18 11:54:45 +02:00
// assert
assert . NoError ( t , err )
} )
t . Run ( "timeout while polling" , func ( t * testing . T ) {
// init
nowString := "2010-05-30 00:15:00 +0100"
2020-10-29 10:21:01 +02:00
now , err := time . Parse ( ws . DateTimeLayout , nowString )
2020-09-18 11:54:45 +02:00
if err != nil {
t . Fatalf ( err . Error ( ) )
}
lastUpdatedDate := "2010-05-30 00:07:00 +0100"
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( lastUpdatedDate )
2020-09-18 11:54:45 +02:00
// test
2020-10-20 09:49:26 +02:00
err = blockUntilProjectIsUpdated ( systemMock . Projects [ 0 ] . Token , systemMock , now , 2 * time . Second , 1 * time . Second , 1 * time . Second )
2020-09-18 11:54:45 +02:00
// assert
if assert . Error ( t , err ) {
assert . Contains ( t , err . Error ( ) , "timeout while waiting" )
}
} )
t . Run ( "timeout while polling, no update time" , func ( t * testing . T ) {
// init
nowString := "2010-05-30 00:15:00 +0100"
2020-10-29 10:21:01 +02:00
now , err := time . Parse ( ws . DateTimeLayout , nowString )
2020-09-18 11:54:45 +02:00
if err != nil {
t . Fatalf ( err . Error ( ) )
}
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "" )
2020-09-18 11:54:45 +02:00
// test
2020-10-20 09:49:26 +02:00
err = blockUntilProjectIsUpdated ( systemMock . Projects [ 0 ] . Token , systemMock , now , 2 * time . Second , 1 * time . Second , 1 * time . Second )
2020-09-18 11:54:45 +02:00
// assert
if assert . Error ( t , err ) {
assert . Contains ( t , err . Error ( ) , "timeout while waiting" )
}
} )
}
2020-10-20 09:49:26 +02:00
func TestPersistScannedProjects ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
resource := filepath . Join ( ".pipeline" , "commonPipelineEnvironment" , "custom" , "whitesourceProjectNames" )
t . Parallel ( )
t . Run ( "write 1 scanned projects" , func ( t * testing . T ) {
// init
config := & ScanOptions { ProductVersion : "1" }
utils := newWhitesourceUtilsMock ( )
scan := newWhitesourceScan ( config )
2020-10-20 09:49:26 +02:00
_ = scan . AppendScannedProject ( "project" )
2020-09-29 12:44:31 +02:00
// test
err := persistScannedProjects ( config , scan , utils )
// assert
if assert . NoError ( t , err ) && assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
assert . Equal ( t , "project - 1" , string ( contents ) )
}
} )
t . Run ( "write 2 scanned projects" , func ( t * testing . T ) {
// init
config := & ScanOptions { ProductVersion : "1" }
utils := newWhitesourceUtilsMock ( )
scan := newWhitesourceScan ( config )
2020-10-20 09:49:26 +02:00
_ = scan . AppendScannedProject ( "project-app" )
_ = scan . AppendScannedProject ( "project-db" )
2020-09-29 12:44:31 +02:00
// test
err := persistScannedProjects ( config , scan , utils )
// assert
if assert . NoError ( t , err ) && assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
assert . Equal ( t , "project-app - 1,project-db - 1" , string ( contents ) )
}
} )
t . Run ( "write no projects" , func ( t * testing . T ) {
// init
config := & ScanOptions { ProductVersion : "1" }
utils := newWhitesourceUtilsMock ( )
scan := newWhitesourceScan ( config )
// test
err := persistScannedProjects ( config , scan , utils )
// assert
if assert . NoError ( t , err ) && assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
assert . Equal ( t , "" , string ( contents ) )
}
} )
t . Run ( "write aggregated project" , func ( t * testing . T ) {
// init
config := & ScanOptions { ProjectName : "project" , ProductVersion : "1" }
utils := newWhitesourceUtilsMock ( )
scan := newWhitesourceScan ( config )
// test
err := persistScannedProjects ( config , scan , utils )
// assert
if assert . NoError ( t , err ) && assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
assert . Equal ( t , "project - 1" , string ( contents ) )
}
} )
}
func TestAggregateVersionWideLibraries ( t * testing . T ) {
t . Parallel ( )
t . Run ( "happy path" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProductVersion : "1" ,
ReportDirectoryName : "mock-reports" ,
}
utils := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
system := ws . NewSystemMock ( "2010-05-30 00:15:00 +0100" )
2020-09-29 12:44:31 +02:00
// test
err := aggregateVersionWideLibraries ( config , utils , system )
// assert
resource := filepath . Join ( "mock-reports" , "libraries-20100510-001542.csv" )
if assert . NoError ( t , err ) && assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
asString := string ( contents )
assert . Equal ( t , "Library Name, Project Name\nmock-library, mock-project\n" , asString )
}
} )
}
func TestAggregateVersionWideVulnerabilities ( t * testing . T ) {
t . Parallel ( )
t . Run ( "happy path" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProductVersion : "1" ,
ReportDirectoryName : "mock-reports" ,
}
utils := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
system := ws . NewSystemMock ( "2010-05-30 00:15:00 +0100" )
2020-09-29 12:44:31 +02:00
// test
err := aggregateVersionWideVulnerabilities ( config , utils , system )
// assert
resource := filepath . Join ( "mock-reports" , "project-names-aggregated.txt" )
assert . NoError ( t , err )
if assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
asString := string ( contents )
assert . Equal ( t , "mock-project - 1\n" , asString )
}
reportSheet := filepath . Join ( "mock-reports" , "vulnerabilities-20100510-001542.xlsx" )
sheetContents , err := utils . FileRead ( reportSheet )
assert . NoError ( t , err )
assert . NotEmpty ( t , sheetContents )
} )
}
func TestCheckAndReportScanResults ( t * testing . T ) {
t . Parallel ( )
t . Run ( "no reports requested" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProjectToken : "mock-project-token" ,
ProductVersion : "1" ,
ReportDirectoryName : "mock-reports" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
2020-10-29 10:21:01 +02:00
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2020-09-29 12:44:31 +02:00
// test
err := checkAndReportScanResults ( config , scan , utils , system )
// assert
assert . NoError ( t , err )
2020-10-29 10:21:01 +02:00
vPath := filepath . Join ( "mock-reports" , "mock-project-vulnerability-report.txt" )
2020-09-29 12:44:31 +02:00
assert . False ( t , utils . HasWrittenFile ( vPath ) )
2020-10-29 10:21:01 +02:00
rPath := filepath . Join ( "mock-reports" , "mock-project-risk-report.pdf" )
2020-09-29 12:44:31 +02:00
assert . False ( t , utils . HasWrittenFile ( rPath ) )
} )
t . Run ( "check vulnerabilities - invalid limit" , func ( t * testing . T ) {
// init
config := & ScanOptions {
SecurityVulnerabilities : true ,
CvssSeverityLimit : "invalid" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
2020-10-29 10:21:01 +02:00
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2020-09-29 12:44:31 +02:00
// test
err := checkAndReportScanResults ( config , scan , utils , system )
// assert
assert . EqualError ( t , err , "failed to parse parameter cvssSeverityLimit (invalid) as floating point number: strconv.ParseFloat: parsing \"invalid\": invalid syntax" )
} )
t . Run ( "check vulnerabilities - limit not hit" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProjectToken : "mock-project-token" ,
ProductVersion : "1" ,
ReportDirectoryName : "mock-reports" ,
SecurityVulnerabilities : true ,
CvssSeverityLimit : "6.0" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
2020-10-29 10:21:01 +02:00
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2020-09-29 12:44:31 +02:00
// test
err := checkAndReportScanResults ( config , scan , utils , system )
// assert
assert . NoError ( t , err )
} )
t . Run ( "check vulnerabilities - limit exceeded" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProjectName : "mock-project - 1" ,
ProjectToken : "mock-project-token" ,
ProductVersion : "1" ,
ReportDirectoryName : "mock-reports" ,
SecurityVulnerabilities : true ,
CvssSeverityLimit : "4" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
2020-10-29 10:21:01 +02:00
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2020-09-29 12:44:31 +02:00
// test
err := checkAndReportScanResults ( config , scan , utils , system )
// assert
assert . EqualError ( t , err , "1 Open Source Software Security vulnerabilities with CVSS score greater or equal to 4.0 detected in project mock-project - 1" )
} )
2020-09-18 11:54:45 +02:00
}