2022-02-09 04:17:59 +08:00
|
|
|
package runner
|
|
|
|
|
|
|
|
import (
|
2022-03-23 05:13:00 +08:00
|
|
|
"context"
|
2022-02-09 04:17:59 +08:00
|
|
|
"io"
|
|
|
|
"io/fs"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/nektos/act/pkg/model"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
|
|
)
|
|
|
|
|
|
|
|
type closerMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *closerMock) Close() error {
|
|
|
|
m.Called()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestActionReader(t *testing.T) {
|
|
|
|
yaml := strings.ReplaceAll(`
|
|
|
|
name: 'name'
|
|
|
|
runs:
|
2022-05-12 03:06:05 +08:00
|
|
|
using: 'node16'
|
|
|
|
main: 'main.js'
|
2022-02-09 04:17:59 +08:00
|
|
|
`, "\t", " ")
|
|
|
|
|
|
|
|
table := []struct {
|
|
|
|
name string
|
|
|
|
step *model.Step
|
|
|
|
filename string
|
|
|
|
fileContent string
|
|
|
|
expected *model.Action
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "readActionYml",
|
|
|
|
step: &model.Step{},
|
|
|
|
filename: "action.yml",
|
|
|
|
fileContent: yaml,
|
|
|
|
expected: &model.Action{
|
|
|
|
Name: "name",
|
|
|
|
Runs: model.ActionRuns{
|
2022-05-24 21:36:06 +08:00
|
|
|
Using: "node16",
|
|
|
|
Main: "main.js",
|
|
|
|
PreIf: "always()",
|
|
|
|
PostIf: "always()",
|
2022-02-09 04:17:59 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "readActionYaml",
|
|
|
|
step: &model.Step{},
|
|
|
|
filename: "action.yaml",
|
|
|
|
fileContent: yaml,
|
|
|
|
expected: &model.Action{
|
|
|
|
Name: "name",
|
|
|
|
Runs: model.ActionRuns{
|
2022-05-24 21:36:06 +08:00
|
|
|
Using: "node16",
|
|
|
|
Main: "main.js",
|
|
|
|
PreIf: "always()",
|
|
|
|
PostIf: "always()",
|
2022-02-09 04:17:59 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "readDockerfile",
|
|
|
|
step: &model.Step{},
|
|
|
|
filename: "Dockerfile",
|
|
|
|
fileContent: "FROM ubuntu:20.04",
|
|
|
|
expected: &model.Action{
|
|
|
|
Name: "(Synthetic)",
|
|
|
|
Runs: model.ActionRuns{
|
|
|
|
Using: "docker",
|
|
|
|
Image: "Dockerfile",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "readWithArgs",
|
|
|
|
step: &model.Step{
|
|
|
|
With: map[string]string{
|
|
|
|
"args": "cmd",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: &model.Action{
|
|
|
|
Name: "(Synthetic)",
|
|
|
|
Inputs: map[string]model.Input{
|
|
|
|
"cwd": {
|
|
|
|
Description: "(Actual working directory)",
|
|
|
|
Required: false,
|
|
|
|
Default: "actionDir/actionPath",
|
|
|
|
},
|
|
|
|
"command": {
|
|
|
|
Description: "(Actual program)",
|
|
|
|
Required: false,
|
|
|
|
Default: "cmd",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Runs: model.ActionRuns{
|
|
|
|
Using: "node12",
|
|
|
|
Main: "trampoline.js",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range table {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
closerMock := &closerMock{}
|
|
|
|
|
|
|
|
readFile := func(filename string) (io.Reader, io.Closer, error) {
|
|
|
|
if tt.filename != filename {
|
|
|
|
return nil, nil, fs.ErrNotExist
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.NewReader(tt.fileContent), closerMock, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
writeFile := func(filename string, data []byte, perm fs.FileMode) error {
|
|
|
|
assert.Equal(t, "actionDir/actionPath/trampoline.js", filename)
|
|
|
|
assert.Equal(t, fs.FileMode(0400), perm)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-23 05:13:00 +08:00
|
|
|
if tt.filename != "" {
|
|
|
|
closerMock.On("Close")
|
|
|
|
}
|
2022-02-09 04:17:59 +08:00
|
|
|
|
2022-06-17 23:55:21 +08:00
|
|
|
action, err := readActionImpl(context.Background(), tt.step, "actionDir", "actionPath", readFile, writeFile)
|
2022-02-09 04:17:59 +08:00
|
|
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, tt.expected, action)
|
2022-03-23 05:13:00 +08:00
|
|
|
|
|
|
|
closerMock.AssertExpectations(t)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestActionRunner(t *testing.T) {
|
|
|
|
table := []struct {
|
2022-05-24 21:36:06 +08:00
|
|
|
name string
|
|
|
|
step actionStep
|
|
|
|
expectedEnv map[string]string
|
2022-03-23 05:13:00 +08:00
|
|
|
}{
|
|
|
|
{
|
2022-05-24 21:36:06 +08:00
|
|
|
name: "with-input",
|
2022-03-23 05:13:00 +08:00
|
|
|
step: &stepActionRemote{
|
|
|
|
Step: &model.Step{
|
2022-05-24 21:36:06 +08:00
|
|
|
Uses: "org/repo/path@ref",
|
2022-03-23 05:13:00 +08:00
|
|
|
},
|
|
|
|
RunContext: &RunContext{
|
2022-05-12 03:06:05 +08:00
|
|
|
Config: &Config{},
|
2022-03-23 05:13:00 +08:00
|
|
|
Run: &model.Run{
|
|
|
|
JobID: "job",
|
|
|
|
Workflow: &model.Workflow{
|
|
|
|
Jobs: map[string]*model.Job{
|
|
|
|
"job": {
|
|
|
|
Name: "job",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
action: &model.Action{
|
|
|
|
Inputs: map[string]model.Input{
|
|
|
|
"key": {
|
|
|
|
Default: "default value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Runs: model.ActionRuns{
|
|
|
|
Using: "node16",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
env: map[string]string{},
|
|
|
|
},
|
2022-05-24 21:36:06 +08:00
|
|
|
expectedEnv: map[string]string{"INPUT_KEY": "default value"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "restore-saved-state",
|
|
|
|
step: &stepActionRemote{
|
|
|
|
Step: &model.Step{
|
|
|
|
ID: "step",
|
|
|
|
Uses: "org/repo/path@ref",
|
|
|
|
},
|
|
|
|
RunContext: &RunContext{
|
2022-10-07 05:58:16 +08:00
|
|
|
ActionPath: "path",
|
|
|
|
Config: &Config{},
|
2022-05-24 21:36:06 +08:00
|
|
|
Run: &model.Run{
|
|
|
|
JobID: "job",
|
|
|
|
Workflow: &model.Workflow{
|
|
|
|
Jobs: map[string]*model.Job{
|
|
|
|
"job": {
|
|
|
|
Name: "job",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
CurrentStep: "post-step",
|
|
|
|
StepResults: map[string]*model.StepResult{
|
2022-12-16 01:08:31 +08:00
|
|
|
"step": {},
|
|
|
|
},
|
|
|
|
IntraActionState: map[string]map[string]string{
|
2022-05-24 21:36:06 +08:00
|
|
|
"step": {
|
2022-12-16 01:08:31 +08:00
|
|
|
"name": "state value",
|
2022-05-24 21:36:06 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
action: &model.Action{
|
|
|
|
Runs: model.ActionRuns{
|
|
|
|
Using: "node16",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
env: map[string]string{},
|
|
|
|
},
|
|
|
|
expectedEnv: map[string]string{"STATE_name": "state value"},
|
2022-03-23 05:13:00 +08:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range table {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
cm := &containerMock{}
|
|
|
|
cm.On("CopyDir", "/var/run/act/actions/dir/", "dir/", false).Return(func(ctx context.Context) error { return nil })
|
|
|
|
|
2022-05-12 03:06:05 +08:00
|
|
|
envMatcher := mock.MatchedBy(func(env map[string]string) bool {
|
2022-05-24 21:36:06 +08:00
|
|
|
for k, v := range tt.expectedEnv {
|
|
|
|
if env[k] != v {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
2022-05-12 03:06:05 +08:00
|
|
|
})
|
2022-05-24 21:36:06 +08:00
|
|
|
|
2022-05-12 03:06:05 +08:00
|
|
|
cm.On("Exec", []string{"node", "/var/run/act/actions/dir/path"}, envMatcher, "", "").Return(func(ctx context.Context) error { return nil })
|
|
|
|
|
|
|
|
tt.step.getRunContext().JobContainer = cm
|
2022-03-23 05:13:00 +08:00
|
|
|
|
2022-03-30 01:42:11 +08:00
|
|
|
err := runActionImpl(tt.step, "dir", newRemoteAction("org/repo/path@ref"))(ctx)
|
2022-03-23 05:13:00 +08:00
|
|
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
cm.AssertExpectations(t)
|
2022-02-09 04:17:59 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|