github.com/fortexxx/gqlgen@v0.10.3-0.20191216030626-ca5ea8b21ead/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"
    11  	"github.com/vektah/gqlparser/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  	now := time.Unix(0, 0)
    19  
    20  	graphql.Now = func() time.Time {
    21  		defer func() {
    22  			now = now.Add(100 * time.Nanosecond)
    23  		}()
    24  		return now
    25  	}
    26  
    27  	schema := gqlparser.MustLoadSchema(&ast.Source{Input: `
    28  		type Query {
    29  			name: String!
    30  			find(id: Int!): String!
    31  		}
    32  		type Mutation {
    33  			name: String!
    34  		}
    35  		type Subscription {
    36  			name: String!
    37  		}
    38  	`})
    39  
    40  	srv := &TestServer{
    41  		next: next,
    42  	}
    43  
    44  	srv.Server = handler.New(&graphql.ExecutableSchemaMock{
    45  		ExecFunc: func(ctx context.Context) graphql.ResponseHandler {
    46  			rc := graphql.GetOperationContext(ctx)
    47  			switch rc.Operation.Operation {
    48  			case ast.Query:
    49  				ran := false
    50  				return func(ctx context.Context) *graphql.Response {
    51  					if ran {
    52  						return nil
    53  					}
    54  					ran = true
    55  					// Field execution happens inside the generated code, lets simulate some of it.
    56  					ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
    57  						Object: "Query",
    58  						Field: graphql.CollectedField{
    59  							Field: &ast.Field{
    60  								Name:       "name",
    61  								Alias:      "name",
    62  								Definition: schema.Types["Query"].Fields.ForName("name"),
    63  							},
    64  						},
    65  					})
    66  					res, err := graphql.GetOperationContext(ctx).ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {
    67  						return &graphql.Response{Data: []byte(`{"name":"test"}`)}, nil
    68  					})
    69  					if err != nil {
    70  						panic(err)
    71  					}
    72  					return res.(*graphql.Response)
    73  				}
    74  			case ast.Mutation:
    75  				return graphql.OneShot(graphql.ErrorResponse(ctx, "mutations are not supported"))
    76  			case ast.Subscription:
    77  				return func(context context.Context) *graphql.Response {
    78  					select {
    79  					case <-ctx.Done():
    80  						return nil
    81  					case <-next:
    82  						return &graphql.Response{
    83  							Data: []byte(`{"name":"test"}`),
    84  						}
    85  					}
    86  				}
    87  			default:
    88  				return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
    89  			}
    90  		},
    91  		SchemaFunc: func() *ast.Schema {
    92  			return schema
    93  		},
    94  		ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (i int, b bool) {
    95  			return srv.complexity, true
    96  		},
    97  	})
    98  	return srv
    99  }
   100  
   101  type TestServer struct {
   102  	*handler.Server
   103  	next       chan struct{}
   104  	complexity int
   105  }
   106  
   107  func (s *TestServer) SendNextSubscriptionMessage() {
   108  	select {
   109  	case s.next <- struct{}{}:
   110  	case <-time.After(1 * time.Second):
   111  		fmt.Println("WARNING: no active subscription")
   112  	}
   113  
   114  }
   115  
   116  func (s *TestServer) SetCalculatedComplexity(complexity int) {
   117  	s.complexity = complexity
   118  }