diff options
Diffstat (limited to 'pkg/runner/step_test.go')
-rw-r--r-- | pkg/runner/step_test.go | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/pkg/runner/step_test.go b/pkg/runner/step_test.go new file mode 100644 index 0000000..d08a129 --- /dev/null +++ b/pkg/runner/step_test.go @@ -0,0 +1,346 @@ +package runner + +import ( + "context" + "testing" + + "github.com/nektos/act/pkg/common" + "github.com/nektos/act/pkg/model" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + yaml "gopkg.in/yaml.v3" +) + +func TestMergeIntoMap(t *testing.T) { + table := []struct { + name string + target map[string]string + maps []map[string]string + expected map[string]string + }{ + { + name: "testEmptyMap", + target: map[string]string{}, + maps: []map[string]string{}, + expected: map[string]string{}, + }, + { + name: "testMergeIntoEmptyMap", + target: map[string]string{}, + maps: []map[string]string{ + { + "key1": "value1", + "key2": "value2", + }, { + "key2": "overridden", + "key3": "value3", + }, + }, + expected: map[string]string{ + "key1": "value1", + "key2": "overridden", + "key3": "value3", + }, + }, + { + name: "testMergeIntoExistingMap", + target: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + maps: []map[string]string{ + { + "key1": "overridden", + }, + }, + expected: map[string]string{ + "key1": "overridden", + "key2": "value2", + }, + }, + } + + for _, tt := range table { + t.Run(tt.name, func(t *testing.T) { + mergeIntoMapCaseSensitive(tt.target, tt.maps...) + assert.Equal(t, tt.expected, tt.target) + mergeIntoMapCaseInsensitive(tt.target, tt.maps...) + assert.Equal(t, tt.expected, tt.target) + }) + } +} + +type stepMock struct { + mock.Mock + step +} + +func (sm *stepMock) pre() common.Executor { + args := sm.Called() + return args.Get(0).(func(context.Context) error) +} + +func (sm *stepMock) main() common.Executor { + args := sm.Called() + return args.Get(0).(func(context.Context) error) +} + +func (sm *stepMock) post() common.Executor { + args := sm.Called() + return args.Get(0).(func(context.Context) error) +} + +func (sm *stepMock) getRunContext() *RunContext { + args := sm.Called() + return args.Get(0).(*RunContext) +} + +func (sm *stepMock) getGithubContext(ctx context.Context) *model.GithubContext { + args := sm.Called() + return args.Get(0).(*RunContext).getGithubContext(ctx) +} + +func (sm *stepMock) getStepModel() *model.Step { + args := sm.Called() + return args.Get(0).(*model.Step) +} + +func (sm *stepMock) getEnv() *map[string]string { + args := sm.Called() + return args.Get(0).(*map[string]string) +} + +func TestSetupEnv(t *testing.T) { + cm := &containerMock{} + sm := &stepMock{} + + rc := &RunContext{ + Config: &Config{ + Env: map[string]string{ + "GITHUB_RUN_ID": "runId", + }, + }, + Run: &model.Run{ + JobID: "1", + Workflow: &model.Workflow{ + Jobs: map[string]*model.Job{ + "1": { + Env: yaml.Node{ + Value: "JOB_KEY: jobvalue", + }, + }, + }, + }, + }, + Env: map[string]string{ + "RC_KEY": "rcvalue", + }, + JobContainer: cm, + } + step := &model.Step{ + With: map[string]string{ + "STEP_WITH": "with-value", + }, + } + env := map[string]string{} + + sm.On("getRunContext").Return(rc) + sm.On("getGithubContext").Return(rc) + sm.On("getStepModel").Return(step) + sm.On("getEnv").Return(&env) + + err := setupEnv(context.Background(), sm) + assert.Nil(t, err) + + // These are commit or system specific + delete((env), "GITHUB_REF") + delete((env), "GITHUB_REF_NAME") + delete((env), "GITHUB_REF_TYPE") + delete((env), "GITHUB_SHA") + delete((env), "GITHUB_WORKSPACE") + delete((env), "GITHUB_REPOSITORY") + delete((env), "GITHUB_REPOSITORY_OWNER") + delete((env), "GITHUB_ACTOR") + + assert.Equal(t, map[string]string{ + "ACT": "true", + "CI": "true", + "GITHUB_ACTION": "", + "GITHUB_ACTIONS": "true", + "GITHUB_ACTION_PATH": "", + "GITHUB_ACTION_REF": "", + "GITHUB_ACTION_REPOSITORY": "", + "GITHUB_API_URL": "https:///api/v3", + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "", + "GITHUB_EVENT_PATH": "/var/run/act/workflow/event.json", + "GITHUB_GRAPHQL_URL": "https:///api/graphql", + "GITHUB_HEAD_REF": "", + "GITHUB_JOB": "1", + "GITHUB_RETENTION_DAYS": "0", + "GITHUB_RUN_ID": "runId", + "GITHUB_RUN_NUMBER": "1", + "GITHUB_SERVER_URL": "https://", + "GITHUB_TOKEN": "", + "GITHUB_WORKFLOW": "", + "INPUT_STEP_WITH": "with-value", + "RC_KEY": "rcvalue", + "RUNNER_PERFLOG": "/dev/null", + "RUNNER_TRACKING_ID": "", + }, env) + + cm.AssertExpectations(t) +} + +func TestIsStepEnabled(t *testing.T) { + createTestStep := func(t *testing.T, input string) step { + var step *model.Step + err := yaml.Unmarshal([]byte(input), &step) + assert.NoError(t, err) + + return &stepRun{ + RunContext: &RunContext{ + Config: &Config{ + Workdir: ".", + Platforms: map[string]string{ + "ubuntu-latest": "ubuntu-latest", + }, + }, + StepResults: map[string]*model.StepResult{}, + Env: map[string]string{}, + Run: &model.Run{ + JobID: "job1", + Workflow: &model.Workflow{ + Name: "workflow1", + Jobs: map[string]*model.Job{ + "job1": createJob(t, `runs-on: ubuntu-latest`, ""), + }, + }, + }, + }, + Step: step, + } + } + + log.SetLevel(log.DebugLevel) + assertObject := assert.New(t) + + // success() + step := createTestStep(t, "if: success()") + assertObject.True(isStepEnabled(context.Background(), step.getIfExpression(context.Background(), stepStageMain), step, stepStageMain)) + + step = createTestStep(t, "if: success()") + step.getRunContext().StepResults["a"] = &model.StepResult{ + Conclusion: model.StepStatusSuccess, + } + assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + step = createTestStep(t, "if: success()") + step.getRunContext().StepResults["a"] = &model.StepResult{ + Conclusion: model.StepStatusFailure, + } + assertObject.False(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + // failure() + step = createTestStep(t, "if: failure()") + assertObject.False(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + step = createTestStep(t, "if: failure()") + step.getRunContext().StepResults["a"] = &model.StepResult{ + Conclusion: model.StepStatusSuccess, + } + assertObject.False(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + step = createTestStep(t, "if: failure()") + step.getRunContext().StepResults["a"] = &model.StepResult{ + Conclusion: model.StepStatusFailure, + } + assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + // always() + step = createTestStep(t, "if: always()") + assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + step = createTestStep(t, "if: always()") + step.getRunContext().StepResults["a"] = &model.StepResult{ + Conclusion: model.StepStatusSuccess, + } + assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) + + step = createTestStep(t, "if: always()") + step.getRunContext().StepResults["a"] = &model.StepResult{ + Conclusion: model.StepStatusFailure, + } + assertObject.True(isStepEnabled(context.Background(), step.getStepModel().If.Value, step, stepStageMain)) +} + +func TestIsContinueOnError(t *testing.T) { + createTestStep := func(t *testing.T, input string) step { + var step *model.Step + err := yaml.Unmarshal([]byte(input), &step) + assert.NoError(t, err) + + return &stepRun{ + RunContext: &RunContext{ + Config: &Config{ + Workdir: ".", + Platforms: map[string]string{ + "ubuntu-latest": "ubuntu-latest", + }, + }, + StepResults: map[string]*model.StepResult{}, + Env: map[string]string{}, + Run: &model.Run{ + JobID: "job1", + Workflow: &model.Workflow{ + Name: "workflow1", + Jobs: map[string]*model.Job{ + "job1": createJob(t, `runs-on: ubuntu-latest`, ""), + }, + }, + }, + }, + Step: step, + } + } + + log.SetLevel(log.DebugLevel) + assertObject := assert.New(t) + + // absent + step := createTestStep(t, "name: test") + continueOnError, err := isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) + assertObject.False(continueOnError) + assertObject.Nil(err) + + // explcit true + step = createTestStep(t, "continue-on-error: true") + continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) + assertObject.True(continueOnError) + assertObject.Nil(err) + + // explicit false + step = createTestStep(t, "continue-on-error: false") + continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) + assertObject.False(continueOnError) + assertObject.Nil(err) + + // expression true + step = createTestStep(t, "continue-on-error: ${{ 'test' == 'test' }}") + continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) + assertObject.True(continueOnError) + assertObject.Nil(err) + + // expression false + step = createTestStep(t, "continue-on-error: ${{ 'test' != 'test' }}") + continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) + assertObject.False(continueOnError) + assertObject.Nil(err) + + // expression parse error + step = createTestStep(t, "continue-on-error: ${{ 'test' != test }}") + continueOnError, err = isContinueOnError(context.Background(), step.getStepModel().RawContinueOnError, step, stepStageMain) + assertObject.False(continueOnError) + assertObject.NotNil(err) +} |