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

Fix applying onyx updates from push notifications #43056

Merged
merged 4 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function applyOnyxData({reportID, reportActionID, onyxData, lastUpdateID, previo
previousUpdateID,
updates: [
{
eventType: 'eventType',
eventType: '', // This is only needed for Pusher events
data: onyxData,
},
],
Expand Down
1 change: 1 addition & 0 deletions src/libs/PusherUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function subscribeToMultiEvent(eventType: string, callback: Callback) {

function triggerMultiEventHandler(eventType: string, data: OnyxUpdate[]): Promise<void> {
if (!multiEventCallbackMapping[eventType]) {
Log.warn('[PusherUtils] Received unexpected multi-event', {eventType});
return Promise.resolve();
}
return multiEventCallbackMapping[eventType](data);
Expand Down
21 changes: 20 additions & 1 deletion src/libs/actions/OnyxUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Onyx.connect({
// even when such events are received over multiple separate pusher updates.
let pusherEventsPromise = Promise.resolve();

let airshipEventsPromise = Promise.resolve();

function applyHTTPSOnyxUpdates(request: Request, response: Response) {
console.debug('[OnyxUpdateManager] Applying https update');
// For most requests we can immediately update Onyx. For write requests we queue the updates and apply them after the sequential queue has flushed to prevent a replay effect in
Expand Down Expand Up @@ -71,6 +73,20 @@ function applyPusherOnyxUpdates(updates: OnyxUpdateEvent[]) {
return pusherEventsPromise;
}

function applyAirshipOnyxUpdates(updates: OnyxUpdateEvent[]) {
airshipEventsPromise = airshipEventsPromise.then(() => {
console.debug('[OnyxUpdateManager] Applying Airship updates');
});

airshipEventsPromise = updates
.reduce((promise, update) => promise.then(() => Onyx.update(update.data)), airshipEventsPromise)
.then(() => {
console.debug('[OnyxUpdateManager] Done applying Airship updates');
});

return airshipEventsPromise;
}

/**
* @param [updateParams.request] Exists if updateParams.type === 'https'
* @param [updateParams.response] Exists if updateParams.type === 'https'
Expand Down Expand Up @@ -108,9 +124,12 @@ function apply({lastUpdateID, type, request, response, updates}: OnyxUpdatesFrom
if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) {
return applyHTTPSOnyxUpdates(request, response);
}
if ((type === CONST.ONYX_UPDATE_TYPES.PUSHER || type === CONST.ONYX_UPDATE_TYPES.AIRSHIP) && updates) {
if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) {
return applyPusherOnyxUpdates(updates);
}
if (type === CONST.ONYX_UPDATE_TYPES.AIRSHIP && updates) {
return applyAirshipOnyxUpdates(updates);
}
}

/**
Expand Down
79 changes: 79 additions & 0 deletions tests/unit/OnyxUpdatesTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type {KeyValueMapping, OnyxEntry, OnyxKey} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import * as OnyxUpdates from '@src/libs/actions/OnyxUpdates';
import DateUtils from '@src/libs/DateUtils';
import * as NumberUtils from '@src/libs/NumberUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import type {OnyxUpdatesFromServer} from '@src/types/onyx';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';

describe('OnyxUpdatesTest', () => {
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
});
});

beforeEach(() => Onyx.clear().then(waitForBatchedUpdates));

it('applies Airship Onyx updates correctly', () => {
const reportID = NumberUtils.rand64();
const reportActionID = NumberUtils.rand64();
const created = DateUtils.getDBTime();

const reportValue = {reportID};
const reportActionValue = {
[reportActionID]: {
reportActionID,
created,
},
};

// Given an onyx update from an Airship push notification
const airshipUpdates: OnyxUpdatesFromServer = {
type: CONST.ONYX_UPDATE_TYPES.AIRSHIP,
previousUpdateID: 0,
lastUpdateID: 1,
updates: [
{
eventType: '',
data: [
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: reportValue,
},
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: reportActionValue,
shouldShowPushNotification: true,
},
],
},
],
};

// When we apply the updates, then their values are updated correctly
return OnyxUpdates.apply(airshipUpdates)
.then(() => getOnyxValues(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`))
.then(([report, reportAction]) => {
expect(report).toStrictEqual(reportValue);
expect(reportAction).toStrictEqual(reportActionValue);
});
});
});

function getOnyxValues<TKey extends OnyxKey>(...keys: TKey[]) {
return Promise.all(keys.map((key) => getOnyxValue(key)));
}

function getOnyxValue<TKey extends OnyxKey>(key: TKey): Promise<OnyxEntry<KeyValueMapping[TKey]>> {
return new Promise((resolve) => {
Onyx.connect({
key,
callback: (value) => resolve(value),
});
});
}
Loading