Skip to content

Commit b02577d

Browse files
authored
release(required): Amplify JS release (#13971)
2 parents f2248ad + e0fdeb7 commit b02577d

File tree

28 files changed

+2728
-1228
lines changed

28 files changed

+2728
-1228
lines changed

.github/CODEOWNERS

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,24 @@
1313

1414
# The following paths involve server-side use cases, token/user session management.
1515
# Changes made to these paths requires additional reviews and approvals.
16-
/packages/auth @haverchuck @cshfang @jimblanc @HuiSF
17-
/packages/aws-amplify/src/adapter-core @haverchuck @cshfang @jimblanc @HuiSF
18-
/packages/core/src/adapterCore @haverchuck @cshfang @jimblanc @HuiSF
19-
/packages/core/src/singleton @haverchuck @cshfang @jimblanc @HuiSF
20-
/packages/core/src/utils/convert @haverchuck @cshfang @jimblanc @HuiSF
21-
/packages/core/src/utils/WordArray.ts @haverchuck @cshfang @jimblanc @HuiSF
22-
/packages/core/src/storage @haverchuck @cshfang @jimblanc @HuiSF
23-
/packages/core/src/utils/generateRandomString.ts @haverchuck @cshfang @jimblanc @HuiSF
24-
/packages/core/src/utils/globalHelpers @haverchuck @cshfang @jimblanc @HuiSF
25-
/packages/core/src/utils/urlSafeDecode.ts @haverchuck @cshfang @jimblanc @HuiSF
26-
/packages/core/src/awsClients/cognitoIdentity @haverchuck @cshfang @jimblanc @HuiSF
27-
/packages/core/src/clients/internal @haverchuck @cshfang @jimblanc @HuiSF
28-
/packages/core/src/Hub @haverchuck @cshfang @jimblanc @HuiSF
29-
/packages/adapter-nextjs @haverchuck @cshfang @jimblanc @HuiSF
30-
/packages/rtn-web-browser @haverchuck @cshfang @jimblanc @HuiSF
31-
/packages/storage/src/providers/s3/apis/internal @haverchuck @cshfang @jimblanc @HuiSF
32-
/packages/storage/src/providers/s3/apis/server @haverchuck @cshfang @jimblanc @HuiSF
33-
/packages/api-rest/src/apis/server.ts @haverchuck @cshfang @jimblanc @HuiSF
34-
/packages/api-rest/src/apis/common/internalPost.ts @haverchuck @cshfang @jimblanc @HuiSF
35-
/packages/api-graphql/src/server @haverchuck @cshfang @jimblanc @HuiSF
36-
/packages/api-graphql/src/internals/server @haverchuck @cshfang @jimblanc @HuiSF
16+
/packages/auth @haverchuck @cshfang @HuiSF @pranavosu
17+
/packages/aws-amplify/src/adapter-core @haverchuck @cshfang @HuiSF @pranavosu
18+
/packages/core/src/adapterCore @haverchuck @cshfang @HuiSF @pranavosu
19+
/packages/core/src/singleton @haverchuck @cshfang @HuiSF @pranavosu
20+
/packages/core/src/utils/convert @haverchuck @cshfang @HuiSF @pranavosu
21+
/packages/core/src/utils/WordArray.ts @haverchuck @cshfang @HuiSF @pranavosu
22+
/packages/core/src/storage @haverchuck @cshfang @HuiSF @pranavosu
23+
/packages/core/src/utils/generateRandomString.ts @haverchuck @cshfang @HuiSF @pranavosu
24+
/packages/core/src/utils/globalHelpers @haverchuck @cshfang @HuiSF @pranavosu
25+
/packages/core/src/utils/urlSafeDecode.ts @haverchuck @cshfang @HuiSF @pranavosu
26+
/packages/core/src/awsClients/cognitoIdentity @haverchuck @cshfang @HuiSF @pranavosu
27+
/packages/core/src/clients/internal @haverchuck @cshfang @HuiSF @pranavosu
28+
/packages/core/src/Hub @haverchuck @cshfang @HuiSF @pranavosu
29+
/packages/adapter-nextjs @haverchuck @cshfang @HuiSF @pranavosu
30+
/packages/rtn-web-browser @haverchuck @cshfang @HuiSF @pranavosu
31+
/packages/storage/src/providers/s3/apis/internal @haverchuck @cshfang @HuiSF @pranavosu
32+
/packages/storage/src/providers/s3/apis/server @haverchuck @cshfang @HuiSF @pranavosu
33+
/packages/api-rest/src/apis/server.ts @haverchuck @cshfang @HuiSF @pranavosu
34+
/packages/api-rest/src/apis/common/internalPost.ts @haverchuck @cshfang @HuiSF @pranavosu
35+
/packages/api-graphql/src/server @haverchuck @cshfang @HuiSF @pranavosu
36+
/packages/api-graphql/src/internals/server @haverchuck @cshfang @HuiSF @pranavosu
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { Observable, Observer } from 'rxjs';
2+
import { Reachability } from '@aws-amplify/core/internals/utils';
3+
import { ConsoleLogger } from '@aws-amplify/core';
4+
import { MESSAGE_TYPES } from '../src/Providers/constants';
5+
import * as constants from '../src/Providers/constants';
6+
7+
import { delay, FakeWebSocketInterface } from './helpers';
8+
import { ConnectionState as CS } from '../src/types/PubSub';
9+
10+
import { AWSAppSyncEventProvider } from '../src/Providers/AWSAppSyncEventsProvider';
11+
12+
describe('AppSyncEventProvider', () => {
13+
describe('subscribe()', () => {
14+
describe('returned observer', () => {
15+
describe('connection logic with mocked websocket', () => {
16+
let fakeWebSocketInterface: FakeWebSocketInterface;
17+
const loggerSpy: jest.SpyInstance = jest.spyOn(
18+
ConsoleLogger.prototype,
19+
'_log',
20+
);
21+
22+
let provider: AWSAppSyncEventProvider;
23+
let reachabilityObserver: Observer<{ online: boolean }>;
24+
25+
beforeEach(async () => {
26+
// Set the network to "online" for these tests
27+
jest
28+
.spyOn(Reachability.prototype, 'networkMonitor')
29+
.mockImplementationOnce(() => {
30+
return new Observable(observer => {
31+
reachabilityObserver = observer;
32+
});
33+
})
34+
// Twice because we subscribe to get the initial state then again to monitor reachability
35+
.mockImplementationOnce(() => {
36+
return new Observable(observer => {
37+
reachabilityObserver = observer;
38+
});
39+
});
40+
41+
fakeWebSocketInterface = new FakeWebSocketInterface();
42+
provider = new AWSAppSyncEventProvider();
43+
44+
// Saving this spy and resetting it by hand causes badness
45+
// Saving it causes new websockets to be reachable across past tests that have not fully closed
46+
// Resetting it proactively causes those same past tests to be dealing with null while they reach a settled state
47+
jest
48+
.spyOn(provider as any, '_getNewWebSocket')
49+
.mockImplementation(() => {
50+
fakeWebSocketInterface.newWebSocket();
51+
return fakeWebSocketInterface.webSocket as WebSocket;
52+
});
53+
54+
// Reduce retry delay for tests to 100ms
55+
Object.defineProperty(constants, 'MAX_DELAY_MS', {
56+
value: 100,
57+
});
58+
// Reduce retry delay for tests to 100ms
59+
Object.defineProperty(constants, 'RECONNECT_DELAY', {
60+
value: 100,
61+
});
62+
});
63+
64+
afterEach(async () => {
65+
provider?.close();
66+
await fakeWebSocketInterface?.closeInterface();
67+
fakeWebSocketInterface?.teardown();
68+
loggerSpy.mockClear();
69+
});
70+
71+
test('subscription observer error is triggered when a connection is formed and a non-retriable connection_error data message is received', async () => {
72+
expect.assertions(3);
73+
74+
const socketCloseSpy = jest.spyOn(
75+
fakeWebSocketInterface.webSocket,
76+
'close',
77+
);
78+
fakeWebSocketInterface.webSocket.readyState = WebSocket.OPEN;
79+
80+
const observer = provider.subscribe({
81+
appSyncGraphqlEndpoint: 'ws://localhost:8080',
82+
});
83+
84+
observer.subscribe({
85+
error: e => {
86+
expect(e.errors[0].message).toEqual(
87+
'Connection failed: UnauthorizedException',
88+
);
89+
},
90+
});
91+
92+
await fakeWebSocketInterface?.readyForUse;
93+
await fakeWebSocketInterface?.triggerOpen();
94+
95+
// Resolve the message delivery actions
96+
await Promise.resolve(
97+
fakeWebSocketInterface?.sendDataMessage({
98+
type: MESSAGE_TYPES.GQL_CONNECTION_ERROR,
99+
errors: [
100+
{
101+
errorType: 'UnauthorizedException', // - non-retriable
102+
errorCode: 401,
103+
},
104+
],
105+
}),
106+
);
107+
108+
// Watching for raised exception to be caught and logged
109+
expect(loggerSpy).toHaveBeenCalledWith(
110+
'DEBUG',
111+
expect.stringContaining('error on bound '),
112+
expect.objectContaining({
113+
message: expect.stringMatching('UnauthorizedException'),
114+
}),
115+
);
116+
117+
await delay(1);
118+
119+
expect(socketCloseSpy).toHaveBeenCalledWith(3001);
120+
});
121+
122+
test('subscription observer error is not triggered when a connection is formed and a retriable connection_error data message is received', async () => {
123+
expect.assertions(2);
124+
125+
const observer = provider.subscribe({
126+
appSyncGraphqlEndpoint: 'ws://localhost:8080',
127+
});
128+
129+
observer.subscribe({
130+
error: x => {},
131+
});
132+
133+
const openSocketAttempt = async () => {
134+
await fakeWebSocketInterface?.readyForUse;
135+
await fakeWebSocketInterface?.triggerOpen();
136+
137+
// Resolve the message delivery actions
138+
await Promise.resolve(
139+
fakeWebSocketInterface?.sendDataMessage({
140+
type: MESSAGE_TYPES.GQL_CONNECTION_ERROR,
141+
errors: [
142+
{
143+
errorType: 'Retriable Test',
144+
errorCode: 408, // Request timed out - retriable
145+
},
146+
],
147+
}),
148+
);
149+
await fakeWebSocketInterface?.resetWebsocket();
150+
};
151+
152+
// Go through two connection attempts to excercise backoff and retriable raise
153+
await openSocketAttempt();
154+
await openSocketAttempt();
155+
156+
// Watching for raised exception to be caught and logged
157+
expect(loggerSpy).toHaveBeenCalledWith(
158+
'DEBUG',
159+
expect.stringContaining('error on bound '),
160+
expect.objectContaining({
161+
message: expect.stringMatching('Retriable Test'),
162+
}),
163+
);
164+
165+
await fakeWebSocketInterface?.waitUntilConnectionStateIn([
166+
CS.ConnectionDisrupted,
167+
]);
168+
169+
expect(loggerSpy).toHaveBeenCalledWith(
170+
'DEBUG',
171+
'Connection failed: Retriable Test',
172+
);
173+
});
174+
});
175+
});
176+
});
177+
});

packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { ConnectionState as CS } from '../src/types/PubSub';
1313

1414
import { AWSAppSyncRealTimeProvider } from '../src/Providers/AWSAppSyncRealTimeProvider';
15+
import { isCustomDomain } from '../src/Providers/AWSWebSocketProvider/appsyncUrl';
1516

1617
// Mock all calls to signRequest
1718
jest.mock('@aws-amplify/core/internals/aws-client-utils', () => {
@@ -20,7 +21,7 @@ jest.mock('@aws-amplify/core/internals/aws-client-utils', () => {
2021
);
2122
return {
2223
...original,
23-
signRequest: (_request, _options) => {
24+
signRequest: (_request: any, _options: any) => {
2425
return {
2526
method: 'test',
2627
headers: { test: 'test' },
@@ -46,7 +47,7 @@ jest.mock('@aws-amplify/core', () => {
4647
};
4748
return {
4849
...original,
49-
fetchAuthSession: (_request, _options) => {
50+
fetchAuthSession: (_request: any, _options: any) => {
5051
return Promise.resolve(session);
5152
},
5253
Amplify: {
@@ -66,24 +67,19 @@ jest.mock('@aws-amplify/core', () => {
6667
describe('AWSAppSyncRealTimeProvider', () => {
6768
describe('isCustomDomain()', () => {
6869
test('Custom domain returns `true`', () => {
69-
const provider = new AWSAppSyncRealTimeProvider();
70-
const result = (provider as any).isCustomDomain(
71-
'https://unit-test.testurl.com/graphql',
72-
);
70+
const result = isCustomDomain('https://unit-test.testurl.com/graphql');
7371
expect(result).toBe(true);
7472
});
7573

7674
test('Non-custom domain returns `false`', () => {
77-
const provider = new AWSAppSyncRealTimeProvider();
78-
const result = (provider as any).isCustomDomain(
75+
const result = isCustomDomain(
7976
'https://12345678901234567890123456.appsync-api.us-west-2.amazonaws.com/graphql',
8077
);
8178
expect(result).toBe(false);
8279
});
8380

8481
test('Non-custom domain in the amazonaws.com.cn subdomain space returns `false`', () => {
85-
const provider = new AWSAppSyncRealTimeProvider();
86-
const result = (provider as any).isCustomDomain(
82+
const result = isCustomDomain(
8783
'https://12345678901234567890123456.appsync-api.cn-north-1.amazonaws.com.cn/graphql',
8884
);
8985
expect(result).toBe(false);
@@ -136,10 +132,12 @@ describe('AWSAppSyncRealTimeProvider', () => {
136132
// Saving this spy and resetting it by hand causes badness
137133
// Saving it causes new websockets to be reachable across past tests that have not fully closed
138134
// Resetting it proactively causes those same past tests to be dealing with null while they reach a settled state
139-
jest.spyOn(provider, 'getNewWebSocket').mockImplementation(() => {
140-
fakeWebSocketInterface.newWebSocket();
141-
return fakeWebSocketInterface.webSocket as WebSocket;
142-
});
135+
jest
136+
.spyOn(provider as any, '_getNewWebSocket')
137+
.mockImplementation(() => {
138+
fakeWebSocketInterface.newWebSocket();
139+
return fakeWebSocketInterface.webSocket as WebSocket;
140+
});
143141

144142
// Reduce retry delay for tests to 100ms
145143
Object.defineProperty(constants, 'MAX_DELAY_MS', {
@@ -228,7 +226,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
228226
expect.assertions(1);
229227

230228
const newSocketSpy = jest
231-
.spyOn(provider, 'getNewWebSocket')
229+
.spyOn(provider as any, '_getNewWebSocket')
232230
.mockImplementation(() => {
233231
fakeWebSocketInterface.newWebSocket();
234232
return fakeWebSocketInterface.webSocket as WebSocket;
@@ -254,7 +252,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
254252
expect.assertions(1);
255253

256254
const newSocketSpy = jest
257-
.spyOn(provider, 'getNewWebSocket')
255+
.spyOn(provider as any, '_getNewWebSocket')
258256
.mockImplementation(() => {
259257
fakeWebSocketInterface.newWebSocket();
260258
return fakeWebSocketInterface.webSocket as WebSocket;
@@ -280,7 +278,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
280278
expect.assertions(1);
281279

282280
const newSocketSpy = jest
283-
.spyOn(provider, 'getNewWebSocket')
281+
.spyOn(provider as any, '_getNewWebSocket')
284282
.mockImplementation(() => {
285283
fakeWebSocketInterface.newWebSocket();
286284
return fakeWebSocketInterface.webSocket as WebSocket;
@@ -307,7 +305,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
307305
expect.assertions(1);
308306

309307
const newSocketSpy = jest
310-
.spyOn(provider, 'getNewWebSocket')
308+
.spyOn(provider as any, '_getNewWebSocket')
311309
.mockImplementation(() => {
312310
fakeWebSocketInterface.newWebSocket();
313311
return fakeWebSocketInterface.webSocket;
@@ -349,7 +347,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
349347
expect.assertions(1);
350348

351349
const newSocketSpy = jest
352-
.spyOn(provider, 'getNewWebSocket')
350+
.spyOn(provider as any, '_getNewWebSocket')
353351
.mockImplementation(() => {
354352
fakeWebSocketInterface.newWebSocket();
355353
return fakeWebSocketInterface.webSocket;
@@ -545,7 +543,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
545543
await fakeWebSocketInterface?.standardConnectionHandshake();
546544

547545
await fakeWebSocketInterface?.sendDataMessage({
548-
type: MESSAGE_TYPES.GQL_DATA,
546+
type: MESSAGE_TYPES.DATA,
549547
payload: { data: {} },
550548
});
551549

@@ -571,7 +569,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
571569
connectionTimeoutMs: 100,
572570
});
573571
await fakeWebSocketInterface?.sendDataMessage({
574-
type: MESSAGE_TYPES.GQL_DATA,
572+
type: MESSAGE_TYPES.DATA,
575573
payload: { data: {} },
576574
});
577575

@@ -597,7 +595,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
597595
connectionTimeoutMs: 100,
598596
});
599597
await fakeWebSocketInterface?.sendDataMessage({
600-
type: MESSAGE_TYPES.GQL_DATA,
598+
type: MESSAGE_TYPES.DATA,
601599
payload: { data: {} },
602600
});
603601
expect(mockNext).toHaveBeenCalled();
@@ -677,7 +675,9 @@ describe('AWSAppSyncRealTimeProvider', () => {
677675
}),
678676
);
679677

680-
expect(socketCloseSpy).toHaveBeenNthCalledWith(1, 3001);
678+
await delay(1);
679+
680+
expect(socketCloseSpy).toHaveBeenCalledWith(3001);
681681
});
682682

683683
test('subscription observer error is triggered when a connection is formed', async () => {
@@ -931,7 +931,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
931931

932932
await fakeWebSocketInterface?.standardConnectionHandshake();
933933
await fakeWebSocketInterface?.sendDataMessage({
934-
type: MESSAGE_TYPES.GQL_DATA,
934+
type: MESSAGE_TYPES.DATA,
935935
payload: { data: {} },
936936
});
937937
await subscription.unsubscribe();
@@ -1181,7 +1181,7 @@ describe('AWSAppSyncRealTimeProvider', () => {
11811181
});
11821182

11831183
test('authenticating with AWS_LAMBDA/custom w/ custom header function that accepts request options', async () => {
1184-
expect.assertions(2);
1184+
expect.assertions(3);
11851185

11861186
provider
11871187
.subscribe({

0 commit comments

Comments
 (0)