github.com/openfga/openfga@v1.5.4-rc1/pkg/storage/memory/memory_test.go (about) 1 package memory 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/oklog/ulid/v2" 9 openfgav1 "github.com/openfga/api/proto/openfga/v1" 10 "github.com/stretchr/testify/require" 11 "golang.org/x/sync/errgroup" 12 "google.golang.org/protobuf/types/known/structpb" 13 "google.golang.org/protobuf/types/known/timestamppb" 14 15 "github.com/openfga/openfga/pkg/storage" 16 "github.com/openfga/openfga/pkg/storage/test" 17 "github.com/openfga/openfga/pkg/tuple" 18 ) 19 20 func TestMemdbStorage(t *testing.T) { 21 ds := New() 22 test.RunAllTests(t, ds) 23 } 24 25 func TestStaticTupleIteratorNoRace(t *testing.T) { 26 now := timestamppb.Now() 27 28 iter := &staticIterator{ 29 records: []*storage.TupleRecord{ 30 { 31 Store: "store", 32 ObjectType: "document", 33 ObjectID: "1", 34 Relation: "viewer", 35 User: "user:jon", 36 Ulid: ulid.MustNew(ulid.Timestamp(now.AsTime()), ulid.DefaultEntropy()).String(), 37 InsertedAt: now.AsTime(), 38 }, 39 { 40 Store: "store", 41 ObjectType: "document", 42 ObjectID: "1", 43 Relation: "viewer", 44 User: "user:jon", 45 ConditionName: "condition", 46 ConditionContext: &structpb.Struct{}, 47 Ulid: ulid.MustNew(ulid.Timestamp(now.AsTime()), ulid.DefaultEntropy()).String(), 48 InsertedAt: now.AsTime(), 49 }, 50 }, 51 } 52 defer iter.Stop() 53 54 var wg errgroup.Group 55 56 wg.Go(func() error { 57 _, err := iter.Next(context.Background()) 58 return err 59 }) 60 61 wg.Go(func() error { 62 _, err := iter.Next(context.Background()) 63 return err 64 }) 65 66 err := wg.Wait() 67 require.NoError(t, err) 68 } 69 70 func TestStaticTupleIteratorContextCanceled(t *testing.T) { 71 iter := &staticIterator{ 72 records: []*storage.TupleRecord{ 73 { 74 ObjectType: "document", 75 ObjectID: "1", 76 Relation: "viewer", 77 User: "user:jon", 78 }, 79 }, 80 } 81 defer iter.Stop() 82 83 ctx, cancel := context.WithCancel(context.Background()) 84 85 _, err := iter.Next(ctx) 86 require.NoError(t, err) 87 88 cancel() 89 90 _, err = iter.Next(ctx) 91 require.ErrorIs(t, err, context.Canceled) 92 } 93 94 func TestStaticTupleIteratorContextDeadlineExceeded(t *testing.T) { 95 iter := &staticIterator{ 96 records: []*storage.TupleRecord{ 97 { 98 ObjectType: "document", 99 ObjectID: "1", 100 Relation: "viewer", 101 User: "user:jon", 102 }, 103 }, 104 } 105 defer iter.Stop() 106 107 deadlineCtx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 108 defer cancel() 109 110 _, err := iter.Next(deadlineCtx) 111 require.NoError(t, err) 112 113 time.Sleep(2 * time.Second) 114 115 _, err = iter.Next(deadlineCtx) 116 require.ErrorIs(t, err, context.DeadlineExceeded) 117 } 118 119 func TestTupleRecordMatchTupleKey(t *testing.T) { 120 var testCases = map[string]struct { 121 target *openfgav1.TupleKey 122 source *storage.TupleRecord 123 match bool 124 }{ 125 `no_match_in_user`: { 126 target: tuple.NewTupleKey("document:x", "viewer", "user:1"), 127 source: &storage.TupleRecord{ 128 ObjectType: "document", 129 ObjectID: "x", 130 Relation: "viewer", 131 User: "user:2", 132 }, 133 match: false, 134 }, 135 `no_match_in_relation`: { 136 target: tuple.NewTupleKey("document:x", "viewer", "user:1"), 137 source: &storage.TupleRecord{ 138 ObjectType: "document", 139 ObjectID: "x", 140 Relation: "writer", 141 User: "user:1", 142 }, 143 match: false, 144 }, 145 `no_match_in_object_type`: { 146 target: tuple.NewTupleKey("document", "viewer", "user:1"), 147 source: &storage.TupleRecord{ 148 ObjectType: "group", 149 ObjectID: "x", 150 Relation: "viewer", 151 User: "user:1", 152 }, 153 match: false, 154 }, 155 `no_match_in_object_id`: { 156 target: tuple.NewTupleKey("document:x", "viewer", "user:1"), 157 source: &storage.TupleRecord{ 158 ObjectType: "document", 159 ObjectID: "z", 160 Relation: "viewer", 161 User: "user:1", 162 }, 163 match: false, 164 }, 165 `match`: { 166 target: tuple.NewTupleKey("document:x", "viewer", "user:1"), 167 source: &storage.TupleRecord{ 168 ObjectType: "document", 169 ObjectID: "x", 170 Relation: "viewer", 171 User: "user:1", 172 }, 173 match: true, 174 }, 175 } 176 for name, test := range testCases { 177 t.Run(name, func(t *testing.T) { 178 require.Equal(t, test.match, match(test.source, test.target)) 179 }) 180 } 181 } 182 183 func TestFindTupleKey(t *testing.T) { 184 var testCases = map[string]struct { 185 records []*storage.TupleRecord 186 tupleKey *openfgav1.TupleKey 187 found bool 188 }{ 189 `not_find`: { 190 tupleKey: tuple.NewTupleKey("document:x", "viewer", "user:1"), 191 records: []*storage.TupleRecord{{ 192 ObjectType: "document", 193 ObjectID: "x", 194 Relation: "viewer", 195 User: "user:2", 196 }}, 197 found: false, 198 }, 199 `find`: { 200 tupleKey: tuple.NewTupleKey("document:x", "viewer", "user:1"), 201 records: []*storage.TupleRecord{{ 202 ObjectType: "document", 203 ObjectID: "x", 204 Relation: "viewer", 205 User: "user:1", 206 }}, 207 found: true, 208 }, 209 } 210 for name, test := range testCases { 211 t.Run(name, func(t *testing.T) { 212 require.Equal(t, test.found, find(test.records, test.tupleKey)) 213 }) 214 } 215 }