backend/remote-state/gcs: Implement additional tests.

This calls backend.TestBackend() and remote.TestRemoteLocks() for
standardized acceptance tests. It removes custom listing tests since
those are performed by backend.TestBackend(), too.

Since each tests uses its own bucket, all tests can be run in parallel.
This commit is contained in:
Florian Forster 2017-09-26 09:20:43 +02:00 committed by James Bardin
parent 927085289d
commit 72ccf22a92
1 changed files with 92 additions and 61 deletions

View File

@ -1,7 +1,9 @@
package gcs
import (
"fmt"
"os"
"strings"
"testing"
"github.com/hashicorp/terraform/backend"
@ -9,6 +11,8 @@ import (
)
func TestStateFile(t *testing.T) {
t.Parallel()
cases := []struct {
prefix string
defaultStateFile string
@ -39,22 +43,89 @@ func TestStateFile(t *testing.T) {
}
}
func TestGCSBackend(t *testing.T) {
// This test creates a bucket in GCS and populates it.
// It may incur costs, so it will only run if the GOOGLE_PROJECT
// environment variable is set.
func TestRemoteClient(t *testing.T) {
t.Parallel()
be := testBackend(t)
ss, err := be.State(backend.DefaultStateName)
if err != nil {
t.Fatalf("be.State(%q) = %v", backend.DefaultStateName, err)
}
rs, ok := ss.(*remote.State)
if !ok {
t.Fatalf("be.State(): got a %T, want a *remote.State", ss)
}
remote.TestClient(t, rs.Client)
cleanBackend(t, be)
}
func TestRemoteLocks(t *testing.T) {
t.Parallel()
be := testBackend(t)
remoteClient := func() (remote.Client, error) {
ss, err := be.State(backend.DefaultStateName)
if err != nil {
return nil, err
}
rs, ok := ss.(*remote.State)
if !ok {
return nil, fmt.Errorf("be.State(): got a %T, want a *remote.State", ss)
}
return rs.Client, nil
}
c0, err := remoteClient()
if err != nil {
t.Fatalf("remoteClient(0) = %v", err)
}
c1, err := remoteClient()
if err != nil {
t.Fatalf("remoteClient(1) = %v", err)
}
remote.TestRemoteLocks(t, c0, c1)
cleanBackend(t, be)
}
func TestBackend(t *testing.T) {
t.Parallel()
be0 := testBackend(t)
be1 := testBackend(t)
// clean up all states left behind by previous runs --
// backend.TestBackend() will complain about any non-default states.
cleanBackend(t, be0)
backend.TestBackend(t, be0, be1)
cleanBackend(t, be0)
}
// testBackend returns a new GCS backend.
// This creates a bucket in GCS and populates it. Since this may incur costs,
// it will only run if the GOOGLE_PROJECT environment variable is set.
func testBackend(t *testing.T) backend.Backend {
t.Helper()
projectID := os.Getenv("GOOGLE_PROJECT")
if projectID == "" {
t.Skipf("skipping; set GOOGLE_PROJECT to activate")
t.Skip("skipping; set GOOGLE_PROJECT to activate")
}
const bucketName = "terraform_remote-state_test"
t.Logf("using bucket %q in project %q", bucketName, projectID)
config := map[string]interface{}{
"bucket": bucketName,
"prefix": "",
"project": projectID,
"bucket": strings.ToLower(t.Name()),
"prefix": "",
}
if creds := os.Getenv("GOOGLE_CREDENTIALS"); creds != "" {
@ -64,63 +135,23 @@ func TestGCSBackend(t *testing.T) {
t.Log("using default credentials; set GOOGLE_CREDENTIALS for custom credentials")
}
be := backend.TestBackendConfig(t, New(), config)
return backend.TestBackendConfig(t, New(), config)
}
gcsBE, ok := be.(*gcsBackend)
if !ok {
t.Fatalf("backend: got %T, want *gcsBackend", be)
}
ctx := gcsBE.storageContext
// create a new bucket and error out if we can't, e.g. because it already exists.
if err := gcsBE.storageClient.Bucket(bucketName).Create(ctx, projectID, nil); err != nil {
t.Fatalf("creating bucket failed: %v", err)
}
t.Log("bucket has been created")
defer func() {
if err := gcsBE.storageClient.Bucket(bucketName).Delete(ctx); err != nil {
t.Errorf("deleting bucket failed: %v", err)
} else {
t.Log("bucket has been deleted")
}
}()
// this should create a new state file
_, err := be.State("TestGCSBackend")
if err != nil {
t.Fatalf("State(\"TestGCSBackend\"): %v", err)
}
// cleanBackend deletes all states from be except the default state.
func cleanBackend(t *testing.T, be backend.Backend) {
t.Helper()
states, err := be.States()
if err != nil {
t.Fatalf("States(): %v", err)
t.Fatalf("be.States() = %v; manual clean-up may be required", err)
}
found := false
for _, st := range states {
if st == "TestGCSBackend" {
found = true
break
if st == backend.DefaultStateName {
continue
}
if err := be.DeleteState(st); err != nil {
t.Fatalf("be.DeleteState(%q) = %v; manual clean-up may be required", st, err)
}
}
if !found {
t.Errorf("be.States() = %#v, missing \"TestGCSBackend\"", states)
}
// ensure state file exists
if _, err := gcsBE.storageClient.Bucket(bucketName).Object("TestGCSBackend.tfstate").Attrs(ctx); err != nil {
t.Fatalf("Attrs(\"TestGCSBackend.tfstate\"): %v", err)
}
c, err := gcsBE.client("TestGCSBackend_remote_TestClient")
if err != nil {
t.Fatal(err)
}
remote.TestClient(t, c)
if err := be.DeleteState("TestGCSBackend"); err != nil {
t.Errorf("DeleteState(\"TestGCSBackend\"): %v", err)
}
}