github.com/nektos/act@v0.2.63/pkg/runner/runner_test.go (about)

     1  package runner
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  	"runtime"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/joho/godotenv"
    16  	log "github.com/sirupsen/logrus"
    17  	assert "github.com/stretchr/testify/assert"
    18  	"gopkg.in/yaml.v3"
    19  
    20  	"github.com/nektos/act/pkg/common"
    21  	"github.com/nektos/act/pkg/model"
    22  )
    23  
    24  var (
    25  	baseImage = "node:16-buster-slim"
    26  	platforms map[string]string
    27  	logLevel  = log.DebugLevel
    28  	workdir   = "testdata"
    29  	secrets   map[string]string
    30  )
    31  
    32  func init() {
    33  	if p := os.Getenv("ACT_TEST_IMAGE"); p != "" {
    34  		baseImage = p
    35  	}
    36  
    37  	platforms = map[string]string{
    38  		"ubuntu-latest": baseImage,
    39  	}
    40  
    41  	if l := os.Getenv("ACT_TEST_LOG_LEVEL"); l != "" {
    42  		if lvl, err := log.ParseLevel(l); err == nil {
    43  			logLevel = lvl
    44  		}
    45  	}
    46  
    47  	if wd, err := filepath.Abs(workdir); err == nil {
    48  		workdir = wd
    49  	}
    50  
    51  	secrets = map[string]string{}
    52  }
    53  
    54  func TestNoWorkflowsFoundByPlanner(t *testing.T) {
    55  	planner, err := model.NewWorkflowPlanner("res", true)
    56  	assert.NoError(t, err)
    57  
    58  	out := log.StandardLogger().Out
    59  	var buf bytes.Buffer
    60  	log.SetOutput(&buf)
    61  	log.SetLevel(log.DebugLevel)
    62  	plan, err := planner.PlanEvent("pull_request")
    63  	assert.NotNil(t, plan)
    64  	assert.NoError(t, err)
    65  	assert.Contains(t, buf.String(), "no workflows found by planner")
    66  	buf.Reset()
    67  	plan, err = planner.PlanAll()
    68  	assert.NotNil(t, plan)
    69  	assert.NoError(t, err)
    70  	assert.Contains(t, buf.String(), "no workflows found by planner")
    71  	log.SetOutput(out)
    72  }
    73  
    74  func TestGraphMissingEvent(t *testing.T) {
    75  	planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-event.yml", true)
    76  	assert.NoError(t, err)
    77  
    78  	out := log.StandardLogger().Out
    79  	var buf bytes.Buffer
    80  	log.SetOutput(&buf)
    81  	log.SetLevel(log.DebugLevel)
    82  
    83  	plan, err := planner.PlanEvent("push")
    84  	assert.NoError(t, err)
    85  	assert.NotNil(t, plan)
    86  	assert.Equal(t, 0, len(plan.Stages))
    87  
    88  	assert.Contains(t, buf.String(), "no events found for workflow: no-event.yml")
    89  	log.SetOutput(out)
    90  }
    91  
    92  func TestGraphMissingFirst(t *testing.T) {
    93  	planner, err := model.NewWorkflowPlanner("testdata/issue-1595/no-first.yml", true)
    94  	assert.NoError(t, err)
    95  
    96  	plan, err := planner.PlanEvent("push")
    97  	assert.EqualError(t, err, "unable to build dependency graph for no first (no-first.yml)")
    98  	assert.NotNil(t, plan)
    99  	assert.Equal(t, 0, len(plan.Stages))
   100  }
   101  
   102  func TestGraphWithMissing(t *testing.T) {
   103  	planner, err := model.NewWorkflowPlanner("testdata/issue-1595/missing.yml", true)
   104  	assert.NoError(t, err)
   105  
   106  	out := log.StandardLogger().Out
   107  	var buf bytes.Buffer
   108  	log.SetOutput(&buf)
   109  	log.SetLevel(log.DebugLevel)
   110  
   111  	plan, err := planner.PlanEvent("push")
   112  	assert.NotNil(t, plan)
   113  	assert.Equal(t, 0, len(plan.Stages))
   114  	assert.EqualError(t, err, "unable to build dependency graph for missing (missing.yml)")
   115  	assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)")
   116  	log.SetOutput(out)
   117  }
   118  
   119  func TestGraphWithSomeMissing(t *testing.T) {
   120  	log.SetLevel(log.DebugLevel)
   121  
   122  	planner, err := model.NewWorkflowPlanner("testdata/issue-1595/", true)
   123  	assert.NoError(t, err)
   124  
   125  	out := log.StandardLogger().Out
   126  	var buf bytes.Buffer
   127  	log.SetOutput(&buf)
   128  	log.SetLevel(log.DebugLevel)
   129  
   130  	plan, err := planner.PlanAll()
   131  	assert.Error(t, err, "unable to build dependency graph for no first (no-first.yml)")
   132  	assert.NotNil(t, plan)
   133  	assert.Equal(t, 1, len(plan.Stages))
   134  	assert.Contains(t, buf.String(), "unable to build dependency graph for missing (missing.yml)")
   135  	assert.Contains(t, buf.String(), "unable to build dependency graph for no first (no-first.yml)")
   136  	log.SetOutput(out)
   137  }
   138  
   139  func TestGraphEvent(t *testing.T) {
   140  	planner, err := model.NewWorkflowPlanner("testdata/basic", true)
   141  	assert.NoError(t, err)
   142  
   143  	plan, err := planner.PlanEvent("push")
   144  	assert.NoError(t, err)
   145  	assert.NotNil(t, plan)
   146  	assert.NotNil(t, plan.Stages)
   147  	assert.Equal(t, len(plan.Stages), 3, "stages")
   148  	assert.Equal(t, len(plan.Stages[0].Runs), 1, "stage0.runs")
   149  	assert.Equal(t, len(plan.Stages[1].Runs), 1, "stage1.runs")
   150  	assert.Equal(t, len(plan.Stages[2].Runs), 1, "stage2.runs")
   151  	assert.Equal(t, plan.Stages[0].Runs[0].JobID, "check", "jobid")
   152  	assert.Equal(t, plan.Stages[1].Runs[0].JobID, "build", "jobid")
   153  	assert.Equal(t, plan.Stages[2].Runs[0].JobID, "test", "jobid")
   154  
   155  	plan, err = planner.PlanEvent("release")
   156  	assert.NoError(t, err)
   157  	assert.NotNil(t, plan)
   158  	assert.Equal(t, 0, len(plan.Stages))
   159  }
   160  
   161  type TestJobFileInfo struct {
   162  	workdir      string
   163  	workflowPath string
   164  	eventName    string
   165  	errorMessage string
   166  	platforms    map[string]string
   167  	secrets      map[string]string
   168  }
   169  
   170  func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config) {
   171  	fmt.Printf("::group::%s\n", j.workflowPath)
   172  
   173  	log.SetLevel(logLevel)
   174  
   175  	workdir, err := filepath.Abs(j.workdir)
   176  	assert.Nil(t, err, workdir)
   177  
   178  	fullWorkflowPath := filepath.Join(workdir, j.workflowPath)
   179  	runnerConfig := &Config{
   180  		Workdir:               workdir,
   181  		BindWorkdir:           false,
   182  		EventName:             j.eventName,
   183  		EventPath:             cfg.EventPath,
   184  		Platforms:             j.platforms,
   185  		ReuseContainers:       false,
   186  		Env:                   cfg.Env,
   187  		Secrets:               cfg.Secrets,
   188  		Inputs:                cfg.Inputs,
   189  		GitHubInstance:        "github.com",
   190  		ContainerArchitecture: cfg.ContainerArchitecture,
   191  		Matrix:                cfg.Matrix,
   192  		ActionCache:           cfg.ActionCache,
   193  	}
   194  
   195  	runner, err := New(runnerConfig)
   196  	assert.Nil(t, err, j.workflowPath)
   197  
   198  	planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true)
   199  	assert.Nil(t, err, fullWorkflowPath)
   200  
   201  	plan, err := planner.PlanEvent(j.eventName)
   202  	assert.True(t, (err == nil) != (plan == nil), "PlanEvent should return either a plan or an error")
   203  	if err == nil && plan != nil {
   204  		err = runner.NewPlanExecutor(plan)(ctx)
   205  		if j.errorMessage == "" {
   206  			assert.Nil(t, err, fullWorkflowPath)
   207  		} else {
   208  			assert.Error(t, err, j.errorMessage)
   209  		}
   210  	}
   211  
   212  	fmt.Println("::endgroup::")
   213  }
   214  
   215  type TestConfig struct {
   216  	LocalRepositories map[string]string `yaml:"local-repositories"`
   217  }
   218  
   219  func TestRunEvent(t *testing.T) {
   220  	if testing.Short() {
   221  		t.Skip("skipping integration test")
   222  	}
   223  
   224  	ctx := context.Background()
   225  
   226  	tables := []TestJobFileInfo{
   227  		// Shells
   228  		{workdir, "shells/defaults", "push", "", platforms, secrets},
   229  		// TODO: figure out why it fails
   230  		// {workdir, "shells/custom", "push", "", map[string]string{"ubuntu-latest": "catthehacker/ubuntu:pwsh-latest"}, }, // custom image with pwsh
   231  		{workdir, "shells/pwsh", "push", "", map[string]string{"ubuntu-latest": "catthehacker/ubuntu:pwsh-latest"}, secrets}, // custom image with pwsh
   232  		{workdir, "shells/bash", "push", "", platforms, secrets},
   233  		{workdir, "shells/python", "push", "", map[string]string{"ubuntu-latest": "node:16-buster"}, secrets}, // slim doesn't have python
   234  		{workdir, "shells/sh", "push", "", platforms, secrets},
   235  
   236  		// Local action
   237  		{workdir, "local-action-docker-url", "push", "", platforms, secrets},
   238  		{workdir, "local-action-dockerfile", "push", "", platforms, secrets},
   239  		{workdir, "local-action-via-composite-dockerfile", "push", "", platforms, secrets},
   240  		{workdir, "local-action-js", "push", "", platforms, secrets},
   241  
   242  		// Uses
   243  		{workdir, "uses-composite", "push", "", platforms, secrets},
   244  		{workdir, "uses-composite-with-error", "push", "Job 'failing-composite-action' failed", platforms, secrets},
   245  		{workdir, "uses-nested-composite", "push", "", platforms, secrets},
   246  		{workdir, "remote-action-composite-js-pre-with-defaults", "push", "", platforms, secrets},
   247  		{workdir, "remote-action-composite-action-ref", "push", "", platforms, secrets},
   248  		{workdir, "uses-workflow", "push", "", platforms, map[string]string{"secret": "keep_it_private"}},
   249  		{workdir, "uses-workflow", "pull_request", "", platforms, map[string]string{"secret": "keep_it_private"}},
   250  		{workdir, "uses-docker-url", "push", "", platforms, secrets},
   251  		{workdir, "act-composite-env-test", "push", "", platforms, secrets},
   252  
   253  		// Eval
   254  		{workdir, "evalmatrix", "push", "", platforms, secrets},
   255  		{workdir, "evalmatrixneeds", "push", "", platforms, secrets},
   256  		{workdir, "evalmatrixneeds2", "push", "", platforms, secrets},
   257  		{workdir, "evalmatrix-merge-map", "push", "", platforms, secrets},
   258  		{workdir, "evalmatrix-merge-array", "push", "", platforms, secrets},
   259  		{workdir, "issue-1195", "push", "", platforms, secrets},
   260  
   261  		{workdir, "basic", "push", "", platforms, secrets},
   262  		{workdir, "fail", "push", "exit with `FAILURE`: 1", platforms, secrets},
   263  		{workdir, "runs-on", "push", "", platforms, secrets},
   264  		{workdir, "checkout", "push", "", platforms, secrets},
   265  		{workdir, "job-container", "push", "", platforms, secrets},
   266  		{workdir, "job-container-non-root", "push", "", platforms, secrets},
   267  		{workdir, "job-container-invalid-credentials", "push", "failed to handle credentials: failed to interpolate container.credentials.password", platforms, secrets},
   268  		{workdir, "container-hostname", "push", "", platforms, secrets},
   269  		{workdir, "remote-action-docker", "push", "", platforms, secrets},
   270  		{workdir, "remote-action-js", "push", "", platforms, secrets},
   271  		{workdir, "remote-action-js-node-user", "push", "", platforms, secrets}, // Test if this works with non root container
   272  		{workdir, "matrix", "push", "", platforms, secrets},
   273  		{workdir, "matrix-include-exclude", "push", "", platforms, secrets},
   274  		{workdir, "matrix-exitcode", "push", "Job 'test' failed", platforms, secrets},
   275  		{workdir, "commands", "push", "", platforms, secrets},
   276  		{workdir, "workdir", "push", "", platforms, secrets},
   277  		{workdir, "defaults-run", "push", "", platforms, secrets},
   278  		{workdir, "composite-fail-with-output", "push", "", platforms, secrets},
   279  		{workdir, "issue-597", "push", "", platforms, secrets},
   280  		{workdir, "issue-598", "push", "", platforms, secrets},
   281  		{workdir, "if-env-act", "push", "", platforms, secrets},
   282  		{workdir, "env-and-path", "push", "", platforms, secrets},
   283  		{workdir, "environment-files", "push", "", platforms, secrets},
   284  		{workdir, "GITHUB_STATE", "push", "", platforms, secrets},
   285  		{workdir, "environment-files-parser-bug", "push", "", platforms, secrets},
   286  		{workdir, "non-existent-action", "push", "Job 'nopanic' failed", platforms, secrets},
   287  		{workdir, "outputs", "push", "", platforms, secrets},
   288  		{workdir, "networking", "push", "", platforms, secrets},
   289  		{workdir, "steps-context/conclusion", "push", "", platforms, secrets},
   290  		{workdir, "steps-context/outcome", "push", "", platforms, secrets},
   291  		{workdir, "job-status-check", "push", "job 'fail' failed", platforms, secrets},
   292  		{workdir, "if-expressions", "push", "Job 'mytest' failed", platforms, secrets},
   293  		{workdir, "actions-environment-and-context-tests", "push", "", platforms, secrets},
   294  		{workdir, "uses-action-with-pre-and-post-step", "push", "", platforms, secrets},
   295  		{workdir, "evalenv", "push", "", platforms, secrets},
   296  		{workdir, "docker-action-custom-path", "push", "", platforms, secrets},
   297  		{workdir, "GITHUB_ENV-use-in-env-ctx", "push", "", platforms, secrets},
   298  		{workdir, "ensure-post-steps", "push", "Job 'second-post-step-should-fail' failed", platforms, secrets},
   299  		{workdir, "workflow_call_inputs", "workflow_call", "", platforms, secrets},
   300  		{workdir, "workflow_dispatch", "workflow_dispatch", "", platforms, secrets},
   301  		{workdir, "workflow_dispatch_no_inputs_mapping", "workflow_dispatch", "", platforms, secrets},
   302  		{workdir, "workflow_dispatch-scalar", "workflow_dispatch", "", platforms, secrets},
   303  		{workdir, "workflow_dispatch-scalar-composite-action", "workflow_dispatch", "", platforms, secrets},
   304  		{workdir, "job-needs-context-contains-result", "push", "", platforms, secrets},
   305  		{"../model/testdata", "strategy", "push", "", platforms, secrets}, // TODO: move all testdata into pkg so we can validate it with planner and runner
   306  		{"../model/testdata", "container-volumes", "push", "", platforms, secrets},
   307  		{workdir, "path-handling", "push", "", platforms, secrets},
   308  		{workdir, "do-not-leak-step-env-in-composite", "push", "", platforms, secrets},
   309  		{workdir, "set-env-step-env-override", "push", "", platforms, secrets},
   310  		{workdir, "set-env-new-env-file-per-step", "push", "", platforms, secrets},
   311  		{workdir, "no-panic-on-invalid-composite-action", "push", "jobs failed due to invalid action", platforms, secrets},
   312  
   313  		// services
   314  		{workdir, "services", "push", "", platforms, secrets},
   315  		{workdir, "services-host-network", "push", "", platforms, secrets},
   316  		{workdir, "services-with-container", "push", "", platforms, secrets},
   317  
   318  		// local remote action overrides
   319  		{workdir, "local-remote-action-overrides", "push", "", platforms, secrets},
   320  	}
   321  
   322  	for _, table := range tables {
   323  		t.Run(table.workflowPath, func(t *testing.T) {
   324  			config := &Config{
   325  				Secrets: table.secrets,
   326  			}
   327  
   328  			eventFile := filepath.Join(workdir, table.workflowPath, "event.json")
   329  			if _, err := os.Stat(eventFile); err == nil {
   330  				config.EventPath = eventFile
   331  			}
   332  
   333  			testConfigFile := filepath.Join(workdir, table.workflowPath, "config.yml")
   334  			if file, err := os.ReadFile(testConfigFile); err == nil {
   335  				testConfig := &TestConfig{}
   336  				if yaml.Unmarshal(file, testConfig) == nil {
   337  					if testConfig.LocalRepositories != nil {
   338  						config.ActionCache = &LocalRepositoryCache{
   339  							Parent: GoGitActionCache{
   340  								path.Clean(path.Join(workdir, "cache")),
   341  							},
   342  							LocalRepositories: testConfig.LocalRepositories,
   343  							CacheDirCache:     map[string]string{},
   344  						}
   345  					}
   346  				}
   347  			}
   348  
   349  			table.runTest(ctx, t, config)
   350  		})
   351  	}
   352  }
   353  
   354  func TestRunEventHostEnvironment(t *testing.T) {
   355  	if testing.Short() {
   356  		t.Skip("skipping integration test")
   357  	}
   358  
   359  	ctx := context.Background()
   360  
   361  	tables := []TestJobFileInfo{}
   362  
   363  	if runtime.GOOS == "linux" {
   364  		platforms := map[string]string{
   365  			"ubuntu-latest": "-self-hosted",
   366  		}
   367  
   368  		tables = append(tables, []TestJobFileInfo{
   369  			// Shells
   370  			{workdir, "shells/defaults", "push", "", platforms, secrets},
   371  			{workdir, "shells/pwsh", "push", "", platforms, secrets},
   372  			{workdir, "shells/bash", "push", "", platforms, secrets},
   373  			{workdir, "shells/python", "push", "", platforms, secrets},
   374  			{workdir, "shells/sh", "push", "", platforms, secrets},
   375  
   376  			// Local action
   377  			{workdir, "local-action-js", "push", "", platforms, secrets},
   378  
   379  			// Uses
   380  			{workdir, "uses-composite", "push", "", platforms, secrets},
   381  			{workdir, "uses-composite-with-error", "push", "Job 'failing-composite-action' failed", platforms, secrets},
   382  			{workdir, "uses-nested-composite", "push", "", platforms, secrets},
   383  			{workdir, "act-composite-env-test", "push", "", platforms, secrets},
   384  
   385  			// Eval
   386  			{workdir, "evalmatrix", "push", "", platforms, secrets},
   387  			{workdir, "evalmatrixneeds", "push", "", platforms, secrets},
   388  			{workdir, "evalmatrixneeds2", "push", "", platforms, secrets},
   389  			{workdir, "evalmatrix-merge-map", "push", "", platforms, secrets},
   390  			{workdir, "evalmatrix-merge-array", "push", "", platforms, secrets},
   391  			{workdir, "issue-1195", "push", "", platforms, secrets},
   392  
   393  			{workdir, "fail", "push", "exit with `FAILURE`: 1", platforms, secrets},
   394  			{workdir, "runs-on", "push", "", platforms, secrets},
   395  			{workdir, "checkout", "push", "", platforms, secrets},
   396  			{workdir, "remote-action-js", "push", "", platforms, secrets},
   397  			{workdir, "matrix", "push", "", platforms, secrets},
   398  			{workdir, "matrix-include-exclude", "push", "", platforms, secrets},
   399  			{workdir, "commands", "push", "", platforms, secrets},
   400  			{workdir, "defaults-run", "push", "", platforms, secrets},
   401  			{workdir, "composite-fail-with-output", "push", "", platforms, secrets},
   402  			{workdir, "issue-597", "push", "", platforms, secrets},
   403  			{workdir, "issue-598", "push", "", platforms, secrets},
   404  			{workdir, "if-env-act", "push", "", platforms, secrets},
   405  			{workdir, "env-and-path", "push", "", platforms, secrets},
   406  			{workdir, "non-existent-action", "push", "Job 'nopanic' failed", platforms, secrets},
   407  			{workdir, "outputs", "push", "", platforms, secrets},
   408  			{workdir, "steps-context/conclusion", "push", "", platforms, secrets},
   409  			{workdir, "steps-context/outcome", "push", "", platforms, secrets},
   410  			{workdir, "job-status-check", "push", "job 'fail' failed", platforms, secrets},
   411  			{workdir, "if-expressions", "push", "Job 'mytest' failed", platforms, secrets},
   412  			{workdir, "uses-action-with-pre-and-post-step", "push", "", platforms, secrets},
   413  			{workdir, "evalenv", "push", "", platforms, secrets},
   414  			{workdir, "ensure-post-steps", "push", "Job 'second-post-step-should-fail' failed", platforms, secrets},
   415  		}...)
   416  	}
   417  	if runtime.GOOS == "windows" {
   418  		platforms := map[string]string{
   419  			"windows-latest": "-self-hosted",
   420  		}
   421  
   422  		tables = append(tables, []TestJobFileInfo{
   423  			{workdir, "windows-prepend-path", "push", "", platforms, secrets},
   424  			{workdir, "windows-add-env", "push", "", platforms, secrets},
   425  			{workdir, "windows-shell-cmd", "push", "", platforms, secrets},
   426  		}...)
   427  	} else {
   428  		platforms := map[string]string{
   429  			"self-hosted":   "-self-hosted",
   430  			"ubuntu-latest": "-self-hosted",
   431  		}
   432  
   433  		tables = append(tables, []TestJobFileInfo{
   434  			{workdir, "nix-prepend-path", "push", "", platforms, secrets},
   435  			{workdir, "inputs-via-env-context", "push", "", platforms, secrets},
   436  			{workdir, "do-not-leak-step-env-in-composite", "push", "", platforms, secrets},
   437  			{workdir, "set-env-step-env-override", "push", "", platforms, secrets},
   438  			{workdir, "set-env-new-env-file-per-step", "push", "", platforms, secrets},
   439  			{workdir, "no-panic-on-invalid-composite-action", "push", "jobs failed due to invalid action", platforms, secrets},
   440  		}...)
   441  	}
   442  
   443  	for _, table := range tables {
   444  		t.Run(table.workflowPath, func(t *testing.T) {
   445  			table.runTest(ctx, t, &Config{})
   446  		})
   447  	}
   448  }
   449  
   450  func TestDryrunEvent(t *testing.T) {
   451  	if testing.Short() {
   452  		t.Skip("skipping integration test")
   453  	}
   454  
   455  	ctx := common.WithDryrun(context.Background(), true)
   456  
   457  	tables := []TestJobFileInfo{
   458  		// Shells
   459  		{workdir, "shells/defaults", "push", "", platforms, secrets},
   460  		{workdir, "shells/pwsh", "push", "", map[string]string{"ubuntu-latest": "catthehacker/ubuntu:pwsh-latest"}, secrets}, // custom image with pwsh
   461  		{workdir, "shells/bash", "push", "", platforms, secrets},
   462  		{workdir, "shells/python", "push", "", map[string]string{"ubuntu-latest": "node:16-buster"}, secrets}, // slim doesn't have python
   463  		{workdir, "shells/sh", "push", "", platforms, secrets},
   464  
   465  		// Local action
   466  		{workdir, "local-action-docker-url", "push", "", platforms, secrets},
   467  		{workdir, "local-action-dockerfile", "push", "", platforms, secrets},
   468  		{workdir, "local-action-via-composite-dockerfile", "push", "", platforms, secrets},
   469  		{workdir, "local-action-js", "push", "", platforms, secrets},
   470  	}
   471  
   472  	for _, table := range tables {
   473  		t.Run(table.workflowPath, func(t *testing.T) {
   474  			table.runTest(ctx, t, &Config{})
   475  		})
   476  	}
   477  }
   478  
   479  func TestDockerActionForcePullForceRebuild(t *testing.T) {
   480  	if testing.Short() {
   481  		t.Skip("skipping integration test")
   482  	}
   483  
   484  	ctx := context.Background()
   485  
   486  	config := &Config{
   487  		ForcePull:    true,
   488  		ForceRebuild: true,
   489  	}
   490  
   491  	tables := []TestJobFileInfo{
   492  		{workdir, "local-action-dockerfile", "push", "", platforms, secrets},
   493  		{workdir, "local-action-via-composite-dockerfile", "push", "", platforms, secrets},
   494  	}
   495  
   496  	for _, table := range tables {
   497  		t.Run(table.workflowPath, func(t *testing.T) {
   498  			table.runTest(ctx, t, config)
   499  		})
   500  	}
   501  }
   502  
   503  func TestRunDifferentArchitecture(t *testing.T) {
   504  	if testing.Short() {
   505  		t.Skip("skipping integration test")
   506  	}
   507  
   508  	tjfi := TestJobFileInfo{
   509  		workdir:      workdir,
   510  		workflowPath: "basic",
   511  		eventName:    "push",
   512  		errorMessage: "",
   513  		platforms:    platforms,
   514  	}
   515  
   516  	tjfi.runTest(context.Background(), t, &Config{ContainerArchitecture: "linux/arm64"})
   517  }
   518  
   519  type maskJobLoggerFactory struct {
   520  	Output bytes.Buffer
   521  }
   522  
   523  func (f *maskJobLoggerFactory) WithJobLogger() *log.Logger {
   524  	logger := log.New()
   525  	logger.SetOutput(io.MultiWriter(&f.Output, os.Stdout))
   526  	logger.SetLevel(log.DebugLevel)
   527  	return logger
   528  }
   529  
   530  func TestMaskValues(t *testing.T) {
   531  	assertNoSecret := func(text string, secret string) {
   532  		index := strings.Index(text, "composite secret")
   533  		if index > -1 {
   534  			fmt.Printf("\nFound Secret in the given text:\n%s\n", text)
   535  		}
   536  		assert.False(t, strings.Contains(text, "composite secret"))
   537  	}
   538  
   539  	if testing.Short() {
   540  		t.Skip("skipping integration test")
   541  	}
   542  
   543  	log.SetLevel(log.DebugLevel)
   544  
   545  	tjfi := TestJobFileInfo{
   546  		workdir:      workdir,
   547  		workflowPath: "mask-values",
   548  		eventName:    "push",
   549  		errorMessage: "",
   550  		platforms:    platforms,
   551  	}
   552  
   553  	logger := &maskJobLoggerFactory{}
   554  	tjfi.runTest(WithJobLoggerFactory(common.WithLogger(context.Background(), logger.WithJobLogger()), logger), t, &Config{})
   555  	output := logger.Output.String()
   556  
   557  	assertNoSecret(output, "secret value")
   558  	assertNoSecret(output, "YWJjCg==")
   559  }
   560  
   561  func TestRunEventSecrets(t *testing.T) {
   562  	if testing.Short() {
   563  		t.Skip("skipping integration test")
   564  	}
   565  	workflowPath := "secrets"
   566  
   567  	tjfi := TestJobFileInfo{
   568  		workdir:      workdir,
   569  		workflowPath: workflowPath,
   570  		eventName:    "push",
   571  		errorMessage: "",
   572  		platforms:    platforms,
   573  	}
   574  
   575  	env, err := godotenv.Read(filepath.Join(workdir, workflowPath, ".env"))
   576  	assert.NoError(t, err, "Failed to read .env")
   577  	secrets, _ := godotenv.Read(filepath.Join(workdir, workflowPath, ".secrets"))
   578  	assert.NoError(t, err, "Failed to read .secrets")
   579  
   580  	tjfi.runTest(context.Background(), t, &Config{Secrets: secrets, Env: env})
   581  }
   582  
   583  func TestRunActionInputs(t *testing.T) {
   584  	if testing.Short() {
   585  		t.Skip("skipping integration test")
   586  	}
   587  	workflowPath := "input-from-cli"
   588  
   589  	tjfi := TestJobFileInfo{
   590  		workdir:      workdir,
   591  		workflowPath: workflowPath,
   592  		eventName:    "workflow_dispatch",
   593  		errorMessage: "",
   594  		platforms:    platforms,
   595  	}
   596  
   597  	inputs := map[string]string{
   598  		"SOME_INPUT": "input",
   599  	}
   600  
   601  	tjfi.runTest(context.Background(), t, &Config{Inputs: inputs})
   602  }
   603  
   604  func TestRunEventPullRequest(t *testing.T) {
   605  	if testing.Short() {
   606  		t.Skip("skipping integration test")
   607  	}
   608  
   609  	workflowPath := "pull-request"
   610  
   611  	tjfi := TestJobFileInfo{
   612  		workdir:      workdir,
   613  		workflowPath: workflowPath,
   614  		eventName:    "pull_request",
   615  		errorMessage: "",
   616  		platforms:    platforms,
   617  	}
   618  
   619  	tjfi.runTest(context.Background(), t, &Config{EventPath: filepath.Join(workdir, workflowPath, "event.json")})
   620  }
   621  
   622  func TestRunMatrixWithUserDefinedInclusions(t *testing.T) {
   623  	if testing.Short() {
   624  		t.Skip("skipping integration test")
   625  	}
   626  	workflowPath := "matrix-with-user-inclusions"
   627  
   628  	tjfi := TestJobFileInfo{
   629  		workdir:      workdir,
   630  		workflowPath: workflowPath,
   631  		eventName:    "push",
   632  		errorMessage: "",
   633  		platforms:    platforms,
   634  	}
   635  
   636  	matrix := map[string]map[string]bool{
   637  		"node": {
   638  			"8":   true,
   639  			"8.x": true,
   640  		},
   641  		"os": {
   642  			"ubuntu-18.04": true,
   643  		},
   644  	}
   645  
   646  	tjfi.runTest(context.Background(), t, &Config{Matrix: matrix})
   647  }