9884da0122
* fix: environment handling windows (host mode) * fixup * fixup * add more tests * fixup * fix setenv * fixes * [skip ci] Apply suggestions from code review Co-authored-by: Jason Song <i@wolfogre.com> * Update side effects --------- Co-authored-by: Jason Song <i@wolfogre.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
346 lines
9.4 KiB
Go
346 lines
9.4 KiB
Go
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)
|
|
}
|