2022-02-08 11:22:41 -06:00
package runner
import (
"context"
"fmt"
2022-06-17 10:55:21 -05:00
"io"
2022-02-08 11:22:41 -06:00
"testing"
"github.com/nektos/act/pkg/common"
2022-06-17 10:55:21 -05:00
"github.com/nektos/act/pkg/container"
2022-02-08 11:22:41 -06:00
"github.com/nektos/act/pkg/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
2022-03-22 16:13:00 -05:00
func TestJobExecutor ( t * testing . T ) {
tables := [ ] TestJobFileInfo {
2022-12-15 10:45:22 -06:00
{ workdir , "uses-and-run-in-one-step" , "push" , "Invalid run/uses syntax for job:test step:Test" , platforms , secrets } ,
{ workdir , "uses-github-empty" , "push" , "Expected format {org}/{repo}[/path]@ref" , platforms , secrets } ,
{ workdir , "uses-github-noref" , "push" , "Expected format {org}/{repo}[/path]@ref" , platforms , secrets } ,
{ workdir , "uses-github-root" , "push" , "" , platforms , secrets } ,
{ workdir , "uses-github-path" , "push" , "" , platforms , secrets } ,
{ workdir , "uses-docker-url" , "push" , "" , platforms , secrets } ,
{ workdir , "uses-github-full-sha" , "push" , "" , platforms , secrets } ,
{ workdir , "uses-github-short-sha" , "push" , "Unable to resolve action `actions/hello-world-docker-action@b136eb8`, the provided ref `b136eb8` is the shortened version of a commit SHA, which is not supported. Please use the full commit SHA `b136eb8894c5cb1dd5807da824be97ccdf9b5423` instead" , platforms , secrets } ,
{ workdir , "job-nil-step" , "push" , "invalid Step 0: missing run or uses key" , platforms , secrets } ,
2022-03-22 16:13:00 -05:00
}
// These tests are sufficient to only check syntax.
ctx := common . WithDryrun ( context . Background ( ) , true )
for _ , table := range tables {
2022-04-19 14:35:42 -05:00
t . Run ( table . workflowPath , func ( t * testing . T ) {
table . runTest ( ctx , t , & Config { } )
} )
2022-03-22 16:13:00 -05:00
}
}
2022-02-08 11:22:41 -06:00
type jobInfoMock struct {
mock . Mock
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) matrix ( ) map [ string ] interface { } {
args := jim . Called ( )
2022-02-08 11:22:41 -06:00
return args . Get ( 0 ) . ( map [ string ] interface { } )
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) steps ( ) [ ] * model . Step {
args := jim . Called ( )
2022-02-08 11:22:41 -06:00
return args . Get ( 0 ) . ( [ ] * model . Step )
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) startContainer ( ) common . Executor {
args := jim . Called ( )
2022-02-08 11:22:41 -06:00
return args . Get ( 0 ) . ( func ( context . Context ) error )
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) stopContainer ( ) common . Executor {
args := jim . Called ( )
2022-02-08 11:22:41 -06:00
return args . Get ( 0 ) . ( func ( context . Context ) error )
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) closeContainer ( ) common . Executor {
args := jim . Called ( )
2022-02-08 11:22:41 -06:00
return args . Get ( 0 ) . ( func ( context . Context ) error )
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) interpolateOutputs ( ) common . Executor {
args := jim . Called ( )
2022-02-08 11:22:41 -06:00
return args . Get ( 0 ) . ( func ( context . Context ) error )
}
2022-03-22 16:13:00 -05:00
func ( jim * jobInfoMock ) result ( result string ) {
jim . Called ( result )
}
2022-02-08 11:22:41 -06:00
2022-06-17 10:55:21 -05:00
type jobContainerMock struct {
container . Container
2022-11-16 15:29:45 -06:00
container . LinuxContainerEnvironmentExtensions
2022-06-17 10:55:21 -05:00
}
func ( jcm * jobContainerMock ) ReplaceLogWriter ( stdout , stderr io . Writer ) ( io . Writer , io . Writer ) {
return nil , nil
}
2022-03-22 16:13:00 -05:00
type stepFactoryMock struct {
mock . Mock
2022-02-08 11:22:41 -06:00
}
2022-03-22 16:13:00 -05:00
func ( sfm * stepFactoryMock ) newStep ( model * model . Step , rc * RunContext ) ( step , error ) {
args := sfm . Called ( model , rc )
return args . Get ( 0 ) . ( step ) , args . Error ( 1 )
2022-02-08 11:22:41 -06:00
}
func TestNewJobExecutor ( t * testing . T ) {
table := [ ] struct {
2022-02-10 10:54:58 -06:00
name string
steps [ ] * model . Step
2022-03-22 16:13:00 -05:00
preSteps [ ] bool
postSteps [ ] bool
2022-02-10 10:54:58 -06:00
executedSteps [ ] string
result string
hasError bool
2022-02-08 11:22:41 -06:00
} {
{
2022-03-22 16:13:00 -05:00
name : "zeroSteps" ,
steps : [ ] * model . Step { } ,
preSteps : [ ] bool { } ,
postSteps : [ ] bool { } ,
executedSteps : [ ] string { } ,
result : "success" ,
hasError : false ,
} ,
{
name : "stepWithoutPrePost" ,
steps : [ ] * model . Step { {
ID : "1" ,
} } ,
preSteps : [ ] bool { false } ,
postSteps : [ ] bool { false } ,
2022-02-10 10:54:58 -06:00
executedSteps : [ ] string {
"startContainer" ,
2022-03-22 16:13:00 -05:00
"step1" ,
2022-02-10 10:54:58 -06:00
"stopContainer" ,
"interpolateOutputs" ,
"closeContainer" ,
} ,
result : "success" ,
hasError : false ,
2022-02-08 11:22:41 -06:00
} ,
{
2022-03-22 16:13:00 -05:00
name : "stepWithFailure" ,
2022-02-10 10:54:58 -06:00
steps : [ ] * model . Step { {
2022-02-08 11:22:41 -06:00
ID : "1" ,
} } ,
2022-03-22 16:13:00 -05:00
preSteps : [ ] bool { false } ,
postSteps : [ ] bool { false } ,
2022-02-10 10:54:58 -06:00
executedSteps : [ ] string {
"startContainer" ,
"step1" ,
2022-03-22 16:13:00 -05:00
"interpolateOutputs" ,
"closeContainer" ,
} ,
result : "failure" ,
hasError : true ,
} ,
{
name : "stepWithPre" ,
steps : [ ] * model . Step { {
ID : "1" ,
} } ,
preSteps : [ ] bool { true } ,
postSteps : [ ] bool { false } ,
executedSteps : [ ] string {
"startContainer" ,
"pre1" ,
"step1" ,
2022-02-10 10:54:58 -06:00
"stopContainer" ,
"interpolateOutputs" ,
"closeContainer" ,
} ,
result : "success" ,
hasError : false ,
2022-02-08 11:22:41 -06:00
} ,
{
2022-03-22 16:13:00 -05:00
name : "stepWithPost" ,
2022-02-10 10:54:58 -06:00
steps : [ ] * model . Step { {
2022-02-08 11:22:41 -06:00
ID : "1" ,
} } ,
2022-03-22 16:13:00 -05:00
preSteps : [ ] bool { false } ,
postSteps : [ ] bool { true } ,
2022-02-10 10:54:58 -06:00
executedSteps : [ ] string {
"startContainer" ,
"step1" ,
2022-03-22 16:13:00 -05:00
"post1" ,
"stopContainer" ,
2022-02-10 10:54:58 -06:00
"interpolateOutputs" ,
"closeContainer" ,
} ,
2022-03-22 16:13:00 -05:00
result : "success" ,
hasError : false ,
2022-02-10 10:54:58 -06:00
} ,
{
2022-03-22 16:13:00 -05:00
name : "stepWithPreAndPost" ,
steps : [ ] * model . Step { {
ID : "1" ,
} } ,
preSteps : [ ] bool { true } ,
postSteps : [ ] bool { true } ,
executedSteps : [ ] string {
"startContainer" ,
"pre1" ,
"step1" ,
"post1" ,
"stopContainer" ,
"interpolateOutputs" ,
"closeContainer" ,
} ,
result : "success" ,
hasError : false ,
} ,
{
name : "stepsWithPreAndPost" ,
2022-02-10 10:54:58 -06:00
steps : [ ] * model . Step { {
ID : "1" ,
} , {
ID : "2" ,
2022-03-22 16:13:00 -05:00
} , {
ID : "3" ,
2022-02-10 10:54:58 -06:00
} } ,
2022-03-22 16:13:00 -05:00
preSteps : [ ] bool { true , false , true } ,
postSteps : [ ] bool { false , true , true } ,
2022-02-10 10:54:58 -06:00
executedSteps : [ ] string {
"startContainer" ,
2022-03-22 16:13:00 -05:00
"pre1" ,
"pre3" ,
2022-02-10 10:54:58 -06:00
"step1" ,
"step2" ,
2022-03-22 16:13:00 -05:00
"step3" ,
"post3" ,
"post2" ,
2022-02-10 10:54:58 -06:00
"stopContainer" ,
"interpolateOutputs" ,
"closeContainer" ,
} ,
result : "success" ,
hasError : false ,
2022-02-08 11:22:41 -06:00
} ,
}
2022-03-22 16:13:00 -05:00
contains := func ( needle string , haystack [ ] string ) bool {
for _ , item := range haystack {
if item == needle {
return true
}
}
return false
}
2022-02-08 11:22:41 -06:00
for _ , tt := range table {
t . Run ( tt . name , func ( t * testing . T ) {
2022-04-20 13:34:27 -05:00
fmt . Printf ( "::group::%s\n" , tt . name )
2022-02-08 11:22:41 -06:00
ctx := common . WithJobErrorContainer ( context . Background ( ) )
2022-03-22 16:13:00 -05:00
jim := & jobInfoMock { }
sfm := & stepFactoryMock { }
2022-06-17 10:55:21 -05:00
rc := & RunContext {
JobContainer : & jobContainerMock { } ,
2022-11-16 15:55:23 -06:00
Run : & model . Run {
JobID : "test" ,
Workflow : & model . Workflow {
Jobs : map [ string ] * model . Job {
"test" : { } ,
} ,
} ,
} ,
Config : & Config { } ,
2022-06-17 10:55:21 -05:00
}
2022-11-16 15:55:23 -06:00
rc . ExprEval = rc . NewExpressionEvaluator ( ctx )
2022-02-10 10:54:58 -06:00
executorOrder := make ( [ ] string , 0 )
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
jim . On ( "steps" ) . Return ( tt . steps )
if len ( tt . steps ) > 0 {
jim . On ( "startContainer" ) . Return ( func ( ctx context . Context ) error {
executorOrder = append ( executorOrder , "startContainer" )
return nil
} )
}
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
for i , stepModel := range tt . steps {
i := i
stepModel := stepModel
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
sm := & stepMock { }
sfm . On ( "newStep" , stepModel , rc ) . Return ( sm , nil )
sm . On ( "pre" ) . Return ( func ( ctx context . Context ) error {
if tt . preSteps [ i ] {
executorOrder = append ( executorOrder , "pre" + stepModel . ID )
}
return nil
} )
sm . On ( "main" ) . Return ( func ( ctx context . Context ) error {
executorOrder = append ( executorOrder , "step" + stepModel . ID )
if tt . hasError {
return fmt . Errorf ( "error" )
}
return nil
} )
sm . On ( "post" ) . Return ( func ( ctx context . Context ) error {
if tt . postSteps [ i ] {
executorOrder = append ( executorOrder , "post" + stepModel . ID )
}
return nil
} )
defer sm . AssertExpectations ( t )
2022-02-08 11:22:41 -06:00
}
2022-03-22 16:13:00 -05:00
if len ( tt . steps ) > 0 {
jim . On ( "matrix" ) . Return ( map [ string ] interface { } { } )
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
jim . On ( "interpolateOutputs" ) . Return ( func ( ctx context . Context ) error {
executorOrder = append ( executorOrder , "interpolateOutputs" )
return nil
} )
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
if contains ( "stopContainer" , tt . executedSteps ) {
jim . On ( "stopContainer" ) . Return ( func ( ctx context . Context ) error {
executorOrder = append ( executorOrder , "stopContainer" )
return nil
} )
}
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
jim . On ( "result" , tt . result )
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
jim . On ( "closeContainer" ) . Return ( func ( ctx context . Context ) error {
executorOrder = append ( executorOrder , "closeContainer" )
return nil
} )
}
2022-02-08 11:22:41 -06:00
2022-03-22 16:13:00 -05:00
executor := newJobExecutor ( jim , sfm , rc )
2022-02-08 11:22:41 -06:00
err := executor ( ctx )
assert . Nil ( t , err )
2022-02-10 10:54:58 -06:00
assert . Equal ( t , tt . executedSteps , executorOrder )
2022-03-22 16:13:00 -05:00
jim . AssertExpectations ( t )
sfm . AssertExpectations ( t )
2022-04-20 13:34:27 -05:00
fmt . Println ( "::endgroup::" )
2022-02-08 11:22:41 -06:00
} )
}
}