...

Source file src/github.com/99designs/gqlgen/graphql/handler/testserver/testserver.go

Documentation: github.com/99designs/gqlgen/graphql/handler/testserver

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

View as plain text