...
1 package testexecutor
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8 "io"
9 "time"
10
11 "github.com/vektah/gqlparser/v2"
12 "github.com/vektah/gqlparser/v2/ast"
13
14 "github.com/99designs/gqlgen/graphql"
15 "github.com/99designs/gqlgen/graphql/executor"
16 )
17
18 type MockResponse struct {
19 Name string `json:"name"`
20 }
21
22 func (mr *MockResponse) UnmarshalGQL(v interface{}) error {
23 return nil
24 }
25
26 func (mr *MockResponse) MarshalGQL(w io.Writer) {
27 buf := new(bytes.Buffer)
28 err := json.NewEncoder(buf).Encode(mr)
29 if err != nil {
30 panic(err)
31 }
32
33 ba := bytes.NewBuffer(bytes.TrimRight(buf.Bytes(), "\n"))
34
35 fmt.Fprint(w, ba)
36 }
37
38
39
40 func New() *TestExecutor {
41 next := make(chan struct{})
42
43 schema := gqlparser.MustLoadSchema(&ast.Source{Input: `
44 type Query {
45 name: String!
46 find(id: Int!): String!
47 }
48 type Mutation {
49 name: String!
50 }
51 type Subscription {
52 name: String!
53 }
54 `})
55
56 exec := &TestExecutor{
57 next: next,
58 }
59
60 exec.schema = &graphql.ExecutableSchemaMock{
61 ExecFunc: func(ctx context.Context) graphql.ResponseHandler {
62 rc := graphql.GetOperationContext(ctx)
63 switch rc.Operation.Operation {
64 case ast.Query:
65 ran := false
66 return func(ctx context.Context) *graphql.Response {
67 if ran {
68 return nil
69 }
70 ran = true
71
72 ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
73 Object: "Query",
74 Field: graphql.CollectedField{
75 Field: &ast.Field{
76 Name: "name",
77 Alias: "name",
78 Definition: schema.Types["Query"].Fields.ForName("name"),
79 },
80 },
81 })
82 data := graphql.GetOperationContext(ctx).RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler {
83 res, err := graphql.GetOperationContext(ctx).ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {
84
85 return &MockResponse{Name: "test"}, nil
86 })
87 if err != nil {
88 panic(err)
89 }
90
91 return res.(*MockResponse)
92 })
93
94 var buf bytes.Buffer
95 data.MarshalGQL(&buf)
96
97 return &graphql.Response{Data: buf.Bytes()}
98 }
99 case ast.Mutation:
100 return graphql.OneShot(graphql.ErrorResponse(ctx, "mutations are not supported"))
101 case ast.Subscription:
102 return func(context context.Context) *graphql.Response {
103 select {
104 case <-ctx.Done():
105 return nil
106 case <-next:
107 return &graphql.Response{
108 Data: []byte(`{"name":"test"}`),
109 }
110 }
111 }
112 default:
113 return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
114 }
115 },
116 SchemaFunc: func() *ast.Schema {
117 return schema
118 },
119 ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (i int, b bool) {
120 return exec.complexity, true
121 },
122 }
123
124 exec.Executor = executor.New(exec.schema)
125 return exec
126 }
127
128
129
130 func NewError() *TestExecutor {
131 next := make(chan struct{})
132
133 schema := gqlparser.MustLoadSchema(&ast.Source{Input: `
134 type Query {
135 name: String!
136 }
137 `})
138
139 exec := &TestExecutor{
140 next: next,
141 }
142
143 exec.schema = &graphql.ExecutableSchemaMock{
144 ExecFunc: func(ctx context.Context) graphql.ResponseHandler {
145 rc := graphql.GetOperationContext(ctx)
146 switch rc.Operation.Operation {
147 case ast.Query:
148 ran := false
149 return func(ctx context.Context) *graphql.Response {
150 if ran {
151 return nil
152 }
153 ran = true
154
155 graphql.AddError(ctx, fmt.Errorf("resolver error"))
156
157 return &graphql.Response{
158 Data: []byte(`null`),
159 }
160 }
161 case ast.Mutation:
162 return graphql.OneShot(graphql.ErrorResponse(ctx, "mutations are not supported"))
163 case ast.Subscription:
164 return graphql.OneShot(graphql.ErrorResponse(ctx, "subscription are not supported"))
165 default:
166 return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
167 }
168 },
169 SchemaFunc: func() *ast.Schema {
170 return schema
171 },
172 ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (i int, b bool) {
173 return exec.complexity, true
174 },
175 }
176
177 exec.Executor = executor.New(exec.schema)
178 return exec
179 }
180
181 type TestExecutor struct {
182 *executor.Executor
183 schema graphql.ExecutableSchema
184 next chan struct{}
185 complexity int
186 }
187
188 func (e *TestExecutor) Schema() graphql.ExecutableSchema {
189 return e.schema
190 }
191
192 func (e *TestExecutor) SendNextSubscriptionMessage() {
193 select {
194 case e.next <- struct{}{}:
195 case <-time.After(1 * time.Second):
196 fmt.Println("WARNING: no active subscription")
197 }
198 }
199
200 func (e *TestExecutor) SetCalculatedComplexity(complexity int) {
201 e.complexity = complexity
202 }
203
View as plain text