-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Moving federation tests to their own folders Reorganizing the tests in the federation plugin a little bit so make it simpler to add more safely without testdata colliding. This is in anticipation for a follow up PR for adding entity resolver tests. Run the tests with `go test ./plugin/federation/...` and verify they all pass. Also verify that the testdata/allthething directory has a `generated` directory specific to that test. NOTE: There is a catch all type of test that I moved to the directory `allthething`. Open to suggestions for a better name! One potential thing to considere here is to split up the tests that use that testdata and break them down into more specific tests. E.g. Add a multikey test in the testdata/entity. For now, Im leaving that as a TODO. * Adding entity resolver tests in the federation plugin The tests work by sending `_entities` queries with `representation` variables directly to the mocked server, which will allow us to test generated federation code end to end. For context, the format of the entity query is something like: ``` query($representations:[_Any!]!){_entities(representations:$representations){ ...on Hello{secondary} }} ``` And `representations` are the list of federated keys for the entities being resovled, and they look like ``` representations: [{ "__typename": "Hello", "name": "federated key value 1", }, { "__typename": "Hello", "name": "federated key value 2", }] ``` The entity resolver tests are in `plugin/federation/federation_entityresolver_test.go` and they rely on `plugin/federation/testdata/entityresolver`. To run the tests: 1. Build the entityresolver testdata - From plugin/federation, run `go run github.com/99designs/gqlgen --config testdata/entityresolver/gqlgen.yml` 2. Run the tests with `go test ./...` or similar
- Loading branch information
1 parent
b7db36d
commit 01d3c4f
Showing
18 changed files
with
3,925 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package federation | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/99designs/gqlgen/client" | ||
"github.com/99designs/gqlgen/graphql/handler" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/99designs/gqlgen/plugin/federation/testdata/entityresolver" | ||
"github.com/99designs/gqlgen/plugin/federation/testdata/entityresolver/generated" | ||
) | ||
|
||
func TestEntityResolver(t *testing.T) { | ||
c := client.New(handler.NewDefaultServer( | ||
generated.NewExecutableSchema(generated.Config{ | ||
Resolvers: &entityresolver.Resolver{}}), | ||
)) | ||
|
||
t.Run("Hello entities - single federation key", func(t *testing.T) { | ||
representations := []map[string]interface{}{ | ||
{ | ||
"__typename": "Hello", | ||
"name": "first name - 1", | ||
}, { | ||
"__typename": "Hello", | ||
"name": "first name - 2", | ||
}, | ||
} | ||
|
||
var resp struct { | ||
Entities []struct { | ||
Name string `json:"name"` | ||
} `json:"_entities"` | ||
} | ||
|
||
err := c.Post( | ||
entityQuery([]string{ | ||
"Hello {name}", | ||
}), | ||
&resp, | ||
client.Var("representations", representations), | ||
) | ||
|
||
require.NoError(t, err) | ||
require.Equal(t, resp.Entities[0].Name, "first name - 1") | ||
require.Equal(t, resp.Entities[1].Name, "first name - 2") | ||
}) | ||
|
||
t.Run("World entity with nested key", func(t *testing.T) { | ||
representations := []map[string]interface{}{ | ||
{ | ||
"__typename": "World", | ||
"hello": map[string]interface{}{ | ||
"name": "world name - 1", | ||
}, | ||
"foo": "foo 1", | ||
}, { | ||
"__typename": "World", | ||
"hello": map[string]interface{}{ | ||
"name": "world name - 2", | ||
}, | ||
"foo": "foo 2", | ||
}, | ||
} | ||
|
||
var resp struct { | ||
Entities []struct { | ||
Foo string `json:"foo"` | ||
Hello struct { | ||
Name string `json:"name"` | ||
} `json:"hello"` | ||
} `json:"_entities"` | ||
} | ||
|
||
err := c.Post( | ||
entityQuery([]string{ | ||
"World {foo hello {name}}", | ||
}), | ||
&resp, | ||
client.Var("representations", representations), | ||
) | ||
|
||
require.NoError(t, err) | ||
require.Equal(t, resp.Entities[0].Foo, "foo 1") | ||
require.Equal(t, resp.Entities[0].Hello.Name, "world name - 1") | ||
require.Equal(t, resp.Entities[1].Foo, "foo 2") | ||
require.Equal(t, resp.Entities[1].Hello.Name, "world name - 2") | ||
}) | ||
} | ||
|
||
func entityQuery(queries []string) string { | ||
// What we want! | ||
//query($representations:[_Any!]!){_entities(representations:$representations){ ...on Hello{secondary} }} | ||
entityQueries := make([]string, len(queries)) | ||
for i, query := range queries { | ||
entityQueries[i] = " ... on " + query | ||
} | ||
|
||
return "query($representations:[_Any!]!){_entities(representations:$representations){" + strings.Join(entityQueries, "") + "}}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Federation plugin | ||
|
||
Add support for graphql federation in your graphql Go server! | ||
|
||
TODO(miguel): add details. | ||
|
||
# Tests | ||
There are several different tests. Some will process the configuration file directly. You can see those in the `federation_test.go`. There are also tests for entity resolvers, which will simulate requests from a federation server like Apollo Federation. | ||
|
||
Running entity resolver tests. | ||
1. Go to `plugin/federation` | ||
2. Run the command `go run github.com/99designs/gqlgen --config testdata/entityresolver/gqlgen.yml` | ||
3. Run the tests with `go test ./...`. | ||
|
||
# Architecture | ||
|
||
TODO(miguel): add details. |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
schema: | ||
- "testdata/allthethings/schema.graphql" | ||
exec: | ||
filename: testdata/allthethings/generated/exec.go | ||
federation: | ||
filename: testdata/allthethings/generated/federation.go | ||
|
||
autobind: | ||
- "github.com/99designs/gqlgen/plugin/federation/testdata/allthethings/model" |
48 changes: 48 additions & 0 deletions
48
plugin/federation/testdata/allthethings/model/federation.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package model | ||
|
||
type _FieldSet string //nolint:deadcode,unused | ||
|
||
type Hello struct { | ||
Name string | ||
Secondary string | ||
} | ||
|
||
func (Hello) IsEntity() {} | ||
|
||
type World struct { | ||
Foo string | ||
Bar int | ||
} | ||
|
||
func (World) IsEntity() {} | ||
|
||
type ExternalExtension struct { | ||
UPC string | ||
Reviews []*World | ||
} | ||
|
||
func (ExternalExtension) IsEntity() {} | ||
|
||
type NestedKey struct { | ||
ID string | ||
Hello *Hello | ||
} | ||
|
||
func (NestedKey) IsEntity() {} | ||
|
||
type MoreNesting struct { | ||
ID string | ||
World *World | ||
} | ||
|
||
func (MoreNesting) IsEntity() {} | ||
|
||
type VeryNestedKey struct { | ||
ID string | ||
Hello *Hello | ||
World *World | ||
Nested *NestedKey | ||
More *MoreNesting | ||
} | ||
|
||
func (VeryNestedKey) IsEntity() {} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
schema: | ||
- "testdata/entities/nokey.graphql" | ||
exec: | ||
filename: testdata/entities/generated/exec.go | ||
federation: | ||
filename: testdata/entities/generated/federation.go |
30 changes: 30 additions & 0 deletions
30
plugin/federation/testdata/entityresolver/entity.resolvers.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package entityresolver | ||
|
||
// This file will be automatically regenerated based on the schema, any resolver implementations | ||
// will be copied through when generating and any unknown code will be moved to the end. | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/99designs/gqlgen/plugin/federation/testdata/entityresolver/generated" | ||
) | ||
|
||
func (r *entityResolver) FindHelloByName(ctx context.Context, name string) (*generated.Hello, error) { | ||
return &generated.Hello{ | ||
Name: name, | ||
}, nil | ||
} | ||
|
||
func (r *entityResolver) FindWorldByHelloNameAndFoo(ctx context.Context, helloName string, foo string) (*generated.World, error) { | ||
return &generated.World{ | ||
Hello: &generated.Hello{ | ||
Name: helloName, | ||
}, | ||
Foo: foo, | ||
}, nil | ||
} | ||
|
||
// Entity returns generated.EntityResolver implementation. | ||
func (r *Resolver) Entity() generated.EntityResolver { return &entityResolver{r} } | ||
|
||
type entityResolver struct{ *Resolver } |
Oops, something went wrong.