Merge branch 'test/add-validation-event-tests' into 'main'
test: add validation and event tests for organization and API key See merge request unboundsoftware/schemas!634
This commit was merged in pull request #638.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
.testCoverage.txt
|
||||
.testCoverage.txt.tmp
|
||||
coverage.html
|
||||
coverage.out
|
||||
/exported
|
||||
/release
|
||||
/schemactl
|
||||
|
||||
@@ -7,10 +7,68 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
|
||||
|
||||
"gitlab.com/unboundsoftware/schemas/hash"
|
||||
)
|
||||
|
||||
// AddOrganization tests
|
||||
|
||||
func TestAddOrganization_Validate_Success(t *testing.T) {
|
||||
cmd := AddOrganization{
|
||||
Name: "Test Org",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
org := &Organization{} // New organization with no identity
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAddOrganization_Validate_AlreadyExists(t *testing.T) {
|
||||
cmd := AddOrganization{
|
||||
Name: "Test Org",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
org := &Organization{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("existing-org-id"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "already exists")
|
||||
}
|
||||
|
||||
func TestAddOrganization_Validate_EmptyName(t *testing.T) {
|
||||
cmd := AddOrganization{
|
||||
Name: "",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
org := &Organization{}
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "name is required")
|
||||
}
|
||||
|
||||
func TestAddOrganization_Event(t *testing.T) {
|
||||
cmd := AddOrganization{
|
||||
Name: "Test Org",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
event := cmd.Event(context.Background())
|
||||
require.NotNil(t, event)
|
||||
|
||||
orgEvent, ok := event.(*OrganizationAdded)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "Test Org", orgEvent.Name)
|
||||
assert.Equal(t, "user@example.com", orgEvent.Initiator)
|
||||
}
|
||||
|
||||
// AddAPIKey tests
|
||||
|
||||
func TestAddAPIKey_Event(t *testing.T) {
|
||||
type fields struct {
|
||||
Name string
|
||||
@@ -74,3 +132,335 @@ func TestAddAPIKey_Event(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAPIKey_Validate_Success(t *testing.T) {
|
||||
cmd := AddAPIKey{
|
||||
Name: "production-key",
|
||||
Key: "us_ak_1234567890123456",
|
||||
Refs: []string{"main"},
|
||||
Read: true,
|
||||
Publish: false,
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
org := &Organization{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
||||
APIKeys: []APIKey{},
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestAddAPIKey_Validate_OrganizationNotExists(t *testing.T) {
|
||||
cmd := AddAPIKey{
|
||||
Name: "production-key",
|
||||
Key: "us_ak_1234567890123456",
|
||||
Refs: []string{"main"},
|
||||
Read: true,
|
||||
Publish: false,
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
org := &Organization{} // No identity means it doesn't exist
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "does not exist")
|
||||
}
|
||||
|
||||
func TestAddAPIKey_Validate_DuplicateKeyName(t *testing.T) {
|
||||
cmd := AddAPIKey{
|
||||
Name: "existing-key",
|
||||
Key: "us_ak_1234567890123456",
|
||||
Refs: []string{"main"},
|
||||
Read: true,
|
||||
Publish: false,
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
org := &Organization{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
||||
APIKeys: []APIKey{
|
||||
{
|
||||
Name: "existing-key",
|
||||
Key: "hashed-key",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "already exist")
|
||||
assert.Contains(t, err.Error(), "existing-key")
|
||||
}
|
||||
|
||||
// UpdateSubGraph tests
|
||||
|
||||
func TestUpdateSubGraph_Validate_Success(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_MissingRef(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "ref is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_RefWhitespaceOnly(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: " ",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "ref is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_MissingService(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "",
|
||||
Url: &url,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "service is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_ServiceWhitespaceOnly(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: " ",
|
||||
Url: &url,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "service is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_MissingSDL(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
Sdl: "",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "SDL is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_SDLWhitespaceOnly(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
Sdl: " \n\t ",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "SDL is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_MissingURL_NoExistingURL(t *testing.T) {
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: nil,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
Url: nil, // No existing URL
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "url is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_MissingURL_HasExistingURL(t *testing.T) {
|
||||
existingURL := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: nil,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
Url: &existingURL, // Has existing URL, so nil is OK
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_EmptyURL_NoExistingURL(t *testing.T) {
|
||||
emptyURL := ""
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &emptyURL,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
Url: nil,
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "url is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_URLWhitespaceOnly_NoExistingURL(t *testing.T) {
|
||||
whitespaceURL := " "
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &whitespaceURL,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
subGraph := &SubGraph{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("subgraph-123"),
|
||||
Url: nil,
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), subGraph)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "url is missing")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Validate_WrongAggregateType(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
// Pass wrong aggregate type
|
||||
org := &Organization{
|
||||
BaseAggregate: eventsourced.BaseAggregateFromString("org-123"),
|
||||
}
|
||||
|
||||
err := cmd.Validate(context.Background(), org)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "not a SubGraph")
|
||||
}
|
||||
|
||||
func TestUpdateSubGraph_Event(t *testing.T) {
|
||||
url := "http://example.com/graphql"
|
||||
wsURL := "ws://example.com/graphql"
|
||||
cmd := UpdateSubGraph{
|
||||
OrganizationId: "org-123",
|
||||
Ref: "main",
|
||||
Service: "users",
|
||||
Url: &url,
|
||||
WSUrl: &wsURL,
|
||||
Sdl: "type Query { hello: String }",
|
||||
Initiator: "user@example.com",
|
||||
}
|
||||
|
||||
event := cmd.Event(context.Background())
|
||||
require.NotNil(t, event)
|
||||
|
||||
subGraphEvent, ok := event.(*SubGraphUpdated)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "org-123", subGraphEvent.OrganizationId)
|
||||
assert.Equal(t, "main", subGraphEvent.Ref)
|
||||
assert.Equal(t, "users", subGraphEvent.Service)
|
||||
assert.Equal(t, url, *subGraphEvent.Url)
|
||||
assert.Equal(t, wsURL, *subGraphEvent.WSUrl)
|
||||
assert.Equal(t, "type Query { hello: String }", subGraphEvent.Sdl)
|
||||
assert.Equal(t, "user@example.com", subGraphEvent.Initiator)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
package sdlmerge
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMergeSDLs_Success(t *testing.T) {
|
||||
// Both types need to be in the same subgraph or properly federated
|
||||
sdl1 := `
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Post {
|
||||
id: ID!
|
||||
title: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl1)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "Post")
|
||||
assert.Contains(t, result, "id")
|
||||
assert.Contains(t, result, "name")
|
||||
assert.Contains(t, result, "title")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_SingleSchema(t *testing.T) {
|
||||
sdl := `
|
||||
type Query {
|
||||
hello: String
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "Query")
|
||||
assert.Contains(t, result, "hello")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_EmptySchemas(t *testing.T) {
|
||||
result, err := MergeSDLs()
|
||||
require.NoError(t, err)
|
||||
// With no schemas, result will be empty after processing
|
||||
// This is valid - just verifies no crash
|
||||
_ = result
|
||||
}
|
||||
|
||||
func TestMergeSDLs_InvalidSyntax(t *testing.T) {
|
||||
invalidSDL := `
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
// Missing closing brace
|
||||
`
|
||||
|
||||
_, err := MergeSDLs(invalidSDL)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "parse graphql document string")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_UnknownType(t *testing.T) {
|
||||
sdl := `
|
||||
type User {
|
||||
id: ID!
|
||||
profile: UnknownType
|
||||
}
|
||||
`
|
||||
|
||||
_, err := MergeSDLs(sdl)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "validate schema")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_DuplicateTypes_DifferentFields(t *testing.T) {
|
||||
// Same type with different fields in different subgraphs - should fail
|
||||
// In federation, shared types must be identical
|
||||
sdl1 := `
|
||||
type User {
|
||||
id: ID!
|
||||
}
|
||||
`
|
||||
sdl2 := `
|
||||
type User {
|
||||
name: String!
|
||||
}
|
||||
`
|
||||
|
||||
_, err := MergeSDLs(sdl1, sdl2)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "shared type")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_ExtendType(t *testing.T) {
|
||||
sdl1 := `
|
||||
type User {
|
||||
id: ID!
|
||||
}
|
||||
`
|
||||
sdl2 := `
|
||||
extend type User {
|
||||
email: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl1, sdl2)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "id")
|
||||
assert.Contains(t, result, "email")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_Scalars(t *testing.T) {
|
||||
sdl := `
|
||||
scalar DateTime
|
||||
|
||||
type Event {
|
||||
id: ID!
|
||||
createdAt: DateTime!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "DateTime")
|
||||
assert.Contains(t, result, "Event")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_Enums(t *testing.T) {
|
||||
sdl := `
|
||||
enum Role {
|
||||
ADMIN
|
||||
USER
|
||||
GUEST
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
role: Role!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "Role")
|
||||
assert.Contains(t, result, "ADMIN")
|
||||
assert.Contains(t, result, "USER")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_Interfaces(t *testing.T) {
|
||||
sdl := `
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type User implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "Node")
|
||||
assert.Contains(t, result, "implements")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_Unions(t *testing.T) {
|
||||
sdl := `
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Bot {
|
||||
id: ID!
|
||||
version: String!
|
||||
}
|
||||
|
||||
union Actor = User | Bot
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "Actor")
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "Bot")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_InputTypes(t *testing.T) {
|
||||
sdl := `
|
||||
input CreateUserInput {
|
||||
name: String!
|
||||
email: String!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createUser(input: CreateUserInput!): User
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "CreateUserInput")
|
||||
assert.Contains(t, result, "createUser")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_Directives(t *testing.T) {
|
||||
sdl := `
|
||||
type User {
|
||||
id: ID!
|
||||
name: String! @deprecated(reason: "Use fullName instead")
|
||||
fullName: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "name")
|
||||
assert.Contains(t, result, "fullName")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_FederationKeys(t *testing.T) {
|
||||
// Federation @key directive
|
||||
sdl := `
|
||||
type User @key(fields: "id") {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
// @key directive should be removed during merge
|
||||
assert.NotContains(t, result, "@key")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_ExternalFields(t *testing.T) {
|
||||
// Federation @external directive
|
||||
sdl1 := `
|
||||
type User @key(fields: "id") {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
`
|
||||
sdl2 := `
|
||||
extend type User @key(fields: "id") {
|
||||
id: ID! @external
|
||||
posts: [Post!]!
|
||||
}
|
||||
|
||||
type Post {
|
||||
id: ID!
|
||||
title: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl1, sdl2)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "Post")
|
||||
// @external fields should be removed
|
||||
assert.NotContains(t, result, "@external")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_ComplexSchema(t *testing.T) {
|
||||
// Multiple subgraphs with various types - simplified to avoid cross-references
|
||||
users := `
|
||||
type User @key(fields: "id") {
|
||||
id: ID!
|
||||
username: String!
|
||||
email: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
user(id: ID!): User
|
||||
users: [User!]!
|
||||
}
|
||||
`
|
||||
|
||||
posts := `
|
||||
extend type User @key(fields: "id") {
|
||||
id: ID! @external
|
||||
posts: [Post!]!
|
||||
}
|
||||
|
||||
type Post @key(fields: "id") {
|
||||
id: ID!
|
||||
title: String!
|
||||
content: String!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
post(id: ID!): Post
|
||||
posts: [Post!]!
|
||||
}
|
||||
`
|
||||
|
||||
comments := `
|
||||
extend type Post @key(fields: "id") {
|
||||
id: ID! @external
|
||||
comments: [Comment!]!
|
||||
}
|
||||
|
||||
type Comment {
|
||||
id: ID!
|
||||
text: String!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
comment(id: ID!): Comment
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(users, posts, comments)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify all types are present
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "Post")
|
||||
assert.Contains(t, result, "Comment")
|
||||
assert.Contains(t, result, "Query")
|
||||
|
||||
// Verify fields from all subgraphs
|
||||
assert.Contains(t, result, "username")
|
||||
assert.Contains(t, result, "posts")
|
||||
assert.Contains(t, result, "comments")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_EmptyTypeDefinition(t *testing.T) {
|
||||
sdl := `
|
||||
type Empty {}
|
||||
`
|
||||
|
||||
_, err := MergeSDLs(sdl)
|
||||
require.Error(t, err)
|
||||
// Empty types are invalid in GraphQL
|
||||
assert.Contains(t, err.Error(), "empty body")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_MultipleValidationErrors(t *testing.T) {
|
||||
// Schema with multiple errors
|
||||
sdl := `
|
||||
type User {
|
||||
id: ID!
|
||||
profile: NonExistentType1
|
||||
settings: NonExistentType2
|
||||
}
|
||||
`
|
||||
|
||||
_, err := MergeSDLs(sdl)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMergeSDLs_ListTypes(t *testing.T) {
|
||||
sdl := `
|
||||
type User {
|
||||
id: ID!
|
||||
tags: [String!]!
|
||||
friends: [User!]
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "tags")
|
||||
assert.Contains(t, result, "friends")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_NonNullTypes(t *testing.T) {
|
||||
sdl := `
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
email: String
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
assert.Contains(t, result, "id")
|
||||
assert.Contains(t, result, "name")
|
||||
assert.Contains(t, result, "email")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_Comments(t *testing.T) {
|
||||
sdl := `
|
||||
# This is a user type
|
||||
type User {
|
||||
# User ID
|
||||
id: ID!
|
||||
# User name
|
||||
name: String!
|
||||
}
|
||||
`
|
||||
|
||||
result, err := MergeSDLs(sdl)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "User")
|
||||
}
|
||||
|
||||
func TestMergeSDLs_LargeSchema(t *testing.T) {
|
||||
// Test with a reasonably large schema to ensure performance
|
||||
var sdlBuilder strings.Builder
|
||||
for i := 0; i < 50; i++ {
|
||||
sdlBuilder.WriteString("type Type")
|
||||
sdlBuilder.WriteString(strings.Repeat(string(rune('A'+i%26)), 1))
|
||||
sdlBuilder.WriteString(string(rune('0' + i/26)))
|
||||
sdlBuilder.WriteString(" { id: ID }\n")
|
||||
}
|
||||
|
||||
result, err := MergeSDLs(sdlBuilder.String())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify some types are present
|
||||
assert.Contains(t, result, "TypeA0")
|
||||
assert.Contains(t, result, "TypeB0")
|
||||
assert.Contains(t, result, "TypeC0")
|
||||
}
|
||||
Reference in New Issue
Block a user