@apollo/gateway 0.45.1 → 0.46.0-alpha.0

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 (87) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/config.d.ts +42 -16
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +28 -18
  5. package/dist/config.js.map +1 -1
  6. package/dist/index.d.ts +35 -23
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +205 -308
  9. package/dist/index.js.map +1 -1
  10. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +31 -0
  11. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -0
  12. package/dist/supergraphManagers/IntrospectAndCompose/index.js +112 -0
  13. package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -0
  14. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +12 -0
  15. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -0
  16. package/dist/{loadServicesFromRemoteEndpoint.js → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js} +6 -6
  17. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -0
  18. package/dist/supergraphManagers/LegacyFetcher/index.d.ts +33 -0
  19. package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -0
  20. package/dist/supergraphManagers/LegacyFetcher/index.js +149 -0
  21. package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -0
  22. package/dist/supergraphManagers/LocalCompose/index.d.ts +19 -0
  23. package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -0
  24. package/dist/supergraphManagers/LocalCompose/index.js +55 -0
  25. package/dist/supergraphManagers/LocalCompose/index.js.map +1 -0
  26. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +32 -0
  27. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -0
  28. package/dist/supergraphManagers/UplinkFetcher/index.js +96 -0
  29. package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -0
  30. package/dist/{loadSupergraphSdlFromStorage.d.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts} +1 -1
  31. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -0
  32. package/dist/{loadSupergraphSdlFromStorage.js → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js} +1 -1
  33. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -0
  34. package/dist/{outOfBandReporter.d.ts → supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts} +0 -0
  35. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -0
  36. package/dist/{outOfBandReporter.js → supergraphManagers/UplinkFetcher/outOfBandReporter.js} +2 -2
  37. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -0
  38. package/dist/supergraphManagers/index.d.ts +5 -0
  39. package/dist/supergraphManagers/index.d.ts.map +1 -0
  40. package/dist/supergraphManagers/index.js +12 -0
  41. package/dist/supergraphManagers/index.js.map +1 -0
  42. package/dist/utilities/createHash.d.ts +2 -0
  43. package/dist/utilities/createHash.d.ts.map +1 -0
  44. package/dist/utilities/createHash.js +15 -0
  45. package/dist/utilities/createHash.js.map +1 -0
  46. package/dist/utilities/isNodeLike.d.ts +3 -0
  47. package/dist/utilities/isNodeLike.d.ts.map +1 -0
  48. package/dist/utilities/isNodeLike.js +8 -0
  49. package/dist/utilities/isNodeLike.js.map +1 -0
  50. package/package.json +6 -4
  51. package/src/__tests__/execution-utils.ts +2 -2
  52. package/src/__tests__/gateway/buildService.test.ts +2 -2
  53. package/src/__tests__/gateway/lifecycle-hooks.test.ts +58 -99
  54. package/src/__tests__/gateway/opentelemetry.test.ts +8 -3
  55. package/src/__tests__/gateway/queryPlanCache.test.ts +25 -9
  56. package/src/__tests__/gateway/reporting.test.ts +4 -6
  57. package/src/__tests__/gateway/supergraphSdl.test.ts +390 -0
  58. package/src/__tests__/integration/aliases.test.ts +9 -3
  59. package/src/__tests__/integration/configuration.test.ts +109 -12
  60. package/src/__tests__/integration/logger.test.ts +1 -1
  61. package/src/__tests__/integration/networkRequests.test.ts +81 -118
  62. package/src/__tests__/integration/nockMocks.ts +15 -8
  63. package/src/config.ts +149 -40
  64. package/src/index.ts +314 -485
  65. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +370 -0
  66. package/src/{__tests__ → supergraphManagers/IntrospectAndCompose/__tests__}/loadServicesFromRemoteEndpoint.test.ts +5 -5
  67. package/src/supergraphManagers/IntrospectAndCompose/__tests__/tsconfig.json +8 -0
  68. package/src/supergraphManagers/IntrospectAndCompose/index.ts +163 -0
  69. package/src/{loadServicesFromRemoteEndpoint.ts → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts} +6 -6
  70. package/src/supergraphManagers/LegacyFetcher/index.ts +229 -0
  71. package/src/supergraphManagers/LocalCompose/index.ts +83 -0
  72. package/src/{__tests__ → supergraphManagers/UplinkFetcher/__tests__}/loadSupergraphSdlFromStorage.test.ts +4 -4
  73. package/src/supergraphManagers/UplinkFetcher/__tests__/tsconfig.json +8 -0
  74. package/src/supergraphManagers/UplinkFetcher/index.ts +128 -0
  75. package/src/{loadSupergraphSdlFromStorage.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts} +3 -3
  76. package/src/{outOfBandReporter.ts → supergraphManagers/UplinkFetcher/outOfBandReporter.ts} +2 -2
  77. package/src/supergraphManagers/index.ts +4 -0
  78. package/src/utilities/createHash.ts +10 -0
  79. package/src/utilities/isNodeLike.ts +11 -0
  80. package/dist/loadServicesFromRemoteEndpoint.d.ts +0 -13
  81. package/dist/loadServicesFromRemoteEndpoint.d.ts.map +0 -1
  82. package/dist/loadServicesFromRemoteEndpoint.js.map +0 -1
  83. package/dist/loadSupergraphSdlFromStorage.d.ts.map +0 -1
  84. package/dist/loadSupergraphSdlFromStorage.js.map +0 -1
  85. package/dist/outOfBandReporter.d.ts.map +0 -1
  86. package/dist/outOfBandReporter.js.map +0 -1
  87. package/src/__tests__/gateway/composedSdl.test.ts +0 -44
@@ -1,5 +1,5 @@
1
1
  import gql from 'graphql-tag';
2
- import { DocumentNode, GraphQLObjectType, GraphQLSchema } from 'graphql';
2
+ import { GraphQLObjectType, GraphQLSchema } from 'graphql';
3
3
  import mockedEnv from 'mocked-env';
4
4
  import { Logger } from 'apollo-server-types';
5
5
  import { ApolloGateway } from '../..';
@@ -19,6 +19,7 @@ import {
19
19
  accounts,
20
20
  books,
21
21
  documents,
22
+ Fixture,
22
23
  fixturesWithUpdate,
23
24
  inventory,
24
25
  product,
@@ -26,14 +27,9 @@ import {
26
27
  } from 'apollo-federation-integration-testsuite';
27
28
  import { getTestingSupergraphSdl } from '../execution-utils';
28
29
  import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
30
+ import resolvable from '@josephg/resolvable';
29
31
 
30
- export interface MockService {
31
- name: string;
32
- url: string;
33
- typeDefs: DocumentNode;
34
- }
35
-
36
- const simpleService: MockService = {
32
+ const simpleService: Fixture = {
37
33
  name: 'accounts',
38
34
  url: 'http://localhost:4001',
39
35
  typeDefs: gql`
@@ -137,28 +133,39 @@ it('Updates Supergraph SDL from remote storage', async () => {
137
133
 
138
134
  // This test is only interested in the second time the gateway notifies of an
139
135
  // update, since the first happens on load.
140
- let secondUpdateResolve: Function;
141
- const secondUpdate = new Promise((res) => (secondUpdateResolve = res));
142
- const schemaChangeCallback = jest
143
- .fn()
144
- .mockImplementationOnce(() => {})
145
- .mockImplementationOnce(() => {
146
- secondUpdateResolve();
147
- });
136
+ const secondUpdate = resolvable();
148
137
 
149
138
  gateway = new ApolloGateway({
150
139
  logger,
151
140
  uplinkEndpoints: [mockCloudConfigUrl1],
152
141
  });
153
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
154
- gateway.experimental_pollInterval = 100;
155
- gateway.onSchemaLoadOrUpdate(schemaChangeCallback);
142
+ // for testing purposes, a short pollInterval is ideal so we'll override here
143
+ gateway['pollIntervalInMs'] = 100;
144
+
145
+ const schemas: GraphQLSchema[] = [];
146
+ gateway.onSchemaLoadOrUpdate(({apiSchema}) => {
147
+ schemas.push(apiSchema);
148
+ });
149
+ gateway.onSchemaLoadOrUpdate(
150
+ jest
151
+ .fn()
152
+ .mockImplementationOnce(() => {})
153
+ .mockImplementationOnce(() => secondUpdate.resolve()),
154
+ );
156
155
 
157
156
  await gateway.load(mockApolloConfig);
158
- expect(gateway['compositionId']).toMatchInlineSnapshot(`"originalId-1234"`);
159
157
 
160
158
  await secondUpdate;
161
- expect(gateway['compositionId']).toMatchInlineSnapshot(`"updatedId-5678"`);
159
+
160
+ // First schema has no 'review' field on the 'Query' type
161
+ expect(
162
+ (schemas[0].getType('Query') as GraphQLObjectType).getFields()['review'],
163
+ ).toBeFalsy();
164
+
165
+ // Updated schema adds 'review' field on the 'Query' type
166
+ expect(
167
+ (schemas[1].getType('Query') as GraphQLObjectType).getFields()['review'],
168
+ ).toBeTruthy();
162
169
  });
163
170
 
164
171
  describe('Supergraph SDL update failures', () => {
@@ -168,7 +175,7 @@ describe('Supergraph SDL update failures', () => {
168
175
  gateway = new ApolloGateway({
169
176
  logger,
170
177
  uplinkEndpoints: [mockCloudConfigUrl1],
171
- uplinkMaxRetries: 0
178
+ uplinkMaxRetries: 0,
172
179
  });
173
180
 
174
181
  await expect(
@@ -190,24 +197,23 @@ describe('Supergraph SDL update failures', () => {
190
197
  mockSupergraphSdlRequestIfAfter('originalId-1234').reply(500);
191
198
 
192
199
  // Spy on logger.error so we can just await once it's been called
193
- let errorLogged: Function;
194
- const errorLoggedPromise = new Promise((r) => (errorLogged = r));
195
- logger.error = jest.fn(() => errorLogged());
200
+ const errorLoggedPromise = resolvable();
201
+ logger.error = jest.fn(() => errorLoggedPromise.resolve());
196
202
 
197
203
  gateway = new ApolloGateway({
198
204
  logger,
199
205
  uplinkEndpoints: [mockCloudConfigUrl1],
200
- uplinkMaxRetries: 0
206
+ uplinkMaxRetries: 0,
201
207
  });
202
208
 
203
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
204
- gateway.experimental_pollInterval = 100;
209
+ // for testing purposes, a short pollInterval is ideal so we'll override here
210
+ gateway['pollIntervalInMs'] = 100;
205
211
 
206
212
  await gateway.load(mockApolloConfig);
207
213
  await errorLoggedPromise;
208
214
 
209
215
  expect(logger.error).toHaveBeenCalledWith(
210
- 'An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
216
+ 'UplinkFetcher failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: 500 Internal Server Error',
211
217
  );
212
218
  });
213
219
 
@@ -224,25 +230,22 @@ describe('Supergraph SDL update failures', () => {
224
230
  });
225
231
 
226
232
  // Spy on logger.error so we can just await once it's been called
227
- let errorLogged: Function;
228
- const errorLoggedPromise = new Promise((r) => (errorLogged = r));
229
- logger.error = jest.fn(() => errorLogged());
233
+ const errorLoggedPromise = resolvable();
234
+ logger.error = jest.fn(() => errorLoggedPromise.resolve());
230
235
 
231
236
  gateway = new ApolloGateway({
232
237
  logger,
233
238
  uplinkEndpoints: [mockCloudConfigUrl1],
234
- uplinkMaxRetries: 0
239
+ uplinkMaxRetries: 0,
235
240
  });
236
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
237
- gateway.experimental_pollInterval = 100;
241
+ // for testing purposes, a short pollInterval is ideal so we'll override here
242
+ gateway['pollIntervalInMs'] = 100;
238
243
 
239
244
  await gateway.load(mockApolloConfig);
240
245
  await errorLoggedPromise;
241
246
 
242
247
  expect(logger.error).toHaveBeenCalledWith(
243
- 'An error occurred while fetching your schema from Apollo: ' +
244
- '\n' +
245
- 'Cannot query field "fail" on type "Query".',
248
+ `UplinkFetcher failed to update supergraph with the following error: An error occurred while fetching your schema from Apollo: \nCannot query field "fail" on type "Query".`,
246
249
  );
247
250
  });
248
251
 
@@ -262,22 +265,21 @@ describe('Supergraph SDL update failures', () => {
262
265
  );
263
266
 
264
267
  // Spy on logger.error so we can just await once it's been called
265
- let errorLogged: Function;
266
- const errorLoggedPromise = new Promise((r) => (errorLogged = r));
267
- logger.error = jest.fn(() => errorLogged());
268
+ const errorLoggedPromise = resolvable();
269
+ logger.error = jest.fn(() => errorLoggedPromise.resolve());
268
270
 
269
271
  gateway = new ApolloGateway({
270
272
  logger,
271
273
  uplinkEndpoints: [mockCloudConfigUrl1],
272
274
  });
273
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
274
- gateway.experimental_pollInterval = 100;
275
+ // for testing purposes, a short pollInterval is ideal so we'll override here
276
+ gateway['pollIntervalInMs'] = 100;
275
277
 
276
278
  await gateway.load(mockApolloConfig);
277
279
  await errorLoggedPromise;
278
280
 
279
281
  expect(logger.error).toHaveBeenCalledWith(
280
- 'Syntax Error: Unexpected Name "Syntax".',
282
+ 'UplinkFetcher failed to update supergraph with the following error: Syntax Error: Unexpected Name "Syntax".',
281
283
  );
282
284
  expect(gateway.schema).toBeTruthy();
283
285
  });
@@ -300,8 +302,8 @@ describe('Supergraph SDL update failures', () => {
300
302
  logger,
301
303
  uplinkEndpoints: [mockCloudConfigUrl1],
302
304
  });
303
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
304
- gateway.experimental_pollInterval = 100;
305
+ // for testing purposes, a short pollInterval is ideal so we'll override here
306
+ gateway['pollIntervalInMs'] = 100;
305
307
 
306
308
  await expect(
307
309
  gateway.load(mockApolloConfig),
@@ -327,25 +329,22 @@ it('Rollsback to a previous schema when triggered', async () => {
327
329
  );
328
330
  mockSupergraphSdlRequestSuccessIfAfter('updatedId-5678');
329
331
 
330
- let firstResolve: Function;
331
- let secondResolve: Function;
332
- let thirdResolve: Function;
333
- const firstSchemaChangeBlocker = new Promise((res) => (firstResolve = res));
334
- const secondSchemaChangeBlocker = new Promise((res) => (secondResolve = res));
335
- const thirdSchemaChangeBlocker = new Promise((res) => (thirdResolve = res));
332
+ const firstSchemaChangeBlocker = resolvable();
333
+ const secondSchemaChangeBlocker = resolvable();
334
+ const thirdSchemaChangeBlocker = resolvable();
336
335
 
337
336
  const onChange = jest
338
337
  .fn()
339
- .mockImplementationOnce(() => firstResolve())
340
- .mockImplementationOnce(() => secondResolve())
341
- .mockImplementationOnce(() => thirdResolve());
338
+ .mockImplementationOnce(() => firstSchemaChangeBlocker.resolve())
339
+ .mockImplementationOnce(() => secondSchemaChangeBlocker.resolve())
340
+ .mockImplementationOnce(() => thirdSchemaChangeBlocker.resolve());
342
341
 
343
342
  gateway = new ApolloGateway({
344
343
  logger,
345
344
  uplinkEndpoints: [mockCloudConfigUrl1],
346
345
  });
347
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
348
- gateway.experimental_pollInterval = 100;
346
+ // for testing purposes, a short pollInterval is ideal so we'll override here
347
+ gateway['pollIntervalInMs'] = 100;
349
348
 
350
349
  gateway.onSchemaChange(onChange);
351
350
  await gateway.load(mockApolloConfig);
@@ -402,9 +401,8 @@ describe('Downstream service health checks', () => {
402
401
  var err = e;
403
402
  }
404
403
 
405
- // TODO: smell that we should be awaiting something else
406
404
  expect(err.message).toMatchInlineSnapshot(`
407
- "The gateway did not update its schema due to failed service health checks. The gateway will continue to operate with the previous schema and reattempt updates. The following error occurred during the health check:
405
+ "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:
408
406
  [accounts]: 500: Internal Server Error"
409
407
  `);
410
408
 
@@ -428,8 +426,8 @@ describe('Downstream service health checks', () => {
428
426
  logger,
429
427
  uplinkEndpoints: [mockCloudConfigUrl1],
430
428
  });
431
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
432
- gateway.experimental_pollInterval = 100;
429
+ // for testing purposes, a short pollInterval is ideal so we'll override here
430
+ gateway['pollIntervalInMs'] = 100;
433
431
 
434
432
  await gateway.load(mockApolloConfig);
435
433
  await gateway.stop();
@@ -468,7 +466,7 @@ describe('Downstream service health checks', () => {
468
466
 
469
467
  // TODO: smell that we should be awaiting something else
470
468
  expect(err.message).toMatchInlineSnapshot(`
471
- "The gateway did not update its schema due to failed service health checks. The gateway will continue to operate with the previous schema and reattempt updates. The following error occurred during the health check:
469
+ "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:
472
470
  [accounts]: 500: Internal Server Error"
473
471
  `);
474
472
 
@@ -497,22 +495,20 @@ describe('Downstream service health checks', () => {
497
495
  );
498
496
  mockAllServicesHealthCheckSuccess();
499
497
 
500
- let resolve1: Function;
501
- let resolve2: Function;
502
- const schemaChangeBlocker1 = new Promise((res) => (resolve1 = res));
503
- const schemaChangeBlocker2 = new Promise((res) => (resolve2 = res));
498
+ const schemaChangeBlocker1 = resolvable();
499
+ const schemaChangeBlocker2 = resolvable();
504
500
  const onChange = jest
505
501
  .fn()
506
- .mockImplementationOnce(() => resolve1())
507
- .mockImplementationOnce(() => resolve2());
502
+ .mockImplementationOnce(() => schemaChangeBlocker1.resolve())
503
+ .mockImplementationOnce(() => schemaChangeBlocker2.resolve());
508
504
 
509
505
  gateway = new ApolloGateway({
510
506
  serviceHealthCheck: true,
511
507
  logger,
512
508
  uplinkEndpoints: [mockCloudConfigUrl1],
513
509
  });
514
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
515
- gateway.experimental_pollInterval = 100;
510
+ // for testing purposes, a short pollInterval is ideal so we'll override here
511
+ gateway['pollIntervalInMs'] = 100;
516
512
 
517
513
  gateway.onSchemaChange(onChange);
518
514
  await gateway.load(mockApolloConfig);
@@ -530,6 +526,10 @@ describe('Downstream service health checks', () => {
530
526
  });
531
527
 
532
528
  it('Preserves original schema when health check fails', async () => {
529
+ const errorLoggedPromise = resolvable();
530
+ const errorSpy = jest.fn(() => errorLoggedPromise.resolve());
531
+ logger.error = errorSpy;
532
+
533
533
  mockSupergraphSdlRequestSuccess();
534
534
  mockAllServicesHealthCheckSuccess();
535
535
 
@@ -546,57 +546,16 @@ describe('Downstream service health checks', () => {
546
546
  mockServiceHealthCheckSuccess(reviews);
547
547
  mockServiceHealthCheckSuccess(documents);
548
548
 
549
- let resolve: Function;
550
- const schemaChangeBlocker = new Promise((res) => (resolve = res));
551
-
552
549
  gateway = new ApolloGateway({
553
550
  serviceHealthCheck: true,
554
551
  logger,
555
552
  uplinkEndpoints: [mockCloudConfigUrl1],
556
553
  });
557
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
558
- gateway.experimental_pollInterval = 100;
559
-
560
- // @ts-ignore for testing purposes, we'll call the original `updateSchema`
561
- // function from our mock. The first call should mimic original behavior,
562
- // but the second call needs to handle the PromiseRejection. Typically for tests
563
- // like these we would leverage the `gateway.onSchemaChange` callback to drive
564
- // the test, but in this case, that callback isn't triggered when the update
565
- // fails (as expected) so we get creative with the second mock as seen below.
566
- const original = gateway.updateSchema;
567
- const mockUpdateSchema = jest
568
- .fn()
569
- .mockImplementationOnce(async () => {
570
- await original.apply(gateway);
571
- })
572
- .mockImplementationOnce(async () => {
573
- // mock the first poll and handle the error which would otherwise be caught
574
- // and logged from within the `pollServices` class method
575
-
576
- // This is the ideal, but our version of Jest has a bug with printing error snapshots.
577
- // See: https://github.com/facebook/jest/pull/10217 (fixed in v26.2.0)
578
- // expect(original.apply(gateway)).rejects.toThrowErrorMatchingInlineSnapshot(`
579
- // The gateway did not update its schema due to failed service health checks. The gateway will continue to operate with the previous schema and reattempt updates. The following error occurred during the health check:
580
- // [accounts]: 500: Internal Server Error"
581
- // `);
582
- // Instead we'll just use the regular snapshot matcher...
583
- try {
584
- await original.apply(gateway);
585
- } catch (e) {
586
- var err = e;
587
- }
588
-
589
- expect(err.message).toMatchInlineSnapshot(`
590
- "The gateway did not update its schema due to failed service health checks. The gateway will continue to operate with the previous schema and reattempt updates. The following error occurred during the health check:
591
- [accounts]: 500: Internal Server Error"
592
- `);
593
- // finally resolve the promise which drives this test
594
- resolve();
595
- });
596
-
597
- // @ts-ignore for testing purposes, replace the `updateSchema`
598
- // function on the gateway with our mock
599
- gateway.updateSchema = mockUpdateSchema;
554
+ // for testing purposes, a short pollInterval is ideal so we'll override here
555
+ gateway['pollIntervalInMs'] = 100;
556
+
557
+ const updateSpy = jest.fn();
558
+ gateway.onSchemaLoadOrUpdate(() => updateSpy());
600
559
 
601
560
  // load the gateway as usual
602
561
  await gateway.load(mockApolloConfig);
@@ -605,11 +564,15 @@ describe('Downstream service health checks', () => {
605
564
  expect(getRootQueryFields(gateway.schema)).toContain('topReviews');
606
565
  expect(getRootQueryFields(gateway.schema)).not.toContain('review');
607
566
 
608
- await schemaChangeBlocker;
567
+ await errorLoggedPromise;
568
+ expect(logger.error).toHaveBeenCalledWith(
569
+ `UplinkFetcher 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`,
570
+ );
609
571
 
610
572
  // At this point, the mock update should have been called but the schema
611
573
  // should still be the original.
612
- expect(mockUpdateSchema).toHaveBeenCalledTimes(2);
574
+ expect(updateSpy).toHaveBeenCalledTimes(1);
575
+
613
576
  expect(getRootQueryFields(gateway.schema)).toContain('topReviews');
614
577
  expect(getRootQueryFields(gateway.schema)).not.toContain('review');
615
578
  });
@@ -1,10 +1,9 @@
1
1
  import nock from 'nock';
2
- import { MockService } from './networkRequests.test';
3
2
  import { HEALTH_CHECK_QUERY, SERVICE_DEFINITION_QUERY } from '../..';
4
- import { SUPERGRAPH_SDL_QUERY } from '../../loadSupergraphSdlFromStorage';
3
+ import { SUPERGRAPH_SDL_QUERY } from '../../supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage';
5
4
  import { getTestingSupergraphSdl } from '../../__tests__/execution-utils';
6
5
  import { print } from 'graphql';
7
- import { fixtures } from 'apollo-federation-integration-testsuite';
6
+ import { Fixture, fixtures as testingFixtures } from 'apollo-federation-integration-testsuite';
8
7
 
9
8
  export const graphRef = 'federated-service@current';
10
9
  export const apiKey = 'service:federated-service:DD71EBbGmsuh-6suUVDwnA';
@@ -19,31 +18,39 @@ export const mockApolloConfig = {
19
18
  };
20
19
 
21
20
  // Service mocks
22
- function mockSdlQuery({ url }: MockService) {
21
+ function mockSdlQuery({ url }: Fixture) {
23
22
  return nock(url).post('/', {
24
23
  query: SERVICE_DEFINITION_QUERY,
25
24
  });
26
25
  }
27
26
 
28
- export function mockSdlQuerySuccess(service: MockService) {
27
+ export function mockSdlQuerySuccess(service: Fixture) {
29
28
  return mockSdlQuery(service).reply(200, {
30
29
  data: { _service: { sdl: print(service.typeDefs) } },
31
30
  });
32
31
  }
33
32
 
34
- export function mockServiceHealthCheck({ url }: MockService) {
33
+ export function mockAllServicesSdlQuerySuccess(
34
+ fixtures: Fixture[] = testingFixtures,
35
+ ) {
36
+ return fixtures.map((fixture) => mockSdlQuerySuccess(fixture));
37
+ }
38
+
39
+ export function mockServiceHealthCheck({ url }: Fixture) {
35
40
  return nock(url).post('/', {
36
41
  query: HEALTH_CHECK_QUERY,
37
42
  });
38
43
  }
39
44
 
40
- export function mockServiceHealthCheckSuccess(service: MockService) {
45
+ export function mockServiceHealthCheckSuccess(service: Fixture) {
41
46
  return mockServiceHealthCheck(service).reply(200, {
42
47
  data: { __typename: 'Query' },
43
48
  });
44
49
  }
45
50
 
46
- export function mockAllServicesHealthCheckSuccess() {
51
+ export function mockAllServicesHealthCheckSuccess(
52
+ fixtures: Fixture[] = testingFixtures,
53
+ ) {
47
54
  return fixtures.map((fixture) =>
48
55
  mockServiceHealthCheck(fixture).reply(200, {
49
56
  data: { __typename: 'Query' },