git.sr.ht/~sircmpwn/gqlgen@v0.0.0-20200522192042-c84d29a1c940/codegen/testserver/directive_test.go (about)

     1  package testserver
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"git.sr.ht/~sircmpwn/gqlgen/client"
     9  	"git.sr.ht/~sircmpwn/gqlgen/graphql"
    10  	"git.sr.ht/~sircmpwn/gqlgen/graphql/handler"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestDirectives(t *testing.T) {
    15  	resolvers := &Stub{}
    16  	ok := "Ok"
    17  	resolvers.QueryResolver.DirectiveArg = func(ctx context.Context, arg string) (i *string, e error) {
    18  		return &ok, nil
    19  	}
    20  
    21  	resolvers.QueryResolver.DirectiveInput = func(ctx context.Context, arg InputDirectives) (i *string, e error) {
    22  		return &ok, nil
    23  	}
    24  
    25  	resolvers.QueryResolver.DirectiveInputNullable = func(ctx context.Context, arg *InputDirectives) (i *string, e error) {
    26  		return &ok, nil
    27  	}
    28  
    29  	resolvers.QueryResolver.DirectiveNullableArg = func(ctx context.Context, arg *int, arg2 *int, arg3 *string) (*string, error) {
    30  		return &ok, nil
    31  	}
    32  
    33  	resolvers.QueryResolver.DirectiveInputType = func(ctx context.Context, arg InnerInput) (i *string, e error) {
    34  		return &ok, nil
    35  	}
    36  
    37  	resolvers.QueryResolver.DirectiveObject = func(ctx context.Context) (*ObjectDirectives, error) {
    38  		return &ObjectDirectives{
    39  			Text:         ok,
    40  			NullableText: &ok,
    41  		}, nil
    42  	}
    43  
    44  	resolvers.QueryResolver.DirectiveObjectWithCustomGoModel = func(ctx context.Context) (*ObjectDirectivesWithCustomGoModel, error) {
    45  		return &ObjectDirectivesWithCustomGoModel{
    46  			NullableText: ok,
    47  		}, nil
    48  	}
    49  
    50  	resolvers.QueryResolver.DirectiveField = func(ctx context.Context) (*string, error) {
    51  		if s, ok := ctx.Value("request_id").(*string); ok {
    52  			return s, nil
    53  		}
    54  
    55  		return nil, nil
    56  	}
    57  
    58  	resolvers.QueryResolver.DirectiveDouble = func(ctx context.Context) (*string, error) {
    59  		return &ok, nil
    60  	}
    61  
    62  	resolvers.QueryResolver.DirectiveUnimplemented = func(ctx context.Context) (*string, error) {
    63  		return &ok, nil
    64  	}
    65  
    66  	okchan := func() (<-chan *string, error) {
    67  		res := make(chan *string, 1)
    68  		res <- &ok
    69  		close(res)
    70  		return res, nil
    71  	}
    72  
    73  	resolvers.SubscriptionResolver.DirectiveArg = func(ctx context.Context, arg string) (strings <-chan *string, e error) {
    74  		return okchan()
    75  	}
    76  
    77  	resolvers.SubscriptionResolver.DirectiveNullableArg = func(ctx context.Context, arg *int, arg2 *int, arg3 *string) (strings <-chan *string, e error) {
    78  		return okchan()
    79  	}
    80  
    81  	resolvers.SubscriptionResolver.DirectiveDouble = func(ctx context.Context) (strings <-chan *string, e error) {
    82  		return okchan()
    83  	}
    84  
    85  	resolvers.SubscriptionResolver.DirectiveUnimplemented = func(ctx context.Context) (<-chan *string, error) {
    86  		return okchan()
    87  	}
    88  	srv := handler.NewDefaultServer(NewExecutableSchema(Config{
    89  		Resolvers: resolvers,
    90  		Directives: DirectiveRoot{
    91  			Length: func(ctx context.Context, obj interface{}, next graphql.Resolver, min int, max *int, message *string) (interface{}, error) {
    92  				e := func(msg string) error {
    93  					if message == nil {
    94  						return fmt.Errorf(msg)
    95  					}
    96  					return fmt.Errorf(*message)
    97  				}
    98  				res, err := next(ctx)
    99  				if err != nil {
   100  					return nil, err
   101  				}
   102  
   103  				s := res.(string)
   104  				if len(s) < min {
   105  					return nil, e("too short")
   106  				}
   107  				if max != nil && len(s) > *max {
   108  					return nil, e("too long")
   109  				}
   110  				return res, nil
   111  			},
   112  			Range: func(ctx context.Context, obj interface{}, next graphql.Resolver, min *int, max *int) (interface{}, error) {
   113  				res, err := next(ctx)
   114  				if err != nil {
   115  					return nil, err
   116  				}
   117  
   118  				switch res := res.(type) {
   119  				case int:
   120  					if min != nil && res < *min {
   121  						return nil, fmt.Errorf("too small")
   122  					}
   123  					if max != nil && res > *max {
   124  						return nil, fmt.Errorf("too large")
   125  					}
   126  					return next(ctx)
   127  
   128  				case int64:
   129  					if min != nil && int(res) < *min {
   130  						return nil, fmt.Errorf("too small")
   131  					}
   132  					if max != nil && int(res) > *max {
   133  						return nil, fmt.Errorf("too large")
   134  					}
   135  					return next(ctx)
   136  
   137  				case *int:
   138  					if min != nil && *res < *min {
   139  						return nil, fmt.Errorf("too small")
   140  					}
   141  					if max != nil && *res > *max {
   142  						return nil, fmt.Errorf("too large")
   143  					}
   144  					return next(ctx)
   145  				}
   146  				return nil, fmt.Errorf("unsupported type %T", res)
   147  			},
   148  			Custom: func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) {
   149  				return next(ctx)
   150  			},
   151  			Logged: func(ctx context.Context, obj interface{}, next graphql.Resolver, id string) (interface{}, error) {
   152  				return next(context.WithValue(ctx, "request_id", &id))
   153  			},
   154  			ToNull: func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) {
   155  				return nil, nil
   156  			},
   157  			Directive1: func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
   158  				return next(ctx)
   159  			},
   160  			Directive2: func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
   161  				return next(ctx)
   162  			},
   163  			Unimplemented: nil,
   164  		},
   165  	}))
   166  
   167  	srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
   168  		path, _ := ctx.Value("path").([]int)
   169  		return next(context.WithValue(ctx, "path", append(path, 1)))
   170  	})
   171  
   172  	srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
   173  		path, _ := ctx.Value("path").([]int)
   174  		return next(context.WithValue(ctx, "path", append(path, 2)))
   175  	})
   176  
   177  	c := client.New(srv)
   178  
   179  	t.Run("arg directives", func(t *testing.T) {
   180  		t.Run("when function errors on directives", func(t *testing.T) {
   181  			var resp struct {
   182  				DirectiveArg *string
   183  			}
   184  
   185  			err := c.Post(`query { directiveArg(arg: "") }`, &resp)
   186  
   187  			require.EqualError(t, err, `[{"message":"invalid length","path":["directiveArg"]}]`)
   188  			require.Nil(t, resp.DirectiveArg)
   189  		})
   190  		t.Run("when function errors on nullable arg directives", func(t *testing.T) {
   191  			var resp struct {
   192  				DirectiveNullableArg *string
   193  			}
   194  
   195  			err := c.Post(`query { directiveNullableArg(arg: -100) }`, &resp)
   196  
   197  			require.EqualError(t, err, `[{"message":"too small","path":["directiveNullableArg"]}]`)
   198  			require.Nil(t, resp.DirectiveNullableArg)
   199  		})
   200  		t.Run("when function success on nullable arg directives", func(t *testing.T) {
   201  			var resp struct {
   202  				DirectiveNullableArg *string
   203  			}
   204  
   205  			err := c.Post(`query { directiveNullableArg }`, &resp)
   206  
   207  			require.Nil(t, err)
   208  			require.Equal(t, "Ok", *resp.DirectiveNullableArg)
   209  		})
   210  		t.Run("when function success on valid nullable arg directives", func(t *testing.T) {
   211  			var resp struct {
   212  				DirectiveNullableArg *string
   213  			}
   214  
   215  			err := c.Post(`query { directiveNullableArg(arg: 1) }`, &resp)
   216  
   217  			require.Nil(t, err)
   218  			require.Equal(t, "Ok", *resp.DirectiveNullableArg)
   219  		})
   220  		t.Run("when function success", func(t *testing.T) {
   221  			var resp struct {
   222  				DirectiveArg *string
   223  			}
   224  
   225  			err := c.Post(`query { directiveArg(arg: "test") }`, &resp)
   226  
   227  			require.Nil(t, err)
   228  			require.Equal(t, "Ok", *resp.DirectiveArg)
   229  		})
   230  	})
   231  	t.Run("field definition directives", func(t *testing.T) {
   232  		resolvers.QueryResolver.DirectiveFieldDef = func(ctx context.Context, ret string) (i string, e error) {
   233  			return ret, nil
   234  		}
   235  
   236  		t.Run("too short", func(t *testing.T) {
   237  			var resp struct {
   238  				DirectiveFieldDef string
   239  			}
   240  
   241  			err := c.Post(`query { directiveFieldDef(ret: "") }`, &resp)
   242  
   243  			require.EqualError(t, err, `[{"message":"not valid","path":["directiveFieldDef"]}]`)
   244  		})
   245  
   246  		t.Run("has 2 directives", func(t *testing.T) {
   247  			var resp struct {
   248  				DirectiveDouble string
   249  			}
   250  
   251  			c.MustPost(`query { directiveDouble }`, &resp)
   252  
   253  			require.Equal(t, "Ok", resp.DirectiveDouble)
   254  		})
   255  
   256  		t.Run("directive is not implemented", func(t *testing.T) {
   257  			var resp struct {
   258  				DirectiveUnimplemented string
   259  			}
   260  
   261  			err := c.Post(`query { directiveUnimplemented }`, &resp)
   262  
   263  			require.EqualError(t, err, `[{"message":"directive unimplemented is not implemented","path":["directiveUnimplemented"]}]`)
   264  		})
   265  
   266  		t.Run("ok", func(t *testing.T) {
   267  			var resp struct {
   268  				DirectiveFieldDef string
   269  			}
   270  
   271  			c.MustPost(`query { directiveFieldDef(ret: "aaa") }`, &resp)
   272  
   273  			require.Equal(t, "aaa", resp.DirectiveFieldDef)
   274  		})
   275  	})
   276  	t.Run("field directives", func(t *testing.T) {
   277  		t.Run("add field directive", func(t *testing.T) {
   278  			var resp struct {
   279  				DirectiveField string
   280  			}
   281  
   282  			c.MustPost(`query { directiveField@logged(id:"testes_id") }`, &resp)
   283  
   284  			require.Equal(t, resp.DirectiveField, `testes_id`)
   285  		})
   286  		t.Run("without field directive", func(t *testing.T) {
   287  			var resp struct {
   288  				DirectiveField *string
   289  			}
   290  
   291  			c.MustPost(`query { directiveField }`, &resp)
   292  
   293  			require.Nil(t, resp.DirectiveField)
   294  		})
   295  	})
   296  	t.Run("input field directives", func(t *testing.T) {
   297  		t.Run("when function errors on directives", func(t *testing.T) {
   298  			var resp struct {
   299  				DirectiveInputNullable *string
   300  			}
   301  
   302  			err := c.Post(`query { directiveInputNullable(arg: {text:"invalid text",inner:{message:"123"}}) }`, &resp)
   303  
   304  			require.EqualError(t, err, `[{"message":"not valid","path":["directiveInputNullable"]}]`)
   305  			require.Nil(t, resp.DirectiveInputNullable)
   306  		})
   307  		t.Run("when function errors on inner directives", func(t *testing.T) {
   308  			var resp struct {
   309  				DirectiveInputNullable *string
   310  			}
   311  
   312  			err := c.Post(`query { directiveInputNullable(arg: {text:"2",inner:{message:""}}) }`, &resp)
   313  
   314  			require.EqualError(t, err, `[{"message":"not valid","path":["directiveInputNullable"]}]`)
   315  			require.Nil(t, resp.DirectiveInputNullable)
   316  		})
   317  		t.Run("when function errors on nullable inner directives", func(t *testing.T) {
   318  			var resp struct {
   319  				DirectiveInputNullable *string
   320  			}
   321  
   322  			err := c.Post(`query { directiveInputNullable(arg: {text:"success",inner:{message:"1"},innerNullable:{message:""}}) }`, &resp)
   323  
   324  			require.EqualError(t, err, `[{"message":"not valid","path":["directiveInputNullable"]}]`)
   325  			require.Nil(t, resp.DirectiveInputNullable)
   326  		})
   327  		t.Run("when function success", func(t *testing.T) {
   328  			var resp struct {
   329  				DirectiveInputNullable *string
   330  			}
   331  
   332  			err := c.Post(`query { directiveInputNullable(arg: {text:"23",inner:{message:"1"}}) }`, &resp)
   333  
   334  			require.Nil(t, err)
   335  			require.Equal(t, "Ok", *resp.DirectiveInputNullable)
   336  		})
   337  		t.Run("when function inner nullable success", func(t *testing.T) {
   338  			var resp struct {
   339  				DirectiveInputNullable *string
   340  			}
   341  
   342  			err := c.Post(`query { directiveInputNullable(arg: {text:"23",nullableText:"23",inner:{message:"1"},innerNullable:{message:"success"}}) }`, &resp)
   343  
   344  			require.Nil(t, err)
   345  			require.Equal(t, "Ok", *resp.DirectiveInputNullable)
   346  		})
   347  		t.Run("when arg has directive", func(t *testing.T) {
   348  			var resp struct {
   349  				DirectiveInputType *string
   350  			}
   351  
   352  			err := c.Post(`query { directiveInputType(arg: {id: 1}) }`, &resp)
   353  
   354  			require.Nil(t, err)
   355  			require.Equal(t, "Ok", *resp.DirectiveInputType)
   356  		})
   357  	})
   358  	t.Run("object field directives", func(t *testing.T) {
   359  		t.Run("when function success", func(t *testing.T) {
   360  			var resp struct {
   361  				DirectiveObject *struct {
   362  					Text         string
   363  					NullableText *string
   364  				}
   365  			}
   366  
   367  			err := c.Post(`query { directiveObject{ text nullableText } }`, &resp)
   368  
   369  			require.Nil(t, err)
   370  			require.Equal(t, "Ok", resp.DirectiveObject.Text)
   371  			require.True(t, resp.DirectiveObject.NullableText == nil)
   372  		})
   373  		t.Run("when directive returns nil & custom go field is not nilable", func(t *testing.T) {
   374  			var resp struct {
   375  				DirectiveObjectWithCustomGoModel *struct {
   376  					NullableText *string
   377  				}
   378  			}
   379  
   380  			err := c.Post(`query { directiveObjectWithCustomGoModel{ nullableText } }`, &resp)
   381  
   382  			require.Nil(t, err)
   383  			require.True(t, resp.DirectiveObjectWithCustomGoModel.NullableText == nil)
   384  		})
   385  	})
   386  
   387  	t.Run("Subscription directives", func(t *testing.T) {
   388  		t.Run("arg directives", func(t *testing.T) {
   389  			t.Run("when function errors on directives", func(t *testing.T) {
   390  				var resp struct {
   391  					DirectiveArg *string
   392  				}
   393  
   394  				err := c.WebsocketOnce(`subscription { directiveArg(arg: "") }`, &resp)
   395  
   396  				require.EqualError(t, err, `[{"message":"invalid length","path":["directiveArg"]}]`)
   397  				require.Nil(t, resp.DirectiveArg)
   398  			})
   399  			t.Run("when function errors on nullable arg directives", func(t *testing.T) {
   400  				var resp struct {
   401  					DirectiveNullableArg *string
   402  				}
   403  
   404  				err := c.WebsocketOnce(`subscription { directiveNullableArg(arg: -100) }`, &resp)
   405  
   406  				require.EqualError(t, err, `[{"message":"too small","path":["directiveNullableArg"]}]`)
   407  				require.Nil(t, resp.DirectiveNullableArg)
   408  			})
   409  			t.Run("when function success on nullable arg directives", func(t *testing.T) {
   410  				var resp struct {
   411  					DirectiveNullableArg *string
   412  				}
   413  
   414  				err := c.WebsocketOnce(`subscription { directiveNullableArg }`, &resp)
   415  
   416  				require.Nil(t, err)
   417  				require.Equal(t, "Ok", *resp.DirectiveNullableArg)
   418  			})
   419  			t.Run("when function success on valid nullable arg directives", func(t *testing.T) {
   420  				var resp struct {
   421  					DirectiveNullableArg *string
   422  				}
   423  
   424  				err := c.WebsocketOnce(`subscription { directiveNullableArg(arg: 1) }`, &resp)
   425  
   426  				require.Nil(t, err)
   427  				require.Equal(t, "Ok", *resp.DirectiveNullableArg)
   428  			})
   429  			t.Run("when function success", func(t *testing.T) {
   430  				var resp struct {
   431  					DirectiveArg *string
   432  				}
   433  
   434  				err := c.WebsocketOnce(`subscription { directiveArg(arg: "test") }`, &resp)
   435  
   436  				require.Nil(t, err)
   437  				require.Equal(t, "Ok", *resp.DirectiveArg)
   438  			})
   439  		})
   440  	})
   441  }