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