github.com/openfga/openfga@v1.5.4-rc1/pkg/storage/test/authz_models.go (about)

     1  package test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/oklog/ulid/v2"
     9  	openfgav1 "github.com/openfga/api/proto/openfga/v1"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/openfga/openfga/pkg/storage"
    13  	"github.com/openfga/openfga/pkg/testutils"
    14  	"github.com/openfga/openfga/pkg/typesystem"
    15  )
    16  
    17  func WriteAndReadAuthorizationModelTest(t *testing.T, datastore storage.OpenFGADatastore) {
    18  	ctx := context.Background()
    19  	storeID := ulid.Make().String()
    20  
    21  	t.Run("write, then read, succeeds", func(t *testing.T) {
    22  		model := &openfgav1.AuthorizationModel{
    23  			Id:              ulid.Make().String(),
    24  			SchemaVersion:   typesystem.SchemaVersion1_0,
    25  			TypeDefinitions: []*openfgav1.TypeDefinition{{Type: "folder"}},
    26  		}
    27  
    28  		err := datastore.WriteAuthorizationModel(ctx, storeID, model)
    29  		require.NoError(t, err)
    30  
    31  		got, err := datastore.ReadAuthorizationModel(ctx, storeID, model.GetId())
    32  		require.NoError(t, err)
    33  
    34  		if diff := cmp.Diff(model, got, cmpOpts...); diff != "" {
    35  			t.Errorf("mismatch (-want +got):\n%s", diff)
    36  		}
    37  	})
    38  
    39  	t.Run("trying_to_get_a_model_which_does_not_exist_returns_not_found", func(t *testing.T) {
    40  		_, err := datastore.ReadAuthorizationModel(ctx, storeID, ulid.Make().String())
    41  		require.ErrorIs(t, err, storage.ErrNotFound)
    42  	})
    43  }
    44  
    45  func ReadAuthorizationModelsTest(t *testing.T, datastore storage.OpenFGADatastore) {
    46  	ctx := context.Background()
    47  	store := ulid.Make().String()
    48  
    49  	model1 := &openfgav1.AuthorizationModel{
    50  		Id:            ulid.Make().String(),
    51  		SchemaVersion: typesystem.SchemaVersion1_0,
    52  		TypeDefinitions: []*openfgav1.TypeDefinition{
    53  			{
    54  				Type: "folder",
    55  				Relations: map[string]*openfgav1.Userset{
    56  					"viewer": {
    57  						Userset: &openfgav1.Userset_This{
    58  							This: &openfgav1.DirectUserset{},
    59  						},
    60  					},
    61  				},
    62  			},
    63  		},
    64  	}
    65  
    66  	err := datastore.WriteAuthorizationModel(ctx, store, model1)
    67  	require.NoError(t, err)
    68  
    69  	model2 := &openfgav1.AuthorizationModel{
    70  		Id:            ulid.Make().String(),
    71  		SchemaVersion: typesystem.SchemaVersion1_0,
    72  		TypeDefinitions: []*openfgav1.TypeDefinition{
    73  			{
    74  				Type: "folder",
    75  				Relations: map[string]*openfgav1.Userset{
    76  					"reader": {
    77  						Userset: &openfgav1.Userset_This{
    78  							This: &openfgav1.DirectUserset{},
    79  						},
    80  					},
    81  				},
    82  			},
    83  		},
    84  	}
    85  
    86  	err = datastore.WriteAuthorizationModel(ctx, store, model2)
    87  	require.NoError(t, err)
    88  
    89  	models, continuationToken, err := datastore.ReadAuthorizationModels(ctx, store, storage.PaginationOptions{
    90  		PageSize: 1,
    91  	})
    92  	require.NoError(t, err)
    93  	require.Len(t, models, 1)
    94  	require.NotEmpty(t, continuationToken)
    95  
    96  	if diff := cmp.Diff(model2, models[0], cmpOpts...); diff != "" {
    97  		t.Fatalf("mismatch (-want +got):\n%s", diff)
    98  	}
    99  
   100  	models, continuationToken, err = datastore.ReadAuthorizationModels(ctx, store, storage.PaginationOptions{
   101  		PageSize: 2,
   102  		From:     string(continuationToken),
   103  	})
   104  	require.NoError(t, err)
   105  	require.Len(t, models, 1)
   106  	require.Empty(t, continuationToken)
   107  
   108  	if diff := cmp.Diff(model1, models[0], cmpOpts...); diff != "" {
   109  		t.Fatalf("mismatch (-want +got):\n%s", diff)
   110  	}
   111  }
   112  
   113  func FindLatestAuthorizationModelTest(t *testing.T, datastore storage.OpenFGADatastore) {
   114  	ctx := context.Background()
   115  
   116  	t.Run("find_latest_authorization_model_should_return_not_found_when_no_models", func(t *testing.T) {
   117  		store := testutils.CreateRandomString(10)
   118  		_, err := datastore.FindLatestAuthorizationModel(ctx, store)
   119  		require.ErrorIs(t, err, storage.ErrNotFound)
   120  	})
   121  
   122  	t.Run("find_latest_authorization_model_should_succeed", func(t *testing.T) {
   123  		store := ulid.Make().String()
   124  
   125  		oldModel := &openfgav1.AuthorizationModel{
   126  			Id:            ulid.Make().String(),
   127  			SchemaVersion: typesystem.SchemaVersion1_1,
   128  			TypeDefinitions: []*openfgav1.TypeDefinition{
   129  				{
   130  					Type: "user",
   131  				},
   132  				{
   133  					Type: "folder",
   134  					Relations: map[string]*openfgav1.Userset{
   135  						"viewer": {
   136  							Userset: &openfgav1.Userset_This{},
   137  						},
   138  					},
   139  					Metadata: &openfgav1.Metadata{
   140  						Relations: map[string]*openfgav1.RelationMetadata{
   141  							"viewer": {
   142  								DirectlyRelatedUserTypes: []*openfgav1.RelationReference{
   143  									{
   144  										Type: "user",
   145  									},
   146  								},
   147  							},
   148  						},
   149  					},
   150  				},
   151  			},
   152  		}
   153  		err := datastore.WriteAuthorizationModel(ctx, store, oldModel)
   154  		require.NoError(t, err)
   155  
   156  		updatedModel := &openfgav1.AuthorizationModel{
   157  			Id:            ulid.Make().String(),
   158  			SchemaVersion: typesystem.SchemaVersion1_1,
   159  			TypeDefinitions: []*openfgav1.TypeDefinition{
   160  				{
   161  					Type: "user",
   162  				},
   163  				{
   164  					Type: "folder",
   165  					Relations: map[string]*openfgav1.Userset{
   166  						"owner": {
   167  							Userset: &openfgav1.Userset_This{},
   168  						},
   169  					},
   170  					Metadata: &openfgav1.Metadata{
   171  						Relations: map[string]*openfgav1.RelationMetadata{
   172  							"owner": {
   173  								DirectlyRelatedUserTypes: []*openfgav1.RelationReference{
   174  									{
   175  										Type: "user",
   176  									},
   177  								},
   178  							},
   179  						},
   180  					},
   181  				},
   182  			},
   183  		}
   184  		err = datastore.WriteAuthorizationModel(ctx, store, updatedModel)
   185  		require.NoError(t, err)
   186  
   187  		latestModel, err := datastore.FindLatestAuthorizationModel(ctx, store)
   188  		require.NoError(t, err)
   189  		if diff := cmp.Diff(updatedModel, latestModel, cmpOpts...); diff != "" {
   190  			t.Errorf("mismatch (-want +got):\n%s", diff)
   191  		}
   192  
   193  		newModel := &openfgav1.AuthorizationModel{
   194  			Id:            ulid.Make().String(),
   195  			SchemaVersion: typesystem.SchemaVersion1_1,
   196  			TypeDefinitions: []*openfgav1.TypeDefinition{
   197  				{
   198  					Type: "user",
   199  				},
   200  				{
   201  					Type: "folder",
   202  					Relations: map[string]*openfgav1.Userset{
   203  						"reader": {
   204  							Userset: &openfgav1.Userset_This{},
   205  						},
   206  					},
   207  					Metadata: &openfgav1.Metadata{
   208  						Relations: map[string]*openfgav1.RelationMetadata{
   209  							"reader": {
   210  								DirectlyRelatedUserTypes: []*openfgav1.RelationReference{
   211  									{
   212  										Type: "user",
   213  									},
   214  								},
   215  							},
   216  						},
   217  					},
   218  				},
   219  			},
   220  		}
   221  		err = datastore.WriteAuthorizationModel(ctx, store, newModel)
   222  		require.NoError(t, err)
   223  
   224  		latestModel, err = datastore.FindLatestAuthorizationModel(ctx, store)
   225  		require.NoError(t, err)
   226  		if diff := cmp.Diff(newModel, latestModel, cmpOpts...); diff != "" {
   227  			t.Errorf("mismatch (-want +got):\n%s", diff)
   228  		}
   229  	})
   230  }