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

     1  package test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/google/go-cmp/cmp"
     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  	"google.golang.org/protobuf/testing/protocmp"
    13  
    14  	"github.com/openfga/openfga/pkg/server/commands"
    15  	serverErrors "github.com/openfga/openfga/pkg/server/errors"
    16  	"github.com/openfga/openfga/pkg/storage"
    17  	"github.com/openfga/openfga/pkg/testutils"
    18  	"github.com/openfga/openfga/pkg/tuple"
    19  	"github.com/openfga/openfga/pkg/typesystem"
    20  )
    21  
    22  func TestWriteAndReadAssertions(t *testing.T, datastore storage.OpenFGADatastore) {
    23  	type writeAssertionsTestSettings struct {
    24  		_name      string
    25  		assertions []*openfgav1.Assertion
    26  	}
    27  
    28  	store := testutils.CreateRandomString(10)
    29  
    30  	githubModelReq := &openfgav1.WriteAuthorizationModelRequest{
    31  		StoreId: store,
    32  		TypeDefinitions: parser.MustTransformDSLToProto(`model
    33    schema 1.1
    34  type user
    35  
    36  type repo
    37    relations
    38  	define reader: [user]
    39  	define can_read: reader`).GetTypeDefinitions(),
    40  		SchemaVersion: typesystem.SchemaVersion1_1,
    41  	}
    42  
    43  	var tests = []writeAssertionsTestSettings{
    44  		{
    45  			_name: "writing_assertions_succeeds",
    46  			assertions: []*openfgav1.Assertion{{
    47  				TupleKey:    tuple.NewAssertionTupleKey("repo:test", "reader", "user:elbuo"),
    48  				Expectation: false,
    49  			}},
    50  		},
    51  		{
    52  			_name: "writing_assertions_succeeds_when_it_is_not_directly_assignable",
    53  			assertions: []*openfgav1.Assertion{{
    54  				TupleKey:    tuple.NewAssertionTupleKey("repo:test", "can_read", "user:elbuo"),
    55  				Expectation: false,
    56  			}},
    57  		},
    58  		{
    59  			_name: "writing_multiple_assertions_succeeds",
    60  			assertions: []*openfgav1.Assertion{
    61  				{
    62  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "reader", "user:elbuo"),
    63  					Expectation: false,
    64  				},
    65  				{
    66  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "reader", "user:maria"),
    67  					Expectation: true,
    68  				},
    69  				{
    70  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "reader", "user:jon"),
    71  					Expectation: false,
    72  				},
    73  				{
    74  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "reader", "user:jose"),
    75  					Expectation: true,
    76  				},
    77  			},
    78  		},
    79  		{
    80  			_name: "writing_multiple_assertions_succeeds_when_it_is_not_directly_assignable",
    81  			assertions: []*openfgav1.Assertion{
    82  				{
    83  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "can_read", "user:elbuo"),
    84  					Expectation: false,
    85  				},
    86  				{
    87  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "can_read", "user:maria"),
    88  					Expectation: false,
    89  				},
    90  				{
    91  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "can_read", "user:jon"),
    92  					Expectation: true,
    93  				},
    94  			},
    95  		},
    96  		{
    97  			_name:      "writing_empty_assertions_succeeds",
    98  			assertions: []*openfgav1.Assertion{},
    99  		},
   100  	}
   101  
   102  	ctx := context.Background()
   103  
   104  	for _, test := range tests {
   105  		t.Run(test._name, func(t *testing.T) {
   106  			model := githubModelReq
   107  
   108  			writeAuthzModelCmd := commands.NewWriteAuthorizationModelCommand(datastore)
   109  
   110  			modelID, err := writeAuthzModelCmd.Execute(ctx, model)
   111  			require.NoError(t, err)
   112  			request := &openfgav1.WriteAssertionsRequest{
   113  				StoreId:              store,
   114  				Assertions:           test.assertions,
   115  				AuthorizationModelId: modelID.GetAuthorizationModelId(),
   116  			}
   117  
   118  			writeAssertionCmd := commands.NewWriteAssertionsCommand(datastore)
   119  			_, err = writeAssertionCmd.Execute(ctx, request)
   120  			require.NoError(t, err)
   121  			query := commands.NewReadAssertionsQuery(datastore)
   122  			actualResponse, actualError := query.Execute(ctx, store, modelID.GetAuthorizationModelId())
   123  			require.NoError(t, actualError)
   124  
   125  			expectedResponse := &openfgav1.ReadAssertionsResponse{
   126  				AuthorizationModelId: modelID.GetAuthorizationModelId(),
   127  				Assertions:           test.assertions,
   128  			}
   129  			if diff := cmp.Diff(expectedResponse, actualResponse, protocmp.Transform()); diff != "" {
   130  				t.Errorf("store mismatch (-want +got):\n%s", diff)
   131  			}
   132  		})
   133  	}
   134  }
   135  
   136  func TestWriteAssertionsFailure(t *testing.T, datastore storage.OpenFGADatastore) {
   137  	type writeAssertionsTestSettings struct {
   138  		_name      string
   139  		assertions []*openfgav1.Assertion
   140  		modelID    string
   141  		err        error
   142  	}
   143  
   144  	store := testutils.CreateRandomString(10)
   145  
   146  	githubModelReq := &openfgav1.WriteAuthorizationModelRequest{
   147  		StoreId: store,
   148  		TypeDefinitions: parser.MustTransformDSLToProto(`model
   149  	schema 1.1
   150  type user
   151  
   152  type repo
   153    relations
   154  	define reader: [user]
   155  	define can_read: reader`).GetTypeDefinitions(),
   156  		SchemaVersion: typesystem.SchemaVersion1_1,
   157  	}
   158  	ctx := context.Background()
   159  
   160  	writeAuthzModelCmd := commands.NewWriteAuthorizationModelCommand(datastore)
   161  	modelID, err := writeAuthzModelCmd.Execute(ctx, githubModelReq)
   162  	require.NoError(t, err)
   163  
   164  	var tests = []writeAssertionsTestSettings{
   165  		{
   166  			_name: "writing_assertion_with_invalid_relation_fails",
   167  			assertions: []*openfgav1.Assertion{
   168  				{
   169  					TupleKey: tuple.NewAssertionTupleKey(
   170  						"repo:test",
   171  						"invalidrelation",
   172  						"user:elbuo",
   173  					),
   174  					Expectation: false,
   175  				},
   176  			},
   177  			modelID: modelID.GetAuthorizationModelId(),
   178  			err: serverErrors.ValidationError(
   179  				fmt.Errorf("relation 'repo#invalidrelation' not found"),
   180  			),
   181  		},
   182  		{
   183  			_name: "writing_assertion_with_not_found_id",
   184  			assertions: []*openfgav1.Assertion{
   185  				{
   186  					TupleKey:    tuple.NewAssertionTupleKey("repo:test", "can_read", "user:elbuo"),
   187  					Expectation: false,
   188  				},
   189  			},
   190  			modelID: "not_valid_id",
   191  			err: serverErrors.AuthorizationModelNotFound(
   192  				"not_valid_id",
   193  			),
   194  		},
   195  	}
   196  
   197  	for _, test := range tests {
   198  		t.Run(test._name, func(t *testing.T) {
   199  			request := &openfgav1.WriteAssertionsRequest{
   200  				StoreId:              store,
   201  				Assertions:           test.assertions,
   202  				AuthorizationModelId: test.modelID,
   203  			}
   204  
   205  			writeAssertionCmd := commands.NewWriteAssertionsCommand(datastore)
   206  			_, err = writeAssertionCmd.Execute(ctx, request)
   207  			require.ErrorIs(t, test.err, err)
   208  		})
   209  	}
   210  }