Skip to content

Commit

Permalink
(HP-2023) Reject old stored queus
Browse files Browse the repository at this point in the history
The queue is used/updated rapidly. If the queue has not been updated for 2 minutes, the user has done something to stop it manually etc. The stored queue should not be used.
  • Loading branch information
NikoHelle committed Oct 20, 2023
1 parent 321f713 commit 1964721
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 13 deletions.
38 changes: 29 additions & 9 deletions src/common/actionQueue/__tests__/useActionQueue.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { fireEvent, render, waitFor } from '@testing-library/react';
import { QueueState, useActionQueue } from '../useActionQueue';
import {
ActionSourceForTesting,
cloneArray,
pickUpdateActionProps,
rejectingActionSource,
resolvingActionSource1,
Expand Down Expand Up @@ -38,10 +39,12 @@ describe('useActionQueue', () => {
resetButton: 'reset-button',
};

const createActionProps = (props: ActionSourceForTesting) =>
createActionWithTriggerableExecutor(props);
const createActionProps = (props: ActionSourceForTesting) => ({
...createActionWithTriggerableExecutor(props),
result: `Result for action ${props.type}`,
});

const getSuccessfulQueue = () => [
const getSuccessfulQueueWithResult = () => [
{
...createActionProps(resolvingActionSource1),
},
Expand All @@ -50,7 +53,7 @@ describe('useActionQueue', () => {
},
];

const getFailingQueue = () => [
const getFailingQueueWithResult = () => [
{
...createActionProps(resolvingActionSource1),
},
Expand All @@ -65,7 +68,8 @@ describe('useActionQueue', () => {
const TestUseActionQueueHook = (props: TestComponentProps = {}) => {
const { fail, storageKey } = props;
const queue = useMemo(
() => (fail ? getFailingQueue() : getSuccessfulQueue()),
() =>
fail ? getFailingQueueWithResult() : getSuccessfulQueueWithResult(),
[fail]
);
const [renderCount, rerender] = useState(0);
Expand Down Expand Up @@ -381,7 +385,7 @@ describe('useActionQueue', () => {
});
});
it('Merges the queue from storage when a storageKey is passed.', async () => {
const queueInStorage = createQueueFromProps(getSuccessfulQueue());
const queueInStorage = createQueueFromProps(getSuccessfulQueueWithResult());
queueInStorage[0].complete = true;
queueInStorage[0].result = '100';
queueInStorage[1].complete = true;
Expand All @@ -396,8 +400,24 @@ describe('useActionQueue', () => {
]);
expect(getNextActionType()).toBeUndefined();
});
it('Discards stored queue if it is older than 2 minutes.', async () => {
const queueInComponent = createQueueFromProps(
getSuccessfulQueueWithResult()
);
const queueInStorage = cloneArray(queueInComponent);
queueInStorage[0].updatedAt = Date.now() - 60 * 1000 * 2 - 1;
queueInStorage[0].result = 'this should not be set';
storeQueue(queueStorageKey, queueInStorage);
const { getQueue } = renderTestComponent({
storageKey: queueStorageKey,
});
expect(getQueue()).toMatchObject([
pickUpdateActionProps(queueInComponent[0], true, false, true),
pickUpdateActionProps(queueInComponent[1], true, false, true),
]);
});
it('Action.active are set to "false" even if stored value is "true" ', async () => {
const queueInStorage = createQueueFromProps(getSuccessfulQueue());
const queueInStorage = createQueueFromProps(getSuccessfulQueueWithResult());
queueInStorage[0].active = true;
queueInStorage[1].active = true;
storeQueue(queueStorageKey, queueInStorage);
Expand Down Expand Up @@ -453,7 +473,7 @@ describe('useActionQueue', () => {
});
});
it('Does not merge stored queue if actions do not match', async () => {
const queue = getSuccessfulQueue();
const queue = getSuccessfulQueueWithResult();
const queueInStorage = createQueueFromProps([queue[1], queue[0]]);
queueInStorage[0].complete = true;
queueInStorage[0].result = '100';
Expand All @@ -478,7 +498,7 @@ describe('useActionQueue', () => {
expect(getNextActionType()).toBe(resolvingActionSource1.type);
});
it('Initial state reflects merged queues', async () => {
const queueInStorage = createQueueFromProps(getSuccessfulQueue());
const queueInStorage = createQueueFromProps(getSuccessfulQueueWithResult());
queueInStorage[0].complete = true;
queueInStorage[1].complete = true;
queueInStorage[1].errorMessage = 'error';
Expand Down
1 change: 1 addition & 0 deletions src/common/actionQueue/mock.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const setStoredState = (
return {
...action,
...overrides,
updatedAt: Date.now(),
};
});
storeQueue(storageKey, createQueueFromProps(queue));
Expand Down
6 changes: 4 additions & 2 deletions src/common/actionQueue/test.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,15 @@ export function getFailingQueue(extraProps?: Partial<Action>[]): InitialQueue {
export function pickUpdateActionProps(
action: Partial<Action>,
addType = true,
filterUndefined = true
filterUndefined = true,
ignoreUpdatedAt = false
): Partial<ActionUpdateProps> & { type?: ActionType } {
const { complete, active, result, errorMessage, updatedAt, type } = action;
return {
complete,
active,
updatedAt,
// when comparing two identical queues created at different times, the 'updatedAt' will not match.
...(!ignoreUpdatedAt && { updatedAt }),
...(addType && { type }),
// json strigify drops "undefined" values, so those props are not present in parsed objects
...(!filterUndefined && typeof result !== 'undefined' && { result }),
Expand Down
11 changes: 9 additions & 2 deletions src/common/actionQueue/useActionQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
createActionQueueRunner,
isGenericError,
} from './actionQueueRunner';
import { getStoredQueue, storeQueue } from './actionQueueStorage';
import { StoredQueue, getStoredQueue, storeQueue } from './actionQueueStorage';

export type QueueState = {
lastActionType: ActionType | undefined;
Expand Down Expand Up @@ -65,6 +65,10 @@ export function useActionQueue(
}
return storeQueue(storageKey, queue);
},
verifyQueueIsCurrent: (queue: StoredQueue) => {
const { updatedAt } = queue[0];
return Date.now() - updatedAt < 2 * 60 * 1000;
},
};

const getNewState = (
Expand Down Expand Up @@ -107,7 +111,10 @@ export function useActionQueue(
if (!storedQueue) {
return primaryQueue;
}
if (!verifyQueuesMatch(primaryQueue, storedQueue)) {
if (
!verifyQueuesMatch(primaryQueue, storedQueue) ||
!storageFunctions.verifyQueueIsCurrent(storedQueue)
) {
return primaryQueue;
}
return mergeQueues(primaryQueue, storedQueue).map(props => {
Expand Down

0 comments on commit 1964721

Please sign in to comment.