Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-9824 - PubSub Connection state tracking for AppSyncRealtime #10063

Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
87ad8f8
feat: Add connection health state monitoring structure
stocaaro Jul 1, 2022
2b8823c
feat: AppSync realtime connection monitoring
stocaaro Jul 1, 2022
6134eb5
feat: AppSync realtime connection monitor test integration
stocaaro Jul 6, 2022
e8f54a8
fix: Include missed changes
stocaaro Jul 6, 2022
e677c04
fix: Restructure Hub dispatch
stocaaro Jul 6, 2022
3ed74f2
Merge branch 'aws-amplify:main' into GH-9824/pubsub/connection-state-…
stocaaro Jul 6, 2022
43dece9
fix: Remove print statement
stocaaro Jul 6, 2022
050a7a2
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 8, 2022
78b0516
fix: PR comment updates
stocaaro Jul 11, 2022
eb11b57
fix: Found more overlooked health state refactoring
stocaaro Jul 13, 2022
cd04b3a
fix: Found even more overlooked health state refactoring
stocaaro Jul 13, 2022
615c0ac
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 15, 2022
03295c0
fix: Enum connection states, record based changes and other minor cha…
stocaaro Jul 19, 2022
0ba9536
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 19, 2022
0bc54bd
fix: State variable naming and related comments for clarity
stocaaro Jul 21, 2022
d1e3cc8
fix: Comment line length
stocaaro Jul 21, 2022
b6f3f0b
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 21, 2022
38ee498
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
elorzafe Jul 22, 2022
995b67f
fix: Update network monitor subscription management and name changes …
stocaaro Jul 26, 2022
abd7509
fix: Private function name change
stocaaro Jul 27, 2022
a1022c3
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 27, 2022
386564d
fix: Network monitoring only active when the connection is intended t…
stocaaro Jul 29, 2022
7233a2a
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 29, 2022
a3f62fa
Merge branch 'main' into GH-9824/pubsub/connection-state-02-realtime-…
stocaaro Jul 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 175 additions & 60 deletions packages/pubsub/__tests__/AWSAppSyncRealTimeProvider.test.ts

Large diffs are not rendered by default.

227 changes: 227 additions & 0 deletions packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
* Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/

jest.mock('@aws-amplify/core', () => ({
__esModule: true,
...jest.requireActual('@aws-amplify/core'),
browserOrNode() {
return {
isBrowser: true,
isNode: false,
};
},
}));

import Observable from 'zen-observable-ts';
import { Reachability } from '@aws-amplify/core';
import {
ConnectionStateMonitor,
CONNECTION_CHANGE,
} from '../src/utils/ConnectionStateMonitor';
import { ConnectionState as CS } from '../src';

describe('ConnectionStateMonitor', () => {
let monitor: ConnectionStateMonitor;
let observedStates: CS[];
let subscription: ZenObservable.Subscription;
let reachabilityObserver: ZenObservable.Observer<{ online: boolean }>;

beforeEach(() => {
const spyon = jest
.spyOn(Reachability.prototype, 'networkMonitor')
.mockImplementationOnce(
() =>
new Observable(observer => {
reachabilityObserver = observer;
})
);
});

describe('when the network is connected', () => {
beforeEach(() => {
reachabilityObserver?.next?.({ online: true });

observedStates = [];
subscription?.unsubscribe();
monitor = new ConnectionStateMonitor();
subscription = monitor.connectionStateObservable.subscribe(value => {
observedStates.push(value);
});
});

test('connection states starts out disconnected', () => {
expect(observedStates).toEqual(['Disconnected']);
});

test('standard states connection pattern', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
expect(observedStates).toEqual([
CS.Disconnected,
CS.Connecting,
CS.Connected,
]);
});

test('connection states when the network is lost while connected', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
reachabilityObserver?.next?.({ online: false });
expect(observedStates).toEqual([
CS.Disconnected,
CS.Connecting,
CS.Connected,
CS.ConnectedPendingNetwork,
]);
});

test('connection states when the network is lost and the connection times out', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
reachabilityObserver?.next?.({ online: false });
monitor.record(CONNECTION_CHANGE.CLOSED);
expect(observedStates).toEqual([
CS.Disconnected,
CS.Connecting,
CS.Connected,
CS.ConnectedPendingNetwork,
CS.ConnectionDisruptedPendingNetwork,
]);
});

test('connection states when the network is lost, the connection times out and then the network recovers', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
reachabilityObserver?.next?.({ online: false });
monitor.record(CONNECTION_CHANGE.CLOSED);
reachabilityObserver?.next?.({ online: true });
expect(observedStates).toEqual([
CS.Disconnected,
CS.Connecting,
CS.Connected,
CS.ConnectedPendingNetwork,
CS.ConnectionDisruptedPendingNetwork,
CS.ConnectionDisrupted,
]);
});

test('connection states when a connection is no longer needed', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
monitor.record(CONNECTION_CHANGE.CLOSING);

expect(observedStates).toEqual([
CS.Disconnected,
CS.Connecting,
CS.Connected,
CS.ConnectedPendingDisconnect,
]);
});

test('connection states when a connection is no longer needed closed', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
monitor.record(CONNECTION_CHANGE.CLOSING);
monitor.record(CONNECTION_CHANGE.CLOSED);

expect(observedStates).toEqual([
CS.Disconnected,
CS.Connecting,
CS.Connected,
CS.ConnectedPendingDisconnect,
CS.Disconnected,
]);
});

test('connection states when a connection misses a keepalive, and then recovers', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE);

expect(observedStates).toEqual([
'Disconnected',
'Connecting',
'Connected',
'ConnectedPendingKeepAlive',
'Connected',
]);
});

test('lots of keep alive messages dont add more connection state events', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE);

expect(observedStates).toEqual([
'Disconnected',
'Connecting',
'Connected',
]);
});

test('missed keep alives during a network outage dont add an additional state change', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
reachabilityObserver?.next?.({ online: false });
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);

expect(observedStates).toEqual([
'Disconnected',
'Connecting',
'Connected',
'ConnectedPendingNetwork',
]);
});

test('when the network recovers, keep alives become the concern until one is seen', () => {
monitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
monitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
reachabilityObserver?.next?.({ online: false });
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
reachabilityObserver?.next?.({ online: true });
monitor.record(CONNECTION_CHANGE.KEEP_ALIVE);

expect(observedStates).toEqual([
'Disconnected',
'Connecting',
'Connected',
'ConnectedPendingNetwork',
'ConnectedPendingKeepAlive',
'Connected',
]);
});
});

describe('when the network is disconnected', () => {
beforeEach(() => {
reachabilityObserver?.next?.({ online: false });

observedStates = [];
subscription?.unsubscribe();
monitor = new ConnectionStateMonitor();
subscription = monitor.connectionStateObservable.subscribe(value => {
observedStates.push(value);
});
});

test('starts out disconnected', () => {
expect(observedStates).toEqual(['Disconnected']);
});
});
});
11 changes: 11 additions & 0 deletions packages/pubsub/__tests__/PubSub-unit-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
jest.mock('@aws-amplify/core', () => ({
__esModule: true,
...jest.requireActual('@aws-amplify/core'),
browserOrNode() {
return {
isBrowser: true,
isNode: false,
};
},
}));

import { PubSubClass as PubSub } from '../src/PubSub';
import {
MqttOverWSProvider,
Expand Down
Loading