Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Provide tests for client introspection query #1492

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
47 changes: 47 additions & 0 deletions tests/integration/schema/client_introspection/one_many_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2023 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package client_introspection

import (
_ "embed"
"testing"

testUtils "github.com/sourcenetwork/defradb/tests/integration"
)

func TestClientIntrospectionWithOneToManySchema(t *testing.T) {
test := testUtils.TestCase{
Actions: []any{
testUtils.SchemaUpdate{
Schema: `
type Book {
name: String
author: Author
}
type Author {
name: String
published: [Book]
}
`,
},
testUtils.ClientIntrospectionRequest{
Request: clientIntrospectionQuery,
// TODO: this should pass without error.
// https://github.com/sourcenetwork/defradb/issues/1502
ExpectedError: "Unknown kind of type: ",
// TODO: this should pass without error.
// https://github.com/sourcenetwork/defradb/issues/1463
// ExpectedError: "InputFields are missing",
},
},
}
testUtils.ExecuteTestCase(t, []string{"Book", "Author"}, test)
}
32 changes: 32 additions & 0 deletions tests/integration/schema/client_introspection/simple_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2023 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package client_introspection

import (
_ "embed"
"testing"

testUtils "github.com/sourcenetwork/defradb/tests/integration"
)

//go:embed altair_graphiql_postman_2023.gql
var clientIntrospectionQuery string

func TestClientIntrospectionBasic(t *testing.T) {
test := testUtils.TestCase{
Actions: []any{
testUtils.ClientIntrospectionRequest{
Request: clientIntrospectionQuery,
},
},
}
testUtils.ExecuteTestCase(t, []string{}, test)
}
14 changes: 14 additions & 0 deletions tests/integration/test_case.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,17 @@ type IntrospectionRequest struct {
// contains this string.
ExpectedError string
}

// ClientIntrospectionRequest represents a GraphQL client introspection request.
// The GraphQL clients usually use this to fetch the schema state with a default introspection
// query they provide.
type ClientIntrospectionRequest struct {
orpheuslummis marked this conversation as resolved.
Show resolved Hide resolved
// The introspection request to use when fetching schema state.
Request string

// Any error expected from the action. Optional.
//
// String can be a partial, and the test will pass if an error is returned that
// contains this string.
ExpectedError string
}
52 changes: 52 additions & 0 deletions tests/integration/utils2.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ func executeTestCase(
case IntrospectionRequest:
assertIntrospectionResults(ctx, t, testCase.Description, db, action)

case ClientIntrospectionRequest:
assertClientIntrospectionResults(ctx, t, testCase.Description, db, action)

case WaitForSync:
waitForSync(t, testCase, action, syncChans)

Expand Down Expand Up @@ -1179,6 +1182,55 @@ func assertIntrospectionResults(
return false
}

// Asserts that the client introspection results conform to our expectations.
func assertClientIntrospectionResults(
orpheuslummis marked this conversation as resolved.
Show resolved Hide resolved
ctx context.Context,
t *testing.T,
description string,
db client.DB,
action ClientIntrospectionRequest,
) bool {
result := db.ExecRequest(ctx, action.Request)

if AssertErrors(t, description, result.GQL.Errors, action.ExpectedError) {
return true
}
resultantData := result.GQL.Data.(map[string]any)

if len(resultantData) == 0 {
return false
}

// Iterate through all types, validating each type definition.
// Inspired from buildClientSchema.ts from graphql-js,
// which is one way that clients do validate the schema.
types := resultantData["__schema"].(map[string]any)["types"].([]any)

for _, typeData := range types {
typeDef := typeData.(map[string]any)
kind := typeDef["kind"].(string)

switch kind {
case "SCALAR", "INTERFACE", "UNION", "ENUM":
// No validation for these types in this test
case "OBJECT":
fields := typeDef["fields"]
if fields == nil {
t.Errorf("Fields are missing for OBJECT type %v", typeDef["name"])
}
case "INPUT_OBJECT":
inputFields := typeDef["inputFields"]
if inputFields == nil {
t.Errorf("InputFields are missing for INPUT_OBJECT type %v", typeDef["name"])
}
default:
// t.Errorf("Unknown type kind: %v", kind)
}
}

return true
}

// Asserts that the `actual` contains the given `contains` value according to the logic
// described on the [RequestTestCase.ContainsData] property.
func assertContains(t *testing.T, contains map[string]any, actual map[string]any) {
Expand Down