@@ -262,6 +262,113 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns() {
262262 }
263263}
264264
265+ func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_AllValuesHaveProperFqns () {
266+ namespace := "testing_multiple_fqns.properfqns"
267+ attr := "test_attr"
268+ value1 := "test_value"
269+ value2 := "test_value_2"
270+ value3 := "testing_values_3"
271+ fqn1 := fqnBuilder (namespace , attr , value1 )
272+ fqn2 := fqnBuilder (namespace , attr , value2 )
273+ fqn3 := fqnBuilder (namespace , attr , value3 )
274+
275+ // Create namespace
276+ n , err := s .db .PolicyClient .CreateNamespace (s .ctx , & namespaces.CreateNamespaceRequest {
277+ Name : namespace ,
278+ })
279+ s .Require ().NoError (err )
280+
281+ // Create attribute
282+ a , err := s .db .PolicyClient .CreateAttribute (s .ctx , & attributes.CreateAttributeRequest {
283+ NamespaceId : n .GetId (),
284+ Name : attr ,
285+ Rule : policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF ,
286+ })
287+ s .Require ().NoError (err )
288+
289+ // Create attribute value1
290+ v1 , err := s .db .PolicyClient .CreateAttributeValue (s .ctx , a .GetId (), & attributes.CreateAttributeValueRequest {
291+ Value : value1 ,
292+ })
293+ s .Require ().NoError (err )
294+
295+ // Get attributes by fqns with a solo value
296+ fqns := []string {fqn1 }
297+ attributeAndValues , err := s .db .PolicyClient .GetAttributesByValueFqns (s .ctx , & attributes.GetAttributeValuesByFqnsRequest {
298+ Fqns : fqns ,
299+ WithValue : & policy.AttributeValueSelector {
300+ WithSubjectMaps : true ,
301+ },
302+ })
303+ s .Require ().NoError (err )
304+
305+ // Verify attribute1 is sole attribute
306+ s .Len (attributeAndValues , 1 )
307+ val , ok := attributeAndValues [fqn1 ]
308+ s .True (ok )
309+ s .Equal (a .GetId (), val .GetAttribute ().GetId ())
310+
311+ s .Equal (v1 .GetId (), val .GetAttribute ().GetValues ()[0 ].GetId ())
312+ s .Equal (v1 .GetValue (), val .GetValue ().GetValue ())
313+
314+ s .Equal (v1 .GetValue (), val .GetAttribute ().GetValues ()[0 ].GetValue ())
315+ s .Equal (v1 .GetId (), val .GetValue ().GetId ())
316+
317+ // Create attribute value2
318+ v2 , err := s .db .PolicyClient .CreateAttributeValue (s .ctx , a .GetId (), & attributes.CreateAttributeValueRequest {
319+ Value : value2 ,
320+ })
321+ s .Require ().NoError (err )
322+
323+ // Create attribute value3
324+ v3 , err := s .db .PolicyClient .CreateAttributeValue (s .ctx , a .GetId (), & attributes.CreateAttributeValueRequest {
325+ Value : value3 ,
326+ })
327+ s .Require ().NoError (err )
328+ s .NotNil (v3 )
329+
330+ // Get attributes by fqns with all three values
331+ fqns = []string {fqn1 , fqn2 , fqn3 }
332+ attributeAndValues , err = s .db .PolicyClient .GetAttributesByValueFqns (s .ctx , & attributes.GetAttributeValuesByFqnsRequest {
333+ Fqns : fqns ,
334+ WithValue : & policy.AttributeValueSelector {
335+ WithSubjectMaps : true ,
336+ },
337+ })
338+ s .Require ().NoError (err )
339+ s .Len (attributeAndValues , 3 )
340+
341+ val , ok = attributeAndValues [fqn2 ]
342+ s .True (ok )
343+ s .Equal (a .GetId (), val .GetAttribute ().GetId ())
344+
345+ val , ok = attributeAndValues [fqn3 ]
346+ s .True (ok )
347+ s .Equal (a .GetId (), val .GetAttribute ().GetId ())
348+
349+ // ensure fqns are properly found in response for each value
350+ for fqn , attrAndVal := range attributeAndValues {
351+ values := attrAndVal .GetAttribute ().GetValues ()
352+ s .Equal (fqn , attrAndVal .GetValue ().GetFqn ())
353+ for i , v := range values {
354+ s .Equal (fqns [i ], v .GetFqn ())
355+ switch {
356+ case v .GetId () == v1 .GetId ():
357+ s .Equal (v1 .GetId (), v .GetId ())
358+ s .Equal (v1 .GetValue (), v .GetValue ())
359+ case v .GetId () == v2 .GetId ():
360+ s .Equal (v2 .GetId (), v .GetId ())
361+ s .Equal (v2 .GetValue (), v .GetValue ())
362+ case v .GetId () == v3 .GetId ():
363+ s .Equal (v3 .GetId (), v .GetId ())
364+ s .Equal (v3 .GetValue (), v .GetValue ())
365+ default :
366+ s .Fail ("unexpected value" , v )
367+ }
368+ }
369+ }
370+ }
371+
265372func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_Fails_WithDeactivatedNamespace () {
266373 // create a new namespace
267374 ns , err := s .db .PolicyClient .CreateNamespace (s .ctx , & namespaces.CreateNamespaceRequest {
@@ -369,7 +476,7 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedAt
369476func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_Fails_WithDeactivatedAttributeValue () {
370477 // create a new namespace
371478 ns , err := s .db .PolicyClient .CreateNamespace (s .ctx , & namespaces.CreateNamespaceRequest {
372- Name : "test_fqn_namespace.goodbye " ,
479+ Name : "test_fqn_namespace.example " ,
373480 })
374481 s .Require ().NoError (err )
375482
@@ -378,20 +485,17 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedAt
378485 NamespaceId : ns .GetId (),
379486 Name : "deactivating_attr" ,
380487 Rule : policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF ,
488+ Values : []string {"value1" , "value2" },
381489 })
382490 s .Require ().NoError (err )
383-
384- v1 , err := s .db .PolicyClient .CreateAttributeValue (s .ctx , attr .GetId (), & attributes.CreateAttributeValueRequest {
385- Value : "value1" ,
386- })
491+ got , _ := s .db .PolicyClient .GetAttribute (s .ctx , attr .GetId ())
387492 s .Require ().NoError (err )
493+ values := got .GetValues ()
494+ s .Len (values , 2 )
495+ v1 := values [0 ]
496+ v2 := values [1 ]
388497
389- v2 , err := s .db .PolicyClient .CreateAttributeValue (s .ctx , attr .GetId (), & attributes.CreateAttributeValueRequest {
390- Value : "value2" ,
391- })
392- s .Require ().NoError (err )
393-
394- // deactivate the first attribute value only
498+ // deactivate an attribute value
395499 _ , err = s .db .PolicyClient .DeactivateAttributeValue (s .ctx , v1 .GetId ())
396500 s .Require ().NoError (err )
397501
@@ -414,7 +518,142 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedAt
414518 },
415519 })
416520 s .Require ().NoError (err )
417- s .Len (v , 1 )
521+ s .NotNil (v )
522+ }
523+
524+ // UnsafeReactivateAttributevalue: active namespace, inactive definition, unsafely active value (fails)
525+ func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_Fails_InactiveDef_ActiveNsAndValue () {
526+ // create a new namespace
527+ ns , err := s .db .PolicyClient .CreateNamespace (s .ctx , & namespaces.CreateNamespaceRequest {
528+ Name : "test_namespace.uk" ,
529+ })
530+ s .Require ().NoError (err )
531+
532+ // give it an attribute with two values
533+ attr , err := s .db .PolicyClient .CreateAttribute (s .ctx , & attributes.CreateAttributeRequest {
534+ NamespaceId : ns .GetId (),
535+ Name : "deactivating_attr" ,
536+ Rule : policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF ,
537+ Values : []string {"value1" , "value2" },
538+ })
539+ s .Require ().NoError (err )
540+ got , _ := s .db .PolicyClient .GetAttribute (s .ctx , attr .GetId ())
541+ s .Require ().NoError (err )
542+ values := got .GetValues ()
543+ s .Len (values , 2 )
544+ v1 := values [0 ]
545+
546+ // deactivate the attribute definition
547+ _ , err = s .db .PolicyClient .DeactivateAttribute (s .ctx , attr .GetId ())
548+ s .Require ().NoError (err )
549+
550+ // unsafely reactivate the first attribute value
551+ v , err := s .db .PolicyClient .UnsafeReactivateAttributeValue (s .ctx , v1 .GetId ())
552+ s .Require ().NoError (err )
553+ s .NotNil (v )
554+
555+ // get the attribute by the value fqn for v1
556+ retrieved , err := s .db .PolicyClient .GetAttributesByValueFqns (s .ctx , & attributes.GetAttributeValuesByFqnsRequest {
557+ Fqns : []string {fqnBuilder (ns .GetName (), attr .GetName (), v1 .GetValue ())},
558+ WithValue : & policy.AttributeValueSelector {
559+ WithSubjectMaps : true ,
560+ },
561+ })
562+ s .Require ().Error (err )
563+ s .Nil (retrieved )
564+ s .Require ().ErrorIs (err , db .ErrNotFound )
565+ }
566+
567+ // UnsafeReactivateAttributevalue: inactive namespace, inactive definition, unsafely active value (fails)
568+ func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_Fails_InactiveNsAndDef_ActiveValue () {
569+ // create a new namespace
570+ ns , err := s .db .PolicyClient .CreateNamespace (s .ctx , & namespaces.CreateNamespaceRequest {
571+ Name : "test_inactive_namespace.co" ,
572+ })
573+ s .Require ().NoError (err )
574+
575+ // give it an attribute with two values
576+ attr , err := s .db .PolicyClient .CreateAttribute (s .ctx , & attributes.CreateAttributeRequest {
577+ NamespaceId : ns .GetId (),
578+ Name : "deactivating_attr" ,
579+ Rule : policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF ,
580+ Values : []string {"value1" , "value2" },
581+ })
582+ s .Require ().NoError (err )
583+ got , _ := s .db .PolicyClient .GetAttribute (s .ctx , attr .GetId ())
584+ s .Require ().NoError (err )
585+ values := got .GetValues ()
586+ s .Len (values , 2 )
587+ v1 := values [0 ]
588+
589+ // deactivate the namespace
590+ _ , err = s .db .PolicyClient .DeactivateNamespace (s .ctx , ns .GetId ())
591+ s .Require ().NoError (err )
592+
593+ // unsafely reactivate the first attribute value
594+ v , err := s .db .PolicyClient .UnsafeReactivateAttributeValue (s .ctx , v1 .GetId ())
595+ s .Require ().NoError (err )
596+ s .NotNil (v )
597+
598+ // get the attribute by the value fqn for v1
599+ retrieved , err := s .db .PolicyClient .GetAttributesByValueFqns (s .ctx , & attributes.GetAttributeValuesByFqnsRequest {
600+ Fqns : []string {fqnBuilder (ns .GetName (), attr .GetName (), v1 .GetValue ())},
601+ WithValue : & policy.AttributeValueSelector {
602+ WithSubjectMaps : true ,
603+ },
604+ })
605+ s .Require ().Error (err )
606+ s .Nil (retrieved )
607+ s .Require ().ErrorIs (err , db .ErrNotFound )
608+ }
609+
610+ // UnsafeReactivateNamespace: active namespace, inactive definition, inactive value (fails)
611+ func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_Fails_ActiveDef_InactiveNsAndValue () {
612+ // create a new namespace
613+ ns , err := s .db .PolicyClient .CreateNamespace (s .ctx , & namespaces.CreateNamespaceRequest {
614+ Name : "test_ns_active.uk" ,
615+ })
616+ s .Require ().NoError (err )
617+
618+ // give it an attribute with two values
619+ attr , err := s .db .PolicyClient .CreateAttribute (s .ctx , & attributes.CreateAttributeRequest {
620+ NamespaceId : ns .GetId (),
621+ Name : "active_attr" ,
622+ Rule : policy .AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF ,
623+ Values : []string {"value1" , "value2" },
624+ })
625+ s .Require ().NoError (err )
626+ got , _ := s .db .PolicyClient .GetAttribute (s .ctx , attr .GetId ())
627+ s .Require ().NoError (err )
628+ values := got .GetValues ()
629+ s .Len (values , 2 )
630+ v1 := values [0 ]
631+
632+ // deactivate the namespace
633+ ns , err = s .db .PolicyClient .DeactivateNamespace (s .ctx , ns .GetId ())
634+ s .Require ().NoError (err )
635+ s .NotNil (ns )
636+
637+ // reactivate the namespace (unsafely)
638+ ns , err = s .db .PolicyClient .UnsafeReactivateNamespace (s .ctx , ns .GetId ())
639+ s .Require ().NoError (err )
640+ s .NotNil (ns )
641+
642+ gotNs , err := s .db .PolicyClient .GetNamespace (s .ctx , ns .GetId ())
643+ s .Require ().NoError (err )
644+ s .NotNil (gotNs )
645+ s .True (gotNs .GetActive ().GetValue ())
646+
647+ // get the attribute by the value fqn for v1
648+ retrieved , err := s .db .PolicyClient .GetAttributesByValueFqns (s .ctx , & attributes.GetAttributeValuesByFqnsRequest {
649+ Fqns : []string {fqnBuilder (ns .GetName (), attr .GetName (), v1 .GetValue ())},
650+ WithValue : & policy.AttributeValueSelector {
651+ WithSubjectMaps : true ,
652+ },
653+ })
654+ s .Require ().Error (err )
655+ s .Nil (retrieved )
656+ s .Require ().ErrorIs (err , db .ErrNotFound )
418657}
419658
420659func (s * AttributeFqnSuite ) TestGetAttributesByValueFqns_Fails_WithNonValueFqns () {
0 commit comments