-
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.
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
95cb68e
commit 2654671
Showing
10 changed files
with
3,859 additions
and
0 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 bar 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 { | ||
// Wha 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
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. |
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.