github.com/openfga/openfga@v1.5.4-rc1/pkg/typesystem/resolver_test.go (about)

     1  package typesystem
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/oklog/ulid/v2"
     9  	openfgav1 "github.com/openfga/api/proto/openfga/v1"
    10  	parser "github.com/openfga/language/pkg/go/transformer"
    11  	"github.com/stretchr/testify/require"
    12  	"go.uber.org/mock/gomock"
    13  	"golang.org/x/sync/errgroup"
    14  
    15  	mockstorage "github.com/openfga/openfga/internal/mocks"
    16  )
    17  
    18  func TestMemoizedTypesystemResolverFunc(t *testing.T) {
    19  	mockController := gomock.NewController(t)
    20  	defer mockController.Finish()
    21  
    22  	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)
    23  
    24  	storeID := ulid.Make().String()
    25  	modelID1 := ulid.Make().String()
    26  	modelID2 := ulid.Make().String()
    27  
    28  	typedefs := parser.MustTransformDSLToProto(`model
    29    schema 1.1
    30  type user
    31  type document
    32    relations
    33  	define viewer: [user]`).GetTypeDefinitions()
    34  
    35  	gomock.InOrder(
    36  		mockDatastore.EXPECT().
    37  			ReadAuthorizationModel(gomock.Any(), storeID, modelID1).
    38  			Return(&openfgav1.AuthorizationModel{
    39  				Id:              modelID1,
    40  				SchemaVersion:   SchemaVersion1_1,
    41  				TypeDefinitions: typedefs,
    42  			}, nil),
    43  
    44  		mockDatastore.EXPECT().
    45  			FindLatestAuthorizationModel(gomock.Any(), storeID).
    46  			Return(&openfgav1.AuthorizationModel{
    47  				Id:              modelID2,
    48  				SchemaVersion:   SchemaVersion1_1,
    49  				TypeDefinitions: typedefs,
    50  			}, nil),
    51  	)
    52  
    53  	resolver, resolverStop := MemoizedTypesystemResolverFunc(
    54  		mockDatastore,
    55  	)
    56  	defer resolverStop()
    57  
    58  	typesys, err := resolver(context.Background(), storeID, modelID1)
    59  	require.NoError(t, err)
    60  	require.NotNil(t, typesys)
    61  
    62  	relation, err := typesys.GetRelation("document", "viewer")
    63  	require.NoError(t, err)
    64  	require.NotNil(t, relation)
    65  
    66  	typesys, err = resolver(context.Background(), storeID, "")
    67  	require.NoError(t, err)
    68  	require.NotNil(t, typesys)
    69  	require.Equal(t, modelID2, typesys.GetAuthorizationModelID())
    70  
    71  	relation, err = typesys.GetRelation("document", "viewer")
    72  	require.NoError(t, err)
    73  	require.NotNil(t, relation)
    74  }
    75  
    76  func TestSingleFlightMemoizedTypesystemResolverFunc(t *testing.T) {
    77  	const numGoroutines = 2
    78  
    79  	mockController := gomock.NewController(t)
    80  	defer mockController.Finish()
    81  
    82  	mockDatastore := mockstorage.NewMockOpenFGADatastore(mockController)
    83  
    84  	storeID := ulid.Make().String()
    85  	modelID := ulid.Make().String()
    86  
    87  	mockDatastore.EXPECT().
    88  		FindLatestAuthorizationModel(gomock.Any(), storeID).
    89  		Return(&openfgav1.AuthorizationModel{
    90  			Id:            modelID,
    91  			SchemaVersion: SchemaVersion1_1,
    92  		}, nil).MinTimes(1).MaxTimes(numGoroutines)
    93  
    94  	resolver, resolverStop := MemoizedTypesystemResolverFunc(
    95  		mockDatastore,
    96  	)
    97  	defer resolverStop()
    98  
    99  	var wg errgroup.Group
   100  
   101  	for i := 0; i < numGoroutines; i++ {
   102  		wg.Go(func() error {
   103  			typesys, err := resolver(context.Background(), storeID, "")
   104  			if err != nil {
   105  				return err
   106  			}
   107  			if typesys.GetAuthorizationModelID() != modelID {
   108  				return fmt.Errorf("expected model %s, actual %s", modelID, typesys.GetAuthorizationModelID())
   109  			}
   110  			return nil
   111  		})
   112  	}
   113  
   114  	err := wg.Wait()
   115  	require.NoError(t, err)
   116  }