mirror of https://github.com/nektos/act
735 lines
22 KiB
Go
735 lines
22 KiB
Go
package runner
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/nektos/act/pkg/exprparser"
|
|
"github.com/nektos/act/pkg/model"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
assert "github.com/stretchr/testify/assert"
|
|
yaml "gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func TestRunContext_EvalBool(t *testing.T) {
|
|
var yml yaml.Node
|
|
err := yml.Encode(map[string][]interface{}{
|
|
"os": {"Linux", "Windows"},
|
|
"foo": {"bar", "baz"},
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
rc := &RunContext{
|
|
Config: &Config{
|
|
Workdir: ".",
|
|
},
|
|
Env: map[string]string{
|
|
"SOMETHING_TRUE": "true",
|
|
"SOMETHING_FALSE": "false",
|
|
"SOME_TEXT": "text",
|
|
},
|
|
Run: &model.Run{
|
|
JobID: "job1",
|
|
Workflow: &model.Workflow{
|
|
Name: "test-workflow",
|
|
Jobs: map[string]*model.Job{
|
|
"job1": {
|
|
Strategy: &model.Strategy{
|
|
RawMatrix: yml,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Matrix: map[string]interface{}{
|
|
"os": "Linux",
|
|
"foo": "bar",
|
|
},
|
|
StepResults: map[string]*model.StepResult{
|
|
"id1": {
|
|
Conclusion: model.StepStatusSuccess,
|
|
Outcome: model.StepStatusFailure,
|
|
Outputs: map[string]string{
|
|
"foo": "bar",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
rc.ExprEval = rc.NewExpressionEvaluator(context.Background())
|
|
|
|
tables := []struct {
|
|
in string
|
|
out bool
|
|
wantErr bool
|
|
}{
|
|
// The basic ones
|
|
{in: "failure()", out: false},
|
|
{in: "success()", out: true},
|
|
{in: "cancelled()", out: false},
|
|
{in: "always()", out: true},
|
|
// TODO: move to sc.NewExpressionEvaluator(), because "steps" context is not available here
|
|
// {in: "steps.id1.conclusion == 'success'", out: true},
|
|
// {in: "steps.id1.conclusion != 'success'", out: false},
|
|
// {in: "steps.id1.outcome == 'failure'", out: true},
|
|
// {in: "steps.id1.outcome != 'failure'", out: false},
|
|
{in: "true", out: true},
|
|
{in: "false", out: false},
|
|
// TODO: This does not throw an error, because the evaluator does not know if the expression is inside ${{ }} or not
|
|
// {in: "!true", wantErr: true},
|
|
// {in: "!false", wantErr: true},
|
|
{in: "1 != 0", out: true},
|
|
{in: "1 != 1", out: false},
|
|
{in: "${{ 1 != 0 }}", out: true},
|
|
{in: "${{ 1 != 1 }}", out: false},
|
|
{in: "1 == 0", out: false},
|
|
{in: "1 == 1", out: true},
|
|
{in: "1 > 2", out: false},
|
|
{in: "1 < 2", out: true},
|
|
// And or
|
|
{in: "true && false", out: false},
|
|
{in: "true && 1 < 2", out: true},
|
|
{in: "false || 1 < 2", out: true},
|
|
{in: "false || false", out: false},
|
|
// None boolable
|
|
{in: "env.UNKNOWN == 'true'", out: false},
|
|
{in: "env.UNKNOWN", out: false},
|
|
// Inline expressions
|
|
{in: "env.SOME_TEXT", out: true},
|
|
{in: "env.SOME_TEXT == 'text'", out: true},
|
|
{in: "env.SOMETHING_TRUE == 'true'", out: true},
|
|
{in: "env.SOMETHING_FALSE == 'true'", out: false},
|
|
{in: "env.SOMETHING_TRUE", out: true},
|
|
{in: "env.SOMETHING_FALSE", out: true},
|
|
// TODO: This does not throw an error, because the evaluator does not know if the expression is inside ${{ }} or not
|
|
// {in: "!env.SOMETHING_TRUE", wantErr: true},
|
|
// {in: "!env.SOMETHING_FALSE", wantErr: true},
|
|
{in: "${{ !env.SOMETHING_TRUE }}", out: false},
|
|
{in: "${{ !env.SOMETHING_FALSE }}", out: false},
|
|
{in: "${{ ! env.SOMETHING_TRUE }}", out: false},
|
|
{in: "${{ ! env.SOMETHING_FALSE }}", out: false},
|
|
{in: "${{ env.SOMETHING_TRUE }}", out: true},
|
|
{in: "${{ env.SOMETHING_FALSE }}", out: true},
|
|
{in: "${{ !env.SOMETHING_TRUE }}", out: false},
|
|
{in: "${{ !env.SOMETHING_FALSE }}", out: false},
|
|
{in: "${{ !env.SOMETHING_TRUE && true }}", out: false},
|
|
{in: "${{ !env.SOMETHING_FALSE && true }}", out: false},
|
|
{in: "${{ !env.SOMETHING_TRUE || true }}", out: true},
|
|
{in: "${{ !env.SOMETHING_FALSE || false }}", out: false},
|
|
{in: "${{ env.SOMETHING_TRUE && true }}", out: true},
|
|
{in: "${{ env.SOMETHING_FALSE || true }}", out: true},
|
|
{in: "${{ env.SOMETHING_FALSE || false }}", out: true},
|
|
// TODO: This does not throw an error, because the evaluator does not know if the expression is inside ${{ }} or not
|
|
// {in: "!env.SOMETHING_TRUE || true", wantErr: true},
|
|
{in: "${{ env.SOMETHING_TRUE == 'true'}}", out: true},
|
|
{in: "${{ env.SOMETHING_FALSE == 'true'}}", out: false},
|
|
{in: "${{ env.SOMETHING_FALSE == 'false'}}", out: true},
|
|
{in: "${{ env.SOMETHING_FALSE }} && ${{ env.SOMETHING_TRUE }}", out: true},
|
|
|
|
// All together now
|
|
{in: "false || env.SOMETHING_TRUE == 'true'", out: true},
|
|
{in: "true || env.SOMETHING_FALSE == 'true'", out: true},
|
|
{in: "true && env.SOMETHING_TRUE == 'true'", out: true},
|
|
{in: "false && env.SOMETHING_TRUE == 'true'", out: false},
|
|
{in: "env.SOMETHING_FALSE == 'true' && env.SOMETHING_TRUE == 'true'", out: false},
|
|
{in: "env.SOMETHING_FALSE == 'true' && true", out: false},
|
|
{in: "${{ env.SOMETHING_FALSE == 'true' }} && true", out: true},
|
|
{in: "true && ${{ env.SOMETHING_FALSE == 'true' }}", out: true},
|
|
// Check github context
|
|
{in: "github.actor == 'nektos/act'", out: true},
|
|
{in: "github.actor == 'unknown'", out: false},
|
|
{in: "github.job == 'job1'", out: true},
|
|
// The special ACT flag
|
|
{in: "${{ env.ACT }}", out: true},
|
|
{in: "${{ !env.ACT }}", out: false},
|
|
// Invalid expressions should be reported
|
|
{in: "INVALID_EXPRESSION", wantErr: true},
|
|
}
|
|
|
|
updateTestIfWorkflow(t, tables, rc)
|
|
for _, table := range tables {
|
|
table := table
|
|
t.Run(table.in, func(t *testing.T) {
|
|
assertObject := assert.New(t)
|
|
b, err := EvalBool(context.Background(), rc.ExprEval, table.in, exprparser.DefaultStatusCheckSuccess)
|
|
if table.wantErr {
|
|
assertObject.Error(err)
|
|
}
|
|
|
|
assertObject.Equal(table.out, b, fmt.Sprintf("Expected %s to be %v, was %v", table.in, table.out, b))
|
|
})
|
|
}
|
|
}
|
|
|
|
func updateTestIfWorkflow(t *testing.T, tables []struct {
|
|
in string
|
|
out bool
|
|
wantErr bool
|
|
}, rc *RunContext) {
|
|
var envs string
|
|
keys := make([]string, 0, len(rc.Env))
|
|
for k := range rc.Env {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, k := range keys {
|
|
envs += fmt.Sprintf(" %s: %s\n", k, rc.Env[k])
|
|
}
|
|
// editorconfig-checker-disable
|
|
workflow := fmt.Sprintf(`
|
|
name: "Test what expressions result in true and false on GitHub"
|
|
on: push
|
|
|
|
env:
|
|
%s
|
|
|
|
jobs:
|
|
test-ifs-and-buts:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
`, envs)
|
|
// editorconfig-checker-enable
|
|
|
|
for i, table := range tables {
|
|
if table.wantErr || strings.HasPrefix(table.in, "github.actor") {
|
|
continue
|
|
}
|
|
expressionPattern := regexp.MustCompile(`\${{\s*(.+?)\s*}}`)
|
|
|
|
expr := expressionPattern.ReplaceAllStringFunc(table.in, func(match string) string {
|
|
return fmt.Sprintf("€{{ %s }}", expressionPattern.ReplaceAllString(match, "$1"))
|
|
})
|
|
echo := fmt.Sprintf(`run: echo "%s should be false, but was evaluated to true;" exit 1;`, table.in)
|
|
name := fmt.Sprintf(`"❌ I should not run, expr: %s"`, expr)
|
|
if table.out {
|
|
echo = `run: echo OK`
|
|
name = fmt.Sprintf(`"✅ I should run, expr: %s"`, expr)
|
|
}
|
|
workflow += fmt.Sprintf("\n - name: %s\n id: step%d\n if: %s\n %s\n", name, i, table.in, echo)
|
|
if table.out {
|
|
workflow += fmt.Sprintf("\n - name: \"Double checking expr: %s\"\n if: steps.step%d.conclusion == 'skipped'\n run: echo \"%s should have been true, but wasn't\"\n", expr, i, table.in)
|
|
}
|
|
}
|
|
|
|
file, err := os.Create("../../.github/workflows/test-if.yml")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = file.WriteString(workflow)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestRunContext_GetBindsAndMounts(t *testing.T) {
|
|
rctemplate := &RunContext{
|
|
Name: "TestRCName",
|
|
Run: &model.Run{
|
|
Workflow: &model.Workflow{
|
|
Name: "TestWorkflowName",
|
|
},
|
|
},
|
|
Config: &Config{
|
|
BindWorkdir: false,
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
windowsPath bool
|
|
name string
|
|
rc *RunContext
|
|
wantbind string
|
|
wantmount string
|
|
}{
|
|
{false, "/mnt/linux", rctemplate, "/mnt/linux", "/mnt/linux"},
|
|
{false, "/mnt/path with spaces/linux", rctemplate, "/mnt/path with spaces/linux", "/mnt/path with spaces/linux"},
|
|
{true, "C:\\Users\\TestPath\\MyTestPath", rctemplate, "/mnt/c/Users/TestPath/MyTestPath", "/mnt/c/Users/TestPath/MyTestPath"},
|
|
{true, "C:\\Users\\Test Path with Spaces\\MyTestPath", rctemplate, "/mnt/c/Users/Test Path with Spaces/MyTestPath", "/mnt/c/Users/Test Path with Spaces/MyTestPath"},
|
|
{true, "/LinuxPathOnWindowsShouldFail", rctemplate, "", ""},
|
|
}
|
|
|
|
isWindows := runtime.GOOS == "windows"
|
|
|
|
for _, testcase := range tests {
|
|
// pin for scopelint
|
|
testcase := testcase
|
|
for _, bindWorkDir := range []bool{true, false} {
|
|
// pin for scopelint
|
|
bindWorkDir := bindWorkDir
|
|
testBindSuffix := ""
|
|
if bindWorkDir {
|
|
testBindSuffix = "Bind"
|
|
}
|
|
|
|
// Only run windows path tests on windows and non-windows on non-windows
|
|
if (isWindows && testcase.windowsPath) || (!isWindows && !testcase.windowsPath) {
|
|
t.Run((testcase.name + testBindSuffix), func(t *testing.T) {
|
|
config := testcase.rc.Config
|
|
config.Workdir = testcase.name
|
|
config.BindWorkdir = bindWorkDir
|
|
gotbind, gotmount := rctemplate.GetBindsAndMounts()
|
|
|
|
// Name binds/mounts are either/or
|
|
if config.BindWorkdir {
|
|
fullBind := testcase.name + ":" + testcase.wantbind
|
|
if runtime.GOOS == "darwin" {
|
|
fullBind += ":delegated"
|
|
}
|
|
assert.Contains(t, gotbind, fullBind)
|
|
} else {
|
|
mountkey := testcase.rc.jobContainerName()
|
|
assert.EqualValues(t, testcase.wantmount, gotmount[mountkey])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
t.Run("ContainerVolumeMountTest", func(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
volumes []string
|
|
wantbind string
|
|
wantmount map[string]string
|
|
}{
|
|
{"BindAnonymousVolume", []string{"/volume"}, "/volume", map[string]string{}},
|
|
{"BindHostFile", []string{"/path/to/file/on/host:/volume"}, "/path/to/file/on/host:/volume", map[string]string{}},
|
|
{"MountExistingVolume", []string{"volume-id:/volume"}, "", map[string]string{"volume-id": "/volume"}},
|
|
}
|
|
|
|
for _, testcase := range tests {
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
job := &model.Job{}
|
|
err := job.RawContainer.Encode(map[string][]string{
|
|
"volumes": testcase.volumes,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
rc := &RunContext{
|
|
Name: "TestRCName",
|
|
Run: &model.Run{
|
|
Workflow: &model.Workflow{
|
|
Name: "TestWorkflowName",
|
|
},
|
|
},
|
|
Config: &Config{
|
|
BindWorkdir: false,
|
|
},
|
|
}
|
|
rc.Run.JobID = "job1"
|
|
rc.Run.Workflow.Jobs = map[string]*model.Job{"job1": job}
|
|
|
|
gotbind, gotmount := rc.GetBindsAndMounts()
|
|
|
|
if len(testcase.wantbind) > 0 {
|
|
assert.Contains(t, gotbind, testcase.wantbind)
|
|
}
|
|
|
|
for k, v := range testcase.wantmount {
|
|
assert.Contains(t, gotmount, k)
|
|
assert.Equal(t, gotmount[k], v)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetGitHubContext(t *testing.T) {
|
|
log.SetLevel(log.DebugLevel)
|
|
|
|
cwd, err := os.Getwd()
|
|
assert.Nil(t, err)
|
|
|
|
rc := &RunContext{
|
|
Config: &Config{
|
|
EventName: "push",
|
|
Workdir: cwd,
|
|
},
|
|
Run: &model.Run{
|
|
Workflow: &model.Workflow{
|
|
Name: "GitHubContextTest",
|
|
},
|
|
},
|
|
Name: "GitHubContextTest",
|
|
CurrentStep: "step",
|
|
Matrix: map[string]interface{}{},
|
|
Env: map[string]string{},
|
|
ExtraPath: []string{},
|
|
StepResults: map[string]*model.StepResult{},
|
|
OutputMappings: map[MappableOutput]MappableOutput{},
|
|
}
|
|
rc.Run.JobID = "job1"
|
|
|
|
ghc := rc.getGithubContext(context.Background())
|
|
|
|
log.Debugf("%v", ghc)
|
|
|
|
actor := "nektos/act"
|
|
if a := os.Getenv("ACT_ACTOR"); a != "" {
|
|
actor = a
|
|
}
|
|
|
|
repo := "nektos/act"
|
|
if r := os.Getenv("ACT_REPOSITORY"); r != "" {
|
|
repo = r
|
|
}
|
|
|
|
owner := "nektos"
|
|
if o := os.Getenv("ACT_OWNER"); o != "" {
|
|
owner = o
|
|
}
|
|
|
|
assert.Equal(t, ghc.RunID, "1")
|
|
assert.Equal(t, ghc.RunNumber, "1")
|
|
assert.Equal(t, ghc.RetentionDays, "0")
|
|
assert.Equal(t, ghc.Actor, actor)
|
|
assert.Equal(t, ghc.Repository, repo)
|
|
assert.Equal(t, ghc.RepositoryOwner, owner)
|
|
assert.Equal(t, ghc.RunnerPerflog, "/dev/null")
|
|
assert.Equal(t, ghc.Token, rc.Config.Secrets["GITHUB_TOKEN"])
|
|
assert.Equal(t, ghc.Job, "job1")
|
|
}
|
|
|
|
func TestGetGithubContextRef(t *testing.T) {
|
|
table := []struct {
|
|
event string
|
|
json string
|
|
ref string
|
|
}{
|
|
{event: "push", json: `{"ref":"0000000000000000000000000000000000000000"}`, ref: "0000000000000000000000000000000000000000"},
|
|
{event: "create", json: `{"ref":"0000000000000000000000000000000000000000"}`, ref: "0000000000000000000000000000000000000000"},
|
|
{event: "workflow_dispatch", json: `{"ref":"0000000000000000000000000000000000000000"}`, ref: "0000000000000000000000000000000000000000"},
|
|
{event: "delete", json: `{"repository":{"default_branch": "main"}}`, ref: "refs/heads/main"},
|
|
{event: "pull_request", json: `{"number":123}`, ref: "refs/pull/123/merge"},
|
|
{event: "pull_request_review", json: `{"number":123}`, ref: "refs/pull/123/merge"},
|
|
{event: "pull_request_review_comment", json: `{"number":123}`, ref: "refs/pull/123/merge"},
|
|
{event: "pull_request_target", json: `{"pull_request":{"base":{"ref": "main"}}}`, ref: "refs/heads/main"},
|
|
{event: "deployment", json: `{"deployment": {"ref": "tag-name"}}`, ref: "tag-name"},
|
|
{event: "deployment_status", json: `{"deployment": {"ref": "tag-name"}}`, ref: "tag-name"},
|
|
{event: "release", json: `{"release": {"tag_name": "tag-name"}}`, ref: "refs/tags/tag-name"},
|
|
}
|
|
|
|
for _, data := range table {
|
|
data := data
|
|
t.Run(data.event, func(t *testing.T) {
|
|
rc := &RunContext{
|
|
EventJSON: data.json,
|
|
Config: &Config{
|
|
EventName: data.event,
|
|
Workdir: "",
|
|
},
|
|
Run: &model.Run{
|
|
Workflow: &model.Workflow{
|
|
Name: "GitHubContextTest",
|
|
},
|
|
},
|
|
}
|
|
|
|
ghc := rc.getGithubContext(context.Background())
|
|
|
|
assert.Equal(t, data.ref, ghc.Ref)
|
|
})
|
|
}
|
|
}
|
|
|
|
func createIfTestRunContext(jobs map[string]*model.Job) *RunContext {
|
|
rc := &RunContext{
|
|
Config: &Config{
|
|
Workdir: ".",
|
|
Platforms: map[string]string{
|
|
"ubuntu-latest": "ubuntu-latest",
|
|
},
|
|
},
|
|
Env: map[string]string{},
|
|
Run: &model.Run{
|
|
JobID: "job1",
|
|
Workflow: &model.Workflow{
|
|
Name: "test-workflow",
|
|
Jobs: jobs,
|
|
},
|
|
},
|
|
}
|
|
rc.ExprEval = rc.NewExpressionEvaluator(context.Background())
|
|
|
|
return rc
|
|
}
|
|
|
|
func createJob(t *testing.T, input string, result string) *model.Job {
|
|
var job *model.Job
|
|
err := yaml.Unmarshal([]byte(input), &job)
|
|
assert.NoError(t, err)
|
|
job.Result = result
|
|
|
|
return job
|
|
}
|
|
|
|
func TestRunContextRunsOnPlatformNames(t *testing.T) {
|
|
log.SetLevel(log.DebugLevel)
|
|
assertObject := assert.New(t)
|
|
|
|
rc := createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, ""),
|
|
})
|
|
assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ${{ 'ubuntu-latest' }}`, ""),
|
|
})
|
|
assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: [self-hosted, my-runner]`, ""),
|
|
})
|
|
assertObject.Equal([]string{"self-hosted", "my-runner"}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: [self-hosted, "${{ 'my-runner' }}"]`, ""),
|
|
})
|
|
assertObject.Equal([]string{"self-hosted", "my-runner"}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ${{ fromJSON('["ubuntu-latest"]') }}`, ""),
|
|
})
|
|
assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
// test missing / invalid runs-on
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `name: something`, ""),
|
|
})
|
|
assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on:
|
|
mapping: value`, ""),
|
|
})
|
|
assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ${{ invalid expression }}`, ""),
|
|
})
|
|
assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background()))
|
|
}
|
|
|
|
func TestRunContextIsEnabled(t *testing.T) {
|
|
log.SetLevel(log.DebugLevel)
|
|
assertObject := assert.New(t)
|
|
|
|
// success()
|
|
rc := createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest
|
|
if: success()`, ""),
|
|
})
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "failure"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
needs: [job1]
|
|
if: success()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.False(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "success"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
needs: [job1]
|
|
if: success()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "failure"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
if: success()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
// failure()
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest
|
|
if: failure()`, ""),
|
|
})
|
|
assertObject.False(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "failure"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
needs: [job1]
|
|
if: failure()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "success"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
needs: [job1]
|
|
if: failure()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.False(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "failure"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
if: failure()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.False(rc.isEnabled(context.Background()))
|
|
|
|
// always()
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest
|
|
if: always()`, ""),
|
|
})
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "failure"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
needs: [job1]
|
|
if: always()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "success"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
needs: [job1]
|
|
if: always()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `runs-on: ubuntu-latest`, "success"),
|
|
"job2": createJob(t, `runs-on: ubuntu-latest
|
|
if: always()`, ""),
|
|
})
|
|
rc.Run.JobID = "job2"
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `uses: ./.github/workflows/reusable.yml`, ""),
|
|
})
|
|
assertObject.True(rc.isEnabled(context.Background()))
|
|
|
|
rc = createIfTestRunContext(map[string]*model.Job{
|
|
"job1": createJob(t, `uses: ./.github/workflows/reusable.yml
|
|
if: false`, ""),
|
|
})
|
|
assertObject.False(rc.isEnabled(context.Background()))
|
|
}
|
|
|
|
func TestRunContextGetEnv(t *testing.T) {
|
|
tests := []struct {
|
|
description string
|
|
rc *RunContext
|
|
targetEnv string
|
|
want string
|
|
}{
|
|
{
|
|
description: "Env from Config should overwrite",
|
|
rc: &RunContext{
|
|
Config: &Config{
|
|
Env: map[string]string{"OVERWRITTEN": "true"},
|
|
},
|
|
Run: &model.Run{
|
|
Workflow: &model.Workflow{
|
|
Jobs: map[string]*model.Job{"test": {Name: "test"}},
|
|
Env: map[string]string{"OVERWRITTEN": "false"},
|
|
},
|
|
JobID: "test",
|
|
},
|
|
},
|
|
targetEnv: "OVERWRITTEN",
|
|
want: "true",
|
|
},
|
|
{
|
|
description: "No overwrite occurs",
|
|
rc: &RunContext{
|
|
Config: &Config{
|
|
Env: map[string]string{"SOME_OTHER_VAR": "true"},
|
|
},
|
|
Run: &model.Run{
|
|
Workflow: &model.Workflow{
|
|
Jobs: map[string]*model.Job{"test": {Name: "test"}},
|
|
Env: map[string]string{"OVERWRITTEN": "false"},
|
|
},
|
|
JobID: "test",
|
|
},
|
|
},
|
|
targetEnv: "OVERWRITTEN",
|
|
want: "false",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.description, func(t *testing.T) {
|
|
envMap := test.rc.GetEnv()
|
|
assert.EqualValues(t, test.want, envMap[test.targetEnv])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSetRuntimeVariables(t *testing.T) {
|
|
rc := &RunContext{
|
|
Config: &Config{
|
|
ArtifactServerAddr: "myhost",
|
|
ArtifactServerPort: "8000",
|
|
},
|
|
}
|
|
v := "http://myhost:8000/"
|
|
env := map[string]string{}
|
|
setActionRuntimeVars(rc, env)
|
|
|
|
assert.Equal(t, v, env["ACTIONS_RESULTS_URL"])
|
|
assert.Equal(t, v, env["ACTIONS_RUNTIME_URL"])
|
|
runtimeToken := env["ACTIONS_RUNTIME_TOKEN"]
|
|
assert.NotEmpty(t, v, runtimeToken)
|
|
|
|
tkn, _, err := jwt.NewParser().ParseUnverified(runtimeToken, jwt.MapClaims{})
|
|
assert.NotNil(t, tkn)
|
|
assert.Nil(t, err)
|
|
}
|
|
|
|
func TestSetRuntimeVariablesWithRunID(t *testing.T) {
|
|
rc := &RunContext{
|
|
Config: &Config{
|
|
ArtifactServerAddr: "myhost",
|
|
ArtifactServerPort: "8000",
|
|
Env: map[string]string{
|
|
"GITHUB_RUN_ID": "45",
|
|
},
|
|
},
|
|
}
|
|
v := "http://myhost:8000/"
|
|
env := map[string]string{}
|
|
setActionRuntimeVars(rc, env)
|
|
|
|
assert.Equal(t, v, env["ACTIONS_RESULTS_URL"])
|
|
assert.Equal(t, v, env["ACTIONS_RUNTIME_URL"])
|
|
runtimeToken := env["ACTIONS_RUNTIME_TOKEN"]
|
|
assert.NotEmpty(t, v, runtimeToken)
|
|
|
|
claims := jwt.MapClaims{}
|
|
tkn, _, err := jwt.NewParser().ParseUnverified(runtimeToken, &claims)
|
|
assert.NotNil(t, tkn)
|
|
assert.Nil(t, err)
|
|
scp, ok := claims["scp"]
|
|
assert.True(t, ok, "scp claim exists")
|
|
assert.Equal(t, "Actions.Results:45:45", scp, "contains expected scp claim")
|
|
}
|