github.com/pdecat/terraform@v0.11.9-beta1/backend/remote-state/swift/backend_test.go (about)

     1  package swift
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/gophercloud/gophercloud"
    11  	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
    12  	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
    13  	"github.com/gophercloud/gophercloud/pagination"
    14  	"github.com/hashicorp/terraform/backend"
    15  	"github.com/hashicorp/terraform/state/remote"
    16  	"github.com/hashicorp/terraform/terraform"
    17  )
    18  
    19  // verify that we are doing ACC tests or the Swift tests specifically
    20  func testACC(t *testing.T) {
    21  	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_SWIFT_TEST") == ""
    22  	if skip {
    23  		t.Log("swift backend tests require setting TF_ACC or TF_SWIFT_TEST")
    24  		t.Skip()
    25  	}
    26  	t.Log("swift backend acceptance tests enabled")
    27  }
    28  
    29  func TestBackend_impl(t *testing.T) {
    30  	var _ backend.Backend = new(Backend)
    31  }
    32  
    33  func testAccPreCheck(t *testing.T) {
    34  	v := os.Getenv("OS_AUTH_URL")
    35  	if v == "" {
    36  		t.Fatal("OS_AUTH_URL must be set for acceptance tests")
    37  	}
    38  }
    39  
    40  func TestBackendConfig(t *testing.T) {
    41  	testACC(t)
    42  
    43  	// Build config
    44  	config := map[string]interface{}{
    45  		"archive_container": "test-tfstate-archive",
    46  		"container":         "test-tfstate",
    47  	}
    48  
    49  	b := backend.TestBackendConfig(t, New(), config).(*Backend)
    50  
    51  	if b.container != "test-tfstate" {
    52  		t.Fatal("Incorrect path was provided.")
    53  	}
    54  	if b.archiveContainer != "test-tfstate-archive" {
    55  		t.Fatal("Incorrect archivepath was provided.")
    56  	}
    57  }
    58  
    59  func TestBackend(t *testing.T) {
    60  	testACC(t)
    61  
    62  	container := fmt.Sprintf("terraform-state-swift-test-%x", time.Now().Unix())
    63  
    64  	b := backend.TestBackendConfig(t, New(), map[string]interface{}{
    65  		"container": container,
    66  	}).(*Backend)
    67  
    68  	defer deleteSwiftContainer(t, b.client, container)
    69  
    70  	backend.TestBackendStates(t, b)
    71  }
    72  
    73  func TestBackendPath(t *testing.T) {
    74  	testACC(t)
    75  
    76  	path := fmt.Sprintf("terraform-state-swift-test-%x", time.Now().Unix())
    77  	t.Logf("[DEBUG] Generating backend config")
    78  	b := backend.TestBackendConfig(t, New(), map[string]interface{}{
    79  		"path": path,
    80  	}).(*Backend)
    81  	t.Logf("[DEBUG] Backend configured")
    82  
    83  	defer deleteSwiftContainer(t, b.client, path)
    84  
    85  	t.Logf("[DEBUG] Testing Backend")
    86  
    87  	// Generate some state
    88  	state1 := terraform.NewState()
    89  	// state1Lineage := state1.Lineage
    90  	t.Logf("state1 lineage = %s, serial = %d", state1.Lineage, state1.Serial)
    91  
    92  	// RemoteClient to test with
    93  	client := &RemoteClient{
    94  		client:           b.client,
    95  		archive:          b.archive,
    96  		archiveContainer: b.archiveContainer,
    97  		container:        b.container,
    98  	}
    99  
   100  	stateMgr := &remote.State{Client: client}
   101  	stateMgr.WriteState(state1)
   102  	if err := stateMgr.PersistState(); err != nil {
   103  		t.Fatal(err)
   104  	}
   105  
   106  	if err := stateMgr.RefreshState(); err != nil {
   107  		t.Fatal(err)
   108  	}
   109  
   110  	// Add some state
   111  	state1.AddModuleState(&terraform.ModuleState{
   112  		Path: []string{"root"},
   113  		Outputs: map[string]*terraform.OutputState{
   114  			"bar": &terraform.OutputState{
   115  				Type:      "string",
   116  				Sensitive: false,
   117  				Value:     "baz",
   118  			},
   119  		},
   120  	})
   121  	stateMgr.WriteState(state1)
   122  	if err := stateMgr.PersistState(); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  }
   127  
   128  func TestBackendArchive(t *testing.T) {
   129  	testACC(t)
   130  
   131  	container := fmt.Sprintf("terraform-state-swift-test-%x", time.Now().Unix())
   132  	archiveContainer := fmt.Sprintf("%s_archive", container)
   133  
   134  	b := backend.TestBackendConfig(t, New(), map[string]interface{}{
   135  		"archive_container": archiveContainer,
   136  		"container":         container,
   137  	}).(*Backend)
   138  
   139  	defer deleteSwiftContainer(t, b.client, container)
   140  	defer deleteSwiftContainer(t, b.client, archiveContainer)
   141  
   142  	// Generate some state
   143  	state1 := terraform.NewState()
   144  	// state1Lineage := state1.Lineage
   145  	t.Logf("state1 lineage = %s, serial = %d", state1.Lineage, state1.Serial)
   146  
   147  	// RemoteClient to test with
   148  	client := &RemoteClient{
   149  		client:           b.client,
   150  		archive:          b.archive,
   151  		archiveContainer: b.archiveContainer,
   152  		container:        b.container,
   153  	}
   154  
   155  	stateMgr := &remote.State{Client: client}
   156  	stateMgr.WriteState(state1)
   157  	if err := stateMgr.PersistState(); err != nil {
   158  		t.Fatal(err)
   159  	}
   160  
   161  	if err := stateMgr.RefreshState(); err != nil {
   162  		t.Fatal(err)
   163  	}
   164  
   165  	// Add some state
   166  	state1.AddModuleState(&terraform.ModuleState{
   167  		Path: []string{"root"},
   168  		Outputs: map[string]*terraform.OutputState{
   169  			"bar": &terraform.OutputState{
   170  				Type:      "string",
   171  				Sensitive: false,
   172  				Value:     "baz",
   173  			},
   174  		},
   175  	})
   176  	stateMgr.WriteState(state1)
   177  	if err := stateMgr.PersistState(); err != nil {
   178  		t.Fatal(err)
   179  	}
   180  
   181  	archiveObjects := getSwiftObjectNames(t, b.client, archiveContainer)
   182  	t.Logf("archiveObjects len = %d. Contents = %+v", len(archiveObjects), archiveObjects)
   183  	if len(archiveObjects) != 1 {
   184  		t.Fatalf("Invalid number of archive objects. Expected 1, got %d", len(archiveObjects))
   185  	}
   186  
   187  	// Download archive state to validate
   188  	archiveData := downloadSwiftObject(t, b.client, archiveContainer, archiveObjects[0])
   189  	t.Logf("Archive data downloaded... Looks like: %+v", archiveData)
   190  	archiveState, err := terraform.ReadState(archiveData)
   191  	if err != nil {
   192  		t.Fatalf("Error Reading State: %s", err)
   193  	}
   194  
   195  	t.Logf("Archive state lineage = %s, serial = %d, lineage match = %t", archiveState.Lineage, archiveState.Serial, stateMgr.State().SameLineage(archiveState))
   196  	if !stateMgr.State().SameLineage(archiveState) {
   197  		t.Fatal("Got a different lineage")
   198  	}
   199  
   200  }
   201  
   202  // Helper function to download an object in a Swift container
   203  func downloadSwiftObject(t *testing.T, osClient *gophercloud.ServiceClient, container, object string) (data io.Reader) {
   204  	t.Logf("Attempting to download object %s from container %s", object, container)
   205  	res := objects.Download(osClient, container, object, nil)
   206  	if res.Err != nil {
   207  		t.Fatalf("Error downloading object: %s", res.Err)
   208  	}
   209  	data = res.Body
   210  	return
   211  }
   212  
   213  // Helper function to get a list of objects in a Swift container
   214  func getSwiftObjectNames(t *testing.T, osClient *gophercloud.ServiceClient, container string) (objectNames []string) {
   215  	_ = objects.List(osClient, container, nil).EachPage(func(page pagination.Page) (bool, error) {
   216  		// Get a slice of object names
   217  		names, err := objects.ExtractNames(page)
   218  		if err != nil {
   219  			t.Fatalf("Error extracting object names from page: %s", err)
   220  		}
   221  		for _, object := range names {
   222  			objectNames = append(objectNames, object)
   223  		}
   224  
   225  		return true, nil
   226  	})
   227  	return
   228  }
   229  
   230  // Helper function to delete Swift container
   231  func deleteSwiftContainer(t *testing.T, osClient *gophercloud.ServiceClient, container string) {
   232  	warning := "WARNING: Failed to delete the test Swift container. It may have been left in your Openstack account and may incur storage charges. (error was %s)"
   233  
   234  	// Remove any objects
   235  	deleteSwiftObjects(t, osClient, container)
   236  
   237  	// Delete the container
   238  	deleteResult := containers.Delete(osClient, container)
   239  	if deleteResult.Err != nil {
   240  		if _, ok := deleteResult.Err.(gophercloud.ErrDefault404); !ok {
   241  			t.Fatalf(warning, deleteResult.Err)
   242  		}
   243  	}
   244  }
   245  
   246  // Helper function to delete Swift objects within a container
   247  func deleteSwiftObjects(t *testing.T, osClient *gophercloud.ServiceClient, container string) {
   248  	// Get a slice of object names
   249  	objectNames := getSwiftObjectNames(t, osClient, container)
   250  
   251  	for _, object := range objectNames {
   252  		result := objects.Delete(osClient, container, object, nil)
   253  		if result.Err != nil {
   254  			t.Fatalf("Error deleting object %s from container %s: %s", object, container, result.Err)
   255  		}
   256  	}
   257  
   258  }