github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/backend/remote-state/oss/backend_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package oss
     5  
     6  import (
     7  	"fmt"
     8  	"math/rand"
     9  	"os"
    10  	"testing"
    11  	"time"
    12  
    13  	"strings"
    14  
    15  	"github.com/aliyun/aliyun-oss-go-sdk/oss"
    16  	"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
    17  	"github.com/terramate-io/tf/backend"
    18  	"github.com/terramate-io/tf/configs/hcl2shim"
    19  )
    20  
    21  // verify that we are doing ACC tests or the OSS tests specifically
    22  func testACC(t *testing.T) {
    23  	skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_OSS_TEST") == ""
    24  	if skip {
    25  		t.Log("oss backend tests require setting TF_ACC or TF_OSS_TEST")
    26  		t.Skip()
    27  	}
    28  	if skip {
    29  		t.Fatal("oss backend tests require setting ALICLOUD_ACCESS_KEY or ALICLOUD_ACCESS_KEY_ID")
    30  	}
    31  	if os.Getenv("ALICLOUD_REGION") == "" {
    32  		os.Setenv("ALICLOUD_REGION", "cn-beijing")
    33  	}
    34  }
    35  
    36  func TestBackend_impl(t *testing.T) {
    37  	var _ backend.Backend = new(Backend)
    38  }
    39  
    40  func TestBackendConfig(t *testing.T) {
    41  	testACC(t)
    42  	config := map[string]interface{}{
    43  		"region":              "cn-beijing",
    44  		"bucket":              "terraform-backend-oss-test",
    45  		"prefix":              "mystate",
    46  		"key":                 "first.tfstate",
    47  		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
    48  		"tablestore_table":    "TableStore",
    49  	}
    50  
    51  	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
    52  
    53  	if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") {
    54  		t.Fatalf("Incorrect region was provided")
    55  	}
    56  	if b.bucketName != "terraform-backend-oss-test" {
    57  		t.Fatalf("Incorrect bucketName was provided")
    58  	}
    59  	if b.statePrefix != "mystate" {
    60  		t.Fatalf("Incorrect state file path was provided")
    61  	}
    62  	if b.stateKey != "first.tfstate" {
    63  		t.Fatalf("Incorrect keyName was provided")
    64  	}
    65  
    66  	if b.ossClient.Config.AccessKeyID == "" {
    67  		t.Fatalf("No Access Key Id was provided")
    68  	}
    69  	if b.ossClient.Config.AccessKeySecret == "" {
    70  		t.Fatalf("No Secret Access Key was provided")
    71  	}
    72  }
    73  
    74  func TestBackendConfigWorkSpace(t *testing.T) {
    75  	testACC(t)
    76  	bucketName := fmt.Sprintf("terraform-backend-oss-test-%d", rand.Intn(1000))
    77  	config := map[string]interface{}{
    78  		"region":              "cn-beijing",
    79  		"bucket":              bucketName,
    80  		"prefix":              "mystate",
    81  		"key":                 "first.tfstate",
    82  		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
    83  		"tablestore_table":    "TableStore",
    84  	}
    85  
    86  	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
    87  	createOSSBucket(t, b.ossClient, bucketName)
    88  	defer deleteOSSBucket(t, b.ossClient, bucketName)
    89  	if _, err := b.Workspaces(); err != nil {
    90  		t.Fatal(err.Error())
    91  	}
    92  	if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") {
    93  		t.Fatalf("Incorrect region was provided")
    94  	}
    95  	if b.bucketName != bucketName {
    96  		t.Fatalf("Incorrect bucketName was provided")
    97  	}
    98  	if b.statePrefix != "mystate" {
    99  		t.Fatalf("Incorrect state file path was provided")
   100  	}
   101  	if b.stateKey != "first.tfstate" {
   102  		t.Fatalf("Incorrect keyName was provided")
   103  	}
   104  
   105  	if b.ossClient.Config.AccessKeyID == "" {
   106  		t.Fatalf("No Access Key Id was provided")
   107  	}
   108  	if b.ossClient.Config.AccessKeySecret == "" {
   109  		t.Fatalf("No Secret Access Key was provided")
   110  	}
   111  }
   112  
   113  func TestBackendConfigProfile(t *testing.T) {
   114  	testACC(t)
   115  	config := map[string]interface{}{
   116  		"region":              "cn-beijing",
   117  		"bucket":              "terraform-backend-oss-test",
   118  		"prefix":              "mystate",
   119  		"key":                 "first.tfstate",
   120  		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
   121  		"tablestore_table":    "TableStore",
   122  		"profile":             "default",
   123  	}
   124  
   125  	b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(config)).(*Backend)
   126  
   127  	if !strings.HasPrefix(b.ossClient.Config.Endpoint, "https://oss-cn-beijing") {
   128  		t.Fatalf("Incorrect region was provided")
   129  	}
   130  	if b.bucketName != "terraform-backend-oss-test" {
   131  		t.Fatalf("Incorrect bucketName was provided")
   132  	}
   133  	if b.statePrefix != "mystate" {
   134  		t.Fatalf("Incorrect state file path was provided")
   135  	}
   136  	if b.stateKey != "first.tfstate" {
   137  		t.Fatalf("Incorrect keyName was provided")
   138  	}
   139  
   140  	if b.ossClient.Config.AccessKeyID == "" {
   141  		t.Fatalf("No Access Key Id was provided")
   142  	}
   143  	if b.ossClient.Config.AccessKeySecret == "" {
   144  		t.Fatalf("No Secret Access Key was provided")
   145  	}
   146  }
   147  
   148  func TestBackendConfig_invalidKey(t *testing.T) {
   149  	testACC(t)
   150  	cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{
   151  		"region":              "cn-beijing",
   152  		"bucket":              "terraform-backend-oss-test",
   153  		"prefix":              "/leading-slash",
   154  		"name":                "/test.tfstate",
   155  		"tablestore_endpoint": "https://terraformstate.cn-beijing.ots.aliyuncs.com",
   156  		"tablestore_table":    "TableStore",
   157  	})
   158  
   159  	_, results := New().PrepareConfig(cfg)
   160  	if !results.HasErrors() {
   161  		t.Fatal("expected config validation error")
   162  	}
   163  }
   164  
   165  func TestBackend(t *testing.T) {
   166  	testACC(t)
   167  
   168  	bucketName := fmt.Sprintf("terraform-remote-oss-test-%x", time.Now().Unix())
   169  	statePrefix := "multi/level/path/"
   170  
   171  	b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
   172  		"bucket": bucketName,
   173  		"prefix": statePrefix,
   174  	})).(*Backend)
   175  
   176  	b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{
   177  		"bucket": bucketName,
   178  		"prefix": statePrefix,
   179  	})).(*Backend)
   180  
   181  	createOSSBucket(t, b1.ossClient, bucketName)
   182  	defer deleteOSSBucket(t, b1.ossClient, bucketName)
   183  
   184  	backend.TestBackendStates(t, b1)
   185  	backend.TestBackendStateLocks(t, b1, b2)
   186  	backend.TestBackendStateForceUnlock(t, b1, b2)
   187  }
   188  
   189  func createOSSBucket(t *testing.T, ossClient *oss.Client, bucketName string) {
   190  	// Be clear about what we're doing in case the user needs to clean this up later.
   191  	if err := ossClient.CreateBucket(bucketName); err != nil {
   192  		t.Fatal("failed to create test OSS bucket:", err)
   193  	}
   194  }
   195  
   196  func deleteOSSBucket(t *testing.T, ossClient *oss.Client, bucketName string) {
   197  	warning := "WARNING: Failed to delete the test OSS bucket. It may have been left in your Alibaba Cloud account and may incur storage charges. (error was %s)"
   198  
   199  	// first we have to get rid of the env objects, or we can't delete the bucket
   200  	bucket, err := ossClient.Bucket(bucketName)
   201  	if err != nil {
   202  		t.Fatal("Error getting bucket:", err)
   203  		return
   204  	}
   205  	objects, err := bucket.ListObjects()
   206  	if err != nil {
   207  		t.Logf(warning, err)
   208  		return
   209  	}
   210  	for _, obj := range objects.Objects {
   211  		if err := bucket.DeleteObject(obj.Key); err != nil {
   212  			// this will need cleanup no matter what, so just warn and exit
   213  			t.Logf(warning, err)
   214  			return
   215  		}
   216  	}
   217  
   218  	if err := ossClient.DeleteBucket(bucketName); err != nil {
   219  		t.Logf(warning, err)
   220  	}
   221  }
   222  
   223  // create the tablestore table, and wait until we can query it.
   224  func createTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, tableName string) {
   225  	tableMeta := new(tablestore.TableMeta)
   226  	tableMeta.TableName = tableName
   227  	tableMeta.AddPrimaryKeyColumn(pkName, tablestore.PrimaryKeyType_STRING)
   228  
   229  	tableOption := new(tablestore.TableOption)
   230  	tableOption.TimeToAlive = -1
   231  	tableOption.MaxVersion = 1
   232  
   233  	reservedThroughput := new(tablestore.ReservedThroughput)
   234  
   235  	_, err := otsClient.CreateTable(&tablestore.CreateTableRequest{
   236  		TableMeta:          tableMeta,
   237  		TableOption:        tableOption,
   238  		ReservedThroughput: reservedThroughput,
   239  	})
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  }
   244  
   245  func deleteTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, tableName string) {
   246  	params := &tablestore.DeleteTableRequest{
   247  		TableName: tableName,
   248  	}
   249  	_, err := otsClient.DeleteTable(params)
   250  	if err != nil {
   251  		t.Logf("WARNING: Failed to delete the test TableStore table %q. It has been left in your Alibaba Cloud account and may incur charges. (error was %s)", tableName, err)
   252  	}
   253  }