|
| 1 | +// Copyright 2024 StreamNative, Inc. |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
1 | 15 | package cloud |
2 | 16 |
|
3 | 17 | import ( |
@@ -36,6 +50,28 @@ func TestSecret(t *testing.T) { |
36 | 50 | }) |
37 | 51 | } |
38 | 52 |
|
| 53 | +func TestSecretStringData(t *testing.T) { |
| 54 | + stringData := map[string]string{ |
| 55 | + "username": "tf-user-string", |
| 56 | + "password": "tf-password-string", |
| 57 | + } |
| 58 | + resource.Test(t, resource.TestCase{ |
| 59 | + PreCheck: func() { |
| 60 | + testAccPreCheck(t) |
| 61 | + }, |
| 62 | + ProviderFactories: testAccProviderFactories, |
| 63 | + CheckDestroy: testCheckSecretDestroy, |
| 64 | + Steps: []resource.TestStep{ |
| 65 | + { |
| 66 | + Config: testResourceDataSourceSecretWithStringData("sndev", "terraform-test-secret-stringdata", stringData), |
| 67 | + Check: resource.ComposeTestCheckFunc( |
| 68 | + testCheckSecretExists("streamnative_secret.test-secret", stringData), |
| 69 | + ), |
| 70 | + }, |
| 71 | + }, |
| 72 | + }) |
| 73 | +} |
| 74 | + |
39 | 75 | func TestSecretRemovedExternally(t *testing.T) { |
40 | 76 | data := map[string]string{ |
41 | 77 | "token": "removed-secret", |
@@ -75,6 +111,43 @@ func TestSecretRemovedExternally(t *testing.T) { |
75 | 111 | }) |
76 | 112 | } |
77 | 113 |
|
| 114 | +func TestSecretUpdate(t *testing.T) { |
| 115 | + initialData := map[string]string{ |
| 116 | + "username": "tf-user-update", |
| 117 | + "password": "tf-password-update", |
| 118 | + } |
| 119 | + updatedStringData := map[string]string{ |
| 120 | + "username": "tf-user-updated", |
| 121 | + "password": "tf-password-updated", |
| 122 | + } |
| 123 | + initialType := "Opaque" |
| 124 | + updatedType := "kubernetes.io/basic-auth" |
| 125 | + initialInstance := "pulsar-instance-a" |
| 126 | + updatedInstance := "pulsar-instance-b" |
| 127 | + |
| 128 | + resource.Test(t, resource.TestCase{ |
| 129 | + PreCheck: func() { |
| 130 | + testAccPreCheck(t) |
| 131 | + }, |
| 132 | + ProviderFactories: testAccProviderFactories, |
| 133 | + CheckDestroy: testCheckSecretDestroy, |
| 134 | + Steps: []resource.TestStep{ |
| 135 | + { |
| 136 | + Config: testResourceDataSourceSecretWithParams("sndev", "terraform-test-secret-update", initialData, nil, initialType, initialInstance), |
| 137 | + Check: resource.ComposeTestCheckFunc( |
| 138 | + testCheckSecretState("streamnative_secret.test-secret", initialData, &initialType, &initialInstance), |
| 139 | + ), |
| 140 | + }, |
| 141 | + { |
| 142 | + Config: testResourceDataSourceSecretWithParams("sndev", "terraform-test-secret-update", nil, updatedStringData, updatedType, updatedInstance), |
| 143 | + Check: resource.ComposeTestCheckFunc( |
| 144 | + testCheckSecretState("streamnative_secret.test-secret", updatedStringData, &updatedType, &updatedInstance), |
| 145 | + ), |
| 146 | + }, |
| 147 | + }, |
| 148 | + }) |
| 149 | +} |
| 150 | + |
78 | 151 | func testCheckSecretDestroy(s *terraform.State) error { |
79 | 152 | time.Sleep(5 * time.Second) |
80 | 153 | for _, rs := range s.RootModule().Resources { |
@@ -135,30 +208,116 @@ func testCheckSecretExists(name string, expectedData map[string]string) resource |
135 | 208 | } |
136 | 209 |
|
137 | 210 | func testResourceDataSourceSecret(organization string, name string, data map[string]string) string { |
138 | | - keys := make([]string, 0, len(data)) |
139 | | - for k := range data { |
140 | | - keys = append(keys, k) |
141 | | - } |
142 | | - sort.Strings(keys) |
143 | | - var builder strings.Builder |
144 | | - for _, k := range keys { |
145 | | - builder.WriteString(fmt.Sprintf(` %s = "%s"`+"\n", k, data[k])) |
146 | | - } |
147 | | - return fmt.Sprintf(` |
148 | | -provider "streamnative" { |
| 211 | + return testResourceDataSourceSecretWithParams(organization, name, data, nil, "", "") |
| 212 | +} |
| 213 | + |
| 214 | +func testResourceDataSourceSecretWithStringData(organization string, name string, stringData map[string]string) string { |
| 215 | + return testResourceDataSourceSecretWithParams(organization, name, nil, stringData, "", "") |
149 | 216 | } |
150 | 217 |
|
151 | | -resource "streamnative_secret" "test-secret" { |
| 218 | +func testResourceDataSourceSecretWithParams( |
| 219 | + organization string, |
| 220 | + name string, |
| 221 | + data map[string]string, |
| 222 | + stringData map[string]string, |
| 223 | + secretType string, |
| 224 | + instanceName string, |
| 225 | +) string { |
| 226 | + var resourceBuilder strings.Builder |
| 227 | + resourceBuilder.WriteString(fmt.Sprintf(`resource "streamnative_secret" "test-secret" { |
152 | 228 | organization = "%s" |
153 | 229 | name = "%s" |
154 | | - data = { |
155 | | -%s } |
| 230 | +`, organization, name)) |
| 231 | + if instanceName != "" { |
| 232 | + resourceBuilder.WriteString(fmt.Sprintf(` instance_name = "%s" |
| 233 | +`, instanceName)) |
| 234 | + } |
| 235 | + if secretType != "" { |
| 236 | + resourceBuilder.WriteString(fmt.Sprintf(` type = "%s" |
| 237 | +`, secretType)) |
| 238 | + } |
| 239 | + if len(data) > 0 { |
| 240 | + resourceBuilder.WriteString(" data = {\n") |
| 241 | + resourceBuilder.WriteString(buildHCLMap(data)) |
| 242 | + resourceBuilder.WriteString(" }\n") |
| 243 | + } |
| 244 | + if len(stringData) > 0 { |
| 245 | + resourceBuilder.WriteString(" string_data = {\n") |
| 246 | + resourceBuilder.WriteString(buildHCLMap(stringData)) |
| 247 | + resourceBuilder.WriteString(" }\n") |
| 248 | + } |
| 249 | + resourceBuilder.WriteString("}\n") |
| 250 | + |
| 251 | + return fmt.Sprintf(` |
| 252 | +provider "streamnative" { |
156 | 253 | } |
157 | 254 |
|
| 255 | +%s |
158 | 256 | data "streamnative_secret" "test-secret" { |
159 | 257 | depends_on = [streamnative_secret.test-secret] |
160 | 258 | organization = streamnative_secret.test-secret.organization |
161 | 259 | name = streamnative_secret.test-secret.name |
162 | 260 | } |
163 | | -`, organization, name, builder.String()) |
| 261 | +`, resourceBuilder.String()) |
| 262 | +} |
| 263 | + |
| 264 | +func buildHCLMap(values map[string]string) string { |
| 265 | + keys := make([]string, 0, len(values)) |
| 266 | + for k := range values { |
| 267 | + keys = append(keys, k) |
| 268 | + } |
| 269 | + sort.Strings(keys) |
| 270 | + var builder strings.Builder |
| 271 | + for _, k := range keys { |
| 272 | + builder.WriteString(fmt.Sprintf(` %s = "%s"`+"\n", k, values[k])) |
| 273 | + } |
| 274 | + return builder.String() |
| 275 | +} |
| 276 | + |
| 277 | +func testCheckSecretState(name string, expectedData map[string]string, expectedType *string, expectedInstanceName *string) resource.TestCheckFunc { |
| 278 | + return func(s *terraform.State) error { |
| 279 | + rs, ok := s.RootModule().Resources[name] |
| 280 | + if !ok { |
| 281 | + return fmt.Errorf(`ERROR_RESOURCE_SECRET_NOT_FOUND: "%s"`, name) |
| 282 | + } |
| 283 | + if rs.Primary.ID == "" { |
| 284 | + return fmt.Errorf(`ERROR_RESOURCE_SECRET_ID_NOT_SET`) |
| 285 | + } |
| 286 | + meta := testAccProvider.Meta() |
| 287 | + clientSet, err := getClientSet(getFactoryFromMeta(meta)) |
| 288 | + if err != nil { |
| 289 | + return err |
| 290 | + } |
| 291 | + parts := strings.Split(rs.Primary.ID, "/") |
| 292 | + secret, err := clientSet.CloudV1alpha1(). |
| 293 | + Secrets(parts[0]). |
| 294 | + Get(context.Background(), parts[1], metav1.GetOptions{}) |
| 295 | + if err != nil { |
| 296 | + return err |
| 297 | + } |
| 298 | + if expectedData != nil { |
| 299 | + if len(secret.Data) != len(expectedData) { |
| 300 | + return fmt.Errorf("unexpected secret data length: got %d, expected %d", len(secret.Data), len(expectedData)) |
| 301 | + } |
| 302 | + for k, v := range expectedData { |
| 303 | + if secret.Data[k] != v { |
| 304 | + return fmt.Errorf("secret data mismatch for key %q: got %q, expected %q", k, secret.Data[k], v) |
| 305 | + } |
| 306 | + } |
| 307 | + } |
| 308 | + if expectedType != nil { |
| 309 | + if secret.Type == nil { |
| 310 | + return fmt.Errorf("secret type is nil, expected %q", *expectedType) |
| 311 | + } |
| 312 | + if string(*secret.Type) != *expectedType { |
| 313 | + return fmt.Errorf("secret type mismatch: got %q, expected %q", string(*secret.Type), *expectedType) |
| 314 | + } |
| 315 | + } |
| 316 | + if expectedInstanceName != nil { |
| 317 | + if secret.InstanceName != *expectedInstanceName { |
| 318 | + return fmt.Errorf("secret instance_name mismatch: got %q, expected %q", secret.InstanceName, *expectedInstanceName) |
| 319 | + } |
| 320 | + } |
| 321 | + return nil |
| 322 | + } |
164 | 323 | } |
0 commit comments