github.com/opentofu/opentofu@v1.7.1/internal/backend/remote-state/cos/backend_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package cos
     7  
     8  import (
     9  	"crypto/md5"
    10  	"fmt"
    11  	"os"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/opentofu/opentofu/internal/backend"
    16  	"github.com/opentofu/opentofu/internal/encryption"
    17  	"github.com/opentofu/opentofu/internal/states/remote"
    18  )
    19  
    20  const (
    21  	defaultPrefix = ""
    22  	defaultKey    = "terraform.tfstate"
    23  )
    24  
    25  // Testing Thanks to GCS
    26  
    27  func TestStateFile(t *testing.T) {
    28  	t.Parallel()
    29  
    30  	cases := []struct {
    31  		prefix        string
    32  		stateName     string
    33  		key           string
    34  		wantStateFile string
    35  		wantLockFile  string
    36  	}{
    37  		{"", "default", "default.tfstate", "default.tfstate", "default.tfstate.tflock"},
    38  		{"", "default", "test.tfstate", "test.tfstate", "test.tfstate.tflock"},
    39  		{"", "dev", "test.tfstate", "dev/test.tfstate", "dev/test.tfstate.tflock"},
    40  		{"terraform/test", "default", "default.tfstate", "terraform/test/default.tfstate", "terraform/test/default.tfstate.tflock"},
    41  		{"terraform/test", "default", "test.tfstate", "terraform/test/test.tfstate", "terraform/test/test.tfstate.tflock"},
    42  		{"terraform/test", "dev", "test.tfstate", "terraform/test/dev/test.tfstate", "terraform/test/dev/test.tfstate.tflock"},
    43  	}
    44  
    45  	for _, c := range cases {
    46  		t.Run(fmt.Sprintf("%s %s %s", c.prefix, c.key, c.stateName), func(t *testing.T) {
    47  			b := &Backend{
    48  				prefix: c.prefix,
    49  				key:    c.key,
    50  			}
    51  			if got, want := b.stateFile(c.stateName), c.wantStateFile; got != want {
    52  				t.Errorf("wrong state file name\ngot:  %s\nwant: %s", got, want)
    53  			}
    54  			if got, want := b.lockFile(c.stateName), c.wantLockFile; got != want {
    55  				t.Errorf("wrong lock file name\ngot:  %s\nwant: %s", got, want)
    56  			}
    57  		})
    58  	}
    59  }
    60  
    61  func TestRemoteClient(t *testing.T) {
    62  	t.Parallel()
    63  
    64  	bucket := bucketName(t)
    65  
    66  	be := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
    67  	defer teardownBackend(t, be)
    68  
    69  	ss, err := be.StateMgr(backend.DefaultStateName)
    70  	if err != nil {
    71  		t.Fatalf("unexpected error: %s", err)
    72  	}
    73  
    74  	rs, ok := ss.(*remote.State)
    75  	if !ok {
    76  		t.Fatalf("wrong state manager type\ngot:  %T\nwant: %T", ss, rs)
    77  	}
    78  
    79  	remote.TestClient(t, rs.Client)
    80  }
    81  
    82  func TestRemoteClientWithPrefix(t *testing.T) {
    83  	t.Parallel()
    84  
    85  	prefix := "prefix/test"
    86  	bucket := bucketName(t)
    87  
    88  	be := setupBackend(t, bucket, prefix, defaultKey, false)
    89  	defer teardownBackend(t, be)
    90  
    91  	ss, err := be.StateMgr(backend.DefaultStateName)
    92  	if err != nil {
    93  		t.Fatalf("unexpected error: %s", err)
    94  	}
    95  
    96  	rs, ok := ss.(*remote.State)
    97  	if !ok {
    98  		t.Fatalf("wrong state manager type\ngot:  %T\nwant: %T", ss, rs)
    99  	}
   100  
   101  	remote.TestClient(t, rs.Client)
   102  }
   103  
   104  func TestRemoteClientWithEncryption(t *testing.T) {
   105  	t.Parallel()
   106  
   107  	bucket := bucketName(t)
   108  
   109  	be := setupBackend(t, bucket, defaultPrefix, defaultKey, true)
   110  	defer teardownBackend(t, be)
   111  
   112  	ss, err := be.StateMgr(backend.DefaultStateName)
   113  	if err != nil {
   114  		t.Fatalf("unexpected error: %s", err)
   115  	}
   116  
   117  	rs, ok := ss.(*remote.State)
   118  	if !ok {
   119  		t.Fatalf("wrong state manager type\ngot:  %T\nwant: %T", ss, rs)
   120  	}
   121  
   122  	remote.TestClient(t, rs.Client)
   123  }
   124  
   125  func TestRemoteLocks(t *testing.T) {
   126  	t.Parallel()
   127  
   128  	bucket := bucketName(t)
   129  
   130  	be := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
   131  	defer teardownBackend(t, be)
   132  
   133  	remoteClient := func() (remote.Client, error) {
   134  		ss, err := be.StateMgr(backend.DefaultStateName)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  
   139  		rs, ok := ss.(*remote.State)
   140  		if !ok {
   141  			return nil, fmt.Errorf("be.StateMgr(): got a %T, want a *remote.State", ss)
   142  		}
   143  
   144  		return rs.Client, nil
   145  	}
   146  
   147  	c0, err := remoteClient()
   148  	if err != nil {
   149  		t.Fatalf("unexpected error: %s", err)
   150  	}
   151  
   152  	c1, err := remoteClient()
   153  	if err != nil {
   154  		t.Fatalf("unexpected error: %s", err)
   155  	}
   156  
   157  	remote.TestRemoteLocks(t, c0, c1)
   158  }
   159  
   160  func TestBackend(t *testing.T) {
   161  	t.Parallel()
   162  
   163  	bucket := bucketName(t)
   164  
   165  	be0 := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
   166  	defer teardownBackend(t, be0)
   167  
   168  	be1 := setupBackend(t, bucket, defaultPrefix, defaultKey, false)
   169  	defer teardownBackend(t, be1)
   170  
   171  	backend.TestBackendStates(t, be0)
   172  	backend.TestBackendStateLocks(t, be0, be1)
   173  	backend.TestBackendStateForceUnlock(t, be0, be1)
   174  }
   175  
   176  func TestBackendWithPrefix(t *testing.T) {
   177  	t.Parallel()
   178  
   179  	prefix := "prefix/test"
   180  	bucket := bucketName(t)
   181  
   182  	be0 := setupBackend(t, bucket, prefix, defaultKey, false)
   183  	defer teardownBackend(t, be0)
   184  
   185  	be1 := setupBackend(t, bucket, prefix+"/", defaultKey, false)
   186  	defer teardownBackend(t, be1)
   187  
   188  	backend.TestBackendStates(t, be0)
   189  	backend.TestBackendStateLocks(t, be0, be1)
   190  }
   191  
   192  func TestBackendWithEncryption(t *testing.T) {
   193  	t.Parallel()
   194  
   195  	bucket := bucketName(t)
   196  
   197  	be0 := setupBackend(t, bucket, defaultPrefix, defaultKey, true)
   198  	defer teardownBackend(t, be0)
   199  
   200  	be1 := setupBackend(t, bucket, defaultPrefix, defaultKey, true)
   201  	defer teardownBackend(t, be1)
   202  
   203  	backend.TestBackendStates(t, be0)
   204  	backend.TestBackendStateLocks(t, be0, be1)
   205  }
   206  
   207  func setupBackend(t *testing.T, bucket, prefix, key string, encrypt bool) backend.Backend {
   208  	t.Helper()
   209  
   210  	skip := os.Getenv("TF_COS_APPID") == ""
   211  	if skip {
   212  		t.Skip("This test require setting TF_COS_APPID environment variables")
   213  	}
   214  
   215  	if os.Getenv(PROVIDER_REGION) == "" {
   216  		t.Setenv(PROVIDER_REGION, "ap-guangzhou")
   217  	}
   218  
   219  	appId := os.Getenv("TF_COS_APPID")
   220  	region := os.Getenv(PROVIDER_REGION)
   221  
   222  	config := map[string]interface{}{
   223  		"region": region,
   224  		"bucket": bucket + appId,
   225  		"prefix": prefix,
   226  		"key":    key,
   227  	}
   228  
   229  	b := backend.TestBackendConfig(t, New(encryption.StateEncryptionDisabled()), backend.TestWrapConfig(config))
   230  	be := b.(*Backend)
   231  
   232  	c, err := be.client("tencentcloud")
   233  	if err != nil {
   234  		t.Fatalf("unexpected error: %s", err)
   235  	}
   236  
   237  	err = c.putBucket()
   238  	if err != nil {
   239  		t.Fatalf("unexpected error: %s", err)
   240  	}
   241  
   242  	return b
   243  }
   244  
   245  func teardownBackend(t *testing.T, b backend.Backend) {
   246  	t.Helper()
   247  
   248  	c, err := b.(*Backend).client("tencentcloud")
   249  	if err != nil {
   250  		t.Fatalf("unexpected error: %s", err)
   251  	}
   252  
   253  	err = c.deleteBucket(true)
   254  	if err != nil {
   255  		t.Fatalf("unexpected error: %s", err)
   256  	}
   257  }
   258  
   259  func bucketName(t *testing.T) string {
   260  	unique := fmt.Sprintf("%s-%x", t.Name(), time.Now().UnixNano())
   261  	return fmt.Sprintf("terraform-test-%s-%s", fmt.Sprintf("%x", md5.Sum([]byte(unique)))[:10], "")
   262  }