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 }