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  }