github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datasets/subjectsetbyresourceid_test.go (about) 1 package datasets 2 3 import ( 4 "slices" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 "github.com/authzed/spicedb/internal/testutil" 10 v1 "github.com/authzed/spicedb/pkg/proto/dispatch/v1" 11 "github.com/authzed/spicedb/pkg/tuple" 12 ) 13 14 func TestSubjectSetByResourceIDBasicOperations(t *testing.T) { 15 ssr := NewSubjectSetByResourceID() 16 require.True(t, ssr.IsEmpty()) 17 18 require.NoError(t, ssr.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 19 require.False(t, ssr.IsEmpty()) 20 21 require.NoError(t, ssr.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:sarah#..."))) 22 require.NoError(t, ssr.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:fred#..."))) 23 24 expected := map[string]*v1.FoundSubjects{ 25 "firstdoc": { 26 FoundSubjects: []*v1.FoundSubject{ 27 {SubjectId: "tom"}, 28 {SubjectId: "sarah"}, 29 }, 30 }, 31 "seconddoc": { 32 FoundSubjects: []*v1.FoundSubject{ 33 {SubjectId: "fred"}, 34 }, 35 }, 36 } 37 asMap := ssr.AsMap() 38 39 slices.SortFunc(expected["firstdoc"].FoundSubjects, testutil.CmpSubjects) 40 slices.SortFunc(expected["seconddoc"].FoundSubjects, testutil.CmpSubjects) 41 42 slices.SortFunc(asMap["firstdoc"].FoundSubjects, testutil.CmpSubjects) 43 slices.SortFunc(asMap["seconddoc"].FoundSubjects, testutil.CmpSubjects) 44 45 require.Equal(t, expected, asMap) 46 require.Equal(t, 3, ssr.ConcreteSubjectCount()) 47 } 48 49 func TestSubjectSetByResourceIDUnionWith(t *testing.T) { 50 ssr := NewSubjectSetByResourceID() 51 require.NoError(t, ssr.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 52 require.NoError(t, ssr.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:sarah#..."))) 53 require.NoError(t, ssr.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:fred#..."))) 54 55 err := ssr.UnionWith(map[string]*v1.FoundSubjects{ 56 "firstdoc": { 57 FoundSubjects: []*v1.FoundSubject{ 58 {SubjectId: "tom"}, 59 {SubjectId: "micah"}, 60 }, 61 }, 62 "thirddoc": { 63 FoundSubjects: []*v1.FoundSubject{ 64 {SubjectId: "george"}, 65 }, 66 }, 67 }) 68 require.NoError(t, err) 69 70 found := ssr.AsMap() 71 slices.SortFunc(found["firstdoc"].FoundSubjects, testutil.CmpSubjects) 72 73 require.Equal(t, map[string]*v1.FoundSubjects{ 74 "firstdoc": { 75 FoundSubjects: []*v1.FoundSubject{ 76 {SubjectId: "micah"}, 77 {SubjectId: "sarah"}, 78 {SubjectId: "tom"}, 79 }, 80 }, 81 "seconddoc": { 82 FoundSubjects: []*v1.FoundSubject{ 83 {SubjectId: "fred"}, 84 }, 85 }, 86 "thirddoc": { 87 FoundSubjects: []*v1.FoundSubject{ 88 {SubjectId: "george"}, 89 }, 90 }, 91 }, found) 92 93 require.Equal(t, 5, ssr.ConcreteSubjectCount()) 94 } 95 96 func TestSubjectSetByResourceIDIntersectionDifference(t *testing.T) { 97 first := NewSubjectSetByResourceID() 98 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 99 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:sarah#..."))) 100 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:fred#..."))) 101 102 second := NewSubjectSetByResourceID() 103 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 104 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:micah#..."))) 105 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:george#..."))) 106 107 err := first.IntersectionDifference(second) 108 require.NoError(t, err) 109 110 require.Equal(t, map[string]*v1.FoundSubjects{ 111 "firstdoc": { 112 FoundSubjects: []*v1.FoundSubject{ 113 {SubjectId: "tom"}, 114 }, 115 }, 116 }, first.AsMap()) 117 } 118 119 func TestSubjectSetByResourceIDIntersectionDifferenceMissingKey(t *testing.T) { 120 first := NewSubjectSetByResourceID() 121 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 122 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:sarah#..."))) 123 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:fred#..."))) 124 125 second := NewSubjectSetByResourceID() 126 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 127 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:micah#..."))) 128 129 err := first.IntersectionDifference(second) 130 require.NoError(t, err) 131 132 require.Equal(t, map[string]*v1.FoundSubjects{ 133 "firstdoc": { 134 FoundSubjects: []*v1.FoundSubject{ 135 {SubjectId: "tom"}, 136 }, 137 }, 138 }, first.AsMap()) 139 } 140 141 func TestSubjectSetByResourceIDIntersectionDifferenceItemInSecondSet(t *testing.T) { 142 first := NewSubjectSetByResourceID() 143 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 144 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:sarah#..."))) 145 146 second := NewSubjectSetByResourceID() 147 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 148 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:micah#..."))) 149 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:fred#..."))) 150 151 err := first.IntersectionDifference(second) 152 require.NoError(t, err) 153 154 require.Equal(t, map[string]*v1.FoundSubjects{ 155 "firstdoc": { 156 FoundSubjects: []*v1.FoundSubject{ 157 {SubjectId: "tom"}, 158 }, 159 }, 160 }, first.AsMap()) 161 } 162 163 func TestSubjectSetByResourceIDSubtractAll(t *testing.T) { 164 first := NewSubjectSetByResourceID() 165 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 166 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:sarah#..."))) 167 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:fred#..."))) 168 169 second := NewSubjectSetByResourceID() 170 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 171 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:micah#..."))) 172 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:seconddoc#viewer@user:george#..."))) 173 174 first.SubtractAll(second) 175 176 require.Equal(t, map[string]*v1.FoundSubjects{ 177 "firstdoc": { 178 FoundSubjects: []*v1.FoundSubject{ 179 {SubjectId: "sarah"}, 180 }, 181 }, 182 "seconddoc": { 183 FoundSubjects: []*v1.FoundSubject{ 184 {SubjectId: "fred"}, 185 }, 186 }, 187 }, first.AsMap()) 188 } 189 190 func TestSubjectSetByResourceIDSubtractAllEmpty(t *testing.T) { 191 first := NewSubjectSetByResourceID() 192 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:tom#..."))) 193 require.NoError(t, first.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:mi#..."))) 194 195 second := NewSubjectSetByResourceID() 196 require.NoError(t, second.AddFromRelationship(tuple.MustParse("document:firstdoc#viewer@user:*#..."))) 197 198 first.SubtractAll(second) 199 200 require.Equal(t, map[string]*v1.FoundSubjects{}, first.AsMap()) 201 } 202 203 func TestSubjectSetByResourceIDBasicCaveatedOperations(t *testing.T) { 204 ssr := NewSubjectSetByResourceID() 205 require.True(t, ssr.IsEmpty()) 206 207 require.NoError(t, ssr.AddFromRelationship(tuple.MustWithCaveat(tuple.MustParse("document:firstdoc#viewer@user:tom#..."), "first"))) 208 require.NoError(t, ssr.AddFromRelationship(tuple.MustWithCaveat(tuple.MustParse("document:firstdoc#viewer@user:tom#..."), "second"))) 209 210 expected := map[string]*v1.FoundSubjects{ 211 "firstdoc": { 212 FoundSubjects: []*v1.FoundSubject{ 213 { 214 SubjectId: "tom", 215 CaveatExpression: caveatOr(caveatexpr("first"), caveatexpr("second")), 216 }, 217 }, 218 }, 219 } 220 asMap := ssr.AsMap() 221 222 slices.SortFunc(expected["firstdoc"].FoundSubjects, testutil.CmpSubjects) 223 slices.SortFunc(asMap["firstdoc"].FoundSubjects, testutil.CmpSubjects) 224 225 require.Equal(t, expected, asMap) 226 } 227 228 func TestSubjectSetByResoureIDUnionWithBadMap(t *testing.T) { 229 ssr := NewSubjectSetByResourceID() 230 require.True(t, ssr.IsEmpty()) 231 232 err := ssr.UnionWith(map[string]*v1.FoundSubjects{ 233 "isnil": nil, 234 }) 235 require.NotNil(t, err) 236 }