github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/graphql/executor/testexecutor/testexecutor.go (about) 1 package testexecutor 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/99designs/gqlgen/graphql" 9 "github.com/99designs/gqlgen/graphql/executor" 10 "github.com/vektah/gqlparser/v2" 11 "github.com/vektah/gqlparser/v2/ast" 12 ) 13 14 // New provides a server for use in tests that isn't relying on generated code. It isnt a perfect reproduction of 15 // a generated server, but it aims to be good enough to test the handler package without relying on codegen. 16 func New() *TestExecutor { 17 next := make(chan struct{}) 18 19 schema := gqlparser.MustLoadSchema(&ast.Source{Input: ` 20 type Query { 21 name: String! 22 find(id: Int!): String! 23 } 24 type Mutation { 25 name: String! 26 } 27 type Subscription { 28 name: String! 29 } 30 `}) 31 32 exec := &TestExecutor{ 33 next: next, 34 } 35 36 exec.schema = &graphql.ExecutableSchemaMock{ 37 ExecFunc: func(ctx context.Context) graphql.ResponseHandler { 38 rc := graphql.GetOperationContext(ctx) 39 switch rc.Operation.Operation { 40 case ast.Query: 41 ran := false 42 return func(ctx context.Context) *graphql.Response { 43 if ran { 44 return nil 45 } 46 ran = true 47 // Field execution happens inside the generated code, lets simulate some of it. 48 ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ 49 Object: "Query", 50 Field: graphql.CollectedField{ 51 Field: &ast.Field{ 52 Name: "name", 53 Alias: "name", 54 Definition: schema.Types["Query"].Fields.ForName("name"), 55 }, 56 }, 57 }) 58 res, err := graphql.GetOperationContext(ctx).ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { 59 return &graphql.Response{Data: []byte(`{"name":"test"}`)}, nil 60 }) 61 if err != nil { 62 panic(err) 63 } 64 return res.(*graphql.Response) 65 } 66 case ast.Mutation: 67 return graphql.OneShot(graphql.ErrorResponse(ctx, "mutations are not supported")) 68 case ast.Subscription: 69 return func(context context.Context) *graphql.Response { 70 select { 71 case <-ctx.Done(): 72 return nil 73 case <-next: 74 return &graphql.Response{ 75 Data: []byte(`{"name":"test"}`), 76 } 77 } 78 } 79 default: 80 return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) 81 } 82 }, 83 SchemaFunc: func() *ast.Schema { 84 return schema 85 }, 86 ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (i int, b bool) { 87 return exec.complexity, true 88 }, 89 } 90 91 exec.Executor = executor.New(exec.schema) 92 return exec 93 } 94 95 // NewError provides a server for use in resolver error tests that isn't relying on generated code. It isnt a perfect reproduction of 96 // a generated server, but it aims to be good enough to test the handler package without relying on codegen. 97 func NewError() *TestExecutor { 98 next := make(chan struct{}) 99 100 schema := gqlparser.MustLoadSchema(&ast.Source{Input: ` 101 type Query { 102 name: String! 103 } 104 `}) 105 106 exec := &TestExecutor{ 107 next: next, 108 } 109 110 exec.schema = &graphql.ExecutableSchemaMock{ 111 ExecFunc: func(ctx context.Context) graphql.ResponseHandler { 112 rc := graphql.GetOperationContext(ctx) 113 switch rc.Operation.Operation { 114 case ast.Query: 115 ran := false 116 return func(ctx context.Context) *graphql.Response { 117 if ran { 118 return nil 119 } 120 ran = true 121 122 graphql.AddError(ctx, fmt.Errorf("resolver error")) 123 124 return &graphql.Response{ 125 Data: []byte(`null`), 126 } 127 } 128 case ast.Mutation: 129 return graphql.OneShot(graphql.ErrorResponse(ctx, "mutations are not supported")) 130 case ast.Subscription: 131 return graphql.OneShot(graphql.ErrorResponse(ctx, "subscription are not supported")) 132 default: 133 return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) 134 } 135 }, 136 SchemaFunc: func() *ast.Schema { 137 return schema 138 }, 139 ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (i int, b bool) { 140 return exec.complexity, true 141 }, 142 } 143 144 exec.Executor = executor.New(exec.schema) 145 return exec 146 } 147 148 type TestExecutor struct { 149 *executor.Executor 150 schema graphql.ExecutableSchema 151 next chan struct{} 152 complexity int 153 } 154 155 func (e *TestExecutor) Schema() graphql.ExecutableSchema { 156 return e.schema 157 } 158 159 func (e *TestExecutor) SendNextSubscriptionMessage() { 160 select { 161 case e.next <- struct{}{}: 162 case <-time.After(1 * time.Second): 163 fmt.Println("WARNING: no active subscription") 164 } 165 } 166 167 func (e *TestExecutor) SetCalculatedComplexity(complexity int) { 168 e.complexity = complexity 169 }