@apollo/gateway 2.4.5 → 2.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/__generated__/graphqlTypes.d.ts +19 -1
  2. package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
  3. package/dist/__generated__/graphqlTypes.js +1 -0
  4. package/dist/__generated__/graphqlTypes.js.map +1 -1
  5. package/package.json +4 -4
  6. package/src/__generated__/graphqlTypes.ts +33 -2
  7. package/src/__mocks__/tsconfig.json +0 -7
  8. package/src/__tests__/.gitkeep +0 -0
  9. package/src/__tests__/CucumberREADME.md +0 -96
  10. package/src/__tests__/build-query-plan.feature +0 -1471
  11. package/src/__tests__/buildQueryPlan.test.ts +0 -1225
  12. package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
  13. package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
  14. package/src/__tests__/executeQueryPlan.test.ts +0 -6140
  15. package/src/__tests__/execution-utils.ts +0 -124
  16. package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
  17. package/src/__tests__/gateway/buildService.test.ts +0 -249
  18. package/src/__tests__/gateway/endToEnd.test.ts +0 -486
  19. package/src/__tests__/gateway/executor.test.ts +0 -96
  20. package/src/__tests__/gateway/extensions.test.ts +0 -37
  21. package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
  22. package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
  23. package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
  24. package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
  25. package/src/__tests__/gateway/reporting.test.ts +0 -616
  26. package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
  27. package/src/__tests__/gateway/testUtils.ts +0 -89
  28. package/src/__tests__/integration/abstract-types.test.ts +0 -1861
  29. package/src/__tests__/integration/aliases.test.ts +0 -180
  30. package/src/__tests__/integration/boolean.test.ts +0 -279
  31. package/src/__tests__/integration/complex-key.test.ts +0 -197
  32. package/src/__tests__/integration/configuration.test.ts +0 -404
  33. package/src/__tests__/integration/custom-directives.test.ts +0 -174
  34. package/src/__tests__/integration/execution-style.test.ts +0 -35
  35. package/src/__tests__/integration/fragments.test.ts +0 -237
  36. package/src/__tests__/integration/list-key.test.ts +0 -128
  37. package/src/__tests__/integration/logger.test.ts +0 -122
  38. package/src/__tests__/integration/managed.test.ts +0 -319
  39. package/src/__tests__/integration/merge-arrays.test.ts +0 -34
  40. package/src/__tests__/integration/multiple-key.test.ts +0 -327
  41. package/src/__tests__/integration/mutations.test.ts +0 -287
  42. package/src/__tests__/integration/networkRequests.test.ts +0 -542
  43. package/src/__tests__/integration/nockMocks.ts +0 -157
  44. package/src/__tests__/integration/provides.test.ts +0 -77
  45. package/src/__tests__/integration/requires.test.ts +0 -359
  46. package/src/__tests__/integration/scope.test.ts +0 -557
  47. package/src/__tests__/integration/single-service.test.ts +0 -119
  48. package/src/__tests__/integration/unions.test.ts +0 -79
  49. package/src/__tests__/integration/value-types.test.ts +0 -382
  50. package/src/__tests__/integration/variables.test.ts +0 -120
  51. package/src/__tests__/nockAssertions.ts +0 -20
  52. package/src/__tests__/queryPlanCucumber.test.ts +0 -55
  53. package/src/__tests__/resultShaping.test.ts +0 -605
  54. package/src/__tests__/testSetup.ts +0 -1
  55. package/src/__tests__/tsconfig.json +0 -8
  56. package/src/core/__tests__/core.test.ts +0 -412
  57. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
  58. package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
  59. package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
  60. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
  61. package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
  62. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
  63. package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
  64. package/src/utilities/__tests__/deepMerge.test.ts +0 -77
@@ -1,542 +0,0 @@
1
- import gql from 'graphql-tag';
2
- import { GraphQLObjectType, GraphQLSchema } from 'graphql';
3
- import mockedEnv from 'mocked-env';
4
- import type { Logger } from '@apollo/utils.logger';
5
- import { ApolloGateway, UplinkSupergraphManager } from '../..';
6
- import {
7
- mockSdlQuerySuccess,
8
- mockServiceHealthCheckSuccess,
9
- mockAllServicesHealthCheckSuccess,
10
- mockServiceHealthCheck,
11
- mockSupergraphSdlRequestSuccess,
12
- mockSupergraphSdlRequest,
13
- mockApolloConfig,
14
- mockCloudConfigUrl1,
15
- mockSupergraphSdlRequestIfAfter,
16
- mockSupergraphSdlRequestSuccessIfAfter,
17
- } from './nockMocks';
18
- import {
19
- accounts,
20
- books,
21
- documents,
22
- Fixture,
23
- fixturesWithUpdate,
24
- inventory,
25
- product,
26
- reviews,
27
- } from 'apollo-federation-integration-testsuite';
28
- import { getTestingSupergraphSdl } from '../execution-utils';
29
- import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
30
- import resolvable from '@josephg/resolvable';
31
-
32
- const simpleService: Fixture = {
33
- name: 'accounts',
34
- url: 'http://localhost:4001',
35
- typeDefs: gql`
36
- extend type Query {
37
- me: User
38
- everyone: [User]
39
- }
40
-
41
- "This is my User"
42
- type User @key(fields: "id") {
43
- id: ID!
44
- name: String
45
- username: String
46
- }
47
- `,
48
- };
49
-
50
- function getRootQueryFields(schema?: GraphQLSchema): string[] {
51
- return Object.keys(
52
- (schema?.getType('Query') as GraphQLObjectType).getFields(),
53
- );
54
- }
55
-
56
- let logger: Logger;
57
- let gateway: ApolloGateway | null = null;
58
- let cleanUp: (() => void) | null = null;
59
- let originalMinPollInterval = UplinkSupergraphManager.MIN_POLL_INTERVAL_MS;
60
-
61
- beforeEach(() => {
62
- // Set the min poll interval artificially low so we're not waiting during tests
63
- // @ts-ignore
64
- UplinkSupergraphManager['MIN_POLL_INTERVAL_MS'] = 100;
65
- nockBeforeEach();
66
-
67
- const warn = jest.fn();
68
- const debug = jest.fn();
69
- const error = jest.fn();
70
- const info = jest.fn();
71
-
72
- logger = {
73
- warn,
74
- debug,
75
- error,
76
- info,
77
- };
78
- });
79
-
80
- afterEach(async () => {
81
- // @ts-ignore
82
- UplinkSupergraphManager['MIN_POLL_INTERVAL_MS'] = originalMinPollInterval;
83
- if (gateway) {
84
- await gateway.stop();
85
- gateway = null;
86
- }
87
-
88
- nockAfterEach();
89
-
90
- if (cleanUp) {
91
- cleanUp();
92
- cleanUp = null;
93
- }
94
- });
95
-
96
- it('Queries remote endpoints for their SDLs', async () => {
97
- mockSdlQuerySuccess(simpleService);
98
-
99
- gateway = new ApolloGateway({ serviceList: [simpleService], logger });
100
- await gateway.load();
101
- expect(gateway.schema!.getType('User')!.description).toBe('This is my User');
102
- });
103
-
104
- it('Fetches Supergraph SDL from remote storage', async () => {
105
- mockSupergraphSdlRequestSuccess();
106
-
107
- gateway = new ApolloGateway({
108
- logger,
109
- uplinkEndpoints: [mockCloudConfigUrl1],
110
- });
111
-
112
- await gateway.load(mockApolloConfig);
113
- await gateway.stop();
114
- expect(gateway.schema?.getType('User')).toBeTruthy();
115
- });
116
-
117
- it('Fetches Supergraph SDL from remote storage using a configured env variable', async () => {
118
- cleanUp = mockedEnv({
119
- APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT: mockCloudConfigUrl1,
120
- });
121
- mockSupergraphSdlRequestSuccess();
122
-
123
- gateway = new ApolloGateway({
124
- logger,
125
- });
126
-
127
- await gateway.load(mockApolloConfig);
128
- await gateway.stop();
129
- expect(gateway.schema?.getType('User')).toBeTruthy();
130
- });
131
-
132
- it('Updates Supergraph SDL from remote storage', async () => {
133
- mockSupergraphSdlRequestSuccess();
134
- mockSupergraphSdlRequestSuccessIfAfter(
135
- 'originalId-1234',
136
- 'updatedId-5678',
137
- getTestingSupergraphSdl(fixturesWithUpdate),
138
- );
139
-
140
- // This test is only interested in the second time the gateway notifies of an
141
- // update, since the first happens on load.
142
- const secondUpdate = resolvable();
143
-
144
- gateway = new ApolloGateway({
145
- logger,
146
- uplinkEndpoints: [mockCloudConfigUrl1],
147
- });
148
-
149
- const schemas: GraphQLSchema[] = [];
150
- gateway.onSchemaLoadOrUpdate(({ apiSchema }) => {
151
- schemas.push(apiSchema);
152
- });
153
- gateway.onSchemaLoadOrUpdate(
154
- jest
155
- .fn()
156
- .mockImplementationOnce(() => {})
157
- .mockImplementationOnce(() => secondUpdate.resolve()),
158
- );
159
-
160
- await gateway.load(mockApolloConfig);
161
-
162
- await secondUpdate;
163
-
164
- // First schema has no 'review' field on the 'Query' type
165
- expect(
166
- (schemas[0].getType('Query') as GraphQLObjectType).getFields()['review'],
167
- ).toBeFalsy();
168
-
169
- // Updated schema adds 'review' field on the 'Query' type
170
- expect(
171
- (schemas[1].getType('Query') as GraphQLObjectType).getFields()['review'],
172
- ).toBeTruthy();
173
- });
174
-
175
- describe('Supergraph SDL update failures', () => {
176
- it('Gateway throws on initial load failure', async () => {
177
- mockSupergraphSdlRequest().reply(401);
178
-
179
- gateway = new ApolloGateway({
180
- logger,
181
- uplinkEndpoints: [mockCloudConfigUrl1],
182
- uplinkMaxRetries: 0,
183
- });
184
-
185
- await expect(
186
- gateway.load(mockApolloConfig),
187
- ).rejects.toThrowErrorMatchingInlineSnapshot(
188
- `"An error occurred while fetching your schema from Apollo: 401 Unauthorized"`,
189
- );
190
- });
191
-
192
- it('Handles arbitrary fetch failures (non 200 response)', async () => {
193
- mockSupergraphSdlRequestSuccess();
194
- mockSupergraphSdlRequestIfAfter('originalId-1234').reply(500);
195
-
196
- // Spy on logger.error so we can just await once it's been called
197
- const errorLoggedPromise = resolvable();
198
- logger.error = jest.fn(() => errorLoggedPromise.resolve());
199
-
200
- gateway = new ApolloGateway({
201
- logger,
202
- uplinkEndpoints: [mockCloudConfigUrl1],
203
- uplinkMaxRetries: 0,
204
- });
205
-
206
- await gateway.load(mockApolloConfig);
207
- await errorLoggedPromise;
208
-
209
- expect(logger.error).toHaveBeenCalledWith(
210
- 'UplinkSupergraphManager failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
211
- );
212
- });
213
-
214
- it('Handles GraphQL errors', async () => {
215
- mockSupergraphSdlRequestSuccess();
216
- mockSupergraphSdlRequest('originalId-1234').reply(200, {
217
- errors: [
218
- {
219
- message: 'Cannot query field "fail" on type "Query".',
220
- locations: [{ line: 1, column: 3 }],
221
- extensions: { code: 'GRAPHQL_VALIDATION_FAILED' },
222
- },
223
- ],
224
- });
225
-
226
- // Spy on logger.error so we can just await once it's been called
227
- const errorLoggedPromise = resolvable();
228
- logger.error = jest.fn(() => errorLoggedPromise.resolve());
229
-
230
- gateway = new ApolloGateway({
231
- logger,
232
- uplinkEndpoints: [mockCloudConfigUrl1],
233
- uplinkMaxRetries: 0,
234
- });
235
-
236
- await gateway.load(mockApolloConfig);
237
- await errorLoggedPromise;
238
-
239
- expect(logger.error).toHaveBeenCalledWith(
240
- `UplinkSupergraphManager failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: \nCannot query field "fail" on type "Query".`,
241
- );
242
- });
243
-
244
- it("Doesn't update and logs on receiving unparseable Supergraph SDL", async () => {
245
- mockSupergraphSdlRequestSuccess();
246
- mockSupergraphSdlRequestIfAfter('originalId-1234').reply(
247
- 200,
248
- JSON.stringify({
249
- data: {
250
- routerConfig: {
251
- __typename: 'RouterConfigResult',
252
- id: 'failure',
253
- supergraphSdl: 'Syntax Error - invalid SDL',
254
- },
255
- },
256
- }),
257
- );
258
-
259
- // Spy on logger.error so we can just await once it's been called
260
- const errorLoggedPromise = resolvable();
261
- logger.error = jest.fn(() => errorLoggedPromise.resolve());
262
-
263
- gateway = new ApolloGateway({
264
- logger,
265
- uplinkEndpoints: [mockCloudConfigUrl1],
266
- });
267
-
268
- await gateway.load(mockApolloConfig);
269
- await errorLoggedPromise;
270
-
271
- expect(logger.error).toHaveBeenCalledWith(
272
- 'UplinkSupergraphManager failed to update supergraph with the following error: Syntax Error: Unexpected Name "Syntax".',
273
- );
274
- expect(gateway.schema).toBeTruthy();
275
- });
276
-
277
- it('Throws on initial load when receiving unparseable Supergraph SDL', async () => {
278
- mockSupergraphSdlRequest().reply(
279
- 200,
280
- JSON.stringify({
281
- data: {
282
- routerConfig: {
283
- __typename: 'RouterConfigResult',
284
- id: 'failure',
285
- supergraphSdl: 'Syntax Error - invalid SDL',
286
- },
287
- },
288
- }),
289
- );
290
-
291
- gateway = new ApolloGateway({
292
- logger,
293
- uplinkEndpoints: [mockCloudConfigUrl1],
294
- });
295
-
296
- await expect(
297
- gateway.load(mockApolloConfig),
298
- ).rejects.toThrowErrorMatchingInlineSnapshot(
299
- `"Syntax Error: Unexpected Name \\"Syntax\\"."`,
300
- );
301
-
302
- expect(gateway['state'].phase).toEqual('failed to load');
303
- });
304
- });
305
-
306
- it('Rollsback to a previous schema when triggered', async () => {
307
- // Init
308
- mockSupergraphSdlRequestSuccess();
309
- mockSupergraphSdlRequestSuccessIfAfter(
310
- 'originalId-1234',
311
- 'updatedId-5678',
312
- getTestingSupergraphSdl(fixturesWithUpdate),
313
- );
314
- mockSupergraphSdlRequestSuccessIfAfter('updatedId-5678');
315
-
316
- const firstSchemaChangeBlocker = resolvable();
317
- const secondSchemaChangeBlocker = resolvable();
318
- const thirdSchemaChangeBlocker = resolvable();
319
-
320
- const onChange = jest
321
- .fn()
322
- .mockImplementationOnce(() => firstSchemaChangeBlocker.resolve())
323
- .mockImplementationOnce(() => secondSchemaChangeBlocker.resolve())
324
- .mockImplementationOnce(() => thirdSchemaChangeBlocker.resolve());
325
-
326
- gateway = new ApolloGateway({
327
- logger,
328
- uplinkEndpoints: [mockCloudConfigUrl1],
329
- });
330
-
331
- gateway.onSchemaChange(onChange);
332
- await gateway.load(mockApolloConfig);
333
-
334
- await firstSchemaChangeBlocker;
335
- expect(onChange).toHaveBeenCalledTimes(1);
336
-
337
- await secondSchemaChangeBlocker;
338
- expect(onChange).toHaveBeenCalledTimes(2);
339
-
340
- await thirdSchemaChangeBlocker;
341
- expect(onChange).toHaveBeenCalledTimes(3);
342
- });
343
-
344
- describe('Downstream service health checks', () => {
345
- describe('Unmanaged mode', () => {
346
- it(`Performs health checks to downstream services on load`, async () => {
347
- mockSdlQuerySuccess(simpleService);
348
- mockServiceHealthCheckSuccess(simpleService);
349
-
350
- gateway = new ApolloGateway({
351
- logger,
352
- serviceList: [simpleService],
353
- serviceHealthCheck: true,
354
- });
355
-
356
- await gateway.load();
357
- expect(gateway.schema!.getType('User')!.description).toBe(
358
- 'This is my User',
359
- );
360
- });
361
-
362
- it(`Rejects on initial load when health check fails`, async () => {
363
- mockSdlQuerySuccess(simpleService);
364
- mockServiceHealthCheck(simpleService).reply(500);
365
-
366
- gateway = new ApolloGateway({
367
- serviceList: [simpleService],
368
- serviceHealthCheck: true,
369
- logger,
370
- });
371
-
372
- // This is the ideal, but our version of Jest has a bug with printing error snapshots.
373
- // See: https://github.com/facebook/jest/pull/10217 (fixed in v26.2.0)
374
- // expect(gateway.load(mockApolloConfig)).rejects.toThrowErrorMatchingInlineSnapshot(`
375
- // "A valid schema couldn't be composed. The following composition errors were found:
376
- // [accounts] User -> A @key selects id, but User.id could not be found
377
- // [accounts] Account -> A @key selects id, but Account.id could not be found"
378
- // `);
379
- // Instead we'll just use the regular snapshot matcher...
380
- let err;
381
- try {
382
- await gateway.load(mockApolloConfig);
383
- } catch (e) {
384
- err = e;
385
- }
386
-
387
- expect(err.message).toMatchInlineSnapshot(`
388
- "The gateway subgraphs health check failed. Updating to the provided \`supergraphSdl\` will likely result in future request failures to subgraphs. The following error occurred during the health check:
389
- [accounts]: 500: Internal Server Error"
390
- `);
391
- });
392
- });
393
-
394
- describe('Managed mode', () => {
395
- it('Performs health checks to downstream services on load', async () => {
396
- mockSupergraphSdlRequestSuccess();
397
- mockAllServicesHealthCheckSuccess();
398
-
399
- gateway = new ApolloGateway({
400
- serviceHealthCheck: true,
401
- logger,
402
- uplinkEndpoints: [mockCloudConfigUrl1],
403
- });
404
-
405
- await gateway.load(mockApolloConfig);
406
- await gateway.stop();
407
-
408
- expect(gateway.schema!.getType('User')!).toBeTruthy();
409
- });
410
-
411
- it('Rejects on initial load when health check fails', async () => {
412
- mockSupergraphSdlRequestSuccess();
413
- mockServiceHealthCheck(accounts).reply(500);
414
- mockServiceHealthCheckSuccess(books);
415
- mockServiceHealthCheckSuccess(inventory);
416
- mockServiceHealthCheckSuccess(product);
417
- mockServiceHealthCheckSuccess(reviews);
418
- mockServiceHealthCheckSuccess(documents);
419
-
420
- gateway = new ApolloGateway({
421
- serviceHealthCheck: true,
422
- logger,
423
- uplinkEndpoints: [mockCloudConfigUrl1],
424
- });
425
-
426
- // This is the ideal, but our version of Jest has a bug with printing error snapshots.
427
- // See: https://github.com/facebook/jest/pull/10217 (fixed in v26.2.0)
428
- // expect(gateway.load(mockApolloConfig)).rejects.toThrowErrorMatchingInlineSnapshot(`
429
- // "A valid schema couldn't be composed. The following composition errors were found:
430
- // [accounts] User -> A @key selects id, but User.id could not be found
431
- // [accounts] Account -> A @key selects id, but Account.id could not be found"
432
- // `);
433
- // Instead we'll just use the regular snapshot matcher...
434
- let err;
435
- try {
436
- await gateway.load(mockApolloConfig);
437
- } catch (e) {
438
- err = e;
439
- }
440
-
441
- // TODO: smell that we should be awaiting something else
442
- expect(err.message).toMatchInlineSnapshot(`
443
- "The gateway subgraphs health check failed. Updating to the provided \`supergraphSdl\` will likely result in future request failures to subgraphs. The following error occurred during the health check:
444
- [accounts]: 500: Internal Server Error"
445
- `);
446
- });
447
-
448
- // This test has been flaky for a long time, and fails consistently after changes
449
- // introduced by https://github.com/apollographql/apollo-server/pull/4277.
450
- // I've decided to skip this test for now with hopes that we can one day
451
- // determine the root cause and test this behavior in a reliable manner.
452
- it('Rolls over to new schema when health check succeeds', async () => {
453
- mockSupergraphSdlRequestSuccess();
454
- mockAllServicesHealthCheckSuccess();
455
-
456
- // Update
457
- mockSupergraphSdlRequestSuccessIfAfter(
458
- 'originalId-1234',
459
- 'updatedId-5678',
460
- getTestingSupergraphSdl(fixturesWithUpdate),
461
- );
462
- mockAllServicesHealthCheckSuccess();
463
-
464
- const schemaChangeBlocker1 = resolvable();
465
- const schemaChangeBlocker2 = resolvable();
466
- const onChange = jest
467
- .fn()
468
- .mockImplementationOnce(() => schemaChangeBlocker1.resolve())
469
- .mockImplementationOnce(() => schemaChangeBlocker2.resolve());
470
-
471
- gateway = new ApolloGateway({
472
- serviceHealthCheck: true,
473
- logger,
474
- uplinkEndpoints: [mockCloudConfigUrl1],
475
- });
476
-
477
- gateway.onSchemaChange(onChange);
478
- await gateway.load(mockApolloConfig);
479
-
480
- // Basic testing schema doesn't contain a `review` field on `Query` type
481
- await schemaChangeBlocker1;
482
- expect(getRootQueryFields(gateway.schema)).not.toContain('review');
483
- expect(onChange).toHaveBeenCalledTimes(1);
484
-
485
- // "Updated" testing schema adds a `review` field on `Query` type
486
- await schemaChangeBlocker2;
487
- expect(getRootQueryFields(gateway.schema)).toContain('review');
488
-
489
- expect(onChange).toHaveBeenCalledTimes(2);
490
- });
491
-
492
- it('Preserves original schema when health check fails', async () => {
493
- const errorLoggedPromise = resolvable();
494
- const errorSpy = jest.fn(() => errorLoggedPromise.resolve());
495
- logger.error = errorSpy;
496
-
497
- mockSupergraphSdlRequestSuccess();
498
- mockAllServicesHealthCheckSuccess();
499
-
500
- // Update (with one health check failure)
501
- mockSupergraphSdlRequestSuccessIfAfter(
502
- 'originalId-1234',
503
- 'updatedId-5678',
504
- getTestingSupergraphSdl(fixturesWithUpdate),
505
- );
506
- mockServiceHealthCheck(accounts).reply(500);
507
- mockServiceHealthCheckSuccess(books);
508
- mockServiceHealthCheckSuccess(inventory);
509
- mockServiceHealthCheckSuccess(product);
510
- mockServiceHealthCheckSuccess(reviews);
511
- mockServiceHealthCheckSuccess(documents);
512
-
513
- gateway = new ApolloGateway({
514
- serviceHealthCheck: true,
515
- logger,
516
- uplinkEndpoints: [mockCloudConfigUrl1],
517
- });
518
-
519
- const updateSpy = jest.fn();
520
- gateway.onSchemaLoadOrUpdate(() => updateSpy());
521
-
522
- // load the gateway as usual
523
- await gateway.load(mockApolloConfig);
524
-
525
- // Validate we have the original schema
526
- expect(getRootQueryFields(gateway.schema)).toContain('topReviews');
527
- expect(getRootQueryFields(gateway.schema)).not.toContain('review');
528
-
529
- await errorLoggedPromise;
530
- expect(logger.error).toHaveBeenCalledWith(
531
- `UplinkSupergraphManager failed to update supergraph with the following error: The gateway subgraphs health check failed. Updating to the provided \`supergraphSdl\` will likely result in future request failures to subgraphs. The following error occurred during the health check:\n[accounts]: 500: Internal Server Error`,
532
- );
533
-
534
- // At this point, the mock update should have been called but the schema
535
- // should still be the original.
536
- expect(updateSpy).toHaveBeenCalledTimes(1);
537
-
538
- expect(getRootQueryFields(gateway.schema)).toContain('topReviews');
539
- expect(getRootQueryFields(gateway.schema)).not.toContain('review');
540
- });
541
- });
542
- });
@@ -1,157 +0,0 @@
1
- import nock from 'nock';
2
- import { HEALTH_CHECK_QUERY, SERVICE_DEFINITION_QUERY } from '../..';
3
- import { SUPERGRAPH_SDL_QUERY } from '../../supergraphManagers/UplinkSupergraphManager/loadSupergraphSdlFromStorage';
4
- import { getTestingSupergraphSdl } from '../../__tests__/execution-utils';
5
- import { print } from 'graphql';
6
- import { Fixture, fixtures as testingFixtures } from 'apollo-federation-integration-testsuite';
7
-
8
- export const graphRef = 'federated-service@current';
9
- export const apiKey = 'service:federated-service:DD71EBbGmsuh-6suUVDwnA';
10
- const apiKeyHash = 'dd55a79d467976346d229a7b12b673ce';
11
-
12
- export const mockApolloConfig = {
13
- apollo: {
14
- key: apiKey,
15
- keyHash: apiKeyHash,
16
- graphRef,
17
- },
18
- };
19
-
20
- // Service mocks
21
- function mockSdlQuery({ url }: Fixture) {
22
- return nock(url).post('/', {
23
- query: SERVICE_DEFINITION_QUERY,
24
- });
25
- }
26
-
27
- export function mockSdlQuerySuccess(service: Fixture) {
28
- return mockSdlQuery(service).reply(200, {
29
- data: { _service: { sdl: print(service.typeDefs) } },
30
- });
31
- }
32
-
33
- export function mockAllServicesSdlQuerySuccess(
34
- fixtures: Fixture[] = testingFixtures,
35
- ) {
36
- return fixtures.map((fixture) => mockSdlQuerySuccess(fixture));
37
- }
38
-
39
- export function mockServiceHealthCheck({ url }: Fixture) {
40
- return nock(url).post('/', {
41
- query: HEALTH_CHECK_QUERY,
42
- });
43
- }
44
-
45
- export function mockServiceHealthCheckSuccess(service: Fixture) {
46
- return mockServiceHealthCheck(service).reply(200, {
47
- data: { __typename: 'Query' },
48
- });
49
- }
50
-
51
- export function mockAllServicesHealthCheckSuccess(
52
- fixtures: Fixture[] = testingFixtures,
53
- ) {
54
- return fixtures.map((fixture) =>
55
- mockServiceHealthCheck(fixture).reply(200, {
56
- data: { __typename: 'Query' },
57
- }),
58
- );
59
- }
60
-
61
- // Supergraph SDL fetching mocks
62
- function gatewayNock(url: Parameters<typeof nock>[0]): nock.Scope {
63
- const { name, version } = require('../../../package.json');
64
- return nock(url, {
65
- reqheaders: {
66
- 'apollographql-client-name': name,
67
- 'apollographql-client-version': version,
68
- 'user-agent': `${name}/${version}`,
69
- 'content-type': 'application/json',
70
- },
71
- });
72
- }
73
-
74
- export const mockCloudConfigUrl1 =
75
- 'https://example1.cloud-config-url.com/cloudconfig/';
76
-
77
- export const mockCloudConfigUrl2 =
78
- 'https://example2.cloud-config-url.com/cloudconfig/';
79
-
80
- export const mockCloudConfigUrl3 =
81
- 'https://example3.cloud-config-url.com/cloudconfig/';
82
-
83
- export const mockOutOfBandReporterUrl =
84
- 'https://example.outofbandreporter.com/monitoring/';
85
-
86
- export function mockSupergraphSdlRequestIfAfter(ifAfter: string | null, url: string | RegExp = mockCloudConfigUrl1) {
87
- return gatewayNock(url).post('/', {
88
- query: SUPERGRAPH_SDL_QUERY,
89
- variables: {
90
- ref: graphRef,
91
- apiKey: apiKey,
92
- ifAfterId: ifAfter,
93
- },
94
- });
95
- }
96
-
97
- export function mockSupergraphSdlRequest(ifAfter: string | null = null, url: string | RegExp = mockCloudConfigUrl1) {
98
- return mockSupergraphSdlRequestIfAfter(ifAfter, url);
99
- }
100
-
101
- export function mockSupergraphSdlRequestSuccessIfAfter(
102
- ifAfter: string | null = null,
103
- id: string = 'originalId-1234',
104
- supergraphSdl: string = getTestingSupergraphSdl(),
105
- url: string | RegExp = mockCloudConfigUrl1,
106
- ) {
107
- if (supergraphSdl == null) {
108
- supergraphSdl = getTestingSupergraphSdl();
109
- }
110
- return mockSupergraphSdlRequestIfAfter(ifAfter, url).reply(
111
- 200,
112
- JSON.stringify({
113
- data: {
114
- routerConfig: {
115
- __typename: 'RouterConfigResult',
116
- id,
117
- supergraphSdl,
118
- },
119
- },
120
- }),
121
- );
122
- }
123
-
124
- export function mockSupergraphSdlRequestIfAfterUnchanged(
125
- ifAfter: string | null = null,
126
- url: string = mockCloudConfigUrl1,
127
- ) {
128
- return mockSupergraphSdlRequestIfAfter(ifAfter, url).reply(
129
- 200,
130
- JSON.stringify({
131
- data: {
132
- routerConfig: {
133
- __typename: 'Unchanged',
134
- },
135
- },
136
- }),
137
- );
138
- }
139
-
140
- export function mockSupergraphSdlRequestSuccess({supergraphSdl = getTestingSupergraphSdl(), url = mockCloudConfigUrl1}: {supergraphSdl?: string, url?: string | RegExp} = {}) {
141
- return mockSupergraphSdlRequestSuccessIfAfter(null, undefined, supergraphSdl, url);
142
- }
143
-
144
- export function mockOutOfBandReportRequest() {
145
- return gatewayNock(mockOutOfBandReporterUrl).post('/', () => true);
146
- }
147
-
148
- export function mockOutOfBandReportRequestSuccess() {
149
- return mockOutOfBandReportRequest().reply(
150
- 200,
151
- JSON.stringify({
152
- data: {
153
- reportError: true
154
- },
155
- }),
156
- );
157
- }