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

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/SAP/jenkins-library/pkg/mock"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func initRunConfigGlobMock(pattern string) ([]string, error) {
    16  	matches := []string{}
    17  	switch pattern {
    18  	case "**/file1":
    19  		matches = append(matches, "file1")
    20  	case "directory/file2":
    21  		matches = append(matches, "file2")
    22  	}
    23  	return matches, nil
    24  }
    25  
    26  func TestInitRunConfigV1(t *testing.T) {
    27  	tt := []struct {
    28  		name              string
    29  		config            Config
    30  		stageConfig       string
    31  		runStagesExpected map[string]bool
    32  		runStepsExpected  map[string]map[string]bool
    33  		expectedError     error
    34  		errorContains     string
    35  	}{
    36  		{
    37  			name:             "success",
    38  			config:           Config{Stages: map[string]map[string]interface{}{"testStage": {"testKey": "testVal"}}},
    39  			stageConfig:      "spec:\n  stages:\n  - name: testStage\n    displayName: testStage\n    steps:\n    - name: testStep\n      conditions:\n      - configKey: testKey",
    40  			runStepsExpected: map[string]map[string]bool{},
    41  		},
    42  		{
    43  			name:             "error - load conditions",
    44  			stageConfig:      "wrong stage config format",
    45  			runStepsExpected: map[string]map[string]bool{},
    46  			errorContains:    "failed to load pipeline run conditions",
    47  		},
    48  		{
    49  			name:             "error - evaluate conditions",
    50  			config:           Config{Stages: map[string]map[string]interface{}{"testStage": {"testKey": "testVal"}}},
    51  			runStepsExpected: map[string]map[string]bool{},
    52  			stageConfig:      "spec:\n  stages:\n  - name: testStage\n    displayName: testStage\n    steps:\n    - name: testStep\n      conditions:\n      - config:\n          configKey1:\n          - configVal1\n          configKey2:\n          - configVal2",
    53  			errorContains:    "failed to evaluate step conditions",
    54  		},
    55  	}
    56  
    57  	filesMock := mock.FilesMock{}
    58  
    59  	for _, test := range tt {
    60  		stageConfig := ioutil.NopCloser(strings.NewReader(test.stageConfig))
    61  		runConfig := RunConfig{StageConfigFile: stageConfig}
    62  		runConfigV1 := RunConfigV1{RunConfig: runConfig}
    63  		err := runConfigV1.InitRunConfigV1(&test.config, nil, nil, nil, nil, &filesMock, ".pipeline")
    64  		if len(test.errorContains) > 0 {
    65  			assert.Contains(t, fmt.Sprint(err), test.errorContains)
    66  		} else {
    67  			assert.NoError(t, err)
    68  		}
    69  
    70  	}
    71  }
    72  
    73  func TestInitRunConfig(t *testing.T) {
    74  	tests := []struct {
    75  		name             string
    76  		customConfig     io.ReadCloser
    77  		stageConfig      io.ReadCloser
    78  		runStepsExpected map[string]map[string]bool
    79  		wantErr          bool
    80  	}{
    81  		{
    82  			name: "init run config with config condition - success",
    83  			customConfig: ioutil.NopCloser(strings.NewReader(`
    84  general: 
    85    testGeneral: 'myVal1'
    86  stages: 
    87    testStage2: 
    88      testStage: 'myVal2'
    89  steps: 
    90    thirdStep: 
    91      testStep: 'myVal3'
    92              `)),
    93  			stageConfig: ioutil.NopCloser(strings.NewReader(`
    94  stages:
    95    testStage1:
    96      stepConditions:
    97        firstStep:
    98          config: testGeneral
    99    testStage2:
   100      stepConditions:
   101        secondStep:
   102          config: testStage
   103    testStage3:
   104      stepConditions:
   105        thirdStep:
   106          config: testStep
   107              `)),
   108  			runStepsExpected: map[string]map[string]bool{
   109  				"testStage1": {
   110  					"firstStep": true,
   111  				},
   112  				"testStage2": {
   113  					"secondStep": true,
   114  				},
   115  				"testStage3": {
   116  					"thirdStep": true,
   117  				},
   118  			},
   119  			wantErr: false,
   120  		},
   121  		{
   122  			name: "init run config with filePattern condition - success",
   123  			customConfig: ioutil.NopCloser(strings.NewReader(`
   124  general: 
   125    testGeneral: 'myVal1'
   126  stages: 
   127    testStage2: 
   128      testStage: 'myVal2'
   129  steps: 
   130    thirdStep: 
   131      testStep: 'myVal3'
   132              `)),
   133  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   134  stages:
   135    testStage1:
   136      stepConditions:
   137        firstStep:
   138          filePattern: "**/file1"
   139    testStage2:
   140      stepConditions:
   141        secondStep:
   142          filePattern: "directory/file2"
   143    testStage3:
   144      stepConditions:
   145        thirdStep:
   146          filePattern: "file3"
   147              `)),
   148  			runStepsExpected: map[string]map[string]bool{
   149  				"testStage1": {
   150  					"firstStep": true,
   151  				},
   152  				"testStage2": {
   153  					"secondStep": true,
   154  				},
   155  				"testStage3": {
   156  					"thirdStep": false,
   157  				},
   158  			},
   159  			wantErr: false,
   160  		},
   161  		{
   162  			name: "init run config - unknown condition in stage config",
   163  			customConfig: ioutil.NopCloser(strings.NewReader(`
   164  steps: 
   165    testStep: 
   166      testConfig: 'testVal'
   167              `)),
   168  			stageConfig: ioutil.NopCloser(strings.NewReader(`
   169  stages:
   170    testStage:
   171      stepConditions:
   172        testStep:
   173          wrongCondition: "condVal"
   174              `)),
   175  			runStepsExpected: map[string]map[string]bool{},
   176  			wantErr:          true,
   177  		},
   178  		{
   179  			name:             "init run config - load conditions with invalid format",
   180  			stageConfig:      ioutil.NopCloser(strings.NewReader("wrong stage config format")),
   181  			runStepsExpected: map[string]map[string]bool{},
   182  			wantErr:          true,
   183  		},
   184  	}
   185  	for _, tt := range tests {
   186  		t.Run(tt.name, func(t *testing.T) {
   187  			runConfig := RunConfig{StageConfigFile: tt.stageConfig}
   188  			filter := StepFilters{All: []string{}, General: []string{}, Stages: []string{}, Steps: []string{}, Env: []string{}}
   189  			projectConfig := Config{}
   190  			_, err := projectConfig.GetStepConfig(map[string]interface{}{}, "", tt.customConfig,
   191  				[]io.ReadCloser{}, false, filter, StepData{}, nil, "", "")
   192  			assert.NoError(t, err)
   193  			err = runConfig.InitRunConfig(&projectConfig, nil, nil, nil, nil, initRunConfigGlobMock, nil)
   194  			if tt.wantErr {
   195  				assert.Error(t, err)
   196  			} else {
   197  				assert.NoError(t, err)
   198  				assert.Equal(t, tt.runStepsExpected, runConfig.RunSteps)
   199  			}
   200  		})
   201  	}
   202  }
   203  
   204  func TestRunConfigLoadConditions(t *testing.T) {
   205  	stageConfigContent := `stages:
   206    'testStage1':
   207      stepConditions:
   208        firstStep:
   209          filePattern: '**/my.file'
   210  `
   211  	t.Run("load conditions - file of invalid format", func(t *testing.T) {
   212  		runConfig := &RunConfig{StageConfigFile: ioutil.NopCloser(strings.NewReader("-- {{ \\ wrong } file format }"))}
   213  		err := runConfig.loadConditions()
   214  		assert.Error(t, err, "format of configuration is invalid")
   215  	})
   216  
   217  	t.Run("load conditions - success", func(t *testing.T) {
   218  		runConfig := &RunConfig{StageConfigFile: ioutil.NopCloser(strings.NewReader(stageConfigContent))}
   219  
   220  		err := runConfig.loadConditions()
   221  		assert.NoError(t, err)
   222  		condition := map[string]interface{}{
   223  			"filePattern": "**/my.file",
   224  		}
   225  
   226  		assert.Equal(t, 1, len(runConfig.StageConfig.Stages))
   227  		assert.Equal(t, 1, len(runConfig.StageConfig.Stages["testStage1"].Conditions))
   228  		assert.Equal(t, condition, runConfig.StageConfig.Stages["testStage1"].Conditions["firstStep"])
   229  	})
   230  }
   231  
   232  func Test_stepConfigLookup(t *testing.T) {
   233  
   234  	testConfig := map[string]interface{}{
   235  		"general": map[string]interface{}{
   236  			"generalKey": "generalValue",
   237  		},
   238  		"stages": map[string]interface{}{
   239  			"testStep": map[string]interface{}{
   240  				"stagesKey": "stagesValue",
   241  			},
   242  		},
   243  		"steps": map[string]interface{}{
   244  			"testStep": map[string]interface{}{
   245  				"stepKey":            "stepValue",
   246  				"stepKeyStringSlice": []string{"val1", "val2"},
   247  			},
   248  		},
   249  		"configKey": "configValue",
   250  	}
   251  
   252  	type args struct {
   253  		m        map[string]interface{}
   254  		stepName string
   255  		key      string
   256  	}
   257  	tests := []struct {
   258  		name string
   259  		args args
   260  		want interface{}
   261  	}{
   262  		{
   263  			name: "empty map",
   264  			args: args{nil, "", ""},
   265  			want: nil,
   266  		},
   267  		{
   268  			name: "key not in map, invalid stepName",
   269  			args: args{testConfig, "some step", "some key"},
   270  			want: nil,
   271  		},
   272  		{
   273  			name: "key not in map, valid stepName",
   274  			args: args{testConfig, "testStep", "some key"},
   275  			want: nil,
   276  		},
   277  		{
   278  			name: "key in map under general",
   279  			args: args{testConfig, "some step", "generalKey"},
   280  			want: "generalValue",
   281  		},
   282  		{
   283  			name: "key in map under stages",
   284  			args: args{testConfig, "testStep", "stagesKey"},
   285  			want: "stagesValue",
   286  		},
   287  		{
   288  			name: "key in map under general",
   289  			args: args{testConfig, "testStep", "stepKey"},
   290  			want: "stepValue",
   291  		},
   292  		{
   293  			name: "key in map under general",
   294  			args: args{testConfig, "testStep", "stepKeyStringSlice"},
   295  			want: []string{"val1", "val2"},
   296  		},
   297  		{
   298  			name: "key in map on top level string",
   299  			args: args{testConfig, "", "configKey"},
   300  			want: "configValue",
   301  		},
   302  		{
   303  			name: "key in map on top level map",
   304  			args: args{testConfig, "", "general"},
   305  			want: map[string]interface{}{"generalKey": "generalValue"},
   306  		},
   307  	}
   308  	for _, tt := range tests {
   309  		t.Run(tt.name, func(t *testing.T) {
   310  			if got := stepConfigLookup(tt.args.m, tt.args.stepName, tt.args.key); !reflect.DeepEqual(got, tt.want) {
   311  				t.Errorf("stepConfigLookup() = %v, want %v", got, tt.want)
   312  			}
   313  		})
   314  	}
   315  }