github.com/grahambrereton-form3/tilt@v0.10.18/internal/engine/local_target_build_and_deployer_test.go (about)

     1  package engine
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/windmilleng/tilt/internal/testutils/tempdir"
    14  
    15  	"github.com/windmilleng/tilt/internal/store"
    16  	"github.com/windmilleng/tilt/internal/testutils"
    17  	"github.com/windmilleng/tilt/pkg/model"
    18  )
    19  
    20  func TestNoLocalTargets(t *testing.T) {
    21  	f := newLTFixture(t)
    22  	defer f.TearDown()
    23  
    24  	specs := []model.TargetSpec{
    25  		model.ImageTarget{}, model.K8sTarget{}, model.DockerComposeTarget{},
    26  	}
    27  	res, err := f.ltbad.BuildAndDeploy(f.ctx, f.st, specs, store.BuildStateSet{})
    28  	assert.Empty(t, res, "expect empty result for failed BuildAndDeploy")
    29  
    30  	require.NotNil(t, err)
    31  	assert.Contains(t, err.Error(),
    32  		"LocalTargetBuildAndDeployer requires exactly one LocalTarget (got 0)")
    33  }
    34  
    35  func TestTooManyLocalTargets(t *testing.T) {
    36  	f := newLTFixture(t)
    37  	defer f.TearDown()
    38  
    39  	specs := []model.TargetSpec{
    40  		model.LocalTarget{}, model.ImageTarget{}, model.K8sTarget{}, model.LocalTarget{},
    41  	}
    42  	res, err := f.ltbad.BuildAndDeploy(f.ctx, f.st, specs, store.BuildStateSet{})
    43  	assert.Empty(t, res, "expect empty result for failed BuildAndDeploy")
    44  
    45  	require.NotNil(t, err)
    46  	assert.Contains(t, err.Error(),
    47  		"LocalTargetBuildAndDeployer requires exactly one LocalTarget (got 2)")
    48  }
    49  
    50  func TestSuccessfulCommand(t *testing.T) {
    51  	f := newLTFixture(t)
    52  	defer f.TearDown()
    53  
    54  	targ := f.localTarget("echo hello world")
    55  
    56  	res, err := f.ltbad.BuildAndDeploy(f.ctx, f.st, []model.TargetSpec{targ}, store.BuildStateSet{})
    57  	require.Nil(t, err)
    58  
    59  	assert.Equal(t, targ.ID(), res[targ.ID()].TargetID())
    60  
    61  	assert.Contains(t, f.out.String(), "hello world", "expect cmd stdout in logs")
    62  }
    63  
    64  func TestWorkdir(t *testing.T) {
    65  	f := newLTFixture(t)
    66  	defer f.TearDown()
    67  
    68  	f.MkdirAll("some/internal/dir")
    69  	workdir := f.JoinPath("some/internal/dir")
    70  	targ := f.localTargetWithWorkdir("echo the directory is $(pwd)", workdir)
    71  
    72  	res, err := f.ltbad.BuildAndDeploy(f.ctx, f.st, []model.TargetSpec{targ}, store.BuildStateSet{})
    73  	require.Nil(t, err)
    74  
    75  	assert.Equal(t, targ.ID(), res[targ.ID()].TargetID())
    76  
    77  	expectedOut := fmt.Sprintf("the directory is %s", workdir)
    78  	assert.Contains(t, f.out.String(), expectedOut, "expect cmd stdout (with appropriate pwd) in logs")
    79  }
    80  
    81  func TestExtractOneLocalTarget(t *testing.T) {
    82  	f := newLTFixture(t)
    83  	defer f.TearDown()
    84  
    85  	targ := f.localTarget("echo hello world")
    86  
    87  	// Even if there are multiple other targets, should correctly extract and run the one LocalTarget
    88  	specs := []model.TargetSpec{
    89  		targ, model.ImageTarget{}, model.K8sTarget{},
    90  	}
    91  
    92  	res, err := f.ltbad.BuildAndDeploy(f.ctx, f.st, specs, store.BuildStateSet{})
    93  	require.Nil(t, err)
    94  
    95  	assert.Equal(t, targ.ID(), res[targ.ID()].TargetID())
    96  
    97  	assert.Contains(t, f.out.String(), "hello world", "expect cmd stdout in logs")
    98  }
    99  
   100  func TestFailedCommand(t *testing.T) {
   101  	f := newLTFixture(t)
   102  	defer f.TearDown()
   103  
   104  	targ := f.localTarget("echo oh no; false")
   105  
   106  	res, err := f.ltbad.BuildAndDeploy(f.ctx, f.st, []model.TargetSpec{targ}, store.BuildStateSet{})
   107  	assert.Empty(t, res, "expect empty build result for failed cmd")
   108  
   109  	require.NotNil(t, err, "failed cmd should throw error")
   110  	assert.Contains(t, err.Error(),
   111  		"Command \"echo oh no; false\" failed: exit status 1")
   112  	assert.True(t, IsDontFallBackError(err), "expect DontFallBackError")
   113  
   114  	assert.Contains(t, f.out.String(), "oh no", "expect cmd stdout in logs")
   115  }
   116  
   117  type ltFixture struct {
   118  	*tempdir.TempDirFixture
   119  
   120  	ctx   context.Context
   121  	out   *bytes.Buffer
   122  	ltbad *LocalTargetBuildAndDeployer
   123  	st    *store.Store
   124  }
   125  
   126  func newLTFixture(t *testing.T) *ltFixture {
   127  	f := tempdir.NewTempDirFixture(t)
   128  
   129  	out := new(bytes.Buffer)
   130  	ctx, _, _ := testutils.ForkedCtxAndAnalyticsForTest(out)
   131  	clock := fakeClock{time.Date(2019, 1, 1, 1, 1, 1, 1, time.UTC)}
   132  
   133  	ltbad := NewLocalTargetBuildAndDeployer(clock)
   134  	st, _ := store.NewStoreForTesting()
   135  	return &ltFixture{
   136  		TempDirFixture: f,
   137  		ctx:            ctx,
   138  		out:            out,
   139  		ltbad:          ltbad,
   140  		st:             st,
   141  	}
   142  }
   143  
   144  func (f *ltFixture) localTarget(cmd string) model.LocalTarget {
   145  	return f.localTargetWithWorkdir(cmd, f.Path())
   146  }
   147  
   148  func (f *ltFixture) localTargetWithWorkdir(cmd string, workdir string) model.LocalTarget {
   149  	return model.LocalTarget{
   150  		Cmd:     model.ToShellCmd(cmd),
   151  		Workdir: workdir,
   152  	}
   153  }