github.com/jaylevin/jenkins-library@v1.230.4/pkg/config/evaluation_test.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/SAP/jenkins-library/pkg/mock"
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  func evaluateConditionsGlobMock(pattern string) ([]string, error) {
    18  	matches := []string{}
    19  	switch pattern {
    20  	case "**/conf.js":
    21  		matches = append(matches, "conf.js")
    22  	case "**/package.json":
    23  		matches = append(matches, "package.json", "package/node_modules/lib/package.json", "node_modules/package.json", "test/package.json")
    24  
    25  	}
    26  	return matches, nil
    27  }
    28  
    29  func evaluateConditionsOpenFileMock(name string, _ map[string]string) (io.ReadCloser, error) {
    30  	var fileContent io.ReadCloser
    31  	switch name {
    32  	case "package.json":
    33  		fileContent = ioutil.NopCloser(strings.NewReader(`
    34  		{
    35  			"scripts": {
    36  				"npmScript": "echo test",
    37  				"npmScript2": "echo test"
    38  			}
    39  		}
    40  		`))
    41  	case "_package.json":
    42  		fileContent = ioutil.NopCloser(strings.NewReader("wrong json format"))
    43  	case "test/package.json":
    44  		fileContent = ioutil.NopCloser(strings.NewReader("{}"))
    45  	}
    46  	return fileContent, nil
    47  }
    48  
    49  func TestEvaluateConditionsV1(t *testing.T) {
    50  	filesMock := mock.FilesMock{}
    51  
    52  	runConfig := RunConfigV1{
    53  		PipelineConfig: PipelineDefinitionV1{
    54  			Spec: Spec{
    55  				Stages: []Stage{
    56  					{
    57  						Name:        "stage1",
    58  						DisplayName: "Test Stage 1",
    59  						Steps: []Step{
    60  							{
    61  								Name:          "step1_1",
    62  								Conditions:    []StepCondition{},
    63  								Orchestrators: []string{"Jenkins"},
    64  							},
    65  							{
    66  								Name: "step1_2",
    67  								Conditions: []StepCondition{
    68  									{ConfigKey: "testKey"},
    69  								},
    70  							},
    71  							{
    72  								Name:       "step1_3",
    73  								Conditions: []StepCondition{},
    74  							},
    75  						},
    76  					},
    77  					{
    78  						Name:        "stage2",
    79  						DisplayName: "Test Stage 2",
    80  						Steps: []Step{
    81  							{
    82  								Name: "step2_1",
    83  								Conditions: []StepCondition{
    84  									{ConfigKey: "testKeyNotExisting"},
    85  									{ConfigKey: "testKey"},
    86  								},
    87  							},
    88  							{
    89  								Name: "step2_2",
    90  							},
    91  						},
    92  					},
    93  					{
    94  						Name:        "stage3",
    95  						DisplayName: "Test Stage 3",
    96  						Steps: []Step{
    97  							{
    98  								Name: "step3_1",
    99  								Conditions: []StepCondition{
   100  									{ConfigKey: "testKeyNotExisting"},
   101  									{ConfigKey: "testKey"},
   102  								},
   103  							},
   104  						},
   105  					},
   106  				},
   107  			},
   108  		},
   109  	}
   110  	config := Config{Stages: map[string]map[string]interface{}{
   111  		"Test Stage 1": {"step1_3": false, "testKey": "testVal"},
   112  		"Test Stage 2": {"testKey": "testVal"},
   113  	}}
   114  
   115  	expectedSteps := map[string]map[string]bool{
   116  		"Test Stage 1": {
   117  			"step1_2": true,
   118  			"step1_3": false,
   119  		},
   120  		"Test Stage 2": {
   121  			"step2_1": true,
   122  			"step2_2": true,
   123  		},
   124  		"Test Stage 3": {
   125  			"step3_1": false,
   126  		},
   127  	}
   128  
   129  	expectedStages := map[string]bool{
   130  		"Test Stage 1": true,
   131  		"Test Stage 2": true,
   132  		"Test Stage 3": false,
   133  	}
   134  
   135  	err := runConfig.evaluateConditionsV1(&config, nil, nil, nil, nil, &filesMock, ".pipeline")
   136  	assert.NoError(t, err)
   137  	assert.Equal(t, expectedSteps, runConfig.RunSteps)
   138  	assert.Equal(t, expectedStages, runConfig.RunStages)
   139  
   140  }
   141  
   142  func TestNotActiveEvaluateConditionsV1(t *testing.T) {
   143  	filesMock := mock.FilesMock{}
   144  
   145  	runConfig := RunConfigV1{
   146  		PipelineConfig: PipelineDefinitionV1{
   147  			Spec: Spec{
   148  				Stages: []Stage{
   149  					{
   150  						Name:        "stage1",
   151  						DisplayName: "Test Stage 1",
   152  						Steps: []Step{
   153  							{
   154  								Name:          "step1_1",
   155  								Conditions:    []StepCondition{},
   156  								Orchestrators: []string{"Jenkins"},
   157  							},
   158  							{
   159  								Name: "step1_2",
   160  								Conditions: []StepCondition{
   161  									{ConfigKey: "testKey"},
   162  								},
   163  								NotActiveConditions: []StepCondition{
   164  									{ConfigKey: "testKeyNotExisting"},
   165  								},
   166  							},
   167  							{
   168  								Name:       "step1_3",
   169  								Conditions: []StepCondition{},
   170  								NotActiveConditions: []StepCondition{
   171  									{ConfigKey: "testKeyNotExisting"},
   172  									{ConfigKey: "testKey"},
   173  								},
   174  							},
   175  						},
   176  					},
   177  					{
   178  						Name:        "stage2",
   179  						DisplayName: "Test Stage 2",
   180  						Steps: []Step{
   181  							{
   182  								Name: "step2_1",
   183  								Conditions: []StepCondition{
   184  									{ConfigKey: "testKeyNotExisting"},
   185  									{ConfigKey: "testKey"},
   186  								},
   187  							},
   188  						},
   189  					},
   190  					{
   191  						Name:        "stage3",
   192  						DisplayName: "Test Stage 3",
   193  						Steps: []Step{
   194  							{
   195  								Name: "step3_1",
   196  								NotActiveConditions: []StepCondition{
   197  									{ConfigKey: "testKey"},
   198  								},
   199  							},
   200  						},
   201  					},
   202  				},
   203  			},
   204  		},
   205  	}
   206  	config := Config{Stages: map[string]map[string]interface{}{
   207  		"Test Stage 1": {"testKey": "testVal"},
   208  		"Test Stage 2": {"testKey": "testVal"},
   209  		"Test Stage 3": {"testKey": "testVal"},
   210  	}}
   211  
   212  	expectedSteps := map[string]map[string]bool{
   213  		"Test Stage 1": {
   214  			"step1_2": true,
   215  			"step1_3": false,
   216  		},
   217  		"Test Stage 2": {
   218  			"step2_1": true,
   219  		},
   220  		"Test Stage 3": {
   221  			"step3_1": false,
   222  		},
   223  	}
   224  
   225  	expectedStages := map[string]bool{
   226  		"Test Stage 1": true,
   227  		"Test Stage 2": true,
   228  		"Test Stage 3": false,
   229  	}
   230  
   231  	err := runConfig.evaluateConditionsV1(&config, nil, nil, nil, nil, &filesMock, ".pipeline")
   232  	assert.NoError(t, err)
   233  	assert.Equal(t, expectedSteps, runConfig.RunSteps)
   234  	assert.Equal(t, expectedStages, runConfig.RunStages)
   235  
   236  }
   237  
   238  func TestEvaluateV1(t *testing.T) {
   239  	tt := []struct {
   240  		name          string
   241  		config        StepConfig
   242  		stepCondition StepCondition
   243  		expected      bool
   244  		expectedError error
   245  	}{
   246  		{
   247  			name: "Config condition - true",
   248  			config: StepConfig{Config: map[string]interface{}{
   249  				"deployTool": "helm3",
   250  			}},
   251  			stepCondition: StepCondition{Config: map[string][]interface{}{"deployTool": {"helm", "helm3", "kubectl"}}},
   252  			expected:      true,
   253  		},
   254  		{
   255  			name: "Config condition - false",
   256  			config: StepConfig{Config: map[string]interface{}{
   257  				"deployTool": "notsupported",
   258  			}},
   259  			stepCondition: StepCondition{Config: map[string][]interface{}{"deployTool": {"helm", "helm3", "kubectl"}}},
   260  			expected:      false,
   261  		},
   262  		{
   263  			name: "Config condition - integer - true",
   264  			config: StepConfig{Config: map[string]interface{}{
   265  				"executors": 1,
   266  			}},
   267  			stepCondition: StepCondition{Config: map[string][]interface{}{"executors": {1}}},
   268  			expected:      true,
   269  		},
   270  		{
   271  			name: "Config condition - wrong condition definition",
   272  			config: StepConfig{Config: map[string]interface{}{
   273  				"deployTool": "helm3",
   274  			}},
   275  			stepCondition: StepCondition{Config: map[string][]interface{}{"deployTool": {"helm", "helm3", "kubectl"}, "deployTool2": {"myTool"}}},
   276  			expectedError: fmt.Errorf("only one config key allowed per condition but 2 provided"),
   277  		},
   278  		{
   279  			name: "ConfigKey condition - true",
   280  			config: StepConfig{Config: map[string]interface{}{
   281  				"dockerRegistryUrl": "https://my.docker.registry.url",
   282  			}},
   283  			stepCondition: StepCondition{ConfigKey: "dockerRegistryUrl"},
   284  			expected:      true,
   285  		},
   286  		{
   287  			name:          "ConfigKey condition - false",
   288  			config:        StepConfig{Config: map[string]interface{}{}},
   289  			stepCondition: StepCondition{ConfigKey: "dockerRegistryUrl"},
   290  			expected:      false,
   291  		},
   292  		{
   293  			name:          "FilePattern condition - true",
   294  			config:        StepConfig{Config: map[string]interface{}{}},
   295  			stepCondition: StepCondition{FilePattern: "**/conf.js"},
   296  			expected:      true,
   297  		},
   298  		{
   299  			name:          "FilePattern condition - false",
   300  			config:        StepConfig{Config: map[string]interface{}{}},
   301  			stepCondition: StepCondition{FilePattern: "**/confx.js"},
   302  			expected:      false,
   303  		},
   304  		{
   305  			name: "FilePatternFromConfig condition - true",
   306  			config: StepConfig{Config: map[string]interface{}{
   307  				"newmanCollection": "**/*.postman_collection.json",
   308  			}},
   309  			stepCondition: StepCondition{FilePatternFromConfig: "newmanCollection"},
   310  			expected:      true,
   311  		},
   312  		{
   313  			name: "FilePatternFromConfig condition - false",
   314  			config: StepConfig{Config: map[string]interface{}{
   315  				"newmanCollection": "**/*.postmanx_collection.json",
   316  			}},
   317  			stepCondition: StepCondition{FilePatternFromConfig: "newmanCollection"},
   318  			expected:      false,
   319  		},
   320  		{
   321  			name: "FilePatternFromConfig condition - false, empty value",
   322  			config: StepConfig{Config: map[string]interface{}{
   323  				"newmanCollection": "",
   324  			}},
   325  			stepCondition: StepCondition{FilePatternFromConfig: "newmanCollection"},
   326  			expected:      false,
   327  		},
   328  		{
   329  			name:          "NpmScript condition - true",
   330  			config:        StepConfig{Config: map[string]interface{}{}},
   331  			stepCondition: StepCondition{NpmScript: "testScript"},
   332  			expected:      true,
   333  		},
   334  		{
   335  			name:          "NpmScript condition - true",
   336  			config:        StepConfig{Config: map[string]interface{}{}},
   337  			stepCondition: StepCondition{NpmScript: "missingScript"},
   338  			expected:      false,
   339  		},
   340  		{
   341  			name:          "Inactive condition - false",
   342  			config:        StepConfig{Config: map[string]interface{}{}},
   343  			stepCondition: StepCondition{Inactive: true},
   344  			expected:      false,
   345  		},
   346  		{
   347  			name:          "Inactive condition - true",
   348  			config:        StepConfig{Config: map[string]interface{}{}},
   349  			stepCondition: StepCondition{Inactive: false},
   350  			expected:      true,
   351  		},
   352  		{
   353  			name:          "CommonPipelineEnvironment - true",
   354  			config:        StepConfig{Config: map[string]interface{}{}},
   355  			stepCondition: StepCondition{CommonPipelineEnvironment: map[string]interface{}{"myCpeTrueFile": "myTrueValue"}},
   356  			expected:      true,
   357  		},
   358  		{
   359  			name:          "CommonPipelineEnvironment - false",
   360  			config:        StepConfig{Config: map[string]interface{}{}},
   361  			stepCondition: StepCondition{CommonPipelineEnvironment: map[string]interface{}{"myCpeTrueFile": "notMyTrueValue"}},
   362  			expected:      false,
   363  		},
   364  		{
   365  			name:     "No condition - true",
   366  			config:   StepConfig{Config: map[string]interface{}{}},
   367  			expected: true,
   368  		},
   369  	}
   370  
   371  	packageJson := `{
   372  	"scripts": {
   373  		"testScript": "whatever"
   374  	}
   375  }`
   376  
   377  	filesMock := mock.FilesMock{}
   378  	filesMock.AddFile("conf.js", []byte("//test"))
   379  	filesMock.AddFile("my.postman_collection.json", []byte("{}"))
   380  	filesMock.AddFile("package.json", []byte(packageJson))
   381  
   382  	dir, err := ioutil.TempDir("", "")
   383  	if err != nil {
   384  		t.Fatal("Failed to create temporary directory")
   385  	}
   386  	// clean up tmp dir
   387  	defer os.RemoveAll(dir)
   388  
   389  	cpeDir := filepath.Join(dir, "commonPipelineEnvironment")
   390  	err = os.MkdirAll(cpeDir, 0700)
   391  	if err != nil {
   392  		t.Fatal("Failed to create sub directory")
   393  	}
   394  	ioutil.WriteFile(filepath.Join(cpeDir, "myCpeTrueFile"), []byte("myTrueValue"), 0700)
   395  
   396  	for _, test := range tt {
   397  		t.Run(test.name, func(t *testing.T) {
   398  			active, err := test.stepCondition.evaluateV1(test.config, &filesMock, "dummy", dir)
   399  			if test.expectedError == nil {
   400  				assert.NoError(t, err)
   401  			} else {
   402  				assert.EqualError(t, err, fmt.Sprint(test.expectedError))
   403  			}
   404  			assert.Equal(t, test.expected, active)
   405  		})
   406  	}
   407  }
   408  
   409  func TestEvaluateConditions(t *testing.T) {
   410  	tests := []struct {
   411  		name             string
   412  		customConfig     *Config
   413  		stageConfig      io.ReadCloser
   414  		runStepsExpected map[string]map[string]bool
   415  		globFunc         func(pattern string) ([]string, error)
   416  		wantErr          bool
   417  	}{
   418  		{
   419  			name: "test config condition - success",
   420  			customConfig: &Config{
   421  				General: map[string]interface{}{
   422  					"testGeneral": "myVal1",
   423  				},
   424  				Stages: map[string]map[string]interface{}{
   425  					"testStage2": {
   426  						"testStage": "myVal2",
   427  					},
   428  				},
   429  				Steps: map[string]map[string]interface{}{
   430  					"thirdStep": {
   431  						"testStep1": "myVal3",
   432  					},
   433  				},
   434  			},
   435  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   436  stages:
   437    testStage1:
   438      stepConditions:
   439        firstStep:
   440          config: testGeneral
   441    testStage2:
   442      stepConditions:
   443        secondStep:
   444          config: testStage
   445    testStage3:
   446      stepConditions:
   447        thirdStep:
   448          config: testStep1
   449        forthStep:
   450          config: testStep2
   451              `)),
   452  			runStepsExpected: map[string]map[string]bool{
   453  				"testStage1": {"firstStep": true},
   454  				"testStage2": {"secondStep": true},
   455  				"testStage3": {
   456  					"thirdStep": true,
   457  					"forthStep": false,
   458  				},
   459  			},
   460  			wantErr: false,
   461  		},
   462  		{
   463  			name: "test config condition - wrong usage with list",
   464  			customConfig: &Config{
   465  				General: map[string]interface{}{},
   466  				Stages:  map[string]map[string]interface{}{},
   467  				Steps:   map[string]map[string]interface{}{},
   468  			},
   469  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   470  stages:
   471    testStage1:
   472      stepConditions:
   473        firstStep:
   474          config: 
   475           - testGeneral
   476              `)),
   477  			runStepsExpected: map[string]map[string]bool{},
   478  			wantErr:          true,
   479  		},
   480  		{
   481  			name: "test config value condition - success",
   482  			customConfig: &Config{
   483  				General: map[string]interface{}{
   484  					"testGeneral": "myVal1",
   485  				},
   486  				Stages: map[string]map[string]interface{}{},
   487  				Steps: map[string]map[string]interface{}{
   488  					"thirdStep": {
   489  						"testStep": "myVal3",
   490  					},
   491  				},
   492  			},
   493  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   494  stages:
   495    testStage1:
   496      stepConditions:
   497        firstStep:
   498          config:
   499            testGeneral:
   500              - myValx
   501              - myVal1
   502    testStage2:
   503      stepConditions:
   504        secondStep:
   505          config:
   506            testStage:
   507              - maValXyz
   508    testStage3:
   509      stepConditions:
   510        thirdStep:
   511          config:
   512            testStep:
   513              - myVal3
   514              `)),
   515  			runStepsExpected: map[string]map[string]bool{
   516  				"testStage1": {"firstStep": true},
   517  				"testStage2": {"secondStep": false},
   518  				"testStage3": {"thirdStep": true},
   519  			},
   520  			wantErr: false,
   521  		},
   522  		{
   523  			name: "test configKey condition - success",
   524  			customConfig: &Config{
   525  				General: map[string]interface{}{
   526  					"myKey1_1": "myVal1_1",
   527  				},
   528  				Stages: map[string]map[string]interface{}{},
   529  				Steps: map[string]map[string]interface{}{
   530  					"thirdStep": {
   531  						"myKey3_1": "myVal3_1",
   532  					},
   533  				},
   534  			},
   535  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   536  stages:
   537    testStage1:
   538      stepConditions:
   539        firstStep:
   540          configKeys:
   541            - myKey1_1
   542            - myKey1_2
   543    testStage2:
   544      stepConditions:
   545        secondStep:
   546          configKeys:
   547            - myKey2_1
   548    testStage3:
   549      stepConditions:
   550        thirdStep:
   551          configKeys:
   552            - myKey3_1
   553              `)),
   554  			runStepsExpected: map[string]map[string]bool{
   555  				"testStage1": {"firstStep": true},
   556  				"testStage2": {"secondStep": false},
   557  				"testStage3": {"thirdStep": true},
   558  			},
   559  			wantErr: false,
   560  		},
   561  		{
   562  			name: "test configKey condition - not list",
   563  			customConfig: &Config{
   564  				General: map[string]interface{}{
   565  					"myKey1_1": "myVal1_1",
   566  				},
   567  				Stages: map[string]map[string]interface{}{},
   568  				Steps:  map[string]map[string]interface{}{},
   569  			},
   570  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   571  stages:
   572    testStage1:
   573      stepConditions:
   574        firstStep:
   575          configKeys: myKey1_1
   576              `)),
   577  			wantErr: true,
   578  		},
   579  		{
   580  			name: "test configKey condition - success",
   581  			customConfig: &Config{
   582  				General: map[string]interface{}{
   583  					"myKey1_1": "myVal1_1",
   584  				},
   585  				Stages: map[string]map[string]interface{}{},
   586  				Steps: map[string]map[string]interface{}{
   587  					"thirdStep": {
   588  						"myKey3_1": "myVal3_1",
   589  					},
   590  				},
   591  			},
   592  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   593  stages:
   594    testStage1:
   595      stepConditions:
   596        firstStep:
   597          configKeys:
   598            - myKey1_1
   599            - myKey1_2
   600    testStage2:
   601      stepConditions:
   602        secondStep:
   603          configKeys:
   604            - myKey2_1
   605    testStage3:
   606      stepConditions:
   607        thirdStep:
   608          configKeys:
   609            - myKey3_1
   610              `)),
   611  			runStepsExpected: map[string]map[string]bool{
   612  				"testStage1": {"firstStep": true},
   613  				"testStage2": {"secondStep": false},
   614  				"testStage3": {"thirdStep": true},
   615  			},
   616  			wantErr: false,
   617  		},
   618  		{
   619  			name:     "test filePattern condition - success",
   620  			globFunc: evaluateConditionsGlobMock,
   621  			customConfig: &Config{
   622  				General: map[string]interface{}{},
   623  				Stages:  map[string]map[string]interface{}{},
   624  				Steps:   map[string]map[string]interface{}{},
   625  			},
   626  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   627  stages:
   628    testStage1:
   629      stepConditions:
   630        firstStep:
   631          filePattern: '**/conf.js'
   632        secondStep:
   633          filePattern: '**/conf.jsx'
   634              `)),
   635  			runStepsExpected: map[string]map[string]bool{
   636  				"testStage1": {
   637  					"firstStep":  true,
   638  					"secondStep": false,
   639  				},
   640  			},
   641  			wantErr: false,
   642  		},
   643  		{
   644  			name: "test filePattern condition - error while searching files by pattern",
   645  			customConfig: &Config{
   646  				General: map[string]interface{}{},
   647  				Stages:  map[string]map[string]interface{}{},
   648  				Steps:   map[string]map[string]interface{}{},
   649  			},
   650  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   651  stages:
   652    testStage1:
   653      stepConditions:
   654        firstStep:
   655          filePattern: '**/conf.js'
   656              `)),
   657  			runStepsExpected: map[string]map[string]bool{},
   658  			globFunc: func(pattern string) ([]string, error) {
   659  				return nil, errors.New("failed to check if file exists")
   660  			},
   661  			wantErr: true,
   662  		},
   663  		{
   664  			name:     "test filePattern condition with list - success",
   665  			globFunc: evaluateConditionsGlobMock,
   666  			customConfig: &Config{
   667  				General: map[string]interface{}{},
   668  				Stages:  map[string]map[string]interface{}{},
   669  				Steps:   map[string]map[string]interface{}{},
   670  			},
   671  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   672  stages:
   673    testStage1:
   674      stepConditions:
   675        firstStep:
   676          filePattern:
   677           - '**/conf.js'
   678           - 'myCollection.json'
   679        secondStep:
   680          filePattern: 
   681           - '**/conf.jsx'
   682              `)),
   683  			runStepsExpected: map[string]map[string]bool{
   684  				"testStage1": {
   685  					"firstStep":  true,
   686  					"secondStep": false,
   687  				},
   688  			},
   689  			wantErr: false,
   690  		},
   691  		{
   692  			name: "test filePattern condition with list - error while searching files by pattern",
   693  			customConfig: &Config{
   694  				General: map[string]interface{}{},
   695  				Stages:  map[string]map[string]interface{}{},
   696  				Steps:   map[string]map[string]interface{}{},
   697  			},
   698  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   699  stages:
   700    testStage1:
   701      stepConditions:
   702        firstStep:
   703          filePattern:
   704           - '**/conf.js'
   705           - 'myCollection.json'
   706              `)),
   707  			runStepsExpected: map[string]map[string]bool{},
   708  			globFunc: func(pattern string) ([]string, error) {
   709  				return nil, errors.New("failed to check if file exists")
   710  			},
   711  			wantErr: true,
   712  		},
   713  		{
   714  			name:     "test filePatternFromConfig condition - success",
   715  			globFunc: evaluateConditionsGlobMock,
   716  			customConfig: &Config{
   717  				General: map[string]interface{}{},
   718  				Stages:  map[string]map[string]interface{}{},
   719  				Steps: map[string]map[string]interface{}{
   720  					"firstStep": {
   721  						"myVal1": "**/conf.js",
   722  					},
   723  					"thirdStep": {
   724  						"myVal3": "**/conf.jsx",
   725  					},
   726  				},
   727  			},
   728  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   729  stages:
   730    testStage1:
   731      stepConditions:
   732        firstStep:
   733          filePatternFromConfig: myVal1
   734        secondStep:
   735          filePatternFromConfig: myVal2
   736        thirdStep:
   737          filePatternFromConfig: myVal3
   738              `)),
   739  			runStepsExpected: map[string]map[string]bool{
   740  				"testStage1": {
   741  					"firstStep":  true,
   742  					"secondStep": false,
   743  					"thirdStep":  false,
   744  				},
   745  			},
   746  			wantErr: false,
   747  		},
   748  		{
   749  			name: "test filePatternFromConfig condition - error while searching files by pattern",
   750  			customConfig: &Config{
   751  				General: map[string]interface{}{},
   752  				Stages:  map[string]map[string]interface{}{},
   753  				Steps: map[string]map[string]interface{}{
   754  					"firstStep": {
   755  						"myVal1": "**/conf.js",
   756  					},
   757  				},
   758  			},
   759  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   760  stages:
   761    testStage1:
   762      stepConditions:
   763        firstStep:
   764          filePatternFromConfig: myVal1
   765              `)),
   766  			runStepsExpected: map[string]map[string]bool{},
   767  			globFunc: func(pattern string) ([]string, error) {
   768  				return nil, errors.New("failed to check if file exists")
   769  			},
   770  			wantErr: true,
   771  		},
   772  		{
   773  			name:     "test npmScripts condition - success",
   774  			globFunc: evaluateConditionsGlobMock,
   775  			customConfig: &Config{
   776  				General: map[string]interface{}{},
   777  				Stages:  map[string]map[string]interface{}{},
   778  				Steps:   map[string]map[string]interface{}{},
   779  			},
   780  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   781  stages:
   782    testStage1:
   783      stepConditions:
   784        firstStep:
   785          npmScripts: 'npmScript'
   786        secondStep:
   787          npmScripts: 'npmScript1'
   788              `)),
   789  			runStepsExpected: map[string]map[string]bool{
   790  				"testStage1": {
   791  					"firstStep":  true,
   792  					"secondStep": false,
   793  				},
   794  			},
   795  			wantErr: false,
   796  		},
   797  		{
   798  			name:     "test npmScripts condition with list - success",
   799  			globFunc: evaluateConditionsGlobMock,
   800  			customConfig: &Config{
   801  				General: map[string]interface{}{},
   802  				Stages:  map[string]map[string]interface{}{},
   803  				Steps:   map[string]map[string]interface{}{},
   804  			},
   805  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   806  stages:
   807    testStage1:
   808      stepConditions:
   809        firstStep:
   810          npmScripts:
   811           - 'npmScript'
   812           - 'npmScript2'
   813        secondStep:
   814          npmScripts:
   815           - 'npmScript3'
   816           - 'npmScript4'
   817              `)),
   818  			runStepsExpected: map[string]map[string]bool{
   819  				"testStage1": {
   820  					"firstStep":  true,
   821  					"secondStep": false,
   822  				},
   823  			},
   824  			wantErr: false,
   825  		},
   826  		{
   827  			name: "test npmScripts condition - json with wrong format",
   828  			customConfig: &Config{
   829  				General: map[string]interface{}{},
   830  				Stages:  map[string]map[string]interface{}{},
   831  				Steps:   map[string]map[string]interface{}{},
   832  			},
   833  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   834  stages:
   835    testStage1:
   836      stepConditions:
   837        firstStep:
   838          npmScripts:
   839           - 'npmScript3'
   840              `)),
   841  			runStepsExpected: map[string]map[string]bool{},
   842  			globFunc: func(pattern string) ([]string, error) {
   843  				return []string{"_package.json"}, nil
   844  			},
   845  			wantErr: true,
   846  		},
   847  		{
   848  			name: "test npmScripts condition - error while searching package.json",
   849  			customConfig: &Config{
   850  				General: map[string]interface{}{},
   851  				Stages:  map[string]map[string]interface{}{},
   852  				Steps:   map[string]map[string]interface{}{},
   853  			},
   854  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   855  stages:
   856    testStage1:
   857      stepConditions:
   858        firstStep:
   859          npmScripts:
   860           - 'npmScript3'
   861              `)),
   862  			runStepsExpected: map[string]map[string]bool{},
   863  			globFunc: func(pattern string) ([]string, error) {
   864  				return nil, errors.New("failed to check if file exists")
   865  			},
   866  			wantErr: true,
   867  		},
   868  		{
   869  			name: "test explicit activation / de-activation of step",
   870  			customConfig: &Config{
   871  				Stages: map[string]map[string]interface{}{
   872  					"testStage1": {
   873  						"firstStep":    true,
   874  						"fisecondStep": false,
   875  					},
   876  				},
   877  			},
   878  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   879  stages:
   880    testStage1:
   881      stepConditions:
   882        firstStep:
   883          config: testGeneral
   884        secondStep:
   885          config: testStage
   886  `)),
   887  			runStepsExpected: map[string]map[string]bool{
   888  				"testStage1": {
   889  					"firstStep":  true,
   890  					"secondStep": false,
   891  				},
   892  			},
   893  		},
   894  	}
   895  	for _, tt := range tests {
   896  		t.Run(tt.name, func(t *testing.T) {
   897  			runConfig := RunConfig{
   898  				StageConfigFile: tt.stageConfig,
   899  				RunSteps:        map[string]map[string]bool{},
   900  				OpenFile:        evaluateConditionsOpenFileMock,
   901  			}
   902  			err := runConfig.loadConditions()
   903  			assert.NoError(t, err)
   904  			err = runConfig.evaluateConditions(tt.customConfig, nil, nil, nil, nil, tt.globFunc)
   905  			if tt.wantErr {
   906  				assert.Error(t, err)
   907  			} else {
   908  				assert.NoError(t, err)
   909  				assert.Equal(t, tt.runStepsExpected, runConfig.RunSteps)
   910  			}
   911  		})
   912  	}
   913  }