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  }