-
Notifications
You must be signed in to change notification settings - Fork 242
/
serviceListShim.test.ts
158 lines (131 loc) 路 4.52 KB
/
serviceListShim.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import nock from 'nock';
import {
fixtures,
fixturesWithUpdate,
} from 'apollo-federation-integration-testsuite';
import { RemoteGraphQLDataSource, ServiceEndpointDefinition } from '../..';
import { ServiceListShim } from '../serviceListShim';
import { mockAllServicesSdlQuerySuccess } from '../../__tests__/integration/nockMocks';
import { wait, waitUntil } from '../../__tests__/execution-utils';
describe('ServiceListShim', () => {
beforeEach(() => {
if (!nock.isActive()) nock.activate();
});
afterEach(async () => {
expect(nock.isDone()).toBeTruthy();
nock.cleanAll();
nock.restore();
});
it('constructs', () => {
expect(
() =>
new ServiceListShim({
serviceList: fixtures,
}),
).not.toThrow();
});
it('is instance callable (simulating the gateway calling it)', async () => {
mockAllServicesSdlQuerySuccess();
const shim = new ServiceListShim({ serviceList: fixtures });
await expect(
shim({ async update() {}, async healthCheck() {} }),
).resolves.toBeTruthy();
});
function getDataSourceSpy(definition: ServiceEndpointDefinition) {
const datasource = new RemoteGraphQLDataSource({
url: definition.url,
});
const processSpy = jest.fn(datasource.process);
datasource.process = processSpy;
return { datasource, processSpy };
}
it('uses `GraphQLDataSource`s provided by the `buildService` function', async () => {
mockAllServicesSdlQuerySuccess();
const processSpies: jest.Mock[] = [];
const shim = new ServiceListShim({
serviceList: fixtures,
buildService(def) {
const { datasource, processSpy } = getDataSourceSpy(def);
processSpies.push(processSpy);
return datasource;
},
});
await shim({ async update() {}, async healthCheck() {} });
expect(processSpies.length).toBe(fixtures.length);
for (const processSpy of processSpies) {
expect(processSpy).toHaveBeenCalledTimes(1);
}
});
it('polls services when a `pollInterval` is set and stops when `cleanup` is called', async () => {
// This is mocked 4 times to include the initial load (followed by 3 polls)
// We need to alternate schemas, else the update will be ignored
mockAllServicesSdlQuerySuccess();
mockAllServicesSdlQuerySuccess(fixturesWithUpdate);
mockAllServicesSdlQuerySuccess();
mockAllServicesSdlQuerySuccess(fixturesWithUpdate);
const [p1, r1] = waitUntil();
const [p2, r2] = waitUntil();
const [p3, r3] = waitUntil();
// `update` (below) is called each time we poll (and there's an update to
// the supergraph), so this is a reasonable hook into "when" the poll
// happens and drives this test cleanly with `Promise`s.
const updateSpy = jest
.fn()
.mockImplementationOnce(() => r1())
.mockImplementationOnce(() => r2())
.mockImplementationOnce(() => r3());
const shim = new ServiceListShim({
serviceList: fixtures,
pollIntervalInMs: 10,
});
const { cleanup } = await shim({
async update(supergraphSdl) {
updateSpy(supergraphSdl);
},
async healthCheck() {},
});
await Promise.all([p1, p2, p3]);
expect(updateSpy).toHaveBeenCalledTimes(3);
// stop polling
await cleanup!();
expect(updateSpy).toHaveBeenCalledTimes(3);
// ensure we cancelled the timer
// @ts-ignore
expect(shim.timerRef).toBe(null);
});
// TODO: useFakeTimers (though I'm struggling to get this to work as expected)
it("doesn't call `update` when there's no change to the supergraph", async () => {
const fetcher =
jest.requireActual<typeof import('apollo-server-env')>(
'apollo-server-env',
).fetch;
// mock for initial load and a few polls against an unchanging schema
mockAllServicesSdlQuerySuccess();
mockAllServicesSdlQuerySuccess();
mockAllServicesSdlQuerySuccess();
mockAllServicesSdlQuerySuccess();
const shim = new ServiceListShim({
serviceList: fixtures,
pollIntervalInMs: 100,
buildService(service) {
return new RemoteGraphQLDataSource({
url: service.url,
fetcher,
});
},
});
const updateSpy = jest.fn();
const { cleanup } = await shim({
async update(supergraphSdl) {
updateSpy(supergraphSdl);
},
async healthCheck() {},
});
// let the shim poll through all the active mocks
while (nock.activeMocks().length > 0) {
await wait(0);
}
await cleanup!();
expect(updateSpy).not.toHaveBeenCalled();
});
});