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 }