@apollo/gateway 2.0.0-alpha.3 → 2.0.0-alpha.4

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 (116) hide show
  1. package/dist/config.d.ts +41 -15
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +28 -18
  4. package/dist/config.js.map +1 -1
  5. package/dist/datasources/LocalGraphQLDataSource.js.map +1 -1
  6. package/dist/executeQueryPlan.d.ts.map +1 -1
  7. package/dist/executeQueryPlan.js +1 -1
  8. package/dist/executeQueryPlan.js.map +1 -1
  9. package/dist/index.d.ts +36 -24
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +197 -295
  12. package/dist/index.js.map +1 -1
  13. package/dist/schema-helper/addResolversToSchema.d.ts +4 -0
  14. package/dist/schema-helper/addResolversToSchema.d.ts.map +1 -0
  15. package/dist/schema-helper/addResolversToSchema.js +62 -0
  16. package/dist/schema-helper/addResolversToSchema.js.map +1 -0
  17. package/dist/schema-helper/error.d.ts +6 -0
  18. package/dist/schema-helper/error.d.ts.map +1 -0
  19. package/dist/schema-helper/error.js +14 -0
  20. package/dist/schema-helper/error.js.map +1 -0
  21. package/dist/schema-helper/index.d.ts +4 -0
  22. package/dist/schema-helper/index.d.ts.map +1 -0
  23. package/dist/schema-helper/index.js +16 -0
  24. package/dist/schema-helper/index.js.map +1 -0
  25. package/dist/schema-helper/resolverMap.d.ts +16 -0
  26. package/dist/schema-helper/resolverMap.d.ts.map +1 -0
  27. package/dist/schema-helper/resolverMap.js +3 -0
  28. package/dist/schema-helper/resolverMap.js.map +1 -0
  29. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +31 -0
  30. package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -0
  31. package/dist/supergraphManagers/IntrospectAndCompose/index.js +112 -0
  32. package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -0
  33. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts +12 -0
  34. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.d.ts.map +1 -0
  35. package/dist/{loadServicesFromRemoteEndpoint.js → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js} +6 -6
  36. package/dist/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.js.map +1 -0
  37. package/dist/supergraphManagers/LegacyFetcher/index.d.ts +33 -0
  38. package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -0
  39. package/dist/supergraphManagers/LegacyFetcher/index.js +149 -0
  40. package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -0
  41. package/dist/supergraphManagers/LocalCompose/index.d.ts +19 -0
  42. package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -0
  43. package/dist/supergraphManagers/LocalCompose/index.js +55 -0
  44. package/dist/supergraphManagers/LocalCompose/index.js.map +1 -0
  45. package/dist/supergraphManagers/UplinkFetcher/index.d.ts +32 -0
  46. package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -0
  47. package/dist/supergraphManagers/UplinkFetcher/index.js +96 -0
  48. package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -0
  49. package/dist/{loadSupergraphSdlFromStorage.d.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts} +1 -1
  50. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -0
  51. package/dist/{loadSupergraphSdlFromStorage.js → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js} +1 -1
  52. package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -0
  53. package/dist/{outOfBandReporter.d.ts → supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts} +0 -0
  54. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.d.ts.map +1 -0
  55. package/dist/{outOfBandReporter.js → supergraphManagers/UplinkFetcher/outOfBandReporter.js} +2 -2
  56. package/dist/supergraphManagers/UplinkFetcher/outOfBandReporter.js.map +1 -0
  57. package/dist/supergraphManagers/index.d.ts +5 -0
  58. package/dist/supergraphManagers/index.d.ts.map +1 -0
  59. package/dist/supergraphManagers/index.js +12 -0
  60. package/dist/supergraphManagers/index.js.map +1 -0
  61. package/dist/utilities/createHash.d.ts +2 -0
  62. package/dist/utilities/createHash.d.ts.map +1 -0
  63. package/dist/utilities/createHash.js +15 -0
  64. package/dist/utilities/createHash.js.map +1 -0
  65. package/dist/utilities/isNodeLike.d.ts +3 -0
  66. package/dist/utilities/isNodeLike.d.ts.map +1 -0
  67. package/dist/utilities/isNodeLike.js +8 -0
  68. package/dist/utilities/isNodeLike.js.map +1 -0
  69. package/package.json +8 -7
  70. package/src/__tests__/executeQueryPlan.test.ts +1 -1
  71. package/src/__tests__/execution-utils.ts +3 -3
  72. package/src/__tests__/gateway/buildService.test.ts +2 -2
  73. package/src/__tests__/gateway/endToEnd.test.ts +1 -1
  74. package/src/__tests__/gateway/lifecycle-hooks.test.ts +59 -125
  75. package/src/__tests__/gateway/opentelemetry.test.ts +8 -4
  76. package/src/__tests__/gateway/queryPlanCache.test.ts +25 -12
  77. package/src/__tests__/gateway/reporting.test.ts +34 -8
  78. package/src/__tests__/gateway/supergraphSdl.test.ts +397 -0
  79. package/src/__tests__/integration/aliases.test.ts +9 -4
  80. package/src/__tests__/integration/configuration.test.ts +109 -12
  81. package/src/__tests__/integration/logger.test.ts +1 -1
  82. package/src/__tests__/integration/networkRequests.test.ts +81 -131
  83. package/src/__tests__/integration/nockMocks.ts +15 -8
  84. package/src/config.ts +148 -39
  85. package/src/datasources/LocalGraphQLDataSource.ts +1 -1
  86. package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +1 -1
  87. package/src/executeQueryPlan.ts +3 -1
  88. package/src/index.ts +322 -466
  89. package/src/schema-helper/addResolversToSchema.ts +83 -0
  90. package/src/schema-helper/error.ts +11 -0
  91. package/src/schema-helper/index.ts +3 -0
  92. package/src/schema-helper/resolverMap.ts +23 -0
  93. package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +370 -0
  94. package/src/{__tests__ → supergraphManagers/IntrospectAndCompose/__tests__}/loadServicesFromRemoteEndpoint.test.ts +5 -5
  95. package/src/supergraphManagers/IntrospectAndCompose/__tests__/tsconfig.json +8 -0
  96. package/src/supergraphManagers/IntrospectAndCompose/index.ts +160 -0
  97. package/src/{loadServicesFromRemoteEndpoint.ts → supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts} +6 -6
  98. package/src/supergraphManagers/LegacyFetcher/index.ts +226 -0
  99. package/src/supergraphManagers/LocalCompose/index.ts +79 -0
  100. package/src/{__tests__ → supergraphManagers/UplinkFetcher/__tests__}/loadSupergraphSdlFromStorage.test.ts +4 -4
  101. package/src/supergraphManagers/UplinkFetcher/__tests__/tsconfig.json +8 -0
  102. package/src/supergraphManagers/UplinkFetcher/index.ts +128 -0
  103. package/src/{loadSupergraphSdlFromStorage.ts → supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts} +3 -3
  104. package/src/{outOfBandReporter.ts → supergraphManagers/UplinkFetcher/outOfBandReporter.ts} +2 -2
  105. package/src/supergraphManagers/index.ts +4 -0
  106. package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +12 -9
  107. package/src/utilities/createHash.ts +10 -0
  108. package/src/utilities/isNodeLike.ts +11 -0
  109. package/dist/loadServicesFromRemoteEndpoint.d.ts +0 -13
  110. package/dist/loadServicesFromRemoteEndpoint.d.ts.map +0 -1
  111. package/dist/loadServicesFromRemoteEndpoint.js.map +0 -1
  112. package/dist/loadSupergraphSdlFromStorage.d.ts.map +0 -1
  113. package/dist/loadSupergraphSdlFromStorage.js.map +0 -1
  114. package/dist/outOfBandReporter.d.ts.map +0 -1
  115. package/dist/outOfBandReporter.js.map +0 -1
  116. package/src/__tests__/gateway/composedSdl.test.ts +0 -44
@@ -1,10 +1,10 @@
1
- import { GraphQLSchemaModule } from 'apollo-graphql';
2
1
  import { buildSubgraphSchema } from '@apollo/subgraph';
3
2
  import { ApolloServer } from 'apollo-server';
4
3
  import fetch from 'node-fetch';
5
4
  import { ApolloGateway } from '../..';
6
5
  import { fixtures } from 'apollo-federation-integration-testsuite';
7
6
  import { ApolloServerPluginInlineTrace } from 'apollo-server-core';
7
+ import { GraphQLSchemaModule } from '../../schema-helper';
8
8
 
9
9
  async function startFederatedServer(modules: GraphQLSchemaModule[]) {
10
10
  const schema = buildSubgraphSchema(modules);
@@ -1,8 +1,10 @@
1
1
  import gql from 'graphql-tag';
2
2
  import { ApolloGateway } from '../..';
3
3
  import {
4
+ DynamicGatewayConfig,
4
5
  Experimental_DidResolveQueryPlanCallback,
5
6
  Experimental_UpdateServiceDefinitions,
7
+ ServiceDefinitionUpdate,
6
8
  } from '../../config';
7
9
  import {
8
10
  product,
@@ -11,10 +13,11 @@ import {
11
13
  accounts,
12
14
  books,
13
15
  documents,
16
+ fixtures,
17
+ fixturesWithUpdate,
14
18
  } from 'apollo-federation-integration-testsuite';
15
19
  import { Logger } from 'apollo-server-types';
16
-
17
- type GenericFunction = (...args: unknown[]) => unknown;
20
+ import resolvable from '@josephg/resolvable';
18
21
 
19
22
  // The order of this was specified to preserve existing test coverage. Typically
20
23
  // we would just import and use the `fixtures` array.
@@ -49,16 +52,14 @@ beforeEach(() => {
49
52
 
50
53
  describe('lifecycle hooks', () => {
51
54
  it('uses updateServiceDefinitions override', async () => {
52
- const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions = jest.fn(
53
- async () => {
55
+ const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
56
+ jest.fn(async () => {
54
57
  return { serviceDefinitions, isNewSchema: true };
55
- },
56
- );
58
+ });
57
59
 
58
60
  const gateway = new ApolloGateway({
59
61
  serviceList: serviceDefinitions,
60
62
  experimental_updateServiceDefinitions,
61
- experimental_didUpdateComposition: jest.fn(),
62
63
  logger,
63
64
  });
64
65
 
@@ -69,61 +70,7 @@ describe('lifecycle hooks', () => {
69
70
  await gateway.stop();
70
71
  });
71
72
 
72
- it('calls experimental_didFailComposition with a bad config', async () => {
73
- const experimental_didFailComposition = jest.fn();
74
-
75
- // Creating 2 subservices that clearly cannot composed.
76
- const s1 = {
77
- name: 'S1',
78
- url: 'http://S1',
79
- typeDefs: gql`
80
- type T {
81
- a: Int
82
- }
83
- `
84
- };
85
-
86
- const s2 = {
87
- name: 'S2',
88
- url: 'http://S2',
89
- typeDefs: gql`
90
- type T {
91
- a: String
92
- }
93
- `
94
- };
95
-
96
-
97
- const gateway = new ApolloGateway({
98
- async experimental_updateServiceDefinitions() {
99
- return {
100
- serviceDefinitions: [s1, s2],
101
- compositionMetadata: {
102
- formatVersion: 1,
103
- id: 'abc',
104
- implementingServiceLocations: [],
105
- schemaHash: 'abc',
106
- },
107
- isNewSchema: true,
108
- };
109
- },
110
- serviceList: [],
111
- experimental_didFailComposition,
112
- logger,
113
- });
114
-
115
- await expect(gateway.load()).rejects.toThrowError("A valid schema couldn't be composed");
116
-
117
- const callbackArgs = experimental_didFailComposition.mock.calls[0][0];
118
- expect(callbackArgs.serviceList).toHaveLength(2);
119
- expect(callbackArgs.errors[0]).toMatchInlineSnapshot(
120
- `[GraphQLError: Field "T.a" has incompatible types across subgraphs: it has type "Int" in subgraph "S1" but type "String" in subgraph "S2"]`,
121
- );
122
- expect(callbackArgs.compositionMetadata.id).toEqual('abc');
123
- expect(experimental_didFailComposition).toBeCalled();
124
- });
125
-
126
- it('calls experimental_didUpdateComposition on schema update', async () => {
73
+ it('calls experimental_didUpdateSupergraph on schema update', async () => {
127
74
  const compositionMetadata = {
128
75
  formatVersion: 1,
129
76
  id: 'abc',
@@ -131,82 +78,73 @@ describe('lifecycle hooks', () => {
131
78
  schemaHash: 'hash1',
132
79
  };
133
80
 
134
- const update: Experimental_UpdateServiceDefinitions = async () => ({
135
- serviceDefinitions,
136
- isNewSchema: true,
137
- compositionMetadata: {
138
- ...compositionMetadata,
139
- id: '123',
140
- schemaHash: 'hash2',
141
- },
142
- });
143
-
144
- // This is the simplest way I could find to achieve mocked functions that leverage our types
145
- const mockUpdate = jest.fn(update);
146
-
147
- // We want to return a different composition across two ticks, so we mock it
148
- // slightly differenty
149
- mockUpdate.mockImplementationOnce(async () => {
150
- const services = serviceDefinitions.filter(s => s.name !== 'books');
151
- return {
152
- serviceDefinitions: [
153
- ...services,
154
- {
155
- name: 'book',
156
- typeDefs: books.typeDefs,
157
- url: 'http://localhost:32542',
81
+ const mockUpdate = jest
82
+ .fn<Promise<ServiceDefinitionUpdate>, [config: DynamicGatewayConfig]>()
83
+ .mockImplementationOnce(async () => {
84
+ return {
85
+ serviceDefinitions: fixtures,
86
+ isNewSchema: true,
87
+ compositionMetadata: {
88
+ ...compositionMetadata,
89
+ id: '123',
90
+ schemaHash: 'hash2',
158
91
  },
159
- ],
160
- isNewSchema: true,
161
- compositionMetadata,
162
- };
163
- });
92
+ };
93
+ })
94
+ // We want to return a different composition across two ticks, so we mock it
95
+ // slightly differently
96
+ .mockImplementationOnce(async () => {
97
+ return {
98
+ serviceDefinitions: fixturesWithUpdate,
99
+ isNewSchema: true,
100
+ compositionMetadata,
101
+ };
102
+ });
164
103
 
165
104
  const mockDidUpdate = jest.fn();
166
105
 
167
106
  const gateway = new ApolloGateway({
168
107
  experimental_updateServiceDefinitions: mockUpdate,
169
- experimental_didUpdateComposition: mockDidUpdate,
108
+ experimental_didUpdateSupergraph: mockDidUpdate,
170
109
  logger,
171
110
  });
172
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
173
- // @ts-ignore for testing purposes, a short pollInterval is ideal so we'll override here
174
- gateway.experimental_pollInterval = 100;
111
+ // for testing purposes, a short pollInterval is ideal so we'll override here
112
+ gateway['pollIntervalInMs'] = 100;
175
113
 
176
- let resolve1: GenericFunction;
177
- let resolve2: GenericFunction;
178
- const schemaChangeBlocker1 = new Promise(res => (resolve1 = res));
179
- const schemaChangeBlocker2 = new Promise(res => (resolve2 = res));
114
+ const schemaChangeBlocker1 = resolvable();
115
+ const schemaChangeBlocker2 = resolvable();
180
116
 
181
- gateway.onSchemaChange(
117
+ gateway.onSchemaLoadOrUpdate(
182
118
  jest
183
119
  .fn()
184
- .mockImplementationOnce(() => resolve1())
185
- .mockImplementationOnce(() => resolve2()),
120
+ .mockImplementationOnce(() => schemaChangeBlocker1.resolve())
121
+ .mockImplementationOnce(() => schemaChangeBlocker2.resolve()),
186
122
  );
187
123
 
188
124
  await gateway.load();
189
125
 
190
126
  await schemaChangeBlocker1;
127
+
191
128
  expect(mockUpdate).toBeCalledTimes(1);
192
129
  expect(mockDidUpdate).toBeCalledTimes(1);
193
130
 
194
131
  await schemaChangeBlocker2;
132
+
195
133
  expect(mockUpdate).toBeCalledTimes(2);
196
134
  expect(mockDidUpdate).toBeCalledTimes(2);
197
135
 
198
136
  const [firstCall, secondCall] = mockDidUpdate.mock.calls;
199
137
 
200
- expect(firstCall[0]!.schema).toBeDefined();
201
- expect(firstCall[0].compositionMetadata!.schemaHash).toEqual('hash1');
138
+ const expectedFirstId = 'd20cfb7a9c51179aa494ed9e98153f0042892bd225437af064bf1c1aa68eab86'
139
+ expect(firstCall[0]!.compositionId).toEqual(expectedFirstId);
202
140
  // first call should have no second "previous" argument
203
141
  expect(firstCall[1]).toBeUndefined();
204
142
 
205
- expect(secondCall[0].schema).toBeDefined();
206
- expect(secondCall[0].compositionMetadata!.schemaHash).toEqual('hash2');
143
+ expect(secondCall[0]!.compositionId).toEqual(
144
+ '7dad7ab8284165a86241b8973d71f0d6ac8cb142095c717dd23443522850c225',
145
+ );
207
146
  // second call should have previous info in the second arg
208
- expect(secondCall[1]!.schema).toBeDefined();
209
- expect(secondCall[1]!.compositionMetadata!.schemaHash).toEqual('hash1');
147
+ expect(secondCall[1]!.compositionId).toEqual(expectedFirstId);
210
148
 
211
149
  await gateway.stop();
212
150
  });
@@ -231,34 +169,31 @@ describe('lifecycle hooks', () => {
231
169
  it('warns when polling on the default fetcher', async () => {
232
170
  new ApolloGateway({
233
171
  serviceList: serviceDefinitions,
234
- experimental_pollInterval: 10,
172
+ pollIntervalInMs: 10,
235
173
  logger,
236
174
  });
237
- expect(logger.warn).toHaveBeenCalledTimes(1);
238
175
  expect(logger.warn).toHaveBeenCalledWith(
239
176
  'Polling running services is dangerous and not recommended in production. Polling should only be used against a registry. If you are polling running services, use with caution.',
240
177
  );
241
178
  });
242
179
 
243
180
  it('registers schema change callbacks when experimental_pollInterval is set for unmanaged configs', async () => {
244
- const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions = jest.fn(
245
- async (_config) => {
181
+ const experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions =
182
+ jest.fn(async (_config) => {
246
183
  return { serviceDefinitions, isNewSchema: true };
247
- },
248
- );
184
+ });
249
185
 
250
186
  const gateway = new ApolloGateway({
251
187
  serviceList: [{ name: 'book', url: 'http://localhost:32542' }],
252
188
  experimental_updateServiceDefinitions,
253
- experimental_pollInterval: 100,
189
+ pollIntervalInMs: 100,
254
190
  logger,
255
191
  });
256
192
 
257
- let resolve: GenericFunction;
258
- const schemaChangeBlocker = new Promise(res => (resolve = res));
259
- const schemaChangeCallback = jest.fn(() => resolve());
193
+ const schemaChangeBlocker = resolvable();
194
+ const schemaChangeCallback = jest.fn(() => schemaChangeBlocker.resolve());
260
195
 
261
- gateway.onSchemaChange(schemaChangeCallback);
196
+ gateway.onSchemaLoadOrUpdate(schemaChangeCallback);
262
197
  await gateway.load();
263
198
 
264
199
  await schemaChangeBlocker;
@@ -268,12 +203,11 @@ describe('lifecycle hooks', () => {
268
203
  });
269
204
 
270
205
  it('calls experimental_didResolveQueryPlan when executor is called', async () => {
271
- const experimental_didResolveQueryPlan: Experimental_DidResolveQueryPlanCallback = jest.fn()
206
+ const experimental_didResolveQueryPlan: Experimental_DidResolveQueryPlanCallback =
207
+ jest.fn();
272
208
 
273
209
  const gateway = new ApolloGateway({
274
- localServiceList: [
275
- books
276
- ],
210
+ localServiceList: [books],
277
211
  experimental_didResolveQueryPlan,
278
212
  });
279
213
 
@@ -283,8 +217,8 @@ describe('lifecycle hooks', () => {
283
217
  { book(isbn: "0262510871") { year } }
284
218
  `;
285
219
 
286
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
287
- // @ts-ignore
220
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
221
+ // @ts-ignore
288
222
  await executor({
289
223
  source,
290
224
  document: gql(source),
@@ -36,12 +36,16 @@ describe('opentelemetry', () => {
36
36
  describe('with local data', () =>
37
37
  {
38
38
  async function gateway() {
39
+ const localDataSources = Object.fromEntries(
40
+ fixtures.map((f) => [
41
+ f.name,
42
+ new LocalGraphQLDataSource(buildSubgraphSchema(f)),
43
+ ]),
44
+ );
39
45
  const gateway = new ApolloGateway({
40
46
  localServiceList: fixtures,
41
- buildService: service => {
42
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
43
- // @ts-ignore
44
- return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
47
+ buildService(service) {
48
+ return localDataSources[service.name];
45
49
  },
46
50
  });
47
51
 
@@ -6,15 +6,20 @@ import { LocalGraphQLDataSource } from '../../datasources/LocalGraphQLDataSource
6
6
  import { ApolloGateway } from '../../';
7
7
  import { fixtures } from 'apollo-federation-integration-testsuite';
8
8
  import { QueryPlanner } from '@apollo/query-planner';
9
+
9
10
  it('caches the query plan for a request', async () => {
10
11
  const buildQueryPlanSpy = jest.spyOn(QueryPlanner.prototype, 'buildQueryPlan');
11
12
 
13
+ const localDataSources = Object.fromEntries(
14
+ fixtures.map((f) => [
15
+ f.name,
16
+ new LocalGraphQLDataSource(buildSubgraphSchema(f)),
17
+ ]),
18
+ );
12
19
  const gateway = new ApolloGateway({
13
20
  localServiceList: fixtures,
14
- buildService: service => {
15
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
16
- // @ts-ignore
17
- return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
21
+ buildService(service) {
22
+ return localDataSources[service.name];
18
23
  },
19
24
  });
20
25
 
@@ -66,12 +71,17 @@ it('supports multiple operations and operationName', async () => {
66
71
  }
67
72
  `;
68
73
 
74
+ const localDataSources = Object.fromEntries(
75
+ fixtures.map((f) => [
76
+ f.name,
77
+ new LocalGraphQLDataSource(buildSubgraphSchema(f)),
78
+ ]),
79
+ );
80
+
69
81
  const gateway = new ApolloGateway({
70
82
  localServiceList: fixtures,
71
- buildService: service => {
72
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
73
- // @ts-ignore
74
- return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
83
+ buildService(service) {
84
+ return localDataSources[service.name];
75
85
  },
76
86
  });
77
87
 
@@ -172,12 +182,15 @@ it('does not corrupt cached queryplan data across requests', async () => {
172
182
  },
173
183
  };
174
184
 
185
+ const dataSources: Record<string, LocalGraphQLDataSource> = {
186
+ a: new LocalGraphQLDataSource(buildSubgraphSchema(serviceA)),
187
+ b: new LocalGraphQLDataSource(buildSubgraphSchema(serviceB)),
188
+ };
189
+
175
190
  const gateway = new ApolloGateway({
176
191
  localServiceList: [serviceA, serviceB],
177
- buildService: service => {
178
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
179
- // @ts-ignore
180
- return new LocalGraphQLDataSource(buildSubgraphSchema([service]));
192
+ buildService(service) {
193
+ return dataSources[service.name];
181
194
  },
182
195
  });
183
196
 
@@ -1,6 +1,5 @@
1
1
  import { gunzipSync } from 'zlib';
2
2
  import nock from 'nock';
3
- import { GraphQLSchemaModule } from 'apollo-graphql';
4
3
  import gql from 'graphql-tag';
5
4
  import { buildSubgraphSchema } from '@apollo/subgraph';
6
5
  import { ApolloServer } from 'apollo-server';
@@ -14,6 +13,8 @@ import { Plugin, Config, Refs } from 'pretty-format';
14
13
  import { Report, Trace } from 'apollo-reporting-protobuf';
15
14
  import { fixtures } from 'apollo-federation-integration-testsuite';
16
15
  import { nockAfterEach, nockBeforeEach } from '../nockAssertions';
16
+ import { GraphQLSchemaModule } from '../../schema-helper';
17
+ import resolvable, { Resolvable } from '@josephg/resolvable';
17
18
 
18
19
  // Normalize specific fields that change often (eg timestamps) to static values,
19
20
  // to make snapshot testing viable. (If these helpers are more generally
@@ -90,19 +91,16 @@ describe('reporting', () => {
90
91
  let backendServers: ApolloServer[];
91
92
  let gatewayServer: ApolloServer;
92
93
  let gatewayUrl: string;
93
- let reportPromise: Promise<any>;
94
+ let reportPromise: Resolvable<any>;
94
95
 
95
96
  beforeEach(async () => {
96
- let reportResolver: (report: any) => void;
97
- reportPromise = new Promise<any>((resolve) => {
98
- reportResolver = resolve;
99
- });
97
+ reportPromise = resolvable();
100
98
 
101
99
  nockBeforeEach();
102
100
  nock('https://usage-reporting.api.apollographql.com')
103
101
  .post('/api/ingress/traces')
104
102
  .reply(200, (_: any, requestBody: string) => {
105
- reportResolver(requestBody);
103
+ reportPromise.resolve(requestBody);
106
104
  return 'ok';
107
105
  });
108
106
 
@@ -234,6 +232,34 @@ describe('reporting', () => {
234
232
  "tracesPerQuery": Object {
235
233
  "# -
236
234
  {me{name{first last}}topProducts{name}}": Object {
235
+ "referencedFieldsByType": Object {
236
+ "Name": Object {
237
+ "fieldNames": Array [
238
+ "first",
239
+ "last",
240
+ ],
241
+ "isInterface": false,
242
+ },
243
+ "Product": Object {
244
+ "fieldNames": Array [
245
+ "name",
246
+ ],
247
+ "isInterface": true,
248
+ },
249
+ "Query": Object {
250
+ "fieldNames": Array [
251
+ "me",
252
+ "topProducts",
253
+ ],
254
+ "isInterface": false,
255
+ },
256
+ "User": Object {
257
+ "fieldNames": Array [
258
+ "name",
259
+ ],
260
+ "isInterface": false,
261
+ },
262
+ },
237
263
  "trace": Array [
238
264
  Object {
239
265
  "cachePolicy": Object {
@@ -241,7 +267,6 @@ describe('reporting', () => {
241
267
  "scope": "PRIVATE",
242
268
  },
243
269
  "clientName": "",
244
- "clientReferenceId": "",
245
270
  "clientVersion": "",
246
271
  "details": Object {},
247
272
  "durationNs": 12345,
@@ -249,6 +274,7 @@ describe('reporting', () => {
249
274
  "nanos": 123000000,
250
275
  "seconds": "1562203363",
251
276
  },
277
+ "fieldExecutionWeight": 1,
252
278
  "forbiddenOperation": false,
253
279
  "fullQueryCacheHit": false,
254
280
  "http": Object {