mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-02 12:17:39 -06:00
8364383c35
Previously we did plugin discovery in the main package, but as we move towards versioned plugins we need more information available in order to resolve plugins, so we move this responsibility into the command package itself. For the moment this is just preserving the existing behavior as long as there are only internal and unversioned plugins present. This is the final state for provisioners in 0.10, since we don't want to support versioned provisioners yet. For providers this is just a checkpoint along the way, since further work is required to apply version constraints from configuration and support additional plugin search directories. The automatic plugin discovery behavior is not desirable for tests because we want to mock the plugins there, so we add a new backdoor for the tests to use to skip the plugin discovery and just provide their own mock implementations. Most of this diff is thus noisy rework of the tests to use this new mechanism.
869 lines
20 KiB
Go
869 lines
20 KiB
Go
package command
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
atlas "github.com/hashicorp/atlas-go/v1"
|
|
"github.com/hashicorp/terraform/helper/copy"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
"github.com/mitchellh/cli"
|
|
)
|
|
|
|
func TestPush_good(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
testFixturePath("push"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
variables := make(map[string]interface{})
|
|
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
}
|
|
|
|
func TestPush_goodBackendInit(t *testing.T) {
|
|
// Create a temporary working directory that is empty
|
|
td := tempDir(t)
|
|
copy.CopyDir(testFixturePath("push-backend-new"), td)
|
|
defer os.RemoveAll(td)
|
|
defer testChdir(t, td)()
|
|
|
|
// init backend
|
|
ui := new(cli.MockUi)
|
|
ci := &InitCommand{
|
|
Meta: Meta{
|
|
Ui: ui,
|
|
},
|
|
}
|
|
if code := ci.Run(nil); code != 0 {
|
|
t.Fatalf("bad: %d\n%s", code, ui.ErrorWriter)
|
|
}
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui = new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
td,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
// Expected weird behavior, doesn't affect unpackaging
|
|
".terraform/",
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
variables := make(map[string]interface{})
|
|
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "hello" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
}
|
|
|
|
func TestPush_noUploadModules(t *testing.T) {
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
// Path of the test. We have to do some renaming to avoid our own
|
|
// VCS getting in the way.
|
|
path := testFixturePath("push-no-upload")
|
|
defer os.RemoveAll(filepath.Join(path, ".terraform"))
|
|
|
|
// Move into that directory
|
|
defer testChdir(t, path)()
|
|
|
|
// Do a "terraform get"
|
|
{
|
|
ui := new(cli.MockUi)
|
|
c := &GetCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
if code := c.Run([]string{}); code != 0 {
|
|
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
defer os.Remove(testStateFileRemote(t, s))
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
"-name=mitchellh/tf-test",
|
|
"-upload-modules=false",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
// NOTE: The duplicates below are not ideal but are how things work
|
|
// currently due to how we manually add the files to the archive. This
|
|
// is definitely a "bug" we can fix in the future.
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
".terraform/terraform.tfstate",
|
|
"child/",
|
|
"child/main.tf",
|
|
"main.tf",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestPush_input(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("foo\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
testFixturePath("push-input"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
variables := map[string]interface{}{
|
|
"foo": "foo",
|
|
}
|
|
|
|
if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions.Variables)
|
|
}
|
|
}
|
|
|
|
// We want a variable from atlas to fill a missing variable locally
|
|
func TestPush_inputPartial(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{
|
|
File: archivePath,
|
|
GetResult: map[string]atlas.TFVar{
|
|
"foo": atlas.TFVar{Key: "foo", Value: "bar"},
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("foo\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
testFixturePath("push-input-partial"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
expectedTFVars := []atlas.TFVar{
|
|
{Key: "bar", Value: "foo"},
|
|
{Key: "foo", Value: "bar"},
|
|
}
|
|
if !reflect.DeepEqual(client.UpsertOptions.TFVars, expectedTFVars) {
|
|
t.Logf("expected: %#v", expectedTFVars)
|
|
t.Fatalf("got: %#v", client.UpsertOptions.TFVars)
|
|
}
|
|
}
|
|
|
|
// This tests that the push command will override Atlas variables
|
|
// if requested.
|
|
func TestPush_localOverride(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
// Provided vars should override existing ones
|
|
client.GetResult = map[string]atlas.TFVar{
|
|
"foo": atlas.TFVar{
|
|
Key: "foo",
|
|
Value: "old",
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
"-overwrite=foo",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
expectedTFVars := pushTFVars()
|
|
|
|
if !reflect.DeepEqual(client.UpsertOptions.TFVars, expectedTFVars) {
|
|
t.Logf("expected: %#v", expectedTFVars)
|
|
t.Fatalf("got: %#v", client.UpsertOptions.TFVars)
|
|
}
|
|
}
|
|
|
|
// This tests that the push command will override Atlas variables
|
|
// even if we don't have it defined locally
|
|
func TestPush_remoteOverride(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
// Provided vars should override existing ones
|
|
client.GetResult = map[string]atlas.TFVar{
|
|
"remote": atlas.TFVar{
|
|
Key: "remote",
|
|
Value: "old",
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
"-overwrite=remote",
|
|
"-var",
|
|
"remote=new",
|
|
path,
|
|
}
|
|
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
found := false
|
|
// find the "remote" var and make sure we're going to set it
|
|
for _, tfVar := range client.UpsertOptions.TFVars {
|
|
if tfVar.Key == "remote" {
|
|
found = true
|
|
if tfVar.Value != "new" {
|
|
t.Log("'remote' variable should be set to 'new'")
|
|
t.Fatalf("sending instead: %#v", tfVar)
|
|
}
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Fatal("'remote' variable not being sent to atlas")
|
|
}
|
|
}
|
|
|
|
// This tests that the push command prefers Atlas variables over
|
|
// local ones.
|
|
func TestPush_preferAtlas(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
// Provided vars should override existing ones
|
|
client.GetResult = map[string]atlas.TFVar{
|
|
"foo": atlas.TFVar{
|
|
Key: "foo",
|
|
Value: "old",
|
|
},
|
|
}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
// change the expected response to match our change
|
|
expectedTFVars := pushTFVars()
|
|
for i, v := range expectedTFVars {
|
|
if v.Key == "foo" {
|
|
expectedTFVars[i] = atlas.TFVar{Key: "foo", Value: "old"}
|
|
}
|
|
}
|
|
|
|
if !reflect.DeepEqual(expectedTFVars, client.UpsertOptions.TFVars) {
|
|
t.Logf("expected: %#v", expectedTFVars)
|
|
t.Fatalf("got: %#v", client.UpsertOptions.TFVars)
|
|
}
|
|
}
|
|
|
|
// This tests that the push command will send the variables in tfvars
|
|
func TestPush_tfvars(t *testing.T) {
|
|
// Disable test mode so input would be asked and setup the
|
|
// input reader/writers.
|
|
test = false
|
|
defer func() { test = true }()
|
|
defaultInputReader = bytes.NewBufferString("nope\n")
|
|
defaultInputWriter = new(bytes.Buffer)
|
|
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
path := testFixturePath("push-tfvars")
|
|
args := []string{
|
|
"-var-file", path + "/terraform.tfvars",
|
|
"-vcs=false",
|
|
"-var",
|
|
"bar=[1,2]",
|
|
path,
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
actual := testArchiveStr(t, archivePath)
|
|
expected := []string{
|
|
".terraform/",
|
|
".terraform/terraform.tfstate",
|
|
"main.tf",
|
|
"terraform.tfvars",
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "foo" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
|
|
//now check TFVars
|
|
tfvars := pushTFVars()
|
|
// update bar to match cli value
|
|
for i, v := range tfvars {
|
|
if v.Key == "bar" {
|
|
tfvars[i].Value = "[1, 2]"
|
|
tfvars[i].IsHCL = true
|
|
}
|
|
}
|
|
|
|
for i, expected := range tfvars {
|
|
got := client.UpsertOptions.TFVars[i]
|
|
if got != expected {
|
|
t.Logf("%2d expected: %#v", i, expected)
|
|
t.Fatalf(" got: %#v", got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPush_name(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-name", "bar",
|
|
"-vcs=false",
|
|
testFixturePath("push"),
|
|
}
|
|
if code := c.Run(args); code != 0 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
if client.UpsertOptions.Name != "bar" {
|
|
t.Fatalf("bad: %#v", client.UpsertOptions)
|
|
}
|
|
}
|
|
|
|
func TestPush_noState(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
func TestPush_noRemoteState(t *testing.T) {
|
|
// Create a temporary working directory that is empty
|
|
td := tempDir(t)
|
|
copy.CopyDir(testFixturePath("push-no-remote"), td)
|
|
defer os.RemoveAll(td)
|
|
defer testChdir(t, td)()
|
|
|
|
state := &terraform.State{
|
|
Modules: []*terraform.ModuleState{
|
|
&terraform.ModuleState{
|
|
Path: []string{"root"},
|
|
Resources: map[string]*terraform.ResourceState{
|
|
"test_instance.foo": &terraform.ResourceState{
|
|
Type: "test_instance",
|
|
Primary: &terraform.InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
statePath := testStateFile(t, state)
|
|
|
|
// Path where the archive will be "uploaded" to
|
|
archivePath := testTempFile(t)
|
|
defer os.Remove(archivePath)
|
|
|
|
client := &mockPushClient{File: archivePath}
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
Ui: ui,
|
|
},
|
|
client: client,
|
|
}
|
|
|
|
args := []string{
|
|
"-vcs=false",
|
|
"-state", statePath,
|
|
td,
|
|
}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
|
|
errStr := ui.ErrorWriter.String()
|
|
if !strings.Contains(errStr, "remote backend") {
|
|
t.Fatalf("bad: %s", errStr)
|
|
}
|
|
}
|
|
|
|
func TestPush_plan(t *testing.T) {
|
|
tmp, cwd := testCwd(t)
|
|
defer testFixCwd(t, tmp, cwd)
|
|
|
|
// Create remote state file, this should be pulled
|
|
conf, srv := testRemoteState(t, testState(), 200)
|
|
defer srv.Close()
|
|
|
|
// Persist local remote state
|
|
s := terraform.NewState()
|
|
s.Serial = 5
|
|
s.Remote = conf
|
|
testStateFileRemote(t, s)
|
|
|
|
// Create a plan
|
|
planPath := testPlanFile(t, &terraform.Plan{
|
|
Module: testModule(t, "apply"),
|
|
})
|
|
|
|
ui := new(cli.MockUi)
|
|
c := &PushCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
},
|
|
}
|
|
|
|
args := []string{planPath}
|
|
if code := c.Run(args); code != 1 {
|
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
|
}
|
|
}
|
|
|
|
func testArchiveStr(t *testing.T, path string) []string {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
// Ungzip
|
|
gzipR, err := gzip.NewReader(f)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Accumulator
|
|
result := make([]string, 0, 10)
|
|
|
|
// Untar
|
|
tarR := tar.NewReader(gzipR)
|
|
for {
|
|
header, err := tarR.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
result = append(result, header.Name)
|
|
}
|
|
|
|
sort.Strings(result)
|
|
return result
|
|
}
|
|
|
|
// we always quote map keys to be safe
|
|
func pushTFVars() []atlas.TFVar {
|
|
return []atlas.TFVar{
|
|
{Key: "bar", Value: "foo", IsHCL: false},
|
|
{Key: "baz", Value: `{
|
|
"A" = "a"
|
|
}`, IsHCL: true},
|
|
{Key: "fob", Value: `["a", "quotes \"in\" quotes"]`, IsHCL: true},
|
|
{Key: "foo", Value: "bar", IsHCL: false},
|
|
}
|
|
}
|
|
|
|
// the structure returned from the push-tfvars test fixture
|
|
func pushTFVarsMap() map[string]atlas.TFVar {
|
|
vars := make(map[string]atlas.TFVar)
|
|
for _, v := range pushTFVars() {
|
|
vars[v.Key] = v
|
|
}
|
|
return vars
|
|
}
|