github.com/nektos/act@v0.2.63/pkg/runner/step_test.go (about)

     1  package runner
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/nektos/act/pkg/common"
     8  	"github.com/nektos/act/pkg/model"
     9  	log "github.com/sirupsen/logrus"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/mock"
    12  	yaml "gopkg.in/yaml.v3"
    13  )
    14  
    15  func TestMergeIntoMap(t *testing.T) {
    16  	table := []struct {
    17  		name     string
    18  		target   map[string]string
    19  		maps     []map[string]string
    20  		expected map[string]string
    21  	}{
    22  		{
    23  			name:     "testEmptyMap",
    24  			target:   map[string]string{},
    25  			maps:     []map[string]string{},
    26  			expected: map[string]string{},
    27  		},
    28  		{
    29  			name:   "testMergeIntoEmptyMap",
    30  			target: map[string]string{},
    31  			maps: []map[string]string{
    32  				{
    33  					"key1": "value1",
    34  					"key2": "value2",
    35  				}, {
    36  					"key2": "overridden",
    37  					"key3": "value3",
    38  				},
    39  			},
    40  			expected: map[string]string{
    41  				"key1": "value1",
    42  				"key2": "overridden",
    43  				"key3": "value3",
    44  			},
    45  		},
    46  		{
    47  			name: "testMergeIntoExistingMap",
    48  			target: map[string]string{
    49  				"key1": "value1",
    50  				"key2": "value2",
    51  			},
    52  			maps: []map[string]string{
    53  				{
    54  					"key1": "overridden",
    55  				},
    56  			},
    57  			expected: map[string]string{
    58  				"key1": "overridden",
    59  				"key2": "value2",
    60  			},
    61  		},
    62  	}
    63  
    64  	for _, tt := range table {
    65  		t.Run(tt.name, func(t *testing.T) {
    66  			mergeIntoMapCaseSensitive(tt.target, tt.maps...)
    67  			assert.Equal(t, tt.expected, tt.target)
    68  			mergeIntoMapCaseInsensitive(tt.target, tt.maps...)
    69  			assert.Equal(t, tt.expected, tt.target)
    70  		})
    71  	}
    72  }
    73  
    74  type stepMock struct {
    75  	mock.Mock
    76  	step
    77  }
    78  
    79  func (sm *stepMock) pre() common.Executor {
    80  	args := sm.Called()
    81  	return args.Get(0).(func(context.Context) error)
    82  }
    83  
    84  func (sm *stepMock) main() common.Executor {
    85  	args := sm.Called()
    86  	return args.Get(0).(func(context.Context) error)
    87  }
    88  
    89  func (sm *stepMock) post() common.Executor {
    90  	args := sm.Called()
    91  	return args.Get(0).(func(context.Context) error)
    92  }
    93  
    94  func (sm *stepMock) getRunContext() *RunContext {
    95  	args := sm.Called()
    96  	return args.Get(0).(*RunContext)
    97  }
    98  
    99  func (sm *stepMock) getGithubContext(ctx context.Context) *model.GithubContext {
   100  	args := sm.Called()
   101  	return args.Get(0).(*RunContext).getGithubContext(ctx)
   102  }
   103  
   104  func (sm *stepMock) getStepModel() *model.Step {
   105  	args := sm.Called()
   106  	return args.Get(0).(*model.Step)
   107  }
   108  
   109  func (sm *stepMock) getEnv() *map[string]string {
   110  	args := sm.Called()
   111  	return args.Get(0).(*map[string]string)
   112  }
   113  
   114  func TestSetupEnv(t *testing.T) {
   115  	cm := &containerMock{}
   116  	sm := &stepMock{}
   117  
   118  	rc := &RunContext{
   119  		Config: &Config{
   120  			Env: map[string]string{
   121  				"GITHUB_RUN_ID": "runId",
   122  			},
   123  		},
   124  		Run: &model.Run{
   125  			JobID: "1",
   126  			Workflow: &model.Workflow{
   127  				Jobs: map[string]*model.Job{
   128  					"1": {
   129  						Env: yaml.Node{
   130  							Value: "JOB_KEY: jobvalue",
   131  						},
   132  					},
   133  				},
   134  			},
   135  		},
   136  		Env: map[string]string{
   137  			"RC_KEY": "rcvalue",
   138  		},
   139  		JobContainer: cm,
   140  	}
   141  	step := &model.Step{
   142  		With: map[string]string{
   143  			"STEP_WITH": "with-value",
   144  		},
   145  	}
   146  	env := map[string]string{}
   147  
   148  	sm.On("getRunContext").Return(rc)
   149  	sm.On("getGithubContext").Return(rc)
   150  	sm.On("getStepModel").Return(step)
   151  	sm.On("getEnv").Return(&env)
   152  
   153  	err := setupEnv(context.Background(), sm)
   154  	assert.Nil(t, err)
   155  
   156  	// These are commit or system specific
   157  	delete((env), "GITHUB_REF")
   158  	delete((env), "GITHUB_REF_NAME")
   159  	delete((env), "GITHUB_REF_TYPE")
   160  	delete((env), "GITHUB_SHA")
   161  	delete((env), "GITHUB_WORKSPACE")
   162  	delete((env), "GITHUB_REPOSITORY")
   163  	delete((env), "GITHUB_REPOSITORY_OWNER")
   164  	delete((env), "GITHUB_ACTOR")
   165  
   166  	assert.Equal(t, map[string]string{
   167  		"ACT":                      "true",
   168  		"CI":                       "true",
   169  		"GITHUB_ACTION":            "",
   170  		"GITHUB_ACTIONS":           "true",
   171  		"GITHUB_ACTION_PATH":       "",
   172  		"GITHUB_ACTION_REF":        "",
   173  		"GITHUB_ACTION_REPOSITORY": "",
   174  		"GITHUB_API_URL":           "https:///api/v3",
   175  		"GITHUB_BASE_REF":          "",
   176  		"GITHUB_EVENT_NAME":        "",
   177  		"GITHUB_EVENT_PATH":        "/var/run/act/workflow/event.json",
   178  		"GITHUB_GRAPHQL_URL":       "https:///api/graphql",
   179  		"GITHUB_HEAD_REF":          "",
   180  		"GITHUB_JOB":               "1",
   181  		"GITHUB_RETENTION_DAYS":    "0",
   182  		"GITHUB_RUN_ID":            "runId",
   183  		"GITHUB_RUN_NUMBER":        "1",
   184  		"GITHUB_SERVER_URL":        "https://",
   185  		"GITHUB_WORKFLOW":          "",
   186  		"INPUT_STEP_WITH":          "with-value",
   187  		"RC_KEY":                   "rcvalue",
   188  		"RUNNER_PERFLOG":           "/dev/null",
   189  		"RUNNER_TRACKING_ID":       "",
   190  	}, env)
   191  
   192  	cm.AssertExpectations(t)
   193  }
   194  
   195  func TestIsStepEnabled(t *testing.T) {
   196  	createTestStep := func(t *testing.T, input string) step {
   197  		var step *model.Step
   198  		err := yaml.Unmarshal([]byte(input), &step)
   199  		assert.NoError(t, err)
   200  
   201  		return &stepRun{
   202  			RunContext: &RunContext{
   203  				Config: &Config{
   204  					Workdir: ".",
   205  					Platforms: map[string]string{
   206  						"ubuntu-latest": "ubuntu-latest",
   207  					},
   208  				},
   209  				StepResults: map[string]*model.StepResult{},
   210  				Env:         map[string]string{},
   211  				Run: &model.Run{
   212  					JobID: "job1",
   213  					Workflow: &model.Workflow{
   214  						Name: "workflow1",
   215  						Jobs: map[string]*model.Job{
   216  							"job1": createJob(t, `runs-on: ubuntu-latest`, ""),
   217  						},
   218  					},
   219  				},
   220  			},
   221  			Step: step,
   222  		}
   223  	}
   224  
   225  	log.SetLevel(log.DebugLevel)
   226  	assertObject := assert.New(t)
   227  
   228  	// success()
   229  	step := createTestStep(t, "if: success()")
   230  	assertObject.True(isStepEnabled(context.Background(), step.getIfExpression(context.Background(), stepStageMain), step, stepStageMain))
   231  
   232  	step = createTestStep(t, "if: success()")
   233  	step.getRunContext().StepResults["a"] = &model.StepResult{
   234  		Conclusion: model.StepStatusSuccess,
   235  	}
   236  	assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   237  
   238  	step = createTestStep(t, "if: success()")
   239  	step.getRunContext().StepResults["a"] = &model.StepResult{
   240  		Conclusion: model.StepStatusFailure,
   241  	}
   242  	assertObject.False(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   243  
   244  	// failure()
   245  	step = createTestStep(t, "if: failure()")
   246  	assertObject.False(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   247  
   248  	step = createTestStep(t, "if: failure()")
   249  	step.getRunContext().StepResults["a"] = &model.StepResult{
   250  		Conclusion: model.StepStatusSuccess,
   251  	}
   252  	assertObject.False(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   253  
   254  	step = createTestStep(t, "if: failure()")
   255  	step.getRunContext().StepResults["a"] = &model.StepResult{
   256  		Conclusion: model.StepStatusFailure,
   257  	}
   258  	assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   259  
   260  	// always()
   261  	step = createTestStep(t, "if: always()")
   262  	assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   263  
   264  	step = createTestStep(t, "if: always()")
   265  	step.getRunContext().StepResults["a"] = &model.StepResult{
   266  		Conclusion: model.StepStatusSuccess,
   267  	}
   268  	assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   269  
   270  	step = createTestStep(t, "if: always()")
   271  	step.getRunContext().StepResults["a"] = &model.StepResult{
   272  		Conclusion: model.StepStatusFailure,
   273  	}
   274  	assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain))
   275  }
   276  
   277  func TestIsContinueOnError(t *testing.T) {
   278  	createTestStep := func(t *testing.T, input string) step {
   279  		var step *model.Step
   280  		err := yaml.Unmarshal([]byte(input), &step)
   281  		assert.NoError(t, err)
   282  
   283  		return &stepRun{
   284  			RunContext: &RunContext{
   285  				Config: &Config{
   286  					Workdir: ".",
   287  					Platforms: map[string]string{
   288  						"ubuntu-latest": "ubuntu-latest",
   289  					},
   290  				},
   291  				StepResults: map[string]*model.StepResult{},
   292  				Env:         map[string]string{},
   293  				Run: &model.Run{
   294  					JobID: "job1",
   295  					Workflow: &model.Workflow{
   296  						Name: "workflow1",
   297  						Jobs: map[string]*model.Job{
   298  							"job1": createJob(t, `runs-on: ubuntu-latest`, ""),
   299  						},
   300  					},
   301  				},
   302  			},
   303  			Step: step,
   304  		}
   305  	}
   306  
   307  	log.SetLevel(log.DebugLevel)
   308  	assertObject := assert.New(t)
   309  
   310  	// absent
   311  	step := createTestStep(t, "name: test")
   312  	continueOnError, err := isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
   313  	assertObject.False(continueOnError)
   314  	assertObject.Nil(err)
   315  
   316  	// explicit true
   317  	step = createTestStep(t, "continue-on-error: true")
   318  	continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
   319  	assertObject.True(continueOnError)
   320  	assertObject.Nil(err)
   321  
   322  	// explicit false
   323  	step = createTestStep(t, "continue-on-error: false")
   324  	continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
   325  	assertObject.False(continueOnError)
   326  	assertObject.Nil(err)
   327  
   328  	// expression true
   329  	step = createTestStep(t, "continue-on-error: ${{ 'test' == 'test' }}")
   330  	continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
   331  	assertObject.True(continueOnError)
   332  	assertObject.Nil(err)
   333  
   334  	// expression false
   335  	step = createTestStep(t, "continue-on-error: ${{ 'test' != 'test' }}")
   336  	continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
   337  	assertObject.False(continueOnError)
   338  	assertObject.Nil(err)
   339  
   340  	// expression parse error
   341  	step = createTestStep(t, "continue-on-error: ${{ 'test' != test }}")
   342  	continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain)
   343  	assertObject.False(continueOnError)
   344  	assertObject.NotNil(err)
   345  }