Skip to content

Commit

Permalink
Capture sentry error if there is an empty/corrupt vault, and handle m…
Browse files Browse the repository at this point in the history
…ore possible empty/corrupt vault types
  • Loading branch information
danjm committed Nov 15, 2024
1 parent 660065a commit 70e6191
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 7 deletions.
72 changes: 68 additions & 4 deletions app/scripts/lib/Stores/ExtensionStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,28 +118,92 @@ describe('ExtensionStore', () => {
get: jest
.fn()
.mockImplementation(() =>
Promise.resolve({ appState: { test: true } }),
Promise.resolve({ data: { test: true } }),
),
} as unknown as browser.Storage.LocalStorageArea,
});

await localStore.get();

expect(localStore.mostRecentRetrievedState).toStrictEqual({
appState: { test: true },
data: { test: true },
});
});

it('should reset mostRecentRetrievedState to null if storage.local is empty', async () => {
it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local is an empty object', async () => {
const localStore = setup({
localMock: {
get: jest.fn().mockImplementation(() => Promise.resolve({})),
} as unknown as browser.Storage.LocalStorageArea,
});

await localStore.get();
const result = await localStore.get();

expect(result).toStrictEqual({
data: { config: {} },
meta: { version: 0 },
});

expect(localStore.mostRecentRetrievedState).toStrictEqual(null);
expect(localStore.stateCorruptionDetected).toStrictEqual(true);
});

it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local returns undefined', async () => {
const localStore = setup({
localMock: {
get: jest.fn().mockImplementation(() => Promise.resolve()),
} as unknown as browser.Storage.LocalStorageArea,
});

const result = await localStore.get();

expect(result).toStrictEqual({
data: { config: {} },
meta: { version: 0 },
});

expect(localStore.mostRecentRetrievedState).toStrictEqual(null);
expect(localStore.stateCorruptionDetected).toStrictEqual(true);
});

it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local returns an object without a data property', async () => {
const localStore = setup({
localMock: {
get: jest
.fn()
.mockImplementation(() => Promise.resolve({ foo: 'bar' })),
} as unknown as browser.Storage.LocalStorageArea,
});

const result = await localStore.get();

expect(result).toStrictEqual({
data: { config: {} },
meta: { version: 0 },
});

expect(localStore.mostRecentRetrievedState).toStrictEqual(null);
expect(localStore.stateCorruptionDetected).toStrictEqual(true);
});

it('should return default state, reset mostRecentRetrievedState to null, and set stateCorruptionDetected to true, if storage.local returns an object with an undefined data property', async () => {
const localStore = setup({
localMock: {
get: jest
.fn()
.mockImplementation(() => Promise.resolve({ data: undefined })),
} as unknown as browser.Storage.LocalStorageArea,
});

const result = await localStore.get();

expect(result).toStrictEqual({
data: { config: {} },
meta: { version: 0 },
});

expect(localStore.mostRecentRetrievedState).toStrictEqual(null);
expect(localStore.stateCorruptionDetected).toStrictEqual(true);
});

it('should set mostRecentRetrievedState to current state if isExtensionInitialized is true', async () => {
Expand Down
10 changes: 7 additions & 3 deletions app/scripts/lib/Stores/ExtensionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
EmptyState,
} from './BaseStore';

const { sentry } = global;

/**
* Returns whether or not the given object contains no keys
*
Expand Down Expand Up @@ -112,18 +114,20 @@ export class ExtensionStore extends BaseStore {
* which will not be persisted. This should probably be a bug that we
* report to sentry.
*
* TODO: Investigate what happens in this case and log sentry report.
*/
if (!this.isSupported) {
return this.generateFirstTimeState();
}
try {
const result = await this.#get();
const result = await this.#get();
// extension.storage.local always returns an obj
// if the object is empty, treat it as undefined
if (isEmpty(result)) {
if (!result?.data) {
this.mostRecentRetrievedState = null;
this.stateCorruptionDetected = true;

sentry.captureMessage('Empty/corrupted vault found');

// If the data is missing, but we have a record of it existing at some
// point return an empty object, return the fallback state tree from
return this.generateFirstTimeState();
Expand Down

0 comments on commit 70e6191

Please sign in to comment.