1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-03 15:02:35 +02:00
sap-jenkins-library/cmd/whitesourceExecuteScan_test.go

374 lines
11 KiB
Go
Raw Normal View History

package cmd
import (
"encoding/json"
"fmt"
"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"
"net/http"
"os"
"path/filepath"
"testing"
"time"
)
type whitesourceSystemMock struct {
productName string
products []ws.Product
projects []ws.Project
alerts []ws.Alert
libraries []ws.Library
riskReport []byte
vulnerabilityReport []byte
}
func (m *whitesourceSystemMock) GetProductByName(productName string) (ws.Product, error) {
for _, product := range m.products {
if product.Name == productName {
return product, nil
}
}
return ws.Product{}, fmt.Errorf("no product with name '%s' found in Whitesource", productName)
}
func (m *whitesourceSystemMock) GetProjectsMetaInfo(productToken string) ([]ws.Project, error) {
return m.projects, nil
}
func (m *whitesourceSystemMock) GetProjectToken(productToken, projectName string) (string, error) {
return "mock-project-token", nil
}
func (m *whitesourceSystemMock) GetProjectByToken(projectToken string) (ws.Project, error) {
for _, project := range m.projects {
if project.Token == projectToken {
return project, nil
}
}
return ws.Project{}, fmt.Errorf("no project with token '%s' found in Whitesource", projectToken)
}
func (m *whitesourceSystemMock) GetProjectRiskReport(projectToken string) ([]byte, error) {
return m.riskReport, nil
}
func (m *whitesourceSystemMock) GetProjectVulnerabilityReport(projectToken string, format string) ([]byte, error) {
_, err := m.GetProjectByToken(projectToken)
if err != nil {
return nil, err
}
if m.vulnerabilityReport == nil {
return nil, fmt.Errorf("no report available")
}
return m.vulnerabilityReport, nil
}
func (m *whitesourceSystemMock) GetProjectAlerts(projectToken string) ([]ws.Alert, error) {
return m.alerts, nil
}
func (m *whitesourceSystemMock) GetProjectLibraryLocations(projectToken string) ([]ws.Library, error) {
return m.libraries, nil
}
var mockLibrary = ws.Library{
Name: "mock-library",
Filename: "mock-library-file",
Version: "mock-library-version",
Project: "mock-project",
}
func newWhitesourceSystemMock(lastUpdateDate string) *whitesourceSystemMock {
return &whitesourceSystemMock{
productName: "mock-product",
products: []ws.Product{
{
Name: "mock-product",
Token: "mock-product-token",
CreationDate: "last-thursday",
LastUpdateDate: lastUpdateDate,
},
},
projects: []ws.Project{
{
ID: 42,
Name: "mock-project",
PluginName: "mock-plugin-name",
Token: "mock-project-token",
UploadedBy: "MrBean",
CreationDate: "last-thursday",
LastUpdateDate: lastUpdateDate,
},
},
alerts: []ws.Alert{
{
Vulnerability: ws.Vulnerability{},
Library: mockLibrary,
Project: "mock-project",
CreationDate: "last-thursday",
},
},
libraries: []ws.Library{mockLibrary},
riskReport: []byte("mock-risk-report"),
vulnerabilityReport: []byte("mock-vulnerability-report"),
}
}
type whitesourceCoordinatesMock struct {
GroupID string
ArtifactID string
Version string
}
type downloadedFile struct {
sourceURL string
filePath string
}
type whitesourceUtilsMock struct {
*mock.FilesMock
*mock.ExecMockRunner
coordinates whitesourceCoordinatesMock
downloadedFiles []downloadedFile
}
func (w *whitesourceUtilsMock) DownloadFile(url, filename string, _ http.Header, _ []*http.Cookie) error {
w.downloadedFiles = append(w.downloadedFiles, downloadedFile{sourceURL: url, filePath: filename})
return nil
}
func (w *whitesourceUtilsMock) FileOpen(name string, flag int, perm os.FileMode) (*os.File, error) {
return nil, fmt.Errorf("FileOpen() is unsupported by the mock implementation")
}
func (w *whitesourceUtilsMock) RemoveAll(path string) error {
// TODO: Implement in FS Mock
return nil
}
func (w *whitesourceUtilsMock) GetArtifactCoordinates(_ *ScanOptions) (versioning.Coordinates, error) {
return w.coordinates, nil
}
func (w *whitesourceUtilsMock) FindPackageJSONFiles(_ *ScanOptions) ([]string, error) {
matches, _ := w.Glob("**/package.json")
return matches, nil
}
func (w *whitesourceUtilsMock) InstallAllNPMDependencies(_ *ScanOptions, _ []string) error {
return nil
}
func newWhitesourceUtilsMock() *whitesourceUtilsMock {
return &whitesourceUtilsMock{
FilesMock: &mock.FilesMock{},
ExecMockRunner: &mock.ExecMockRunner{},
coordinates: whitesourceCoordinatesMock{
GroupID: "mock-group-id",
ArtifactID: "mock-artifact-id",
Version: "1.0.42",
},
}
}
func TestResolveProjectIdentifiers(t *testing.T) {
t.Run("happy path", func(t *testing.T) {
// init
config := ScanOptions{
ScanType: "mta",
VersioningModel: "major",
ProductName: "mock-product",
}
utilsMock := newWhitesourceUtilsMock()
systemMock := newWhitesourceSystemMock("ignored")
// test
err := resolveProjectIdentifiers(&config, utilsMock, systemMock)
// assert
if assert.NoError(t, err) {
assert.Equal(t, "mock-group-id-mock-artifact-id", config.ProjectName)
assert.Equal(t, "1", config.ProductVersion)
assert.Equal(t, "mock-project-token", config.ProjectToken)
assert.Equal(t, "mock-product-token", config.ProductToken)
}
})
t.Run("product not found", func(t *testing.T) {
// init
config := ScanOptions{
ScanType: "mta",
VersioningModel: "major",
ProductName: "does-not-exist",
}
utilsMock := newWhitesourceUtilsMock()
systemMock := newWhitesourceSystemMock("ignored")
// test
err := resolveProjectIdentifiers(&config, utilsMock, systemMock)
// assert
assert.EqualError(t, err, "no product with name 'does-not-exist' found in Whitesource")
})
}
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"
now, err := time.Parse(whitesourceDateTimeLayout, nowString)
if err != nil {
t.Fatalf(err.Error())
}
lastUpdatedDate := "2010-05-30 00:15:01 +0100"
systemMock := newWhitesourceSystemMock(lastUpdatedDate)
config := &ScanOptions{
ProjectToken: systemMock.projects[0].Token,
}
// test
err = blockUntilProjectIsUpdated(config, systemMock, now, 2*time.Second, 1*time.Second, 2*time.Second)
// assert
assert.NoError(t, err)
})
t.Run("timeout while polling", func(t *testing.T) {
// init
nowString := "2010-05-30 00:15:00 +0100"
now, err := time.Parse(whitesourceDateTimeLayout, nowString)
if err != nil {
t.Fatalf(err.Error())
}
lastUpdatedDate := "2010-05-30 00:07:00 +0100"
systemMock := newWhitesourceSystemMock(lastUpdatedDate)
config := &ScanOptions{
ProjectToken: systemMock.projects[0].Token,
}
// test
err = blockUntilProjectIsUpdated(config, systemMock, now, 2*time.Second, 1*time.Second, 1*time.Second)
// 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"
now, err := time.Parse(whitesourceDateTimeLayout, nowString)
if err != nil {
t.Fatalf(err.Error())
}
systemMock := newWhitesourceSystemMock("")
config := &ScanOptions{
ProjectToken: systemMock.projects[0].Token,
}
// test
err = blockUntilProjectIsUpdated(config, systemMock, now, 2*time.Second, 1*time.Second, 1*time.Second)
// assert
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "timeout while waiting")
}
})
}
func TestDownloadReports(t *testing.T) {
t.Parallel()
t.Run("happy path", func(t *testing.T) {
// init
config := &ScanOptions{
ProjectToken: "mock-project-token",
ProjectName: "mock-project",
ReportDirectoryName: "report-dir",
VulnerabilityReportFormat: "txt",
}
utils := newWhitesourceUtilsMock()
system := newWhitesourceSystemMock("2010-05-30 00:15:00 +0100")
// test
paths, err := downloadReports(config, utils, system)
// assert
if assert.NoError(t, err) && assert.Len(t, paths, 2) {
vPath := filepath.Join("report-dir", "mock-project-vulnerability-report.txt")
assert.True(t, utils.HasWrittenFile(vPath))
vContent, _ := utils.FileRead(vPath)
assert.Equal(t, []byte("mock-vulnerability-report"), vContent)
rPath := filepath.Join("report-dir", "mock-project-risk-report.pdf")
assert.True(t, utils.HasWrittenFile(rPath))
rContent, _ := utils.FileRead(rPath)
assert.Equal(t, []byte("mock-risk-report"), rContent)
}
})
t.Run("invalid project token", func(t *testing.T) {
// init
config := &ScanOptions{
ProjectToken: "<invalid>",
}
utils := newWhitesourceUtilsMock()
system := newWhitesourceSystemMock("2010-05-30 00:15:00 +0100")
// test
path, err := downloadReports(config, utils, system)
// assert
assert.EqualError(t, err, "no project with token '<invalid>' found in Whitesource")
assert.Nil(t, path)
})
}
func TestWriteWhitesourceConfigJSON(t *testing.T) {
config := &ScanOptions{
OrgToken: "org-token",
UserToken: "user-token",
ProductName: "mock-product",
ProjectName: "mock-project",
ProductVersion: "42",
}
expected := make(map[string]interface{})
expected["apiKey"] = "org-token"
expected["userKey"] = "user-token"
expected["checkPolicies"] = true
expected["productName"] = "mock-product"
expected["projectName"] = "mock-project"
expected["productVer"] = "42"
expected["devDep"] = true
expected["ignoreNpmLsErrors"] = true
t.Parallel()
t.Run("write config from scratch", func(t *testing.T) {
// init
utils := newWhitesourceUtilsMock()
// test
err := writeWhitesourceConfigJSON(config, utils, true, true)
// assert
if assert.NoError(t, err) && assert.True(t, utils.HasWrittenFile(whiteSourceConfig)) {
contents, _ := utils.FileRead(whiteSourceConfig)
actual := make(map[string]interface{})
_ = json.Unmarshal(contents, &actual)
assert.Equal(t, expected, actual)
}
})
t.Run("extend and merge config", func(t *testing.T) {
// init
initial := make(map[string]interface{})
initial["checkPolicies"] = false
initial["productName"] = "mock-product"
initial["productVer"] = "41"
initial["unknown"] = "preserved"
encoded, _ := json.Marshal(initial)
utils := newWhitesourceUtilsMock()
utils.AddFile(whiteSourceConfig, encoded)
// test
err := writeWhitesourceConfigJSON(config, utils, true, true)
// assert
if assert.NoError(t, err) && assert.True(t, utils.HasWrittenFile(whiteSourceConfig)) {
contents, _ := utils.FileRead(whiteSourceConfig)
actual := make(map[string]interface{})
_ = json.Unmarshal(contents, &actual)
mergedExpected := expected
mergedExpected["unknown"] = "preserved"
assert.Equal(t, mergedExpected, actual)
}
})
}