github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/whitesource/scanNPM_test.go (about)

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