@@ -4,11 +4,16 @@ package dataprocmetastore_test
44
55import (
66 "fmt"
7- "github.com/hashicorp/terraform-provider-google/google/acctest "
7+ "net/url "
88 "regexp"
99 "testing"
1010
1111 "github.com/hashicorp/terraform-plugin-testing/helper/resource"
12+ "github.com/hashicorp/terraform-plugin-testing/terraform"
13+ "github.com/hashicorp/terraform-provider-google/google/acctest"
14+ "github.com/hashicorp/terraform-provider-google/google/envvar"
15+ transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
16+ "strings"
1217)
1318
1419func TestAccMetastoreFederation_deletionprotection (t * testing.T ) {
@@ -46,6 +51,37 @@ func TestAccMetastoreFederation_deletionprotection(t *testing.T) {
4651 })
4752}
4853
54+ func TestAccMetastoreFederation_tags (t * testing.T ) {
55+ t .Parallel ()
56+ tagKey := acctest .BootstrapSharedTestOrganizationTagKey (t , "metastore-fed-tagkey" , map [string ]interface {}{})
57+ context := map [string ]interface {}{
58+ "random_suffix" : acctest .RandString (t , 10 ),
59+ "org" : envvar .GetTestOrgFromEnv (t ),
60+ "tagKey" : tagKey ,
61+ "tagValue" : acctest .BootstrapSharedTestOrganizationTagValue (t , "metastore-fed-tagvalue" , tagKey ),
62+ }
63+ acctest .VcrTest (t , resource.TestCase {
64+ PreCheck : func () { acctest .AccTestPreCheck (t ) },
65+ ProtoV5ProviderFactories : acctest .ProtoV5ProviderFactories (t ),
66+ CheckDestroy : testAccCheckDataprocMetastoreFederationDestroyProducer (t ),
67+ Steps : []resource.TestStep {
68+ {
69+ Config : testAccMetastoreFederationTags (context ),
70+ Check : resource .ComposeTestCheckFunc (
71+ resource .TestCheckResourceAttrSet ("google_dataproc_metastore_federation.default" , "tags.%" ),
72+ testAccCheckMetastoreFederationHasTagBindings (t ),
73+ ),
74+ },
75+ {
76+ ResourceName : "google_dataproc_metastore_federation.default" ,
77+ ImportState : true ,
78+ ImportStateVerify : true ,
79+ ImportStateVerifyIgnore : []string {"federation_id" , "location" , "tags" },
80+ },
81+ },
82+ })
83+ }
84+
4985func testAccMetastoreFederationDeletionProtection (name string , location string ) string {
5086
5187 return fmt .Sprintf (`
@@ -97,3 +133,136 @@ func testAccMetastoreFederationDeletionProtectionFalse(name string, location str
97133}
98134` , name , name , location )
99135}
136+
137+ func testAccCheckMetastoreFederationHasTagBindings (t * testing.T ) func (s * terraform.State ) error {
138+ return func (s * terraform.State ) error {
139+ for name , rs := range s .RootModule ().Resources {
140+ if rs .Type != "google_dataproc_metastore_federation" {
141+ continue
142+ }
143+ if strings .HasPrefix (name , "data." ) {
144+ continue
145+ }
146+
147+ config := acctest .GoogleProviderConfig (t )
148+
149+ var configuredTagValueNamespacedName string
150+ var tagKeyNamespacedName , tagValueShortName string
151+ for key , val := range rs .Primary .Attributes {
152+ if strings .HasPrefix (key , "tags." ) && key != "tags.%" {
153+ tagKeyNamespacedName = strings .TrimPrefix (key , "tags." )
154+ tagValueShortName = val
155+ if tagValueShortName != "" {
156+ configuredTagValueNamespacedName = fmt .Sprintf ("%s/%s" , tagKeyNamespacedName , tagValueShortName )
157+ break
158+ }
159+ }
160+ }
161+
162+ if configuredTagValueNamespacedName == "" {
163+ return fmt .Errorf ("could not find a configured tag value in the state for resource %s" , rs .Primary .ID )
164+ }
165+
166+ if strings .Contains (configuredTagValueNamespacedName , "%{" ) {
167+ return fmt .Errorf ("tag namespaced name contains unsubstituted variables: %q. Ensure the context map in the test step is populated" , configuredTagValueNamespacedName )
168+ }
169+
170+ safeNamespacedName := url .QueryEscape (configuredTagValueNamespacedName )
171+ describeTagValueURL := fmt .Sprintf ("https://cloudresourcemanager.googleapis.com/v3/tagValues/namespaced?name=%s" , safeNamespacedName )
172+
173+ respDescribe , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
174+ Config : config ,
175+ Method : "GET" ,
176+ RawURL : describeTagValueURL ,
177+ UserAgent : config .UserAgent ,
178+ })
179+
180+ if err != nil {
181+ return fmt .Errorf ("error describing tag value using namespaced name %q: %v" , configuredTagValueNamespacedName , err )
182+ }
183+
184+ fullTagValueName , ok := respDescribe ["name" ].(string )
185+ if ! ok || fullTagValueName == "" {
186+ return fmt .Errorf ("tag value details (name) not found in response for namespaced name: %q, response: %v" , configuredTagValueNamespacedName , respDescribe )
187+ }
188+
189+ parts := strings .Split (rs .Primary .ID , "/" )
190+ if len (parts ) != 6 {
191+ return fmt .Errorf ("invalid resource ID format: %s" , rs .Primary .ID )
192+ }
193+ project := parts [1 ]
194+ location := parts [3 ]
195+ federation_id := parts [5 ]
196+
197+ parentURL := fmt .Sprintf ("//metastore.googleapis.com/projects/%s/locations/%s/federations/%s" , project , location , federation_id )
198+ listBindingsURL := fmt .Sprintf ("https://%s-cloudresourcemanager.googleapis.com/v3/tagBindings?parent=%s" , location , url .QueryEscape (parentURL ))
199+
200+ resp , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
201+ Config : config ,
202+ Method : "GET" ,
203+ RawURL : listBindingsURL ,
204+ UserAgent : config .UserAgent ,
205+ })
206+
207+ if err != nil {
208+ return fmt .Errorf ("error calling TagBindings API: %v" , err )
209+ }
210+
211+ tagBindingsVal , exists := resp ["tagBindings" ]
212+ if ! exists {
213+ tagBindingsVal = []interface {}{}
214+ }
215+
216+ tagBindings , ok := tagBindingsVal .([]interface {})
217+ if ! ok {
218+ return fmt .Errorf ("'tagBindings' is not a slice in response for resource %s. Response: %v" , rs .Primary .ID , resp )
219+ }
220+
221+ foundMatch := false
222+ for _ , binding := range tagBindings {
223+ bindingMap , ok := binding .(map [string ]interface {})
224+ if ! ok {
225+ continue
226+ }
227+ if bindingMap ["tagValue" ] == fullTagValueName {
228+ foundMatch = true
229+ break
230+ }
231+ }
232+
233+ if ! foundMatch {
234+ return fmt .Errorf ("expected tag value %s (from namespaced %q) not found in tag bindings for resource %s. Bindings: %v" , fullTagValueName , configuredTagValueNamespacedName , rs .Primary .ID , tagBindings )
235+ }
236+
237+ t .Logf ("Successfully found matching tag binding for %s with tagValue %s" , rs .Primary .ID , fullTagValueName )
238+ }
239+
240+ return nil
241+ }
242+ }
243+
244+ func testAccMetastoreFederationTags (context map [string ]interface {}) string {
245+ return acctest .Nprintf (`
246+ resource "google_dataproc_metastore_service" "backend" {
247+ service_id = "tf-test-service-%{random_suffix}"
248+ location = "us-east1"
249+ tier = "DEVELOPER"
250+ hive_metastore_config {
251+ version = "3.1.2"
252+ endpoint_protocol = "GRPC"
253+ }
254+ }
255+ resource "google_dataproc_metastore_federation" "default" {
256+ federation_id = "tf-test-federation-%{random_suffix}"
257+ location = "us-east1"
258+ version = "3.1.2"
259+ backend_metastores {
260+ name = google_dataproc_metastore_service.backend.id
261+ metastore_type = "DATAPROC_METASTORE"
262+ rank = "1"
263+ }
264+ tags = {
265+ "%{org}/%{tagKey}" = "%{tagValue}"
266+ }
267+ }` , context )
268+ }
0 commit comments