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  }