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  }