Skip to content

Commit

Permalink
Adding entity resolver tests in the federation plugin
Browse files Browse the repository at this point in the history
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
MiguelCastillo committed Nov 9, 2021
1 parent 95cb68e commit 2654671
Show file tree
Hide file tree
Showing 10 changed files with 3,859 additions and 0 deletions.
102 changes: 102 additions & 0 deletions plugin/federation/federation_entityresolver_test.go
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, "") + "}}"
}
17 changes: 17 additions & 0 deletions plugin/federation/readme.md
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 plugin/federation/testdata/entityresolver/entity.resolvers.go
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 }
Loading

0 comments on commit 2654671

Please sign in to comment.