Skip to content

Commit

Permalink
Merge pull request #1956 from josephschorr/additional-steelthread-tests
Browse files Browse the repository at this point in the history
Add additional steelthread tests and fix a memdb bug
  • Loading branch information
josephschorr authored Jun 26, 2024
2 parents 37bf916 + 822b392 commit a43e7dd
Show file tree
Hide file tree
Showing 14 changed files with 3,298 additions and 2 deletions.
15 changes: 14 additions & 1 deletion internal/datastore/memdb/readonly.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,20 @@ func (r *memdbReader) ReverseQueryRelationships(
)
filteredIterator := memdb.NewFilterIterator(iterator, matchingRelationshipsFilterFunc)

return newMemdbTupleIterator(filteredIterator, queryOpts.LimitForReverse, queryOpts.SortForReverse), nil
switch queryOpts.SortForReverse {
case options.Unsorted:
fallthrough

case options.ByResource:
iter := newMemdbTupleIterator(filteredIterator, queryOpts.LimitForReverse, queryOpts.SortForReverse)
return iter, nil

case options.BySubject:
return newSubjectSortedIterator(filteredIterator, queryOpts.LimitForReverse)

default:
return nil, spiceerrors.MustBugf("unsupported sort order: %v", queryOpts.SortForReverse)
}
}

// ReadNamespace reads a namespace definition and version and returns it, and the revision at
Expand Down
87 changes: 87 additions & 0 deletions internal/services/steelthreadtesting/definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,91 @@ var steelThreadTestCases = []steelThreadTestCase{
},
},
},
{
name: "lookup subjects intersection",
datafile: "document-with-intersect.yaml",
operations: []steelThreadOperationCase{
{
name: "uncursored lookup subjects for somedoc",
operationName: "lookupSubjects",
arguments: map[string]any{
"resource_type": "document",
"resource_object_id": "somedoc",
"permission": "view",
"subject_type": "user",
},
},
},
},
{
name: "basic lookup resources",
datafile: "document-with-many-resources.yaml",
operations: []steelThreadOperationCase{
{
name: "uncursored lookup resources for fred",
operationName: "lookupResources",
arguments: map[string]any{
"resource_type": "document",
"permission": "view",
"subject_type": "user",
"subject_object_id": "fred",
},
},
{
name: "cursored lookup resources for fred, page size 5",
operationName: "cursoredLookupResources",
arguments: map[string]any{
"resource_type": "document",
"permission": "view",
"subject_type": "user",
"subject_object_id": "fred",
"page_size": 5,
},
},
{
name: "cursored lookup resources for fred, page size 16",
operationName: "cursoredLookupResources",
arguments: map[string]any{
"resource_type": "document",
"permission": "view",
"subject_type": "user",
"subject_object_id": "fred",
"page_size": 16,
},
},
{
name: "cursored lookup resources for fred, page size 53",
operationName: "cursoredLookupResources",
arguments: map[string]any{
"resource_type": "document",
"permission": "view",
"subject_type": "user",
"subject_object_id": "fred",
"page_size": 53,
},
},
{
name: "cursored lookup resources for fred, page size 54",
operationName: "cursoredLookupResources",
arguments: map[string]any{
"resource_type": "document",
"permission": "view",
"subject_type": "user",
"subject_object_id": "fred",
"page_size": 54,
},
},
{
name: "cursored lookup resources for fred, page size 100",
operationName: "cursoredLookupResources",
arguments: map[string]any{
"resource_type": "document",
"permission": "view",
"subject_type": "user",
"subject_object_id": "fred",
"page_size": 100,
},
},
},
},
}
154 changes: 153 additions & 1 deletion internal/services/steelthreadtesting/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"google.golang.org/protobuf/types/known/structpb"
"gopkg.in/yaml.v3"

"github.com/authzed/spicedb/pkg/genutil/mapz"
Expand Down Expand Up @@ -68,8 +69,159 @@ func lookupSubjects(parameters map[string]any, client v1.PermissionsServiceClien
return yamlNodes, nil
}

func lookupResources(parameters map[string]any, client v1.PermissionsServiceClient) (any, error) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

var context *structpb.Struct
if contextMap, ok := parameters["context"].(map[string]any); ok {
c, err := structpb.NewStruct(contextMap)
if err != nil {
return nil, err
}
context = c
}

r, err := client.LookupResources(ctx, &v1.LookupResourcesRequest{
ResourceObjectType: parameters["resource_type"].(string),
Permission: parameters["permission"].(string),
Subject: &v1.SubjectReference{
Object: &v1.ObjectReference{
ObjectType: parameters["subject_type"].(string),
ObjectId: parameters["subject_object_id"].(string),
},
},
Context: context,
Consistency: &v1.Consistency{
Requirement: &v1.Consistency_FullyConsistent{
FullyConsistent: true,
},
},
})
if err != nil {
return nil, err
}

foundResources := mapz.NewSet[string]()
for {
resp, err := r.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}

return nil, err
}

if !foundResources.Add(formatResolvedResource(resp)) {
return nil, errors.New("duplicate resource found")
}
}

foundResourcesSlice := foundResources.AsSlice()
sort.Strings(foundResourcesSlice)

yamlNodes := make([]yaml.Node, 0, len(foundResourcesSlice))
for _, subject := range foundResourcesSlice {
yamlNodes = append(yamlNodes, yaml.Node{
Kind: yaml.ScalarNode,
Value: subject,
Style: yaml.SingleQuotedStyle,
})
}
return yamlNodes, nil
}

func cursoredLookupResources(parameters map[string]any, client v1.PermissionsServiceClient) (any, error) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

var context *structpb.Struct
if contextMap, ok := parameters["context"].(map[string]any); ok {
c, err := structpb.NewStruct(contextMap)
if err != nil {
return nil, err
}
context = c
}

var currentCursor *v1.Cursor
nodeSets := make([][]yaml.Node, 0)
for {
r, err := client.LookupResources(ctx, &v1.LookupResourcesRequest{
ResourceObjectType: parameters["resource_type"].(string),
Permission: parameters["permission"].(string),
Subject: &v1.SubjectReference{
Object: &v1.ObjectReference{
ObjectType: parameters["subject_type"].(string),
ObjectId: parameters["subject_object_id"].(string),
},
},
Context: context,
Consistency: &v1.Consistency{
Requirement: &v1.Consistency_FullyConsistent{
FullyConsistent: true,
},
},
OptionalLimit: uint32(parameters["page_size"].(int)),
OptionalCursor: currentCursor,
})
if err != nil {
return nil, err
}

foundResources := mapz.NewSet[string]()
for {
resp, err := r.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}

return nil, err
}

foundResources.Add(formatResolvedResource(resp))
currentCursor = resp.AfterResultCursor
}

if foundResources.IsEmpty() {
break
}

foundResourcesSlice := foundResources.AsSlice()
sort.Strings(foundResourcesSlice)

yamlNodes := make([]yaml.Node, 0, len(foundResourcesSlice))
for _, subject := range foundResourcesSlice {
yamlNodes = append(yamlNodes, yaml.Node{
Kind: yaml.ScalarNode,
Value: subject,
Style: yaml.SingleQuotedStyle,
})
}

nodeSets = append(nodeSets, yamlNodes)
}

return nodeSets, nil
}

var operations = map[string]stOperation{
"lookupSubjects": lookupSubjects,
"lookupSubjects": lookupSubjects,
"lookupResources": lookupResources,
"cursoredLookupResources": cursoredLookupResources,
}

func formatResolvedResource(resource *v1.LookupResourcesResponse) string {
var sb strings.Builder
sb.WriteString(resource.ResourceObjectId)

if resource.Permissionship == v1.LookupPermissionship_LOOKUP_PERMISSIONSHIP_CONDITIONAL_PERMISSION {
sb.WriteString(" (conditional)")
}

return sb.String()
}

func formatResolvedSubject(sub *v1.LookupSubjectsResponse) string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
- - 'doc-0'
- 'doc-1'
- 'doc-10'
- 'doc-11'
- 'doc-12'
- 'doc-13'
- 'doc-14'
- 'doc-15'
- 'doc-16'
- 'doc-17'
- 'doc-18'
- 'doc-19'
- 'doc-2'
- 'doc-20'
- 'doc-21'
- 'doc-22'
- 'doc-23'
- 'doc-24'
- 'doc-25'
- 'doc-26'
- 'doc-27'
- 'doc-28'
- 'doc-29'
- 'doc-3'
- 'doc-30'
- 'doc-31'
- 'doc-32'
- 'doc-33'
- 'doc-34'
- 'doc-35'
- 'doc-36'
- 'doc-37'
- 'doc-38'
- 'doc-39'
- 'doc-4'
- 'doc-40'
- 'doc-41'
- 'doc-42'
- 'doc-43'
- 'doc-44'
- 'doc-45'
- 'doc-46'
- 'doc-47'
- 'doc-48'
- 'doc-49'
- 'doc-5'
- 'doc-50'
- 'doc-51'
- 'doc-52'
- 'doc-53'
- 'doc-54'
- 'doc-55'
- 'doc-56'
- 'doc-57'
- 'doc-58'
- 'doc-59'
- 'doc-6'
- 'doc-60'
- 'doc-61'
- 'doc-62'
- 'doc-63'
- 'doc-64'
- 'doc-65'
- 'doc-66'
- 'doc-67'
- 'doc-68'
- 'doc-69'
- 'doc-7'
- 'doc-70'
- 'doc-71'
- 'doc-72'
- 'doc-73'
- 'doc-74'
- 'doc-75'
- 'doc-76'
- 'doc-77'
- 'doc-78'
- 'doc-79'
- 'doc-8'
- 'doc-9'
- 'doc-90'
- 'doc-91'
- 'doc-92'
- 'doc-93'
- 'doc-94'
- 'doc-95'
- 'doc-96'
- 'doc-97'
- 'doc-98'
- 'doc-99'
- - 'doc-95'
- 'doc-96'
- 'doc-97'
- 'doc-98'
- 'doc-99'
- 'public-doc-0'
- 'public-doc-1'
- 'public-doc-3'
Loading

0 comments on commit a43e7dd

Please sign in to comment.