github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/middleware/consistency/consistency_test.go (about) 1 package consistency 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 8 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 9 "github.com/stretchr/testify/require" 10 11 "github.com/authzed/spicedb/internal/datastore/proxy/proxy_test" 12 "github.com/authzed/spicedb/internal/datastore/revisions" 13 "github.com/authzed/spicedb/pkg/cursor" 14 dispatch "github.com/authzed/spicedb/pkg/proto/dispatch/v1" 15 "github.com/authzed/spicedb/pkg/zedtoken" 16 ) 17 18 var ( 19 zero = revisions.NewForTransactionID(0) 20 optimized = revisions.NewForTransactionID(100) 21 exact = revisions.NewForTransactionID(123) 22 head = revisions.NewForTransactionID(145) 23 ) 24 25 func TestAddRevisionToContextNoneSupplied(t *testing.T) { 26 require := require.New(t) 27 28 ds := &proxy_test.MockDatastore{} 29 ds.On("OptimizedRevision").Return(optimized, nil).Once() 30 31 updated := ContextWithHandle(context.Background()) 32 err := AddRevisionToContext(updated, &v1.ReadRelationshipsRequest{}, ds) 33 require.NoError(err) 34 35 rev, _, err := RevisionFromContext(updated) 36 require.NoError(err) 37 38 require.True(optimized.Equal(rev)) 39 ds.AssertExpectations(t) 40 } 41 42 func TestAddRevisionToContextMinimizeLatency(t *testing.T) { 43 require := require.New(t) 44 45 ds := &proxy_test.MockDatastore{} 46 ds.On("OptimizedRevision").Return(optimized, nil).Once() 47 48 updated := ContextWithHandle(context.Background()) 49 err := AddRevisionToContext(updated, &v1.ReadRelationshipsRequest{ 50 Consistency: &v1.Consistency{ 51 Requirement: &v1.Consistency_MinimizeLatency{ 52 MinimizeLatency: true, 53 }, 54 }, 55 }, ds) 56 require.NoError(err) 57 58 rev, _, err := RevisionFromContext(updated) 59 require.NoError(err) 60 61 require.True(optimized.Equal(rev)) 62 ds.AssertExpectations(t) 63 } 64 65 func TestAddRevisionToContextFullyConsistent(t *testing.T) { 66 require := require.New(t) 67 68 ds := &proxy_test.MockDatastore{} 69 ds.On("HeadRevision").Return(head, nil).Once() 70 71 updated := ContextWithHandle(context.Background()) 72 err := AddRevisionToContext(updated, &v1.ReadRelationshipsRequest{ 73 Consistency: &v1.Consistency{ 74 Requirement: &v1.Consistency_FullyConsistent{ 75 FullyConsistent: true, 76 }, 77 }, 78 }, ds) 79 require.NoError(err) 80 81 rev, _, err := RevisionFromContext(updated) 82 require.NoError(err) 83 84 require.True(head.Equal(rev)) 85 ds.AssertExpectations(t) 86 } 87 88 func TestAddRevisionToContextAtLeastAsFresh(t *testing.T) { 89 require := require.New(t) 90 91 ds := &proxy_test.MockDatastore{} 92 ds.On("OptimizedRevision").Return(optimized, nil).Once() 93 ds.On("RevisionFromString", exact.String()).Return(exact, nil).Once() 94 95 updated := ContextWithHandle(context.Background()) 96 err := AddRevisionToContext(updated, &v1.ReadRelationshipsRequest{ 97 Consistency: &v1.Consistency{ 98 Requirement: &v1.Consistency_AtLeastAsFresh{ 99 AtLeastAsFresh: zedtoken.MustNewFromRevision(exact), 100 }, 101 }, 102 }, ds) 103 require.NoError(err) 104 105 rev, _, err := RevisionFromContext(updated) 106 require.NoError(err) 107 108 require.True(exact.Equal(rev)) 109 ds.AssertExpectations(t) 110 } 111 112 func TestAddRevisionToContextAtValidExactSnapshot(t *testing.T) { 113 require := require.New(t) 114 115 ds := &proxy_test.MockDatastore{} 116 ds.On("CheckRevision", exact).Return(nil).Times(1) 117 ds.On("RevisionFromString", exact.String()).Return(exact, nil).Once() 118 119 updated := ContextWithHandle(context.Background()) 120 err := AddRevisionToContext(updated, &v1.ReadRelationshipsRequest{ 121 Consistency: &v1.Consistency{ 122 Requirement: &v1.Consistency_AtExactSnapshot{ 123 AtExactSnapshot: zedtoken.MustNewFromRevision(exact), 124 }, 125 }, 126 }, ds) 127 require.NoError(err) 128 129 rev, _, err := RevisionFromContext(updated) 130 require.NoError(err) 131 132 require.True(exact.Equal(rev)) 133 ds.AssertExpectations(t) 134 } 135 136 func TestAddRevisionToContextAtInvalidExactSnapshot(t *testing.T) { 137 require := require.New(t) 138 139 ds := &proxy_test.MockDatastore{} 140 ds.On("CheckRevision", zero).Return(errors.New("bad revision")).Times(1) 141 ds.On("RevisionFromString", zero.String()).Return(zero, nil).Once() 142 143 updated := ContextWithHandle(context.Background()) 144 err := AddRevisionToContext(updated, &v1.ReadRelationshipsRequest{ 145 Consistency: &v1.Consistency{ 146 Requirement: &v1.Consistency_AtExactSnapshot{ 147 AtExactSnapshot: zedtoken.MustNewFromRevision(zero), 148 }, 149 }, 150 }, ds) 151 require.Error(err) 152 ds.AssertExpectations(t) 153 } 154 155 func TestAddRevisionToContextNoConsistencyAPI(t *testing.T) { 156 require := require.New(t) 157 158 updated := ContextWithHandle(context.Background()) 159 160 _, _, err := RevisionFromContext(updated) 161 require.Error(err) 162 } 163 164 func TestAddRevisionToContextWithCursor(t *testing.T) { 165 require := require.New(t) 166 167 ds := &proxy_test.MockDatastore{} 168 ds.On("CheckRevision", optimized).Return(nil).Times(1) 169 ds.On("RevisionFromString", optimized.String()).Return(optimized, nil).Once() 170 171 // cursor is at `optimized` 172 cursor, err := cursor.EncodeFromDispatchCursor(&dispatch.Cursor{}, "somehash", optimized) 173 require.NoError(err) 174 175 // revision in context is at `exact` 176 updated := ContextWithHandle(context.Background()) 177 err = AddRevisionToContext(updated, &v1.LookupResourcesRequest{ 178 Consistency: &v1.Consistency{ 179 Requirement: &v1.Consistency_AtExactSnapshot{ 180 AtExactSnapshot: zedtoken.MustNewFromRevision(exact), 181 }, 182 }, 183 OptionalCursor: cursor, 184 }, ds) 185 require.NoError(err) 186 187 // ensure we get back `optimized` from the cursor 188 rev, _, err := RevisionFromContext(updated) 189 require.NoError(err) 190 191 require.True(optimized.Equal(rev)) 192 ds.AssertExpectations(t) 193 }