2018-03-10 20:44:05 +01:00
|
|
|
package configupgrade
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-06-21 02:02:29 +02:00
|
|
|
"io"
|
2018-03-10 20:44:05 +01:00
|
|
|
"io/ioutil"
|
2018-06-21 02:02:29 +02:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2018-03-10 20:44:05 +01:00
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
2018-06-29 02:26:06 +02:00
|
|
|
|
|
|
|
testprovider "github.com/hashicorp/terraform/builtin/providers/test"
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
2018-03-10 20:44:05 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestUpgradeValid(t *testing.T) {
|
|
|
|
// This test uses the contents of the test-fixtures/valid directory as
|
|
|
|
// a table of tests. Every directory there must have both "input" and
|
|
|
|
// "want" subdirectories, where "input" is the configuration to be
|
|
|
|
// upgraded and "want" is the expected result.
|
|
|
|
fixtureDir := "test-fixtures/valid"
|
|
|
|
testDirs, err := ioutil.ReadDir(fixtureDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, entry := range testDirs {
|
|
|
|
if !entry.IsDir() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
t.Run(entry.Name(), func(t *testing.T) {
|
|
|
|
inputDir := filepath.Join(fixtureDir, entry.Name(), "input")
|
|
|
|
wantDir := filepath.Join(fixtureDir, entry.Name(), "want")
|
2018-06-29 02:26:06 +02:00
|
|
|
u := &Upgrader{
|
|
|
|
Providers: terraform.ResourceProviderResolverFixed(testProviders),
|
|
|
|
}
|
2018-03-10 20:44:05 +01:00
|
|
|
|
|
|
|
inputSrc, err := LoadModule(inputDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
wantSrc, err := LoadModule(wantDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-29 02:26:06 +02:00
|
|
|
gotSrc, diags := u.Upgrade(inputSrc)
|
2018-03-10 20:44:05 +01:00
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Error(diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upgrade uses a nil entry as a signal to delete a file, which
|
|
|
|
// we can't test here because we aren't modifying an existing
|
|
|
|
// dir in place, so we'll just ignore those and leave that mechanism
|
|
|
|
// to be tested elsewhere.
|
|
|
|
|
|
|
|
for name, got := range gotSrc {
|
|
|
|
if gotSrc[name] == nil {
|
|
|
|
delete(gotSrc, name)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
want, wanted := wantSrc[name]
|
|
|
|
if !wanted {
|
|
|
|
t.Errorf("unexpected extra output file %q\n=== GOT ===\n%s", name, got)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-06-21 02:02:29 +02:00
|
|
|
got = bytes.TrimSpace(got)
|
|
|
|
want = bytes.TrimSpace(want)
|
2018-03-10 20:44:05 +01:00
|
|
|
if !bytes.Equal(got, want) {
|
2018-06-21 02:02:29 +02:00
|
|
|
diff := diffSourceFiles(got, want)
|
|
|
|
t.Errorf("wrong content in %q\n%s", name, diff)
|
2018-03-10 20:44:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, want := range wantSrc {
|
|
|
|
if _, present := gotSrc[name]; !present {
|
|
|
|
t.Errorf("missing output file %q\n=== WANT ===\n%s", name, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpgradeRenameJSON(t *testing.T) {
|
|
|
|
inputDir := filepath.Join("test-fixtures/valid/rename-json/input")
|
|
|
|
inputSrc, err := LoadModule(inputDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-29 02:26:06 +02:00
|
|
|
u := &Upgrader{
|
|
|
|
Providers: terraform.ResourceProviderResolverFixed(testProviders),
|
|
|
|
}
|
|
|
|
gotSrc, diags := u.Upgrade(inputSrc)
|
2018-03-10 20:44:05 +01:00
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Error(diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
// This test fixture is also fully covered by TestUpgradeValid, so
|
|
|
|
// we're just testing that the file was renamed here.
|
|
|
|
src, exists := gotSrc["misnamed-json.tf"]
|
|
|
|
if src != nil {
|
|
|
|
t.Errorf("misnamed-json.tf still has content")
|
|
|
|
} else if !exists {
|
|
|
|
t.Errorf("misnamed-json.tf not marked for deletion")
|
|
|
|
}
|
|
|
|
|
|
|
|
src, exists = gotSrc["misnamed-json.tf.json"]
|
|
|
|
if src == nil || !exists {
|
|
|
|
t.Errorf("misnamed-json.tf.json was not created")
|
|
|
|
}
|
|
|
|
}
|
2018-06-21 02:02:29 +02:00
|
|
|
|
|
|
|
func diffSourceFiles(got, want []byte) []byte {
|
|
|
|
// We'll try to run "diff -u" here to get nice output, but if that fails
|
|
|
|
// (e.g. because we're running on a machine without diff installed) then
|
|
|
|
// we'll fall back on just printing out the before and after in full.
|
|
|
|
gotR, gotW, err := os.Pipe()
|
|
|
|
if err != nil {
|
|
|
|
return diffSourceFilesFallback(got, want)
|
|
|
|
}
|
|
|
|
defer gotR.Close()
|
|
|
|
defer gotW.Close()
|
|
|
|
wantR, wantW, err := os.Pipe()
|
|
|
|
if err != nil {
|
|
|
|
return diffSourceFilesFallback(got, want)
|
|
|
|
}
|
|
|
|
defer wantR.Close()
|
|
|
|
defer wantW.Close()
|
|
|
|
|
|
|
|
cmd := exec.Command("diff", "-u", "--label=GOT", "--label=WANT", "/dev/fd/3", "/dev/fd/4")
|
|
|
|
cmd.ExtraFiles = []*os.File{gotR, wantR}
|
|
|
|
stdout, err := cmd.StdoutPipe()
|
|
|
|
stderr, err := cmd.StderrPipe()
|
|
|
|
if err != nil {
|
|
|
|
return diffSourceFilesFallback(got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
wantW.Write(want)
|
|
|
|
wantW.Close()
|
|
|
|
}()
|
|
|
|
go func() {
|
|
|
|
gotW.Write(got)
|
|
|
|
gotW.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
err = cmd.Start()
|
|
|
|
if err != nil {
|
|
|
|
return diffSourceFilesFallback(got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
outR := io.MultiReader(stdout, stderr)
|
|
|
|
out, err := ioutil.ReadAll(outR)
|
|
|
|
if err != nil {
|
|
|
|
return diffSourceFilesFallback(got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.Wait() // not checking errors here because on failure we'll have stderr captured to return
|
|
|
|
|
|
|
|
const noNewline = "\\ No newline at end of file\n"
|
|
|
|
if bytes.HasSuffix(out, []byte(noNewline)) {
|
|
|
|
out = out[:len(out)-len(noNewline)]
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func diffSourceFilesFallback(got, want []byte) []byte {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("=== GOT ===\n")
|
|
|
|
buf.Write(got)
|
|
|
|
buf.WriteString("\n=== WANT ===\n")
|
|
|
|
buf.Write(want)
|
|
|
|
buf.WriteString("\n")
|
|
|
|
return buf.Bytes()
|
|
|
|
}
|
2018-06-29 02:26:06 +02:00
|
|
|
|
|
|
|
var testProviders = map[string]terraform.ResourceProviderFactory{
|
|
|
|
"test": terraform.ResourceProviderFactory(func() (terraform.ResourceProvider, error) {
|
|
|
|
return testprovider.Provider(), nil
|
|
|
|
}),
|
|
|
|
}
|