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  }