Skip to content

Commit ebe6469

Browse files
fix(policy): Return the correct total during list responses. [backport to release/service/v0.11] (#2843)
# Description Backport of #2836 to `release/service/v0.11`. Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.com>
1 parent e353b0b commit ebe6469

File tree

11 files changed

+514
-121
lines changed

11 files changed

+514
-121
lines changed

service/integration/attribute_values_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,91 @@ func (s *AttributeValuesSuite) Test_ListAttributeValues_Offset_Succeeds() {
205205
}
206206
}
207207

208+
func (s *AttributeValuesSuite) Test_ListAttributeValues_AttributeDefID_Succeeds() {
209+
// Create a namespace
210+
ns, err := s.db.PolicyClient.CreateNamespace(s.ctx, &namespaces.CreateNamespaceRequest{
211+
Name: "test-pagination.com",
212+
})
213+
s.Require().NoError(err)
214+
s.NotNil(ns)
215+
s.namespaces = append(s.namespaces, ns)
216+
217+
// Create an attribute definition
218+
attr, err := s.db.PolicyClient.CreateAttribute(s.ctx, &attributes.CreateAttributeRequest{
219+
Name: "test-attr-pagination",
220+
NamespaceId: ns.GetId(),
221+
Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF,
222+
})
223+
s.Require().NoError(err)
224+
s.NotNil(attr)
225+
226+
// Create multiple attribute values
227+
expectedValues := make([]string, 5)
228+
createdValueIDs := make([]string, 5)
229+
for i := 0; i < 5; i++ {
230+
value := fmt.Sprintf("test-value-%d", i+1)
231+
expectedValues[i] = value
232+
233+
req := &attributes.CreateAttributeValueRequest{
234+
Value: value,
235+
}
236+
createdValue, err := s.db.PolicyClient.CreateAttributeValue(s.ctx, attr.GetId(), req)
237+
s.Require().NoError(err)
238+
s.NotNil(createdValue)
239+
createdValueIDs[i] = createdValue.GetId()
240+
s.Equal(value, createdValue.GetValue())
241+
}
242+
243+
// Test listing all values without pagination
244+
listRsp, err := s.db.PolicyClient.ListAttributeValues(s.ctx, &attributes.ListAttributeValuesRequest{
245+
AttributeId: attr.GetId(),
246+
State: common.ActiveStateEnum_ACTIVE_STATE_ENUM_ACTIVE,
247+
})
248+
s.Require().NoError(err)
249+
s.NotNil(listRsp)
250+
s.Len(listRsp.GetValues(), 5)
251+
252+
// Verify all created values are in the response
253+
foundValues := make(map[string]bool)
254+
for _, val := range listRsp.GetValues() {
255+
foundValues[val.GetValue()] = true
256+
s.Equal(attr.GetId(), val.GetAttribute().GetId())
257+
}
258+
for _, expectedValue := range expectedValues {
259+
s.True(foundValues[expectedValue], "Expected value %s not found in list", expectedValue)
260+
}
261+
s.Require().Equal(int32(5), listRsp.GetPagination().GetTotal())
262+
s.Require().Equal(int32(0), listRsp.GetPagination().GetCurrentOffset())
263+
s.Require().Equal(int32(0), listRsp.GetPagination().GetNextOffset())
264+
265+
// Deactivate one of the attribute values
266+
deactivated, err := s.db.PolicyClient.DeactivateAttributeValue(s.ctx, createdValueIDs[2]) // deactivate "test-value-3"
267+
s.Require().NoError(err)
268+
s.Require().NotNil(deactivated)
269+
s.Require().False(deactivated.GetActive().GetValue())
270+
271+
// Test listing only active values after deactivation
272+
activeListRsp, err := s.db.PolicyClient.ListAttributeValues(s.ctx, &attributes.ListAttributeValuesRequest{
273+
AttributeId: attr.GetId(),
274+
State: common.ActiveStateEnum_ACTIVE_STATE_ENUM_ACTIVE,
275+
})
276+
s.Require().NoError(err)
277+
s.NotNil(activeListRsp)
278+
s.Len(activeListRsp.GetValues(), 4) // should be 4 active values now
279+
280+
// Verify that the deactivated value is not in the active list
281+
activeFoundValues := make(map[string]bool)
282+
for _, val := range activeListRsp.GetValues() {
283+
activeFoundValues[val.GetValue()] = true
284+
s.True(val.GetActive().GetValue(), "All values in active list should be active")
285+
s.Equal(attr.GetId(), val.GetAttribute().GetId())
286+
}
287+
s.False(activeFoundValues["test-value-3"], "Deactivated value should not be in active list")
288+
s.Require().Equal(int32(4), activeListRsp.GetPagination().GetTotal())
289+
s.Require().Equal(int32(0), activeListRsp.GetPagination().GetCurrentOffset())
290+
s.Require().Equal(int32(0), activeListRsp.GetPagination().GetNextOffset())
291+
}
292+
208293
func (s *AttributeValuesSuite) Test_GetAttributeValue() {
209294
f := s.f.GetAttributeValueKey("example.com/attr/attr1/value/value1")
210295

service/integration/attributes_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,85 @@ func (s *AttributesSuite) Test_ListAttributes_ByNamespaceIdOrName() {
560560
}
561561
}
562562

563+
func (s *AttributesSuite) Test_ListAttributes_MultipleAttributes_Succeeds() {
564+
// Create two test namespaces
565+
createdNS := make([]*policy.Namespace, 2)
566+
ns1, err := s.db.PolicyClient.CreateNamespace(s.ctx, &namespaces.CreateNamespaceRequest{
567+
Name: "test-list-ns1.com",
568+
})
569+
s.Require().NoError(err)
570+
s.NotNil(ns1)
571+
createdNS[0] = ns1
572+
573+
ns2, err := s.db.PolicyClient.CreateNamespace(s.ctx, &namespaces.CreateNamespaceRequest{
574+
Name: "test-list-ns2.com",
575+
})
576+
s.Require().NoError(err)
577+
s.NotNil(ns2)
578+
createdNS[1] = ns2
579+
580+
// Cleanup function
581+
defer func() {
582+
// Delete namespaces (this will cascade delete attributes)
583+
for _, ns := range createdNS {
584+
_, err := s.db.PolicyClient.UnsafeDeleteNamespace(s.ctx, ns, ns.GetFqn())
585+
s.Require().NoError(err)
586+
}
587+
}()
588+
589+
// Create one attribute in each namespace
590+
attr1, err := s.db.PolicyClient.CreateAttribute(s.ctx, &attributes.CreateAttributeRequest{
591+
Name: "test_attr_1",
592+
NamespaceId: ns1.GetId(),
593+
Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ALL_OF,
594+
Values: []string{"value1", "value2"},
595+
})
596+
s.Require().NoError(err)
597+
s.NotNil(attr1)
598+
599+
attr2, err := s.db.PolicyClient.CreateAttribute(s.ctx, &attributes.CreateAttributeRequest{
600+
Name: "test_attr_2",
601+
NamespaceId: ns2.GetId(),
602+
Rule: policy.AttributeRuleTypeEnum_ATTRIBUTE_RULE_TYPE_ENUM_ANY_OF,
603+
Values: []string{"valueA", "valueB"},
604+
})
605+
s.Require().NoError(err)
606+
s.NotNil(attr2)
607+
608+
// Test 1: List attributes from first namespace
609+
listReq := &attributes.ListAttributesRequest{
610+
State: common.ActiveStateEnum_ACTIVE_STATE_ENUM_ACTIVE,
611+
Namespace: ns1.GetId(),
612+
}
613+
listResp, err := s.db.PolicyClient.ListAttributes(s.ctx, listReq)
614+
s.Require().NoError(err)
615+
s.NotNil(listResp)
616+
617+
listedAttrs := listResp.GetAttributes()
618+
s.Require().Len(listedAttrs, 1, "Should list one attribute from first namespace")
619+
s.Require().Equal(attr1.GetId(), listedAttrs[0].GetId())
620+
s.Require().Equal(ns1.GetId(), listedAttrs[0].GetNamespace().GetId())
621+
s.Require().NotEmpty(listedAttrs[0].GetFqn())
622+
s.Require().Equal(int32(1), listResp.GetPagination().GetTotal())
623+
s.Require().Equal(int32(0), listResp.GetPagination().GetNextOffset())
624+
s.Require().Equal(int32(0), listResp.GetPagination().GetCurrentOffset())
625+
626+
// Test 2: List attributes from second namespace
627+
listReq.Namespace = ns2.GetId()
628+
listResp, err = s.db.PolicyClient.ListAttributes(s.ctx, listReq)
629+
s.Require().NoError(err)
630+
s.NotNil(listResp)
631+
632+
listedAttrs = listResp.GetAttributes()
633+
s.Require().Len(listedAttrs, 1, "Should list one attribute from second namespace")
634+
s.Require().Equal(attr2.GetId(), listedAttrs[0].GetId())
635+
s.Require().Equal(ns2.GetId(), listedAttrs[0].GetNamespace().GetId())
636+
s.Require().NotEmpty(listedAttrs[0].GetFqn())
637+
s.Require().Equal(int32(1), listResp.GetPagination().GetTotal())
638+
s.Require().Equal(int32(0), listResp.GetPagination().GetNextOffset())
639+
s.Require().Equal(int32(0), listResp.GetPagination().GetCurrentOffset())
640+
}
641+
563642
func (s *AttributesSuite) Test_UpdateAttribute() {
564643
fixedLabel := "fixed label"
565644
updateLabel := "update label"

0 commit comments

Comments
 (0)