github.com/jaylevin/jenkins-library@v1.230.4/pkg/whitesource/scanNPM_test.go (about) 1 package whitesource 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "path/filepath" 7 "testing" 8 9 "github.com/SAP/jenkins-library/pkg/mock" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestExecuteScanNPM(t *testing.T) { 15 config := ScanOptions{ 16 ScanType: "npm", 17 OrgToken: "org-token", 18 UserToken: "user-token", 19 ProductName: "mock-product", 20 ProjectName: "mock-project", 21 } 22 23 t.Parallel() 24 25 t.Run("happy path NPM", func(t *testing.T) { 26 // init 27 utilsMock := NewScanUtilsMock() 28 utilsMock.AddFile("package.json", []byte(`{"name":"my-module-name"}`)) 29 scan := newTestScan(&config) 30 // test 31 err := scan.ExecuteNpmScan(&config, utilsMock) 32 // assert 33 require.NoError(t, err) 34 expectedCalls := []mock.ExecCall{ 35 { 36 Exec: "npm", 37 Params: []string{ 38 "ls", 39 }, 40 }, 41 { 42 Exec: "npx", 43 Params: []string{ 44 "whitesource", 45 "run", 46 }, 47 }, 48 } 49 assert.Equal(t, expectedCalls, utilsMock.Calls) 50 assert.True(t, utilsMock.HasWrittenFile(whiteSourceConfig)) 51 assert.True(t, utilsMock.HasRemovedFile(whiteSourceConfig)) 52 }) 53 t.Run("happy path with excluded modules", func(t *testing.T) { 54 // init 55 utilsMock := NewScanUtilsMock() 56 utilsMock.AddFile("package.json", []byte(`{"name":"my-module-name"}`)) 57 utilsMock.AddFile("sub/package.json", []byte(`{"name":"my-sub-module-name"}`)) 58 utilsMock.AddFile("deep/sub/package.json", []byte(`{"name":"my-deep-sub-module-name"}`)) 59 60 config := ScanOptions{ 61 ScanType: "npm", 62 OrgToken: "org-token", 63 UserToken: "user-token", 64 ProductName: "mock-product", 65 ProjectName: "mock-project", 66 BuildDescriptorExcludeList: []string{"unrelated/pom.xml", "sub/package.json", "deep/sub/package.json"}, 67 } 68 69 scan := newTestScan(&config) 70 // test 71 err := scan.ExecuteNpmScan(&config, utilsMock) 72 // assert 73 require.NoError(t, err) 74 expectedCalls := []mock.ExecCall{ 75 { 76 Exec: "npm", 77 Params: []string{ 78 "ls", 79 }, 80 }, 81 { 82 Exec: "npx", 83 Params: []string{ 84 "whitesource", 85 "run", 86 }, 87 }, 88 } 89 assert.Equal(t, expectedCalls, utilsMock.Calls) 90 assert.True(t, utilsMock.HasWrittenFile(whiteSourceConfig)) 91 assert.True(t, utilsMock.HasRemovedFile(whiteSourceConfig)) 92 assert.False(t, utilsMock.HasWrittenFile(filepath.Join("sub", whiteSourceConfig))) 93 assert.False(t, utilsMock.HasWrittenFile(filepath.Join("deep", "sub", whiteSourceConfig))) 94 }) 95 t.Run("no NPM modules", func(t *testing.T) { 96 // init 97 utilsMock := NewScanUtilsMock() 98 scan := newTestScan(&config) 99 // test 100 err := scan.ExecuteNpmScan(&config, utilsMock) 101 // assert 102 assert.EqualError(t, err, "found no NPM modules to scan. Configured excludes: []") 103 assert.Len(t, utilsMock.Calls, 0) 104 assert.False(t, utilsMock.HasWrittenFile(whiteSourceConfig)) 105 }) 106 t.Run("package.json needs name", func(t *testing.T) { 107 // init 108 utilsMock := NewScanUtilsMock() 109 utilsMock.AddFile("package.json", []byte(`{"key":"value"}`)) 110 scan := newTestScan(&config) 111 // test 112 err := scan.ExecuteNpmScan(&config, utilsMock) 113 // assert 114 assert.EqualError(t, err, "failed to scan NPM module 'package.json': the file 'package.json' must configure a name") 115 }) 116 t.Run("npm ls fails", func(t *testing.T) { 117 // init 118 utilsMock := NewScanUtilsMock() 119 utilsMock.AddFile("package.json", []byte(`{"name":"my-module-name"}`)) 120 utilsMock.AddFile(filepath.Join("app", "package.json"), []byte(`{"name":"my-app-module-name"}`)) 121 utilsMock.AddFile("package-lock.json", []byte("dummy")) 122 123 utilsMock.ShouldFailOnCommand = make(map[string]error) 124 utilsMock.ShouldFailOnCommand["npm ls"] = fmt.Errorf("mock failure") 125 scan := newTestScan(&config) 126 // test 127 err := scan.ExecuteNpmScan(&config, utilsMock) 128 // assert 129 assert.NoError(t, err) 130 expectedNpmInstalls := []NpmInstall{ 131 {CurrentDir: "app", PackageJSON: []string{"package.json"}}, 132 {CurrentDir: "", PackageJSON: []string{"package.json"}}, 133 } 134 assert.Equal(t, expectedNpmInstalls, utilsMock.NpmInstalledModules) 135 assert.True(t, utilsMock.HasRemovedFile("package-lock.json")) 136 }) 137 } 138 139 func TestWriteWhitesourceConfigJSON(t *testing.T) { 140 config := &ScanOptions{ 141 OrgToken: "org-token", 142 UserToken: "user-token", 143 ProductName: "mock-product", 144 ProductVersion: "product-version", 145 ProjectName: "mock-project", 146 ProductToken: "mock-product-token", 147 } 148 149 expected := make(map[string]interface{}) 150 expected["apiKey"] = "org-token" 151 expected["userKey"] = "user-token" 152 expected["checkPolicies"] = true 153 expected["forceUpdate"] = true 154 expected["productName"] = "mock-product" 155 expected["projectName"] = "mock-project" 156 expected["productToken"] = "mock-product-token" 157 expected["productVer"] = "product-version" 158 expected["devDep"] = true 159 expected["ignoreNpmLsErrors"] = true 160 161 t.Parallel() 162 163 t.Run("write config from scratch", func(t *testing.T) { 164 // init 165 utils := NewScanUtilsMock() 166 scan := newTestScan(config) 167 // test 168 err := scan.writeWhitesourceConfigJSON(config, utils, true, true) 169 // assert 170 if assert.NoError(t, err) && assert.True(t, utils.HasWrittenFile(whiteSourceConfig)) { 171 contents, _ := utils.FileRead(whiteSourceConfig) 172 actual := make(map[string]interface{}) 173 _ = json.Unmarshal(contents, &actual) 174 assert.Equal(t, expected, actual) 175 } 176 }) 177 178 t.Run("extend and merge config", func(t *testing.T) { 179 // init 180 initial := make(map[string]interface{}) 181 initial["checkPolicies"] = false 182 initial["productName"] = "mock-product" 183 initial["productVer"] = "41" 184 initial["unknown"] = "preserved" 185 encoded, _ := json.Marshal(initial) 186 187 utils := NewScanUtilsMock() 188 utils.AddFile(whiteSourceConfig, encoded) 189 190 scan := newTestScan(config) 191 192 // test 193 err := scan.writeWhitesourceConfigJSON(config, utils, true, true) 194 // assert 195 if assert.NoError(t, err) && assert.True(t, utils.HasWrittenFile(whiteSourceConfig)) { 196 contents, _ := utils.FileRead(whiteSourceConfig) 197 actual := make(map[string]interface{}) 198 _ = json.Unmarshal(contents, &actual) 199 200 mergedExpected := expected 201 mergedExpected["unknown"] = "preserved" 202 203 assert.Equal(t, mergedExpected, actual) 204 } 205 }) 206 207 t.Run("extend and merge config, omit productToken", func(t *testing.T) { 208 // init 209 initial := make(map[string]interface{}) 210 initial["checkPolicies"] = false 211 initial["productName"] = "mock-product" 212 initial["productVer"] = "41" 213 initial["unknown"] = "preserved" 214 initial["projectToken"] = "mock-project-token" 215 encoded, _ := json.Marshal(initial) 216 217 utils := NewScanUtilsMock() 218 utils.AddFile(whiteSourceConfig, encoded) 219 220 scan := newTestScan(config) 221 222 // test 223 err := scan.writeWhitesourceConfigJSON(config, utils, true, true) 224 // assert 225 if assert.NoError(t, err) && assert.True(t, utils.HasWrittenFile(whiteSourceConfig)) { 226 contents, _ := utils.FileRead(whiteSourceConfig) 227 actual := make(map[string]interface{}) 228 _ = json.Unmarshal(contents, &actual) 229 230 mergedExpected := expected 231 mergedExpected["unknown"] = "preserved" 232 mergedExpected["projectToken"] = "mock-project-token" 233 delete(mergedExpected, "productToken") 234 235 assert.Equal(t, mergedExpected, actual) 236 } 237 }) 238 }