From 7a7d21a7190fce132b08f013b369eb485a17dce0 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 4 Aug 2026 02:48:14 +0530 Subject: [PATCH] test: dial the configured grpc endpoint and seed FGA before public checks Two defects that let integration tests pass without testing anything. The grpc subtests never read AUTHORIZER_TEST_GRPC -- neither protocolClient nor adminClient passed a grpc endpoint, so the SDK derived it from AUTHORIZER_TEST_URL's host plus the DEFAULT grpc port. A suite pointed at a container on a non-default port still sent every grpc call to whatever was listening on 9091, silently testing a different server. Locally that meant an unrelated dev server, which surfaced as "invalid credentials" on grpc login while graphql and rest passed. TestCheckPermissions and TestListPermissions depended on test ordering: TestAdminFgaResetLast wipes the FGA store, and Go runs tests in declaration order, so by the time the public FGA tests ran there was no authorization model. They took the "authorization check failed" branch of skipIfFgaUnavailable and skipped -- so in a full-suite run those two never executed at all, and only passed when run in isolation. They now seed the model they check against. A server with no FGA engine still skips, which is the case that guard is actually for. --- test/admin_test.go | 1 + test/authorizer_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ test/protocol_test.go | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/test/admin_test.go b/test/admin_test.go index 3b76b5d..e791740 100644 --- a/test/admin_test.go +++ b/test/admin_test.go @@ -23,6 +23,7 @@ func adminClient(t *testing.T, p authorizer.Protocol) *authorizer.AuthorizerAdmi t.Helper() c, err := authorizer.NewAuthorizerAdminClient(authorizerURL, adminSecret, authorizer.WithAdminProtocol(p), + authorizer.WithAdminGRPCEndpoint(grpcEndpoint), authorizer.WithAdminExtraHeaders(map[string]string{"Origin": authorizerURL}), ) if err != nil { diff --git a/test/authorizer_test.go b/test/authorizer_test.go index 0b676fb..1a5e6b0 100644 --- a/test/authorizer_test.go +++ b/test/authorizer_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/authorizerdev/authorizer-go/v2" + authorizerv1 "github.com/authorizerdev/authorizer-proto-go/authorizer/v1" ) // Integration-test target. Overridable via env so the same suite runs against a @@ -15,6 +16,12 @@ import ( var ( authorizerURL = envOr("AUTHORIZER_TEST_URL", "http://localhost:8080") clientID = envOr("AUTHORIZER_TEST_CLIENT_ID", "123456") + // grpcEndpoint pins the host:port the grpc subtests dial. Without it the + // SDK derives the endpoint from authorizerURL's host plus the DEFAULT grpc + // port (9091) -- so a suite pointed at a container on a non-default port + // would still send its grpc calls to whatever happens to be on 9091, + // silently testing a different server. Empty keeps the derived default. + grpcEndpoint = envOr("AUTHORIZER_TEST_GRPC", "") ) const testPassword = "Abc@123" @@ -331,6 +338,38 @@ func TestMagicLinkLogin(t *testing.T) { // skipIfFgaUnavailable skips an FGA integration test when the target server has // the fine-grained authorization engine disabled or no model installed, so the // suite stays green on a default (auth-only) deployment. +// ensureFgaModel writes the authorization model the public FGA tests check +// against, so they do not depend on test ordering. +// +// TestAdminFgaResetLast wipes the store, and Go runs tests in declaration +// order, so in a full-suite run the public FGA tests used to find no model, +// take the "authorization check failed" branch of skipIfFgaUnavailable, and +// silently skip -- meaning check_permissions/list_permissions were never +// actually exercised except when run in isolation. Seeding here makes them +// self-sufficient. A server with no FGA engine at all still errors, and those +// tests still skip, which is the case skipIfFgaUnavailable is really for. +func ensureFgaModel(t *testing.T) { + t.Helper() + admin, err := authorizer.NewAuthorizerAdminClient(authorizerURL, adminSecret, + authorizer.WithAdminExtraHeaders(map[string]string{"Origin": authorizerURL})) + if err != nil { + t.Fatalf("admin client for FGA seeding: %v", err) + } + const dsl = `model + schema 1.1 + +type user + +type document + relations + define can_view: [user] + define can_edit: [user] +` + if _, err := admin.FgaWriteModel(&authorizerv1.FgaWriteModelRequest{Dsl: dsl}); err != nil { + t.Logf("could not seed FGA model (%v); the test will skip if FGA is unavailable", err) + } +} + func skipIfFgaUnavailable(t *testing.T, err error) { t.Helper() if err == nil { @@ -352,6 +391,7 @@ func skipIfFgaUnavailable(t *testing.T, err error) { } func TestCheckPermissions(t *testing.T) { + ensureFgaModel(t) c := testClient(t) email := uniqueEmail() @@ -404,6 +444,7 @@ func TestCheckPermissions(t *testing.T) { } func TestListPermissions(t *testing.T) { + ensureFgaModel(t) c := testClient(t) email := uniqueEmail() diff --git a/test/protocol_test.go b/test/protocol_test.go index ccc2418..997753e 100644 --- a/test/protocol_test.go +++ b/test/protocol_test.go @@ -24,7 +24,7 @@ func protocolClient(t *testing.T, p authorizer.Protocol) *authorizer.AuthorizerC t.Helper() c, err := authorizer.NewAuthorizerClient(clientID, authorizerURL, "", map[string]string{ "Origin": authorizerURL, - }, authorizer.WithProtocol(p)) + }, authorizer.WithProtocol(p), authorizer.WithGRPCEndpoint(grpcEndpoint)) if err != nil { t.Fatalf("failed to create %s client: %v", p, err) }