Repository: opentofu/opentofu
File: internal/backend/remote-state/s3/client_test.go (Go)

Code before:
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			rc := RemoteClient{
				s3Client:    s3Cl,
				bucketName:  "test-bucket",
				path:        "state-file",
				useLockfile: true,
				lockTags:    tt.lockTags,
			}

			_, err := rc.Lock(t.Context(), statemgr.NewLockInfo())
			if err != nil {
				t.Fatalf("expected to have no error but got one: %s", err)
			}
			if httpCl.receivedReq == nil {
				t.Fatal("request didn't reach the mock http client")
			}
			gotTags := httpCl.receivedReq.Header.Get("x-amz-tagging")

			expectedTagsHeader := url.Values{}
			for k, v := range tt.lockTags {
				expectedTagsHeader.Add(k, v)
			}
			expectedTags := expectedTagsHeader.Encode()
			if gotTags != expectedTags {
				t.Errorf("Found tags %s did not match expected tags: %s", gotTags, expectedTags)
			}
		})
	}
}

func TestS3StateObjectTagging(t *testing.T) {
	// Configured the aws config the same way it is done for the backend to ensure a similar setup as the actual main logic.
	_, awsCfg, _ := awsbase.GetAwsConfig(context.Background(), &awsbase.Config{Region: "us-east-1", AccessKey: "test", SecretKey: "key"})
	httpCl := &mockHttpClient{resp: &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(""))}}
	s3Cl := s3.NewFromConfig(awsCfg, func(options *s3.Options) {
		options.HTTPClient = httpCl
	})

	tests := []struct {
		name         string
		action       func(cl *RemoteClient) error
		skipChecksum bool

		stateTags map[string]string
	}{
		{
			name:         "s3.Put with no tags",
			skipChecksum: false,

Review comment (suggestion):
Generally I think that it's better to have the expected values clearly stated in the test cases.
Eg:
```
{
  name:         "s3.Put with several tags",
  skipChecksum: false,
  lockTags: map[string]string{
    "a": "b",
    "c": "e",
    "f": "g",
  },
  expectedHeader: "a=b&c=e&f=g"
},
```

Not a big deal, but makes the test easier to read and review.

Code after:
				"f": "g",
			},
			expectedTags: "a=b&c=e&f=g",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			rc := RemoteClient{
				s3Client:    s3Cl,
				bucketName:  "test-bucket",
				path:        "state-file",
				useLockfile: true,
				lockTags:    tt.lockTags,
			}

			_, err := rc.Lock(t.Context(), statemgr.NewLockInfo())
			if err != nil {
				t.Fatalf("expected to have no error but got one: %s", err)
			}
			if httpCl.receivedReq == nil {
				t.Fatal("request didn't reach the mock http client")
			}
			gotTags := httpCl.receivedReq.Header.Get("x-amz-tagging")
			if gotTags != tt.expectedTags {
				t.Errorf("Found tags %s did not match expected tags: %s", gotTags, tt.expectedTags)
			}
		})
	}
}

func TestS3StateObjectTagging(t *testing.T) {
	// Configured the aws config the same way it is done for the backend to ensure a similar setup as the actual main logic.
	_, awsCfg, _ := awsbase.GetAwsConfig(context.Background(), &awsbase.Config{Region: "us-east-1", AccessKey: "test", SecretKey: "key"})
	httpCl := &mockHttpClient{resp: &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(""))}}
	s3Cl := s3.NewFromConfig(awsCfg, func(options *s3.Options) {
		options.HTTPClient = httpCl
	})

	tests := []struct {
		name         string
		action       func(cl *RemoteClient) error
		skipChecksum bool

		stateTags    map[string]string
		expectedTags string
	}{
		{
			name:         "s3.Put with no tags",
			skipChecksum: false,
			stateTags:    map[string]string{},
			expectedTags: "",