github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/graphql/handler/testserver/testserver.go (about) 1 package testserver 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/99designs/gqlgen/graphql" 9 "github.com/99designs/gqlgen/graphql/handler" 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() *TestServer { 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 srv := &TestServer{ 33 next: next, 34 } 35 36 srv.Server = handler.New(&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 srv.complexity, true 88 }, 89 }) 90 return srv 91 } 92 93 // NewError provides a server for use in resolver error tests that isn't relying on generated code. It isnt a perfect reproduction of 94 // a generated server, but it aims to be good enough to test the handler package without relying on codegen. 95 func NewError() *TestServer { 96 next := make(chan struct{}) 97 98 schema := gqlparser.MustLoadSchema(&ast.Source{Input: ` 99 type Query { 100 name: String! 101 } 102 `}) 103 104 srv := &TestServer{ 105 next: next, 106 } 107 108 srv.Server = handler.New(&graphql.ExecutableSchemaMock{ 109 ExecFunc: func(ctx context.Context) graphql.ResponseHandler { 110 rc := graphql.GetOperationContext(ctx) 111 switch rc.Operation.Operation { 112 case ast.Query: 113 ran := false 114 return func(ctx context.Context) *graphql.Response { 115 if ran { 116 return nil 117 } 118 ran = true 119 120 graphql.AddError(ctx, fmt.Errorf("resolver error")) 121 122 return &graphql.Response{ 123 Data: []byte(`null`), 124 } 125 } 126 case ast.Mutation: 127 return graphql.OneShot(graphql.ErrorResponse(ctx, "mutations are not supported")) 128 case ast.Subscription: 129 return graphql.OneShot(graphql.ErrorResponse(ctx, "subscription are not supported")) 130 default: 131 return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) 132 } 133 }, 134 SchemaFunc: func() *ast.Schema { 135 return schema 136 }, 137 ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (i int, b bool) { 138 return srv.complexity, true 139 }, 140 }) 141 return srv 142 } 143 144 type TestServer struct { 145 *handler.Server 146 next chan struct{} 147 complexity int 148 } 149 150 func (s *TestServer) SendNextSubscriptionMessage() { 151 select { 152 case s.next <- struct{}{}: 153 case <-time.After(1 * time.Second): 154 fmt.Println("WARNING: no active subscription") 155 } 156 } 157 158 func (s *TestServer) SetCalculatedComplexity(complexity int) { 159 s.complexity = complexity 160 }