github.com/hugorut/terraform@v1.1.3/src/command/apply_test.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path"
    11  	"path/filepath"
    12  	"reflect"
    13  	"strings"
    14  	"sync"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/google/go-cmp/cmp"
    19  	"github.com/google/go-cmp/cmp/cmpopts"
    20  	"github.com/mitchellh/cli"
    21  	"github.com/zclconf/go-cty/cty"
    22  
    23  	"github.com/hugorut/terraform/src/addrs"
    24  	"github.com/hugorut/terraform/src/command/views"
    25  	"github.com/hugorut/terraform/src/configs/configschema"
    26  	"github.com/hugorut/terraform/src/plans"
    27  	"github.com/hugorut/terraform/src/providers"
    28  	"github.com/hugorut/terraform/src/states"
    29  	"github.com/hugorut/terraform/src/states/statemgr"
    30  	"github.com/hugorut/terraform/src/terraform"
    31  	"github.com/hugorut/terraform/src/tfdiags"
    32  	tfversion "github.com/hugorut/terraform/version"
    33  )
    34  
    35  func TestApply(t *testing.T) {
    36  	// Create a temporary working directory that is empty
    37  	td := tempDir(t)
    38  	testCopyDir(t, testFixturePath("apply"), td)
    39  	defer os.RemoveAll(td)
    40  	defer testChdir(t, td)()
    41  
    42  	statePath := testTempFile(t)
    43  
    44  	p := applyFixtureProvider()
    45  
    46  	view, done := testView(t)
    47  	c := &ApplyCommand{
    48  		Meta: Meta{
    49  			testingOverrides: metaOverridesForProvider(p),
    50  			View:             view,
    51  		},
    52  	}
    53  
    54  	args := []string{
    55  		"-state", statePath,
    56  		"-auto-approve",
    57  	}
    58  	code := c.Run(args)
    59  	output := done(t)
    60  	if code != 0 {
    61  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
    62  	}
    63  
    64  	if _, err := os.Stat(statePath); err != nil {
    65  		t.Fatalf("err: %s", err)
    66  	}
    67  
    68  	state := testStateRead(t, statePath)
    69  	if state == nil {
    70  		t.Fatal("state should not be nil")
    71  	}
    72  }
    73  
    74  func TestApply_path(t *testing.T) {
    75  	// Create a temporary working directory that is empty
    76  	td := tempDir(t)
    77  	testCopyDir(t, testFixturePath("apply"), td)
    78  	defer os.RemoveAll(td)
    79  	defer testChdir(t, td)()
    80  
    81  	p := applyFixtureProvider()
    82  
    83  	view, done := testView(t)
    84  	c := &ApplyCommand{
    85  		Meta: Meta{
    86  			testingOverrides: metaOverridesForProvider(p),
    87  			View:             view,
    88  		},
    89  	}
    90  
    91  	args := []string{
    92  		"-auto-approve",
    93  		testFixturePath("apply"),
    94  	}
    95  	code := c.Run(args)
    96  	output := done(t)
    97  	if code != 1 {
    98  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
    99  	}
   100  	if !strings.Contains(output.Stderr(), "-chdir") {
   101  		t.Fatal("expected command output to refer to -chdir flag, but got:", output.Stderr())
   102  	}
   103  }
   104  
   105  func TestApply_approveNo(t *testing.T) {
   106  	// Create a temporary working directory that is empty
   107  	td := tempDir(t)
   108  	testCopyDir(t, testFixturePath("apply"), td)
   109  	defer os.RemoveAll(td)
   110  	defer testChdir(t, td)()
   111  
   112  	statePath := testTempFile(t)
   113  
   114  	defer testInputMap(t, map[string]string{
   115  		"approve": "no",
   116  	})()
   117  
   118  	// Do not use the NewMockUi initializer here, as we want to delay
   119  	// the call to init until after setting up the input mocks
   120  	ui := new(cli.MockUi)
   121  
   122  	p := applyFixtureProvider()
   123  	view, done := testView(t)
   124  	c := &ApplyCommand{
   125  		Meta: Meta{
   126  			testingOverrides: metaOverridesForProvider(p),
   127  			Ui:               ui,
   128  			View:             view,
   129  		},
   130  	}
   131  
   132  	args := []string{
   133  		"-state", statePath,
   134  	}
   135  	code := c.Run(args)
   136  	output := done(t)
   137  	if code != 1 {
   138  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   139  	}
   140  	if got, want := output.Stdout(), "Apply cancelled"; !strings.Contains(got, want) {
   141  		t.Fatalf("expected output to include %q, but was:\n%s", want, got)
   142  	}
   143  
   144  	if _, err := os.Stat(statePath); err == nil || !os.IsNotExist(err) {
   145  		t.Fatalf("state file should not exist")
   146  	}
   147  }
   148  
   149  func TestApply_approveYes(t *testing.T) {
   150  	// Create a temporary working directory that is empty
   151  	td := tempDir(t)
   152  	testCopyDir(t, testFixturePath("apply"), td)
   153  	defer os.RemoveAll(td)
   154  	defer testChdir(t, td)()
   155  
   156  	statePath := testTempFile(t)
   157  
   158  	p := applyFixtureProvider()
   159  
   160  	defer testInputMap(t, map[string]string{
   161  		"approve": "yes",
   162  	})()
   163  
   164  	// Do not use the NewMockUi initializer here, as we want to delay
   165  	// the call to init until after setting up the input mocks
   166  	ui := new(cli.MockUi)
   167  
   168  	view, done := testView(t)
   169  	c := &ApplyCommand{
   170  		Meta: Meta{
   171  			testingOverrides: metaOverridesForProvider(p),
   172  			Ui:               ui,
   173  			View:             view,
   174  		},
   175  	}
   176  
   177  	args := []string{
   178  		"-state", statePath,
   179  	}
   180  	code := c.Run(args)
   181  	output := done(t)
   182  	if code != 0 {
   183  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   184  	}
   185  
   186  	if _, err := os.Stat(statePath); err != nil {
   187  		t.Fatalf("err: %s", err)
   188  	}
   189  
   190  	state := testStateRead(t, statePath)
   191  	if state == nil {
   192  		t.Fatal("state should not be nil")
   193  	}
   194  }
   195  
   196  // test apply with locked state
   197  func TestApply_lockedState(t *testing.T) {
   198  	// Create a temporary working directory that is empty
   199  	td := tempDir(t)
   200  	testCopyDir(t, testFixturePath("apply"), td)
   201  	defer os.RemoveAll(td)
   202  	defer testChdir(t, td)()
   203  
   204  	statePath := testTempFile(t)
   205  
   206  	unlock, err := testLockState(testDataDir, statePath)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  	defer unlock()
   211  
   212  	p := applyFixtureProvider()
   213  	view, done := testView(t)
   214  	c := &ApplyCommand{
   215  		Meta: Meta{
   216  			testingOverrides: metaOverridesForProvider(p),
   217  			View:             view,
   218  		},
   219  	}
   220  
   221  	args := []string{
   222  		"-state", statePath,
   223  		"-auto-approve",
   224  	}
   225  	code := c.Run(args)
   226  	output := done(t)
   227  	if code == 0 {
   228  		t.Fatal("expected error")
   229  	}
   230  
   231  	if !strings.Contains(output.Stderr(), "lock") {
   232  		t.Fatal("command output does not look like a lock error:", output.Stderr())
   233  	}
   234  }
   235  
   236  // test apply with locked state, waiting for unlock
   237  func TestApply_lockedStateWait(t *testing.T) {
   238  	// Create a temporary working directory that is empty
   239  	td := tempDir(t)
   240  	testCopyDir(t, testFixturePath("apply"), td)
   241  	defer os.RemoveAll(td)
   242  	defer testChdir(t, td)()
   243  
   244  	statePath := testTempFile(t)
   245  
   246  	unlock, err := testLockState(testDataDir, statePath)
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  
   251  	// unlock during apply
   252  	go func() {
   253  		time.Sleep(500 * time.Millisecond)
   254  		unlock()
   255  	}()
   256  
   257  	p := applyFixtureProvider()
   258  	view, done := testView(t)
   259  	c := &ApplyCommand{
   260  		Meta: Meta{
   261  			testingOverrides: metaOverridesForProvider(p),
   262  			View:             view,
   263  		},
   264  	}
   265  
   266  	// wait 4s just in case the lock process doesn't release in under a second,
   267  	// and we want our context to be alive for a second retry at the 3s mark.
   268  	args := []string{
   269  		"-state", statePath,
   270  		"-lock-timeout", "4s",
   271  		"-auto-approve",
   272  	}
   273  	code := c.Run(args)
   274  	output := done(t)
   275  	if code != 0 {
   276  		t.Fatalf("lock should have succeeded in less than 3s: %s", output.Stderr())
   277  	}
   278  }
   279  
   280  // Verify that the parallelism flag allows no more than the desired number of
   281  // concurrent calls to ApplyResourceChange.
   282  func TestApply_parallelism(t *testing.T) {
   283  	// Create a temporary working directory that is empty
   284  	td := tempDir(t)
   285  	testCopyDir(t, testFixturePath("parallelism"), td)
   286  	defer os.RemoveAll(td)
   287  	defer testChdir(t, td)()
   288  
   289  	statePath := testTempFile(t)
   290  
   291  	par := 4
   292  
   293  	// started is a semaphore that we use to ensure that we never have more
   294  	// than "par" apply operations happening concurrently
   295  	started := make(chan struct{}, par)
   296  
   297  	// beginCtx is used as a starting gate to hold back ApplyResourceChange
   298  	// calls until we reach the desired concurrency. The cancel func "begin" is
   299  	// called once we reach the desired concurrency, allowing all apply calls
   300  	// to proceed in unison.
   301  	beginCtx, begin := context.WithCancel(context.Background())
   302  
   303  	// Since our mock provider has its own mutex preventing concurrent calls
   304  	// to ApplyResourceChange, we need to use a number of separate providers
   305  	// here. They will all have the same mock implementation function assigned
   306  	// but crucially they will each have their own mutex.
   307  	providerFactories := map[addrs.Provider]providers.Factory{}
   308  	for i := 0; i < 10; i++ {
   309  		name := fmt.Sprintf("test%d", i)
   310  		provider := &terraform.MockProvider{}
   311  		provider.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   312  			ResourceTypes: map[string]providers.Schema{
   313  				name + "_instance": {Block: &configschema.Block{}},
   314  			},
   315  		}
   316  		provider.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
   317  			return providers.PlanResourceChangeResponse{
   318  				PlannedState: req.ProposedNewState,
   319  			}
   320  		}
   321  		provider.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
   322  
   323  			// If we ever have more than our intended parallelism number of
   324  			// apply operations running concurrently, the semaphore will fail.
   325  			select {
   326  			case started <- struct{}{}:
   327  				defer func() {
   328  					<-started
   329  				}()
   330  			default:
   331  				t.Fatal("too many concurrent apply operations")
   332  			}
   333  
   334  			// If we never reach our intended parallelism, the context will
   335  			// never be canceled and the test will time out.
   336  			if len(started) >= par {
   337  				begin()
   338  			}
   339  			<-beginCtx.Done()
   340  
   341  			// do some "work"
   342  			// Not required for correctness, but makes it easier to spot a
   343  			// failure when there is more overlap.
   344  			time.Sleep(10 * time.Millisecond)
   345  
   346  			return providers.ApplyResourceChangeResponse{
   347  				NewState: cty.EmptyObjectVal,
   348  			}
   349  		}
   350  		providerFactories[addrs.NewDefaultProvider(name)] = providers.FactoryFixed(provider)
   351  	}
   352  	testingOverrides := &testingOverrides{
   353  		Providers: providerFactories,
   354  	}
   355  
   356  	view, done := testView(t)
   357  	c := &ApplyCommand{
   358  		Meta: Meta{
   359  			testingOverrides: testingOverrides,
   360  			View:             view,
   361  		},
   362  	}
   363  
   364  	args := []string{
   365  		"-state", statePath,
   366  		"-auto-approve",
   367  		fmt.Sprintf("-parallelism=%d", par),
   368  	}
   369  
   370  	res := c.Run(args)
   371  	output := done(t)
   372  	if res != 0 {
   373  		t.Fatal(output.Stdout())
   374  	}
   375  }
   376  
   377  func TestApply_configInvalid(t *testing.T) {
   378  	// Create a temporary working directory that is empty
   379  	td := tempDir(t)
   380  	testCopyDir(t, testFixturePath("apply-config-invalid"), td)
   381  	defer os.RemoveAll(td)
   382  	defer testChdir(t, td)()
   383  
   384  	p := testProvider()
   385  	view, done := testView(t)
   386  	c := &ApplyCommand{
   387  		Meta: Meta{
   388  			testingOverrides: metaOverridesForProvider(p),
   389  			View:             view,
   390  		},
   391  	}
   392  
   393  	args := []string{
   394  		"-state", testTempFile(t),
   395  		"-auto-approve",
   396  	}
   397  	code := c.Run(args)
   398  	output := done(t)
   399  	if code != 1 {
   400  		t.Fatalf("bad: \n%s", output.Stdout())
   401  	}
   402  }
   403  
   404  func TestApply_defaultState(t *testing.T) {
   405  	// Create a temporary working directory that is empty
   406  	td := tempDir(t)
   407  	testCopyDir(t, testFixturePath("apply"), td)
   408  	defer os.RemoveAll(td)
   409  	defer testChdir(t, td)()
   410  
   411  	statePath := filepath.Join(td, DefaultStateFilename)
   412  
   413  	// Change to the temporary directory
   414  	cwd, err := os.Getwd()
   415  	if err != nil {
   416  		t.Fatalf("err: %s", err)
   417  	}
   418  	if err := os.Chdir(filepath.Dir(statePath)); err != nil {
   419  		t.Fatalf("err: %s", err)
   420  	}
   421  	defer os.Chdir(cwd)
   422  
   423  	p := applyFixtureProvider()
   424  	view, done := testView(t)
   425  	c := &ApplyCommand{
   426  		Meta: Meta{
   427  			testingOverrides: metaOverridesForProvider(p),
   428  			View:             view,
   429  		},
   430  	}
   431  
   432  	// create an existing state file
   433  	localState := statemgr.NewFilesystem(statePath)
   434  	if err := localState.WriteState(states.NewState()); err != nil {
   435  		t.Fatal(err)
   436  	}
   437  
   438  	args := []string{
   439  		"-auto-approve",
   440  	}
   441  	code := c.Run(args)
   442  	output := done(t)
   443  	if code != 0 {
   444  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   445  	}
   446  
   447  	if _, err := os.Stat(statePath); err != nil {
   448  		t.Fatalf("err: %s", err)
   449  	}
   450  
   451  	state := testStateRead(t, statePath)
   452  	if state == nil {
   453  		t.Fatal("state should not be nil")
   454  	}
   455  }
   456  
   457  func TestApply_error(t *testing.T) {
   458  	// Create a temporary working directory that is empty
   459  	td := tempDir(t)
   460  	testCopyDir(t, testFixturePath("apply-error"), td)
   461  	defer os.RemoveAll(td)
   462  	defer testChdir(t, td)()
   463  
   464  	statePath := testTempFile(t)
   465  
   466  	p := testProvider()
   467  	view, done := testView(t)
   468  	c := &ApplyCommand{
   469  		Meta: Meta{
   470  			testingOverrides: metaOverridesForProvider(p),
   471  			View:             view,
   472  		},
   473  	}
   474  
   475  	var lock sync.Mutex
   476  	errored := false
   477  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   478  		lock.Lock()
   479  		defer lock.Unlock()
   480  
   481  		if !errored {
   482  			errored = true
   483  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
   484  		}
   485  
   486  		s := req.PlannedState.AsValueMap()
   487  		s["id"] = cty.StringVal("foo")
   488  
   489  		resp.NewState = cty.ObjectVal(s)
   490  		return
   491  	}
   492  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   493  		s := req.ProposedNewState.AsValueMap()
   494  		s["id"] = cty.UnknownVal(cty.String)
   495  		resp.PlannedState = cty.ObjectVal(s)
   496  		return
   497  	}
   498  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   499  		ResourceTypes: map[string]providers.Schema{
   500  			"test_instance": {
   501  				Block: &configschema.Block{
   502  					Attributes: map[string]*configschema.Attribute{
   503  						"id":    {Type: cty.String, Optional: true, Computed: true},
   504  						"ami":   {Type: cty.String, Optional: true},
   505  						"error": {Type: cty.Bool, Optional: true},
   506  					},
   507  				},
   508  			},
   509  		},
   510  	}
   511  
   512  	args := []string{
   513  		"-state", statePath,
   514  		"-auto-approve",
   515  	}
   516  	code := c.Run(args)
   517  	output := done(t)
   518  	if code != 1 {
   519  		t.Fatalf("wrong exit code %d; want 1\n%s", code, output.Stdout())
   520  	}
   521  
   522  	if _, err := os.Stat(statePath); err != nil {
   523  		t.Fatalf("err: %s", err)
   524  	}
   525  
   526  	state := testStateRead(t, statePath)
   527  	if state == nil {
   528  		t.Fatal("state should not be nil")
   529  	}
   530  	if len(state.RootModule().Resources) == 0 {
   531  		t.Fatal("no resources in state")
   532  	}
   533  }
   534  
   535  func TestApply_input(t *testing.T) {
   536  	// Create a temporary working directory that is empty
   537  	td := tempDir(t)
   538  	testCopyDir(t, testFixturePath("apply-input"), td)
   539  	defer os.RemoveAll(td)
   540  	defer testChdir(t, td)()
   541  
   542  	// Disable test mode so input would be asked
   543  	test = false
   544  	defer func() { test = true }()
   545  
   546  	// The configuration for this test includes a declaration of variable
   547  	// "foo" with no default, and we don't set it on the command line below,
   548  	// so the apply command will produce an interactive prompt for the
   549  	// value of var.foo. We'll answer "foo" here, and we expect the output
   550  	// value "result" to echo that back to us below.
   551  	defaultInputReader = bytes.NewBufferString("foo\n")
   552  	defaultInputWriter = new(bytes.Buffer)
   553  
   554  	statePath := testTempFile(t)
   555  
   556  	p := testProvider()
   557  	view, done := testView(t)
   558  	c := &ApplyCommand{
   559  		Meta: Meta{
   560  			testingOverrides: metaOverridesForProvider(p),
   561  			View:             view,
   562  		},
   563  	}
   564  
   565  	args := []string{
   566  		"-state", statePath,
   567  		"-auto-approve",
   568  	}
   569  	code := c.Run(args)
   570  	output := done(t)
   571  	if code != 0 {
   572  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   573  	}
   574  
   575  	expected := strings.TrimSpace(`
   576  <no state>
   577  Outputs:
   578  
   579  result = foo
   580  	`)
   581  	testStateOutput(t, statePath, expected)
   582  }
   583  
   584  // When only a partial set of the variables are set, Terraform
   585  // should still ask for the unset ones by default (with -input=true)
   586  func TestApply_inputPartial(t *testing.T) {
   587  	// Create a temporary working directory that is empty
   588  	td := tempDir(t)
   589  	testCopyDir(t, testFixturePath("apply-input-partial"), td)
   590  	defer os.RemoveAll(td)
   591  	defer testChdir(t, td)()
   592  
   593  	// Disable test mode so input would be asked
   594  	test = false
   595  	defer func() { test = true }()
   596  
   597  	// Set some default reader/writers for the inputs
   598  	defaultInputReader = bytes.NewBufferString("one\ntwo\n")
   599  	defaultInputWriter = new(bytes.Buffer)
   600  
   601  	statePath := testTempFile(t)
   602  
   603  	p := testProvider()
   604  	view, done := testView(t)
   605  	c := &ApplyCommand{
   606  		Meta: Meta{
   607  			testingOverrides: metaOverridesForProvider(p),
   608  			View:             view,
   609  		},
   610  	}
   611  
   612  	args := []string{
   613  		"-state", statePath,
   614  		"-auto-approve",
   615  		"-var", "foo=foovalue",
   616  	}
   617  	code := c.Run(args)
   618  	output := done(t)
   619  	if code != 0 {
   620  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   621  	}
   622  
   623  	expected := strings.TrimSpace(`
   624  <no state>
   625  Outputs:
   626  
   627  bar = one
   628  foo = foovalue
   629  	`)
   630  	testStateOutput(t, statePath, expected)
   631  }
   632  
   633  func TestApply_noArgs(t *testing.T) {
   634  	// Create a temporary working directory that is empty
   635  	td := tempDir(t)
   636  	testCopyDir(t, testFixturePath("apply"), td)
   637  	defer os.RemoveAll(td)
   638  	defer testChdir(t, td)()
   639  
   640  	statePath := testTempFile(t)
   641  
   642  	p := applyFixtureProvider()
   643  	view, done := testView(t)
   644  	c := &ApplyCommand{
   645  		Meta: Meta{
   646  			testingOverrides: metaOverridesForProvider(p),
   647  			View:             view,
   648  		},
   649  	}
   650  
   651  	args := []string{
   652  		"-state", statePath,
   653  		"-auto-approve",
   654  	}
   655  	code := c.Run(args)
   656  	output := done(t)
   657  	if code != 0 {
   658  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   659  	}
   660  
   661  	if _, err := os.Stat(statePath); err != nil {
   662  		t.Fatalf("err: %s", err)
   663  	}
   664  
   665  	state := testStateRead(t, statePath)
   666  	if state == nil {
   667  		t.Fatal("state should not be nil")
   668  	}
   669  }
   670  
   671  func TestApply_plan(t *testing.T) {
   672  	// Disable test mode so input would be asked
   673  	test = false
   674  	defer func() { test = true }()
   675  
   676  	// Set some default reader/writers for the inputs
   677  	defaultInputReader = new(bytes.Buffer)
   678  	defaultInputWriter = new(bytes.Buffer)
   679  
   680  	planPath := applyFixturePlanFile(t)
   681  	statePath := testTempFile(t)
   682  
   683  	p := applyFixtureProvider()
   684  	view, done := testView(t)
   685  	c := &ApplyCommand{
   686  		Meta: Meta{
   687  			testingOverrides: metaOverridesForProvider(p),
   688  			View:             view,
   689  		},
   690  	}
   691  
   692  	args := []string{
   693  		"-state-out", statePath,
   694  		planPath,
   695  	}
   696  	code := c.Run(args)
   697  	output := done(t)
   698  	if code != 0 {
   699  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   700  	}
   701  
   702  	if _, err := os.Stat(statePath); err != nil {
   703  		t.Fatalf("err: %s", err)
   704  	}
   705  
   706  	state := testStateRead(t, statePath)
   707  	if state == nil {
   708  		t.Fatal("state should not be nil")
   709  	}
   710  }
   711  
   712  func TestApply_plan_backup(t *testing.T) {
   713  	statePath := testTempFile(t)
   714  	backupPath := testTempFile(t)
   715  
   716  	p := applyFixtureProvider()
   717  	view, done := testView(t)
   718  	c := &ApplyCommand{
   719  		Meta: Meta{
   720  			testingOverrides: metaOverridesForProvider(p),
   721  			View:             view,
   722  		},
   723  	}
   724  
   725  	// create a state file that needs to be backed up
   726  	fs := statemgr.NewFilesystem(statePath)
   727  	fs.StateSnapshotMeta()
   728  	err := fs.WriteState(states.NewState())
   729  	if err != nil {
   730  		t.Fatal(err)
   731  	}
   732  
   733  	// the plan file must contain the metadata from the prior state to be
   734  	// backed up
   735  	planPath := applyFixturePlanFileMatchState(t, fs.StateSnapshotMeta())
   736  
   737  	args := []string{
   738  		"-state", statePath,
   739  		"-backup", backupPath,
   740  		planPath,
   741  	}
   742  	code := c.Run(args)
   743  	output := done(t)
   744  	if code != 0 {
   745  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   746  	}
   747  
   748  	// Should have a backup file
   749  	testStateRead(t, backupPath)
   750  }
   751  
   752  func TestApply_plan_noBackup(t *testing.T) {
   753  	planPath := applyFixturePlanFile(t)
   754  	statePath := testTempFile(t)
   755  
   756  	p := applyFixtureProvider()
   757  	view, done := testView(t)
   758  	c := &ApplyCommand{
   759  		Meta: Meta{
   760  			testingOverrides: metaOverridesForProvider(p),
   761  			View:             view,
   762  		},
   763  	}
   764  
   765  	args := []string{
   766  		"-state-out", statePath,
   767  		"-backup", "-",
   768  		planPath,
   769  	}
   770  	code := c.Run(args)
   771  	output := done(t)
   772  	if code != 0 {
   773  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   774  	}
   775  
   776  	// Ensure there is no backup
   777  	_, err := os.Stat(statePath + DefaultBackupExtension)
   778  	if err == nil || !os.IsNotExist(err) {
   779  		t.Fatalf("backup should not exist")
   780  	}
   781  
   782  	// Ensure there is no literal "-"
   783  	_, err = os.Stat("-")
   784  	if err == nil || !os.IsNotExist(err) {
   785  		t.Fatalf("backup should not exist")
   786  	}
   787  }
   788  
   789  func TestApply_plan_remoteState(t *testing.T) {
   790  	// Disable test mode so input would be asked
   791  	test = false
   792  	defer func() { test = true }()
   793  	tmp, cwd := testCwd(t)
   794  	defer testFixCwd(t, tmp, cwd)
   795  	remoteStatePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
   796  	if err := os.MkdirAll(filepath.Dir(remoteStatePath), 0755); err != nil {
   797  		t.Fatalf("err: %s", err)
   798  	}
   799  
   800  	// Set some default reader/writers for the inputs
   801  	defaultInputReader = new(bytes.Buffer)
   802  	defaultInputWriter = new(bytes.Buffer)
   803  
   804  	// Create a remote state
   805  	state := testState()
   806  	_, srv := testRemoteState(t, state, 200)
   807  	defer srv.Close()
   808  
   809  	_, snap := testModuleWithSnapshot(t, "apply")
   810  	backendConfig := cty.ObjectVal(map[string]cty.Value{
   811  		"address":                cty.StringVal(srv.URL),
   812  		"update_method":          cty.NullVal(cty.String),
   813  		"lock_address":           cty.NullVal(cty.String),
   814  		"unlock_address":         cty.NullVal(cty.String),
   815  		"lock_method":            cty.NullVal(cty.String),
   816  		"unlock_method":          cty.NullVal(cty.String),
   817  		"username":               cty.NullVal(cty.String),
   818  		"password":               cty.NullVal(cty.String),
   819  		"skip_cert_verification": cty.NullVal(cty.Bool),
   820  		"retry_max":              cty.NullVal(cty.String),
   821  		"retry_wait_min":         cty.NullVal(cty.String),
   822  		"retry_wait_max":         cty.NullVal(cty.String),
   823  	})
   824  	backendConfigRaw, err := plans.NewDynamicValue(backendConfig, backendConfig.Type())
   825  	if err != nil {
   826  		t.Fatal(err)
   827  	}
   828  	planPath := testPlanFile(t, snap, state, &plans.Plan{
   829  		Backend: plans.Backend{
   830  			Type:   "http",
   831  			Config: backendConfigRaw,
   832  		},
   833  		Changes: plans.NewChanges(),
   834  	})
   835  
   836  	p := testProvider()
   837  	view, done := testView(t)
   838  	c := &ApplyCommand{
   839  		Meta: Meta{
   840  			testingOverrides: metaOverridesForProvider(p),
   841  			View:             view,
   842  		},
   843  	}
   844  
   845  	args := []string{
   846  		planPath,
   847  	}
   848  	code := c.Run(args)
   849  	output := done(t)
   850  	if code != 0 {
   851  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   852  	}
   853  
   854  	// State file should be not be installed
   855  	if _, err := os.Stat(filepath.Join(tmp, DefaultStateFilename)); err == nil {
   856  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   857  		t.Fatalf("State path should not exist: %s", string(data))
   858  	}
   859  
   860  	// Check that there is no remote state config
   861  	if src, err := ioutil.ReadFile(remoteStatePath); err == nil {
   862  		t.Fatalf("has %s file; should not\n%s", remoteStatePath, src)
   863  	}
   864  }
   865  
   866  func TestApply_planWithVarFile(t *testing.T) {
   867  	varFileDir := testTempDir(t)
   868  	varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
   869  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
   870  		t.Fatalf("err: %s", err)
   871  	}
   872  
   873  	planPath := applyFixturePlanFile(t)
   874  	statePath := testTempFile(t)
   875  
   876  	cwd, err := os.Getwd()
   877  	if err != nil {
   878  		t.Fatalf("err: %s", err)
   879  	}
   880  	if err := os.Chdir(varFileDir); err != nil {
   881  		t.Fatalf("err: %s", err)
   882  	}
   883  	defer os.Chdir(cwd)
   884  
   885  	p := applyFixtureProvider()
   886  	view, done := testView(t)
   887  	c := &ApplyCommand{
   888  		Meta: Meta{
   889  			testingOverrides: metaOverridesForProvider(p),
   890  			View:             view,
   891  		},
   892  	}
   893  
   894  	args := []string{
   895  		"-state-out", statePath,
   896  		planPath,
   897  	}
   898  	code := c.Run(args)
   899  	output := done(t)
   900  	if code != 0 {
   901  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   902  	}
   903  
   904  	if _, err := os.Stat(statePath); err != nil {
   905  		t.Fatalf("err: %s", err)
   906  	}
   907  
   908  	state := testStateRead(t, statePath)
   909  	if state == nil {
   910  		t.Fatal("state should not be nil")
   911  	}
   912  }
   913  
   914  func TestApply_planVars(t *testing.T) {
   915  	planPath := applyFixturePlanFile(t)
   916  	statePath := testTempFile(t)
   917  
   918  	p := applyFixtureProvider()
   919  	view, done := testView(t)
   920  	c := &ApplyCommand{
   921  		Meta: Meta{
   922  			testingOverrides: metaOverridesForProvider(p),
   923  			View:             view,
   924  		},
   925  	}
   926  
   927  	args := []string{
   928  		"-state", statePath,
   929  		"-var", "foo=bar",
   930  		planPath,
   931  	}
   932  	code := c.Run(args)
   933  	output := done(t)
   934  	if code == 0 {
   935  		t.Fatal("should've failed: ", output.Stdout())
   936  	}
   937  }
   938  
   939  // we should be able to apply a plan file with no other file dependencies
   940  func TestApply_planNoModuleFiles(t *testing.T) {
   941  	// temporary data directory which we can remove between commands
   942  	td := testTempDir(t)
   943  	defer os.RemoveAll(td)
   944  
   945  	defer testChdir(t, td)()
   946  
   947  	p := applyFixtureProvider()
   948  	planPath := applyFixturePlanFile(t)
   949  	view, done := testView(t)
   950  	apply := &ApplyCommand{
   951  		Meta: Meta{
   952  			testingOverrides: metaOverridesForProvider(p),
   953  			Ui:               new(cli.MockUi),
   954  			View:             view,
   955  		},
   956  	}
   957  	args := []string{
   958  		planPath,
   959  	}
   960  	apply.Run(args)
   961  	done(t)
   962  }
   963  
   964  func TestApply_refresh(t *testing.T) {
   965  	// Create a temporary working directory that is empty
   966  	td := tempDir(t)
   967  	testCopyDir(t, testFixturePath("apply"), td)
   968  	defer os.RemoveAll(td)
   969  	defer testChdir(t, td)()
   970  
   971  	originalState := states.BuildState(func(s *states.SyncState) {
   972  		s.SetResourceInstanceCurrent(
   973  			addrs.Resource{
   974  				Mode: addrs.ManagedResourceMode,
   975  				Type: "test_instance",
   976  				Name: "foo",
   977  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   978  			&states.ResourceInstanceObjectSrc{
   979  				AttrsJSON: []byte(`{"ami":"bar"}`),
   980  				Status:    states.ObjectReady,
   981  			},
   982  			addrs.AbsProviderConfig{
   983  				Provider: addrs.NewDefaultProvider("test"),
   984  				Module:   addrs.RootModule,
   985  			},
   986  		)
   987  	})
   988  	statePath := testStateFile(t, originalState)
   989  
   990  	p := applyFixtureProvider()
   991  	view, done := testView(t)
   992  	c := &ApplyCommand{
   993  		Meta: Meta{
   994  			testingOverrides: metaOverridesForProvider(p),
   995  			View:             view,
   996  		},
   997  	}
   998  
   999  	args := []string{
  1000  		"-state", statePath,
  1001  		"-auto-approve",
  1002  	}
  1003  	code := c.Run(args)
  1004  	output := done(t)
  1005  	if code != 0 {
  1006  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1007  	}
  1008  
  1009  	if !p.ReadResourceCalled {
  1010  		t.Fatal("should call ReadResource")
  1011  	}
  1012  
  1013  	if _, err := os.Stat(statePath); err != nil {
  1014  		t.Fatalf("err: %s", err)
  1015  	}
  1016  
  1017  	state := testStateRead(t, statePath)
  1018  	if state == nil {
  1019  		t.Fatal("state should not be nil")
  1020  	}
  1021  
  1022  	// Should have a backup file
  1023  	backupState := testStateRead(t, statePath+DefaultBackupExtension)
  1024  
  1025  	actualStr := strings.TrimSpace(backupState.String())
  1026  	expectedStr := strings.TrimSpace(originalState.String())
  1027  	if actualStr != expectedStr {
  1028  		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
  1029  	}
  1030  }
  1031  
  1032  func TestApply_refreshFalse(t *testing.T) {
  1033  	// Create a temporary working directory that is empty
  1034  	td := tempDir(t)
  1035  	testCopyDir(t, testFixturePath("apply"), td)
  1036  	defer os.RemoveAll(td)
  1037  	defer testChdir(t, td)()
  1038  
  1039  	originalState := states.BuildState(func(s *states.SyncState) {
  1040  		s.SetResourceInstanceCurrent(
  1041  			addrs.Resource{
  1042  				Mode: addrs.ManagedResourceMode,
  1043  				Type: "test_instance",
  1044  				Name: "foo",
  1045  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1046  			&states.ResourceInstanceObjectSrc{
  1047  				AttrsJSON: []byte(`{"ami":"bar"}`),
  1048  				Status:    states.ObjectReady,
  1049  			},
  1050  			addrs.AbsProviderConfig{
  1051  				Provider: addrs.NewDefaultProvider("test"),
  1052  				Module:   addrs.RootModule,
  1053  			},
  1054  		)
  1055  	})
  1056  	statePath := testStateFile(t, originalState)
  1057  
  1058  	p := applyFixtureProvider()
  1059  	view, done := testView(t)
  1060  	c := &ApplyCommand{
  1061  		Meta: Meta{
  1062  			testingOverrides: metaOverridesForProvider(p),
  1063  			View:             view,
  1064  		},
  1065  	}
  1066  
  1067  	args := []string{
  1068  		"-state", statePath,
  1069  		"-auto-approve",
  1070  		"-refresh=false",
  1071  	}
  1072  	code := c.Run(args)
  1073  	output := done(t)
  1074  	if code != 0 {
  1075  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1076  	}
  1077  
  1078  	if p.ReadResourceCalled {
  1079  		t.Fatal("should not call ReadResource when refresh=false")
  1080  	}
  1081  }
  1082  func TestApply_shutdown(t *testing.T) {
  1083  	// Create a temporary working directory that is empty
  1084  	td := tempDir(t)
  1085  	testCopyDir(t, testFixturePath("apply-shutdown"), td)
  1086  	defer os.RemoveAll(td)
  1087  	defer testChdir(t, td)()
  1088  
  1089  	cancelled := make(chan struct{})
  1090  	shutdownCh := make(chan struct{})
  1091  
  1092  	statePath := testTempFile(t)
  1093  	p := testProvider()
  1094  
  1095  	view, done := testView(t)
  1096  	c := &ApplyCommand{
  1097  		Meta: Meta{
  1098  			testingOverrides: metaOverridesForProvider(p),
  1099  			View:             view,
  1100  			ShutdownCh:       shutdownCh,
  1101  		},
  1102  	}
  1103  
  1104  	p.StopFn = func() error {
  1105  		close(cancelled)
  1106  		return nil
  1107  	}
  1108  
  1109  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  1110  		resp.PlannedState = req.ProposedNewState
  1111  		return
  1112  	}
  1113  
  1114  	var once sync.Once
  1115  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  1116  		// only cancel once
  1117  		once.Do(func() {
  1118  			shutdownCh <- struct{}{}
  1119  		})
  1120  
  1121  		// Because of the src lock in the MockProvider, we can't
  1122  		// coordiante directly with the calling of Stop, and making the
  1123  		// MockProvider concurrent is disruptive to a lot of existing tests.
  1124  		// Wait here a moment to help make sure the main goroutine gets to the
  1125  		// Stop call before we exit, or the plan may finish before it can be
  1126  		// canceled.
  1127  		time.Sleep(200 * time.Millisecond)
  1128  
  1129  		resp.NewState = req.PlannedState
  1130  		return
  1131  	}
  1132  
  1133  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1134  		ResourceTypes: map[string]providers.Schema{
  1135  			"test_instance": {
  1136  				Block: &configschema.Block{
  1137  					Attributes: map[string]*configschema.Attribute{
  1138  						"ami": {Type: cty.String, Optional: true},
  1139  					},
  1140  				},
  1141  			},
  1142  		},
  1143  	}
  1144  
  1145  	args := []string{
  1146  		"-state", statePath,
  1147  		"-auto-approve",
  1148  	}
  1149  	code := c.Run(args)
  1150  	output := done(t)
  1151  	if code != 1 {
  1152  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1153  	}
  1154  
  1155  	if _, err := os.Stat(statePath); err != nil {
  1156  		t.Fatalf("err: %s", err)
  1157  	}
  1158  
  1159  	select {
  1160  	case <-cancelled:
  1161  	default:
  1162  		t.Fatal("command not cancelled")
  1163  	}
  1164  
  1165  	state := testStateRead(t, statePath)
  1166  	if state == nil {
  1167  		t.Fatal("state should not be nil")
  1168  	}
  1169  }
  1170  
  1171  func TestApply_state(t *testing.T) {
  1172  	// Create a temporary working directory that is empty
  1173  	td := tempDir(t)
  1174  	testCopyDir(t, testFixturePath("apply"), td)
  1175  	defer os.RemoveAll(td)
  1176  	defer testChdir(t, td)()
  1177  
  1178  	originalState := states.BuildState(func(s *states.SyncState) {
  1179  		s.SetResourceInstanceCurrent(
  1180  			addrs.Resource{
  1181  				Mode: addrs.ManagedResourceMode,
  1182  				Type: "test_instance",
  1183  				Name: "foo",
  1184  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1185  			&states.ResourceInstanceObjectSrc{
  1186  				AttrsJSON: []byte(`{"ami":"foo"}`),
  1187  				Status:    states.ObjectReady,
  1188  			},
  1189  			addrs.AbsProviderConfig{
  1190  				Provider: addrs.NewDefaultProvider("test"),
  1191  				Module:   addrs.RootModule,
  1192  			},
  1193  		)
  1194  	})
  1195  	statePath := testStateFile(t, originalState)
  1196  
  1197  	p := applyFixtureProvider()
  1198  	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
  1199  		PlannedState: cty.ObjectVal(map[string]cty.Value{
  1200  			"ami": cty.StringVal("bar"),
  1201  		}),
  1202  	}
  1203  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
  1204  		NewState: cty.ObjectVal(map[string]cty.Value{
  1205  			"ami": cty.StringVal("bar"),
  1206  		}),
  1207  	}
  1208  
  1209  	view, done := testView(t)
  1210  	c := &ApplyCommand{
  1211  		Meta: Meta{
  1212  			testingOverrides: metaOverridesForProvider(p),
  1213  			View:             view,
  1214  		},
  1215  	}
  1216  
  1217  	// Run the apply command pointing to our existing state
  1218  	args := []string{
  1219  		"-state", statePath,
  1220  		"-auto-approve",
  1221  	}
  1222  	code := c.Run(args)
  1223  	output := done(t)
  1224  	if code != 0 {
  1225  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1226  	}
  1227  
  1228  	// Verify that the provider was called with the existing state
  1229  	actual := p.PlanResourceChangeRequest.PriorState
  1230  	expected := cty.ObjectVal(map[string]cty.Value{
  1231  		"id":  cty.NullVal(cty.String),
  1232  		"ami": cty.StringVal("foo"),
  1233  	})
  1234  	if !expected.RawEquals(actual) {
  1235  		t.Fatalf("wrong prior state during plan\ngot: %#v\nwant: %#v", actual, expected)
  1236  	}
  1237  
  1238  	actual = p.ApplyResourceChangeRequest.PriorState
  1239  	expected = cty.ObjectVal(map[string]cty.Value{
  1240  		"id":  cty.NullVal(cty.String),
  1241  		"ami": cty.StringVal("foo"),
  1242  	})
  1243  	if !expected.RawEquals(actual) {
  1244  		t.Fatalf("wrong prior state during apply\ngot: %#v\nwant: %#v", actual, expected)
  1245  	}
  1246  
  1247  	// Verify a new state exists
  1248  	if _, err := os.Stat(statePath); err != nil {
  1249  		t.Fatalf("err: %s", err)
  1250  	}
  1251  
  1252  	state := testStateRead(t, statePath)
  1253  	if state == nil {
  1254  		t.Fatal("state should not be nil")
  1255  	}
  1256  
  1257  	backupState := testStateRead(t, statePath+DefaultBackupExtension)
  1258  
  1259  	actualStr := strings.TrimSpace(backupState.String())
  1260  	expectedStr := strings.TrimSpace(originalState.String())
  1261  	if actualStr != expectedStr {
  1262  		t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
  1263  	}
  1264  }
  1265  
  1266  func TestApply_stateNoExist(t *testing.T) {
  1267  	// Create a temporary working directory that is empty
  1268  	td := tempDir(t)
  1269  	testCopyDir(t, testFixturePath("apply"), td)
  1270  	defer os.RemoveAll(td)
  1271  	defer testChdir(t, td)()
  1272  
  1273  	p := applyFixtureProvider()
  1274  	view, done := testView(t)
  1275  	c := &ApplyCommand{
  1276  		Meta: Meta{
  1277  			testingOverrides: metaOverridesForProvider(p),
  1278  			View:             view,
  1279  		},
  1280  	}
  1281  
  1282  	args := []string{
  1283  		"idontexist.tfstate",
  1284  	}
  1285  	code := c.Run(args)
  1286  	output := done(t)
  1287  	if code != 1 {
  1288  		t.Fatalf("bad: \n%s", output.Stdout())
  1289  	}
  1290  }
  1291  
  1292  func TestApply_sensitiveOutput(t *testing.T) {
  1293  	// Create a temporary working directory that is empty
  1294  	td := tempDir(t)
  1295  	testCopyDir(t, testFixturePath("apply-sensitive-output"), td)
  1296  	defer os.RemoveAll(td)
  1297  	defer testChdir(t, td)()
  1298  
  1299  	p := testProvider()
  1300  	view, done := testView(t)
  1301  	c := &ApplyCommand{
  1302  		Meta: Meta{
  1303  			testingOverrides: metaOverridesForProvider(p),
  1304  			View:             view,
  1305  		},
  1306  	}
  1307  
  1308  	statePath := testTempFile(t)
  1309  
  1310  	args := []string{
  1311  		"-state", statePath,
  1312  		"-auto-approve",
  1313  	}
  1314  
  1315  	code := c.Run(args)
  1316  	output := done(t)
  1317  	if code != 0 {
  1318  		t.Fatalf("bad: \n%s", output.Stdout())
  1319  	}
  1320  
  1321  	stdout := output.Stdout()
  1322  	if !strings.Contains(stdout, "notsensitive = \"Hello world\"") {
  1323  		t.Fatalf("bad: output should contain 'notsensitive' output\n%s", stdout)
  1324  	}
  1325  	if !strings.Contains(stdout, "sensitive = <sensitive>") {
  1326  		t.Fatalf("bad: output should contain 'sensitive' output\n%s", stdout)
  1327  	}
  1328  }
  1329  
  1330  func TestApply_vars(t *testing.T) {
  1331  	// Create a temporary working directory that is empty
  1332  	td := tempDir(t)
  1333  	testCopyDir(t, testFixturePath("apply-vars"), td)
  1334  	defer os.RemoveAll(td)
  1335  	defer testChdir(t, td)()
  1336  
  1337  	statePath := testTempFile(t)
  1338  
  1339  	p := testProvider()
  1340  	view, done := testView(t)
  1341  	c := &ApplyCommand{
  1342  		Meta: Meta{
  1343  			testingOverrides: metaOverridesForProvider(p),
  1344  			View:             view,
  1345  		},
  1346  	}
  1347  
  1348  	actual := ""
  1349  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1350  		ResourceTypes: map[string]providers.Schema{
  1351  			"test_instance": {
  1352  				Block: &configschema.Block{
  1353  					Attributes: map[string]*configschema.Attribute{
  1354  						"value": {Type: cty.String, Optional: true},
  1355  					},
  1356  				},
  1357  			},
  1358  		},
  1359  	}
  1360  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1361  		return providers.ApplyResourceChangeResponse{
  1362  			NewState: req.PlannedState,
  1363  		}
  1364  	}
  1365  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1366  		actual = req.ProposedNewState.GetAttr("value").AsString()
  1367  		return providers.PlanResourceChangeResponse{
  1368  			PlannedState: req.ProposedNewState,
  1369  		}
  1370  	}
  1371  
  1372  	args := []string{
  1373  		"-auto-approve",
  1374  		"-var", "foo=bar",
  1375  		"-state", statePath,
  1376  	}
  1377  	code := c.Run(args)
  1378  	output := done(t)
  1379  	if code != 0 {
  1380  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1381  	}
  1382  
  1383  	if actual != "bar" {
  1384  		t.Fatal("didn't work")
  1385  	}
  1386  }
  1387  
  1388  func TestApply_varFile(t *testing.T) {
  1389  	// Create a temporary working directory that is empty
  1390  	td := tempDir(t)
  1391  	testCopyDir(t, testFixturePath("apply-vars"), td)
  1392  	defer os.RemoveAll(td)
  1393  	defer testChdir(t, td)()
  1394  
  1395  	varFilePath := testTempFile(t)
  1396  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
  1397  		t.Fatalf("err: %s", err)
  1398  	}
  1399  
  1400  	statePath := testTempFile(t)
  1401  
  1402  	p := testProvider()
  1403  	view, done := testView(t)
  1404  	c := &ApplyCommand{
  1405  		Meta: Meta{
  1406  			testingOverrides: metaOverridesForProvider(p),
  1407  			View:             view,
  1408  		},
  1409  	}
  1410  
  1411  	actual := ""
  1412  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1413  		ResourceTypes: map[string]providers.Schema{
  1414  			"test_instance": {
  1415  				Block: &configschema.Block{
  1416  					Attributes: map[string]*configschema.Attribute{
  1417  						"value": {Type: cty.String, Optional: true},
  1418  					},
  1419  				},
  1420  			},
  1421  		},
  1422  	}
  1423  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1424  		return providers.ApplyResourceChangeResponse{
  1425  			NewState: req.PlannedState,
  1426  		}
  1427  	}
  1428  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1429  		actual = req.ProposedNewState.GetAttr("value").AsString()
  1430  		return providers.PlanResourceChangeResponse{
  1431  			PlannedState: req.ProposedNewState,
  1432  		}
  1433  	}
  1434  
  1435  	args := []string{
  1436  		"-auto-approve",
  1437  		"-var-file", varFilePath,
  1438  		"-state", statePath,
  1439  	}
  1440  	code := c.Run(args)
  1441  	output := done(t)
  1442  	if code != 0 {
  1443  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1444  	}
  1445  
  1446  	if actual != "bar" {
  1447  		t.Fatal("didn't work")
  1448  	}
  1449  }
  1450  
  1451  func TestApply_varFileDefault(t *testing.T) {
  1452  	// Create a temporary working directory that is empty
  1453  	td := tempDir(t)
  1454  	testCopyDir(t, testFixturePath("apply-vars"), td)
  1455  	defer os.RemoveAll(td)
  1456  	defer testChdir(t, td)()
  1457  
  1458  	varFilePath := filepath.Join(td, "terraform.tfvars")
  1459  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
  1460  		t.Fatalf("err: %s", err)
  1461  	}
  1462  
  1463  	statePath := testTempFile(t)
  1464  
  1465  	p := testProvider()
  1466  	view, done := testView(t)
  1467  	c := &ApplyCommand{
  1468  		Meta: Meta{
  1469  			testingOverrides: metaOverridesForProvider(p),
  1470  			View:             view,
  1471  		},
  1472  	}
  1473  
  1474  	actual := ""
  1475  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1476  		ResourceTypes: map[string]providers.Schema{
  1477  			"test_instance": {
  1478  				Block: &configschema.Block{
  1479  					Attributes: map[string]*configschema.Attribute{
  1480  						"value": {Type: cty.String, Optional: true},
  1481  					},
  1482  				},
  1483  			},
  1484  		},
  1485  	}
  1486  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1487  		return providers.ApplyResourceChangeResponse{
  1488  			NewState: req.PlannedState,
  1489  		}
  1490  	}
  1491  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1492  		actual = req.ProposedNewState.GetAttr("value").AsString()
  1493  		return providers.PlanResourceChangeResponse{
  1494  			PlannedState: req.ProposedNewState,
  1495  		}
  1496  	}
  1497  
  1498  	args := []string{
  1499  		"-auto-approve",
  1500  		"-state", statePath,
  1501  	}
  1502  	code := c.Run(args)
  1503  	output := done(t)
  1504  	if code != 0 {
  1505  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1506  	}
  1507  
  1508  	if actual != "bar" {
  1509  		t.Fatal("didn't work")
  1510  	}
  1511  }
  1512  
  1513  func TestApply_varFileDefaultJSON(t *testing.T) {
  1514  	// Create a temporary working directory that is empty
  1515  	td := tempDir(t)
  1516  	testCopyDir(t, testFixturePath("apply-vars"), td)
  1517  	defer os.RemoveAll(td)
  1518  	defer testChdir(t, td)()
  1519  
  1520  	varFilePath := filepath.Join(td, "terraform.tfvars.json")
  1521  	if err := ioutil.WriteFile(varFilePath, []byte(applyVarFileJSON), 0644); err != nil {
  1522  		t.Fatalf("err: %s", err)
  1523  	}
  1524  
  1525  	statePath := testTempFile(t)
  1526  
  1527  	p := testProvider()
  1528  	view, done := testView(t)
  1529  	c := &ApplyCommand{
  1530  		Meta: Meta{
  1531  			testingOverrides: metaOverridesForProvider(p),
  1532  			View:             view,
  1533  		},
  1534  	}
  1535  
  1536  	actual := ""
  1537  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1538  		ResourceTypes: map[string]providers.Schema{
  1539  			"test_instance": {
  1540  				Block: &configschema.Block{
  1541  					Attributes: map[string]*configschema.Attribute{
  1542  						"value": {Type: cty.String, Optional: true},
  1543  					},
  1544  				},
  1545  			},
  1546  		},
  1547  	}
  1548  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1549  		return providers.ApplyResourceChangeResponse{
  1550  			NewState: req.PlannedState,
  1551  		}
  1552  	}
  1553  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1554  		actual = req.ProposedNewState.GetAttr("value").AsString()
  1555  		return providers.PlanResourceChangeResponse{
  1556  			PlannedState: req.ProposedNewState,
  1557  		}
  1558  	}
  1559  
  1560  	args := []string{
  1561  		"-auto-approve",
  1562  		"-state", statePath,
  1563  	}
  1564  	code := c.Run(args)
  1565  	output := done(t)
  1566  	if code != 0 {
  1567  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1568  	}
  1569  
  1570  	if actual != "bar" {
  1571  		t.Fatal("didn't work")
  1572  	}
  1573  }
  1574  
  1575  func TestApply_backup(t *testing.T) {
  1576  	// Create a temporary working directory that is empty
  1577  	td := tempDir(t)
  1578  	testCopyDir(t, testFixturePath("apply"), td)
  1579  	defer os.RemoveAll(td)
  1580  	defer testChdir(t, td)()
  1581  
  1582  	originalState := states.BuildState(func(s *states.SyncState) {
  1583  		s.SetResourceInstanceCurrent(
  1584  			addrs.Resource{
  1585  				Mode: addrs.ManagedResourceMode,
  1586  				Type: "test_instance",
  1587  				Name: "foo",
  1588  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1589  			&states.ResourceInstanceObjectSrc{
  1590  				AttrsJSON: []byte("{\n            \"id\": \"bar\"\n          }"),
  1591  				Status:    states.ObjectReady,
  1592  			},
  1593  			addrs.AbsProviderConfig{
  1594  				Provider: addrs.NewDefaultProvider("test"),
  1595  				Module:   addrs.RootModule,
  1596  			},
  1597  		)
  1598  	})
  1599  	statePath := testStateFile(t, originalState)
  1600  	backupPath := testTempFile(t)
  1601  
  1602  	p := applyFixtureProvider()
  1603  	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
  1604  		PlannedState: cty.ObjectVal(map[string]cty.Value{
  1605  			"ami": cty.StringVal("bar"),
  1606  		}),
  1607  	}
  1608  
  1609  	view, done := testView(t)
  1610  	c := &ApplyCommand{
  1611  		Meta: Meta{
  1612  			testingOverrides: metaOverridesForProvider(p),
  1613  			View:             view,
  1614  		},
  1615  	}
  1616  
  1617  	// Run the apply command pointing to our existing state
  1618  	args := []string{
  1619  		"-auto-approve",
  1620  		"-state", statePath,
  1621  		"-backup", backupPath,
  1622  	}
  1623  	code := c.Run(args)
  1624  	output := done(t)
  1625  	if code != 0 {
  1626  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1627  	}
  1628  
  1629  	// Verify a new state exists
  1630  	if _, err := os.Stat(statePath); err != nil {
  1631  		t.Fatalf("err: %s", err)
  1632  	}
  1633  
  1634  	state := testStateRead(t, statePath)
  1635  	if state == nil {
  1636  		t.Fatal("state should not be nil")
  1637  	}
  1638  
  1639  	backupState := testStateRead(t, backupPath)
  1640  
  1641  	actual := backupState.RootModule().Resources["test_instance.foo"]
  1642  	expected := originalState.RootModule().Resources["test_instance.foo"]
  1643  	if !cmp.Equal(actual, expected, cmpopts.EquateEmpty()) {
  1644  		t.Fatalf(
  1645  			"wrong aws_instance.foo state\n%s",
  1646  			cmp.Diff(expected, actual, cmp.Transformer("bytesAsString", func(b []byte) string {
  1647  				return string(b)
  1648  			})),
  1649  		)
  1650  	}
  1651  }
  1652  
  1653  func TestApply_disableBackup(t *testing.T) {
  1654  	// Create a temporary working directory that is empty
  1655  	td := tempDir(t)
  1656  	testCopyDir(t, testFixturePath("apply"), td)
  1657  	defer os.RemoveAll(td)
  1658  	defer testChdir(t, td)()
  1659  
  1660  	originalState := testState()
  1661  	statePath := testStateFile(t, originalState)
  1662  
  1663  	p := applyFixtureProvider()
  1664  	p.PlanResourceChangeResponse = &providers.PlanResourceChangeResponse{
  1665  		PlannedState: cty.ObjectVal(map[string]cty.Value{
  1666  			"ami": cty.StringVal("bar"),
  1667  		}),
  1668  	}
  1669  
  1670  	view, done := testView(t)
  1671  	c := &ApplyCommand{
  1672  		Meta: Meta{
  1673  			testingOverrides: metaOverridesForProvider(p),
  1674  			View:             view,
  1675  		},
  1676  	}
  1677  
  1678  	// Run the apply command pointing to our existing state
  1679  	args := []string{
  1680  		"-auto-approve",
  1681  		"-state", statePath,
  1682  		"-backup", "-",
  1683  	}
  1684  	code := c.Run(args)
  1685  	output := done(t)
  1686  	if code != 0 {
  1687  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1688  	}
  1689  
  1690  	// Verify that the provider was called with the existing state
  1691  	actual := p.PlanResourceChangeRequest.PriorState
  1692  	expected := cty.ObjectVal(map[string]cty.Value{
  1693  		"id":  cty.StringVal("bar"),
  1694  		"ami": cty.NullVal(cty.String),
  1695  	})
  1696  	if !expected.RawEquals(actual) {
  1697  		t.Fatalf("wrong prior state during plan\ngot:  %#v\nwant: %#v", actual, expected)
  1698  	}
  1699  
  1700  	actual = p.ApplyResourceChangeRequest.PriorState
  1701  	expected = cty.ObjectVal(map[string]cty.Value{
  1702  		"id":  cty.StringVal("bar"),
  1703  		"ami": cty.NullVal(cty.String),
  1704  	})
  1705  	if !expected.RawEquals(actual) {
  1706  		t.Fatalf("wrong prior state during apply\ngot:  %#v\nwant: %#v", actual, expected)
  1707  	}
  1708  
  1709  	// Verify a new state exists
  1710  	if _, err := os.Stat(statePath); err != nil {
  1711  		t.Fatalf("err: %s", err)
  1712  	}
  1713  
  1714  	state := testStateRead(t, statePath)
  1715  	if state == nil {
  1716  		t.Fatal("state should not be nil")
  1717  	}
  1718  
  1719  	// Ensure there is no backup
  1720  	_, err := os.Stat(statePath + DefaultBackupExtension)
  1721  	if err == nil || !os.IsNotExist(err) {
  1722  		t.Fatalf("backup should not exist")
  1723  	}
  1724  
  1725  	// Ensure there is no literal "-"
  1726  	_, err = os.Stat("-")
  1727  	if err == nil || !os.IsNotExist(err) {
  1728  		t.Fatalf("backup should not exist")
  1729  	}
  1730  }
  1731  
  1732  // Test that the Terraform env is passed through
  1733  func TestApply_terraformEnv(t *testing.T) {
  1734  	// Create a temporary working directory that is empty
  1735  	td := tempDir(t)
  1736  	testCopyDir(t, testFixturePath("apply-terraform-env"), td)
  1737  	defer os.RemoveAll(td)
  1738  	defer testChdir(t, td)()
  1739  
  1740  	statePath := testTempFile(t)
  1741  
  1742  	p := testProvider()
  1743  	view, done := testView(t)
  1744  	c := &ApplyCommand{
  1745  		Meta: Meta{
  1746  			testingOverrides: metaOverridesForProvider(p),
  1747  			View:             view,
  1748  		},
  1749  	}
  1750  
  1751  	args := []string{
  1752  		"-auto-approve",
  1753  		"-state", statePath,
  1754  	}
  1755  	code := c.Run(args)
  1756  	output := done(t)
  1757  	if code != 0 {
  1758  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1759  	}
  1760  
  1761  	expected := strings.TrimSpace(`
  1762  <no state>
  1763  Outputs:
  1764  
  1765  output = default
  1766  	`)
  1767  	testStateOutput(t, statePath, expected)
  1768  }
  1769  
  1770  // Test that the Terraform env is passed through
  1771  func TestApply_terraformEnvNonDefault(t *testing.T) {
  1772  	// Create a temporary working directory that is empty
  1773  	td := tempDir(t)
  1774  	testCopyDir(t, testFixturePath("apply-terraform-env"), td)
  1775  	defer os.RemoveAll(td)
  1776  	defer testChdir(t, td)()
  1777  
  1778  	// Create new env
  1779  	{
  1780  		ui := new(cli.MockUi)
  1781  		newCmd := &WorkspaceNewCommand{
  1782  			Meta: Meta{
  1783  				Ui: ui,
  1784  			},
  1785  		}
  1786  		if code := newCmd.Run([]string{"test"}); code != 0 {
  1787  			t.Fatal("error creating workspace")
  1788  		}
  1789  	}
  1790  
  1791  	// Switch to it
  1792  	{
  1793  		args := []string{"test"}
  1794  		ui := new(cli.MockUi)
  1795  		selCmd := &WorkspaceSelectCommand{
  1796  			Meta: Meta{
  1797  				Ui: ui,
  1798  			},
  1799  		}
  1800  		if code := selCmd.Run(args); code != 0 {
  1801  			t.Fatal("error switching workspace")
  1802  		}
  1803  	}
  1804  
  1805  	p := testProvider()
  1806  	view, done := testView(t)
  1807  	c := &ApplyCommand{
  1808  		Meta: Meta{
  1809  			testingOverrides: metaOverridesForProvider(p),
  1810  			View:             view,
  1811  		},
  1812  	}
  1813  
  1814  	args := []string{
  1815  		"-auto-approve",
  1816  	}
  1817  	code := c.Run(args)
  1818  	output := done(t)
  1819  	if code != 0 {
  1820  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1821  	}
  1822  
  1823  	statePath := filepath.Join("terraform.tfstate.d", "test", "terraform.tfstate")
  1824  	expected := strings.TrimSpace(`
  1825  <no state>
  1826  Outputs:
  1827  
  1828  output = test
  1829  	`)
  1830  	testStateOutput(t, statePath, expected)
  1831  }
  1832  
  1833  // Config with multiple resources, targeting apply of a subset
  1834  func TestApply_targeted(t *testing.T) {
  1835  	td := tempDir(t)
  1836  	testCopyDir(t, testFixturePath("apply-targeted"), td)
  1837  	defer os.RemoveAll(td)
  1838  	defer testChdir(t, td)()
  1839  
  1840  	p := testProvider()
  1841  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1842  		ResourceTypes: map[string]providers.Schema{
  1843  			"test_instance": {
  1844  				Block: &configschema.Block{
  1845  					Attributes: map[string]*configschema.Attribute{
  1846  						"id": {Type: cty.String, Computed: true},
  1847  					},
  1848  				},
  1849  			},
  1850  		},
  1851  	}
  1852  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1853  		return providers.PlanResourceChangeResponse{
  1854  			PlannedState: req.ProposedNewState,
  1855  		}
  1856  	}
  1857  
  1858  	view, done := testView(t)
  1859  	c := &ApplyCommand{
  1860  		Meta: Meta{
  1861  			testingOverrides: metaOverridesForProvider(p),
  1862  			View:             view,
  1863  		},
  1864  	}
  1865  
  1866  	args := []string{
  1867  		"-auto-approve",
  1868  		"-target", "test_instance.foo",
  1869  		"-target", "test_instance.baz",
  1870  	}
  1871  	code := c.Run(args)
  1872  	output := done(t)
  1873  	if code != 0 {
  1874  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1875  	}
  1876  
  1877  	if got, want := output.Stdout(), "3 added, 0 changed, 0 destroyed"; !strings.Contains(got, want) {
  1878  		t.Fatalf("bad change summary, want %q, got:\n%s", want, got)
  1879  	}
  1880  }
  1881  
  1882  // Diagnostics for invalid -target flags
  1883  func TestApply_targetFlagsDiags(t *testing.T) {
  1884  	testCases := map[string]string{
  1885  		"test_instance.": "Dot must be followed by attribute name.",
  1886  		"test_instance":  "Resource specification must include a resource type and name.",
  1887  	}
  1888  
  1889  	for target, wantDiag := range testCases {
  1890  		t.Run(target, func(t *testing.T) {
  1891  			td := testTempDir(t)
  1892  			defer os.RemoveAll(td)
  1893  			defer testChdir(t, td)()
  1894  
  1895  			view, done := testView(t)
  1896  			c := &ApplyCommand{
  1897  				Meta: Meta{
  1898  					View: view,
  1899  				},
  1900  			}
  1901  
  1902  			args := []string{
  1903  				"-auto-approve",
  1904  				"-target", target,
  1905  			}
  1906  			code := c.Run(args)
  1907  			output := done(t)
  1908  			if code != 1 {
  1909  				t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  1910  			}
  1911  
  1912  			got := output.Stderr()
  1913  			if !strings.Contains(got, target) {
  1914  				t.Fatalf("bad error output, want %q, got:\n%s", target, got)
  1915  			}
  1916  			if !strings.Contains(got, wantDiag) {
  1917  				t.Fatalf("bad error output, want %q, got:\n%s", wantDiag, got)
  1918  			}
  1919  		})
  1920  	}
  1921  }
  1922  
  1923  func TestApply_replace(t *testing.T) {
  1924  	td := tempDir(t)
  1925  	testCopyDir(t, testFixturePath("apply-replace"), td)
  1926  	defer os.RemoveAll(td)
  1927  	defer testChdir(t, td)()
  1928  
  1929  	originalState := states.BuildState(func(s *states.SyncState) {
  1930  		s.SetResourceInstanceCurrent(
  1931  			addrs.Resource{
  1932  				Mode: addrs.ManagedResourceMode,
  1933  				Type: "test_instance",
  1934  				Name: "a",
  1935  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1936  			&states.ResourceInstanceObjectSrc{
  1937  				AttrsJSON: []byte(`{"id":"hello"}`),
  1938  				Status:    states.ObjectReady,
  1939  			},
  1940  			addrs.AbsProviderConfig{
  1941  				Provider: addrs.NewDefaultProvider("test"),
  1942  				Module:   addrs.RootModule,
  1943  			},
  1944  		)
  1945  	})
  1946  	statePath := testStateFile(t, originalState)
  1947  
  1948  	p := testProvider()
  1949  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1950  		ResourceTypes: map[string]providers.Schema{
  1951  			"test_instance": {
  1952  				Block: &configschema.Block{
  1953  					Attributes: map[string]*configschema.Attribute{
  1954  						"id": {Type: cty.String, Computed: true},
  1955  					},
  1956  				},
  1957  			},
  1958  		},
  1959  	}
  1960  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1961  		return providers.PlanResourceChangeResponse{
  1962  			PlannedState: req.ProposedNewState,
  1963  		}
  1964  	}
  1965  	createCount := 0
  1966  	deleteCount := 0
  1967  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1968  		if req.PriorState.IsNull() {
  1969  			createCount++
  1970  		}
  1971  		if req.PlannedState.IsNull() {
  1972  			deleteCount++
  1973  		}
  1974  		return providers.ApplyResourceChangeResponse{
  1975  			NewState: req.PlannedState,
  1976  		}
  1977  	}
  1978  
  1979  	view, done := testView(t)
  1980  	c := &ApplyCommand{
  1981  		Meta: Meta{
  1982  			testingOverrides: metaOverridesForProvider(p),
  1983  			View:             view,
  1984  		},
  1985  	}
  1986  
  1987  	args := []string{
  1988  		"-auto-approve",
  1989  		"-state", statePath,
  1990  		"-replace", "test_instance.a",
  1991  	}
  1992  	code := c.Run(args)
  1993  	output := done(t)
  1994  	if code != 0 {
  1995  		t.Fatalf("wrong exit code %d\n\n%s", code, output.Stderr())
  1996  	}
  1997  
  1998  	if got, want := output.Stdout(), "1 added, 0 changed, 1 destroyed"; !strings.Contains(got, want) {
  1999  		t.Errorf("wrong change summary\ngot output:\n%s\n\nwant substring: %s", got, want)
  2000  	}
  2001  
  2002  	if got, want := createCount, 1; got != want {
  2003  		t.Errorf("wrong create count %d; want %d", got, want)
  2004  	}
  2005  	if got, want := deleteCount, 1; got != want {
  2006  		t.Errorf("wrong create count %d; want %d", got, want)
  2007  	}
  2008  }
  2009  
  2010  func TestApply_pluginPath(t *testing.T) {
  2011  	// Create a temporary working directory that is empty
  2012  	td := tempDir(t)
  2013  	testCopyDir(t, testFixturePath("apply"), td)
  2014  	defer os.RemoveAll(td)
  2015  	defer testChdir(t, td)()
  2016  
  2017  	statePath := testTempFile(t)
  2018  
  2019  	p := applyFixtureProvider()
  2020  
  2021  	view, done := testView(t)
  2022  	c := &ApplyCommand{
  2023  		Meta: Meta{
  2024  			testingOverrides: metaOverridesForProvider(p),
  2025  			View:             view,
  2026  		},
  2027  	}
  2028  
  2029  	pluginPath := []string{"a", "b", "c"}
  2030  
  2031  	if err := c.Meta.storePluginPath(pluginPath); err != nil {
  2032  		t.Fatal(err)
  2033  	}
  2034  	c.Meta.pluginPath = nil
  2035  
  2036  	args := []string{
  2037  		"-state", statePath,
  2038  		"-auto-approve",
  2039  	}
  2040  	code := c.Run(args)
  2041  	output := done(t)
  2042  	if code != 0 {
  2043  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  2044  	}
  2045  
  2046  	if !reflect.DeepEqual(pluginPath, c.Meta.pluginPath) {
  2047  		t.Fatalf("expected plugin path %#v, got %#v", pluginPath, c.Meta.pluginPath)
  2048  	}
  2049  }
  2050  
  2051  func TestApply_jsonGoldenReference(t *testing.T) {
  2052  	// Create a temporary working directory that is empty
  2053  	td := tempDir(t)
  2054  	testCopyDir(t, testFixturePath("apply"), td)
  2055  	defer os.RemoveAll(td)
  2056  	defer testChdir(t, td)()
  2057  
  2058  	statePath := testTempFile(t)
  2059  
  2060  	p := applyFixtureProvider()
  2061  
  2062  	view, done := testView(t)
  2063  	c := &ApplyCommand{
  2064  		Meta: Meta{
  2065  			testingOverrides: metaOverridesForProvider(p),
  2066  			View:             view,
  2067  		},
  2068  	}
  2069  
  2070  	args := []string{
  2071  		"-json",
  2072  		"-state", statePath,
  2073  		"-auto-approve",
  2074  	}
  2075  	code := c.Run(args)
  2076  	output := done(t)
  2077  	if code != 0 {
  2078  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  2079  	}
  2080  
  2081  	if _, err := os.Stat(statePath); err != nil {
  2082  		t.Fatalf("err: %s", err)
  2083  	}
  2084  
  2085  	state := testStateRead(t, statePath)
  2086  	if state == nil {
  2087  		t.Fatal("state should not be nil")
  2088  	}
  2089  
  2090  	// Load the golden reference fixture
  2091  	wantFile, err := os.Open(path.Join(testFixturePath("apply"), "output.jsonlog"))
  2092  	if err != nil {
  2093  		t.Fatalf("failed to open output file: %s", err)
  2094  	}
  2095  	defer wantFile.Close()
  2096  	wantBytes, err := ioutil.ReadAll(wantFile)
  2097  	if err != nil {
  2098  		t.Fatalf("failed to read output file: %s", err)
  2099  	}
  2100  	want := string(wantBytes)
  2101  
  2102  	got := output.Stdout()
  2103  
  2104  	// Split the output and the reference into lines so that we can compare
  2105  	// messages
  2106  	got = strings.TrimSuffix(got, "\n")
  2107  	gotLines := strings.Split(got, "\n")
  2108  
  2109  	want = strings.TrimSuffix(want, "\n")
  2110  	wantLines := strings.Split(want, "\n")
  2111  
  2112  	if len(gotLines) != len(wantLines) {
  2113  		t.Errorf("unexpected number of log lines: got %d, want %d", len(gotLines), len(wantLines))
  2114  	}
  2115  
  2116  	// Verify that the log starts with a version message
  2117  	type versionMessage struct {
  2118  		Level     string `json:"@level"`
  2119  		Message   string `json:"@message"`
  2120  		Type      string `json:"type"`
  2121  		Terraform string `json:"terraform"`
  2122  		UI        string `json:"ui"`
  2123  	}
  2124  	var gotVersion versionMessage
  2125  	if err := json.Unmarshal([]byte(gotLines[0]), &gotVersion); err != nil {
  2126  		t.Errorf("failed to unmarshal version line: %s\n%s", err, gotLines[0])
  2127  	}
  2128  	wantVersion := versionMessage{
  2129  		"info",
  2130  		fmt.Sprintf("Terraform %s", tfversion.String()),
  2131  		"version",
  2132  		tfversion.String(),
  2133  		views.JSON_UI_VERSION,
  2134  	}
  2135  	if !cmp.Equal(wantVersion, gotVersion) {
  2136  		t.Errorf("unexpected first message:\n%s", cmp.Diff(wantVersion, gotVersion))
  2137  	}
  2138  
  2139  	// Compare the rest of the lines against the golden reference
  2140  	var gotLineMaps []map[string]interface{}
  2141  	for i, line := range gotLines[1:] {
  2142  		index := i + 1
  2143  		var gotMap map[string]interface{}
  2144  		if err := json.Unmarshal([]byte(line), &gotMap); err != nil {
  2145  			t.Errorf("failed to unmarshal got line %d: %s\n%s", index, err, gotLines[index])
  2146  		}
  2147  		if _, ok := gotMap["@timestamp"]; !ok {
  2148  			t.Errorf("missing @timestamp field in log: %s", gotLines[index])
  2149  		}
  2150  		delete(gotMap, "@timestamp")
  2151  		gotLineMaps = append(gotLineMaps, gotMap)
  2152  	}
  2153  	var wantLineMaps []map[string]interface{}
  2154  	for i, line := range wantLines[1:] {
  2155  		index := i + 1
  2156  		var wantMap map[string]interface{}
  2157  		if err := json.Unmarshal([]byte(line), &wantMap); err != nil {
  2158  			t.Errorf("failed to unmarshal want line %d: %s\n%s", index, err, gotLines[index])
  2159  		}
  2160  		wantLineMaps = append(wantLineMaps, wantMap)
  2161  	}
  2162  	if diff := cmp.Diff(wantLineMaps, gotLineMaps); diff != "" {
  2163  		t.Errorf("wrong output lines\n%s", diff)
  2164  	}
  2165  }
  2166  
  2167  func TestApply_warnings(t *testing.T) {
  2168  	// Create a temporary working directory that is empty
  2169  	td := tempDir(t)
  2170  	testCopyDir(t, testFixturePath("apply"), td)
  2171  	defer os.RemoveAll(td)
  2172  	defer testChdir(t, td)()
  2173  
  2174  	p := testProvider()
  2175  	p.GetProviderSchemaResponse = applyFixtureSchema()
  2176  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  2177  		return providers.PlanResourceChangeResponse{
  2178  			PlannedState: req.ProposedNewState,
  2179  			Diagnostics: tfdiags.Diagnostics{
  2180  				tfdiags.SimpleWarning("warning 1"),
  2181  				tfdiags.SimpleWarning("warning 2"),
  2182  			},
  2183  		}
  2184  	}
  2185  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  2186  		return providers.ApplyResourceChangeResponse{
  2187  			NewState: cty.UnknownAsNull(req.PlannedState),
  2188  		}
  2189  	}
  2190  
  2191  	t.Run("full warnings", func(t *testing.T) {
  2192  		view, done := testView(t)
  2193  		c := &ApplyCommand{
  2194  			Meta: Meta{
  2195  				testingOverrides: metaOverridesForProvider(p),
  2196  				View:             view,
  2197  			},
  2198  		}
  2199  
  2200  		args := []string{"-auto-approve"}
  2201  		code := c.Run(args)
  2202  		output := done(t)
  2203  		if code != 0 {
  2204  			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  2205  		}
  2206  		wantWarnings := []string{
  2207  			"warning 1",
  2208  			"warning 2",
  2209  		}
  2210  		for _, want := range wantWarnings {
  2211  			if !strings.Contains(output.Stdout(), want) {
  2212  				t.Errorf("missing warning %s", want)
  2213  			}
  2214  		}
  2215  	})
  2216  
  2217  	t.Run("compact warnings", func(t *testing.T) {
  2218  		view, done := testView(t)
  2219  		c := &ApplyCommand{
  2220  			Meta: Meta{
  2221  				testingOverrides: metaOverridesForProvider(p),
  2222  				View:             view,
  2223  			},
  2224  		}
  2225  
  2226  		code := c.Run([]string{"-auto-approve", "-compact-warnings"})
  2227  		output := done(t)
  2228  		if code != 0 {
  2229  			t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
  2230  		}
  2231  		// the output should contain 2 warnings and a message about -compact-warnings
  2232  		wantWarnings := []string{
  2233  			"warning 1",
  2234  			"warning 2",
  2235  			"To see the full warning notes, run Terraform without -compact-warnings.",
  2236  		}
  2237  		for _, want := range wantWarnings {
  2238  			if !strings.Contains(output.Stdout(), want) {
  2239  				t.Errorf("missing warning %s", want)
  2240  			}
  2241  		}
  2242  	})
  2243  }
  2244  
  2245  // applyFixtureSchema returns a schema suitable for processing the
  2246  // configuration in testdata/apply . This schema should be
  2247  // assigned to a mock provider named "test".
  2248  func applyFixtureSchema() *providers.GetProviderSchemaResponse {
  2249  	return &providers.GetProviderSchemaResponse{
  2250  		ResourceTypes: map[string]providers.Schema{
  2251  			"test_instance": {
  2252  				Block: &configschema.Block{
  2253  					Attributes: map[string]*configschema.Attribute{
  2254  						"id":  {Type: cty.String, Optional: true, Computed: true},
  2255  						"ami": {Type: cty.String, Optional: true},
  2256  					},
  2257  				},
  2258  			},
  2259  		},
  2260  	}
  2261  }
  2262  
  2263  // applyFixtureProvider returns a mock provider that is configured for basic
  2264  // operation with the configuration in testdata/apply. This mock has
  2265  // GetSchemaResponse, PlanResourceChangeFn, and ApplyResourceChangeFn populated,
  2266  // with the plan/apply steps just passing through the data determined by
  2267  // Terraform Core.
  2268  func applyFixtureProvider() *terraform.MockProvider {
  2269  	p := testProvider()
  2270  	p.GetProviderSchemaResponse = applyFixtureSchema()
  2271  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  2272  		return providers.PlanResourceChangeResponse{
  2273  			PlannedState: req.ProposedNewState,
  2274  		}
  2275  	}
  2276  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  2277  		return providers.ApplyResourceChangeResponse{
  2278  			NewState: cty.UnknownAsNull(req.PlannedState),
  2279  		}
  2280  	}
  2281  	return p
  2282  }
  2283  
  2284  // applyFixturePlanFile creates a plan file at a temporary location containing
  2285  // a single change to create the test_instance.foo that is included in the
  2286  // "apply" test fixture, returning the location of that plan file.
  2287  func applyFixturePlanFile(t *testing.T) string {
  2288  	return applyFixturePlanFileMatchState(t, statemgr.SnapshotMeta{})
  2289  }
  2290  
  2291  // applyFixturePlanFileMatchState creates a planfile like applyFixturePlanFile,
  2292  // but inserts the state meta information if that plan must match a preexisting
  2293  // state.
  2294  func applyFixturePlanFileMatchState(t *testing.T, stateMeta statemgr.SnapshotMeta) string {
  2295  	_, snap := testModuleWithSnapshot(t, "apply")
  2296  	plannedVal := cty.ObjectVal(map[string]cty.Value{
  2297  		"id":  cty.UnknownVal(cty.String),
  2298  		"ami": cty.StringVal("bar"),
  2299  	})
  2300  	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type())
  2301  	if err != nil {
  2302  		t.Fatal(err)
  2303  	}
  2304  	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type())
  2305  	if err != nil {
  2306  		t.Fatal(err)
  2307  	}
  2308  	plan := testPlan(t)
  2309  	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{
  2310  		Addr: addrs.Resource{
  2311  			Mode: addrs.ManagedResourceMode,
  2312  			Type: "test_instance",
  2313  			Name: "foo",
  2314  		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  2315  		ProviderAddr: addrs.AbsProviderConfig{
  2316  			Provider: addrs.NewDefaultProvider("test"),
  2317  			Module:   addrs.RootModule,
  2318  		},
  2319  		ChangeSrc: plans.ChangeSrc{
  2320  			Action: plans.Create,
  2321  			Before: priorValRaw,
  2322  			After:  plannedValRaw,
  2323  		},
  2324  	})
  2325  	return testPlanFileMatchState(
  2326  		t,
  2327  		snap,
  2328  		states.NewState(),
  2329  		plan,
  2330  		stateMeta,
  2331  	)
  2332  }
  2333  
  2334  const applyVarFile = `
  2335  foo = "bar"
  2336  `
  2337  
  2338  const applyVarFileJSON = `
  2339  { "foo": "bar" }
  2340  `