github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/proxy/readonly_test.go (about) 1 package proxy 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/stretchr/testify/mock" 8 "github.com/stretchr/testify/require" 9 10 "github.com/authzed/spicedb/internal/datastore/common" 11 "github.com/authzed/spicedb/internal/datastore/proxy/proxy_test" 12 "github.com/authzed/spicedb/internal/datastore/revisions" 13 "github.com/authzed/spicedb/pkg/datastore" 14 core "github.com/authzed/spicedb/pkg/proto/core/v1" 15 "github.com/authzed/spicedb/pkg/tuple" 16 ) 17 18 func newReadOnlyMock() (*proxy_test.MockDatastore, *proxy_test.MockReader) { 19 dsMock := &proxy_test.MockDatastore{} 20 readerMock := &proxy_test.MockReader{} 21 22 dsMock.On("ReadWriteTx").Panic("read-only proxy should never open a read-write transaction").Maybe() 23 dsMock.On("SnapshotReader", mock.Anything).Return(readerMock).Maybe() 24 25 return dsMock, readerMock 26 } 27 28 func TestRWOperationErrors(t *testing.T) { 29 require := require.New(t) 30 31 delegate, _ := newReadOnlyMock() 32 33 ds := NewReadonlyDatastore(delegate) 34 ctx := context.Background() 35 36 rev, err := ds.ReadWriteTx(ctx, func(ctx context.Context, rwt datastore.ReadWriteTransaction) error { 37 return rwt.DeleteNamespaces(ctx, "fake") 38 }) 39 require.ErrorAs(err, &datastore.ErrReadOnly{}) 40 require.Equal(datastore.NoRevision, rev) 41 42 rev, err = ds.ReadWriteTx(ctx, func(ctx context.Context, rwt datastore.ReadWriteTransaction) error { 43 return rwt.WriteNamespaces(ctx, &core.NamespaceDefinition{Name: "user"}) 44 }) 45 require.ErrorAs(err, &datastore.ErrReadOnly{}) 46 require.Equal(datastore.NoRevision, rev) 47 48 rev, err = common.WriteTuples(ctx, ds, core.RelationTupleUpdate_CREATE, tuple.Parse("user:test#boss@user:boss")) 49 require.ErrorAs(err, &datastore.ErrReadOnly{}) 50 require.Equal(datastore.NoRevision, rev) 51 } 52 53 var expectedRevision = revisions.NewForTransactionID(123) 54 55 func TestReadyStatePassthrough(t *testing.T) { 56 require := require.New(t) 57 58 delegate, _ := newReadOnlyMock() 59 ds := NewReadonlyDatastore(delegate) 60 ctx := context.Background() 61 62 delegate.On("ReadyState").Return(datastore.ReadyState{IsReady: true}, nil).Times(1) 63 64 resp, err := ds.ReadyState(ctx) 65 require.NoError(err) 66 require.True(resp.IsReady) 67 delegate.AssertExpectations(t) 68 } 69 70 func TestOptimizedRevisionPassthrough(t *testing.T) { 71 require := require.New(t) 72 73 delegate, _ := newReadOnlyMock() 74 ds := NewReadonlyDatastore(delegate) 75 ctx := context.Background() 76 77 delegate.On("OptimizedRevision").Return(expectedRevision, nil).Times(1) 78 79 revision, err := ds.OptimizedRevision(ctx) 80 require.NoError(err) 81 require.Equal(expectedRevision, revision) 82 delegate.AssertExpectations(t) 83 } 84 85 func TestHeadRevisionPassthrough(t *testing.T) { 86 require := require.New(t) 87 88 delegate, _ := newReadOnlyMock() 89 ds := NewReadonlyDatastore(delegate) 90 ctx := context.Background() 91 92 delegate.On("HeadRevision").Return(expectedRevision, nil).Times(1) 93 94 revision, err := ds.HeadRevision(ctx) 95 require.NoError(err) 96 require.Equal(expectedRevision, revision) 97 delegate.AssertExpectations(t) 98 } 99 100 func TestCheckRevisionPassthrough(t *testing.T) { 101 require := require.New(t) 102 103 delegate, _ := newReadOnlyMock() 104 ds := NewReadonlyDatastore(delegate) 105 ctx := context.Background() 106 107 delegate.On("CheckRevision", expectedRevision).Return(nil).Times(1) 108 109 err := ds.CheckRevision(ctx, expectedRevision) 110 require.NoError(err) 111 delegate.AssertExpectations(t) 112 } 113 114 func TestWatchPassthrough(t *testing.T) { 115 delegate, _ := newReadOnlyMock() 116 ds := NewReadonlyDatastore(delegate) 117 ctx := context.Background() 118 119 delegate.On("Watch", expectedRevision).Return( 120 make(<-chan *datastore.RevisionChanges), 121 make(<-chan error), 122 ).Times(1) 123 124 ds.Watch(ctx, expectedRevision, datastore.WatchJustRelationships()) 125 delegate.AssertExpectations(t) 126 } 127 128 func TestSnapshotReaderPassthrough(t *testing.T) { 129 require := require.New(t) 130 131 delegate, reader := newReadOnlyMock() 132 ds := NewReadonlyDatastore(delegate) 133 ctx := context.Background() 134 135 reader.On("ReadNamespaceByName", "fake").Return(nil, expectedRevision, nil).Times(1) 136 137 _, rev, err := ds.SnapshotReader(expectedRevision).ReadNamespaceByName(ctx, "fake") 138 require.NoError(err) 139 require.True(expectedRevision.Equal(rev)) 140 delegate.AssertExpectations(t) 141 reader.AssertExpectations(t) 142 }