@@ -20,11 +20,16 @@ package dataprocmetastore_test
2020
2121import (
2222 "fmt"
23- "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest "
23+ "net/url "
2424 "regexp"
2525 "testing"
2626
2727 "github.com/hashicorp/terraform-plugin-testing/helper/resource"
28+ "github.com/hashicorp/terraform-plugin-testing/terraform"
29+ "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
30+ "github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar"
31+ transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
32+ "strings"
2833)
2934
3035func TestAccMetastoreFederation_deletionprotection (t * testing.T ) {
@@ -62,6 +67,37 @@ func TestAccMetastoreFederation_deletionprotection(t *testing.T) {
6267 })
6368}
6469
70+ func TestAccMetastoreFederation_tags (t * testing.T ) {
71+ t .Parallel ()
72+ tagKey := acctest .BootstrapSharedTestOrganizationTagKey (t , "metastore-fed-tagkey" , map [string ]interface {}{})
73+ context := map [string ]interface {}{
74+ "random_suffix" : acctest .RandString (t , 10 ),
75+ "org" : envvar .GetTestOrgFromEnv (t ),
76+ "tagKey" : tagKey ,
77+ "tagValue" : acctest .BootstrapSharedTestOrganizationTagValue (t , "metastore-fed-tagvalue" , tagKey ),
78+ }
79+ acctest .VcrTest (t , resource.TestCase {
80+ PreCheck : func () { acctest .AccTestPreCheck (t ) },
81+ ProtoV5ProviderFactories : acctest .ProtoV5ProviderFactories (t ),
82+ CheckDestroy : testAccCheckDataprocMetastoreFederationDestroyProducer (t ),
83+ Steps : []resource.TestStep {
84+ {
85+ Config : testAccMetastoreFederationTags (context ),
86+ Check : resource .ComposeTestCheckFunc (
87+ resource .TestCheckResourceAttrSet ("google_dataproc_metastore_federation.default" , "tags.%" ),
88+ testAccCheckMetastoreFederationHasTagBindings (t ),
89+ ),
90+ },
91+ {
92+ ResourceName : "google_dataproc_metastore_federation.default" ,
93+ ImportState : true ,
94+ ImportStateVerify : true ,
95+ ImportStateVerifyIgnore : []string {"federation_id" , "location" , "tags" },
96+ },
97+ },
98+ })
99+ }
100+
65101func testAccMetastoreFederationDeletionProtection (name string , location string ) string {
66102
67103 return fmt .Sprintf (`
@@ -113,3 +149,136 @@ func testAccMetastoreFederationDeletionProtectionFalse(name string, location str
113149}
114150` , name , name , location )
115151}
152+
153+ func testAccCheckMetastoreFederationHasTagBindings (t * testing.T ) func (s * terraform.State ) error {
154+ return func (s * terraform.State ) error {
155+ for name , rs := range s .RootModule ().Resources {
156+ if rs .Type != "google_dataproc_metastore_federation" {
157+ continue
158+ }
159+ if strings .HasPrefix (name , "data." ) {
160+ continue
161+ }
162+
163+ config := acctest .GoogleProviderConfig (t )
164+
165+ var configuredTagValueNamespacedName string
166+ var tagKeyNamespacedName , tagValueShortName string
167+ for key , val := range rs .Primary .Attributes {
168+ if strings .HasPrefix (key , "tags." ) && key != "tags.%" {
169+ tagKeyNamespacedName = strings .TrimPrefix (key , "tags." )
170+ tagValueShortName = val
171+ if tagValueShortName != "" {
172+ configuredTagValueNamespacedName = fmt .Sprintf ("%s/%s" , tagKeyNamespacedName , tagValueShortName )
173+ break
174+ }
175+ }
176+ }
177+
178+ if configuredTagValueNamespacedName == "" {
179+ return fmt .Errorf ("could not find a configured tag value in the state for resource %s" , rs .Primary .ID )
180+ }
181+
182+ if strings .Contains (configuredTagValueNamespacedName , "%{" ) {
183+ return fmt .Errorf ("tag namespaced name contains unsubstituted variables: %q. Ensure the context map in the test step is populated" , configuredTagValueNamespacedName )
184+ }
185+
186+ safeNamespacedName := url .QueryEscape (configuredTagValueNamespacedName )
187+ describeTagValueURL := fmt .Sprintf ("https://cloudresourcemanager.googleapis.com/v3/tagValues/namespaced?name=%s" , safeNamespacedName )
188+
189+ respDescribe , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
190+ Config : config ,
191+ Method : "GET" ,
192+ RawURL : describeTagValueURL ,
193+ UserAgent : config .UserAgent ,
194+ })
195+
196+ if err != nil {
197+ return fmt .Errorf ("error describing tag value using namespaced name %q: %v" , configuredTagValueNamespacedName , err )
198+ }
199+
200+ fullTagValueName , ok := respDescribe ["name" ].(string )
201+ if ! ok || fullTagValueName == "" {
202+ return fmt .Errorf ("tag value details (name) not found in response for namespaced name: %q, response: %v" , configuredTagValueNamespacedName , respDescribe )
203+ }
204+
205+ parts := strings .Split (rs .Primary .ID , "/" )
206+ if len (parts ) != 6 {
207+ return fmt .Errorf ("invalid resource ID format: %s" , rs .Primary .ID )
208+ }
209+ project := parts [1 ]
210+ location := parts [3 ]
211+ federation_id := parts [5 ]
212+
213+ parentURL := fmt .Sprintf ("//metastore.googleapis.com/projects/%s/locations/%s/federations/%s" , project , location , federation_id )
214+ listBindingsURL := fmt .Sprintf ("https://%s-cloudresourcemanager.googleapis.com/v3/tagBindings?parent=%s" , location , url .QueryEscape (parentURL ))
215+
216+ resp , err := transport_tpg .SendRequest (transport_tpg.SendRequestOptions {
217+ Config : config ,
218+ Method : "GET" ,
219+ RawURL : listBindingsURL ,
220+ UserAgent : config .UserAgent ,
221+ })
222+
223+ if err != nil {
224+ return fmt .Errorf ("error calling TagBindings API: %v" , err )
225+ }
226+
227+ tagBindingsVal , exists := resp ["tagBindings" ]
228+ if ! exists {
229+ tagBindingsVal = []interface {}{}
230+ }
231+
232+ tagBindings , ok := tagBindingsVal .([]interface {})
233+ if ! ok {
234+ return fmt .Errorf ("'tagBindings' is not a slice in response for resource %s. Response: %v" , rs .Primary .ID , resp )
235+ }
236+
237+ foundMatch := false
238+ for _ , binding := range tagBindings {
239+ bindingMap , ok := binding .(map [string ]interface {})
240+ if ! ok {
241+ continue
242+ }
243+ if bindingMap ["tagValue" ] == fullTagValueName {
244+ foundMatch = true
245+ break
246+ }
247+ }
248+
249+ if ! foundMatch {
250+ 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 )
251+ }
252+
253+ t .Logf ("Successfully found matching tag binding for %s with tagValue %s" , rs .Primary .ID , fullTagValueName )
254+ }
255+
256+ return nil
257+ }
258+ }
259+
260+ func testAccMetastoreFederationTags (context map [string ]interface {}) string {
261+ return acctest .Nprintf (`
262+ resource "google_dataproc_metastore_service" "backend" {
263+ service_id = "tf-test-service-%{random_suffix}"
264+ location = "us-east1"
265+ tier = "DEVELOPER"
266+ hive_metastore_config {
267+ version = "3.1.2"
268+ endpoint_protocol = "GRPC"
269+ }
270+ }
271+ resource "google_dataproc_metastore_federation" "default" {
272+ federation_id = "tf-test-federation-%{random_suffix}"
273+ location = "us-east1"
274+ version = "3.1.2"
275+ backend_metastores {
276+ name = google_dataproc_metastore_service.backend.id
277+ metastore_type = "DATAPROC_METASTORE"
278+ rank = "1"
279+ }
280+ tags = {
281+ "%{org}/%{tagKey}" = "%{tagValue}"
282+ }
283+ }` , context )
284+ }
0 commit comments