Skip to content
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
14 changes: 9 additions & 5 deletions src/apps/main/device/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,16 @@ export type Device = {
};

export async function getDevices(): Promise<Array<Device>> {
const response = await driveServerModule.backup.getDevices();
if (response.isLeft()) {
try {
const response = await driveServerModule.backup.getDevices();
if (response.isLeft()) {
return [];
} else {
const devices = response.getRight();
return devices.filter(({ removed, hasBackups }) => !removed && hasBackups).map((device) => device);
}
} catch {
return [];
} else {
const devices = response.getRight();
return devices.filter(({ removed, hasBackups }) => !removed && hasBackups).map((device) => device);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/apps/renderer/context/DeviceContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function DeviceProvider({ children }: { children: ReactNode }) {
const refreshDevice = () => {
setDeviceState({ status: 'LOADING' });
window.electron.getOrCreateDevice().then(({ error, data: device }) => {
if (error) {
if (error || !device) {
setDeviceState({ status: 'ERROR' });
return;
}
Expand Down
72 changes: 72 additions & 0 deletions src/backend/features/device/getOrCreateDevice.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { getOrCreateDevice } from './getOrCreateDevice';
import { getDeviceIdentifier } from './getDeviceIdentifier';
import { addUnknownDeviceIssue } from './addUnknownDeviceIssue';
import { fetchDevice } from './fetchDevice';
import configStore from '../../../apps/main/config';

vi.mock('./getDeviceIdentifier');
vi.mock('./addUnknownDeviceIssue');
vi.mock('./fetchDevice');
vi.mock('./fetchDeviceLegacyAndMigrate');
vi.mock('./createAndSetupNewDevice');
vi.mock('../../../apps/main/config', () => ({
default: { get: vi.fn() },
}));
vi.mock('../../../apps/shared/dependency-injection/DependencyInjectionUserProvider', () => ({
DependencyInjectionUserProvider: { get: vi.fn(), updateUser: vi.fn() },
}));

describe('getOrCreateDevice', () => {
const mockedGetDeviceIdentifier = vi.mocked(getDeviceIdentifier);
const mockedAddUnknownDeviceIssue = vi.mocked(addUnknownDeviceIssue);
const mockedFetchDevice = vi.mocked(fetchDevice);
const mockedConfigStore = vi.mocked(configStore);

beforeEach(() => {
vi.clearAllMocks();
});

describe('when an unexpected error is thrown', () => {
it('should return the error and call addUnknownDeviceIssue', async () => {
const unexpectedError = new Error('Unexpected failure');
mockedGetDeviceIdentifier.mockImplementation(() => {
throw unexpectedError;
});

const result = await getOrCreateDevice();

expect(result.error).toBe(unexpectedError);
expect(mockedAddUnknownDeviceIssue).toHaveBeenCalledWith(unexpectedError);
});

it('should wrap non-Error throws in an Error instance', async () => {
mockedGetDeviceIdentifier.mockImplementation(() => {
throw 'something went wrong';
});

const result = await getOrCreateDevice();

expect(result.error).toBeInstanceOf(Error);
expect(result.error?.message).toBe('Unexpected error in getOrCreateDevice');
expect(mockedAddUnknownDeviceIssue).toHaveBeenCalledWith(result.error);
});

it('should return the error when fetchDevice throws', async () => {
mockedGetDeviceIdentifier.mockReturnValue({
data: { key: 'key', platform: 'linux', hostname: 'host' },
});
mockedConfigStore.get.mockImplementation((key: string) => {
if (key === 'deviceId') return -1;
if (key === 'deviceUUID') return '';
return undefined;
});
const fetchError = new Error('Network error');
mockedFetchDevice.mockRejectedValue(fetchError);

const result = await getOrCreateDevice();

expect(result.error).toBe(fetchError);
expect(mockedAddUnknownDeviceIssue).toHaveBeenCalledWith(fetchError);
});
});
});
57 changes: 34 additions & 23 deletions src/backend/features/device/getOrCreateDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,40 @@ async function handleFetchDeviceResult(deviceResult: Result<Device, Error>) {
}

export async function getOrCreateDevice(): Promise<Result<Device, Error>> {
const { error, data } = getDeviceIdentifier();
if (error) return { error };

const legacyId = configStore.get('deviceId');
const savedUUID = configStore.get('deviceUUID');
logger.debug({
tag: 'BACKUPS',
msg: '[DEVICE] Checking saved device identifiers',
legacyId,
savedUUID,
});

const hasLegacyId = legacyId !== -1;
const hasUuid = savedUUID !== '';
if (!hasLegacyId && !hasUuid) {
const result = await fetchDevice({ deviceIdentifier: data });
return await handleFetchDeviceResult(result);
}
try {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could add a test for that

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

const { error, data } = getDeviceIdentifier();
if (error) return { error };

const legacyId = configStore.get('deviceId');
const savedUUID = configStore.get('deviceUUID');
logger.debug({
tag: 'BACKUPS',
msg: '[DEVICE] Checking saved device identifiers',
legacyId,
savedUUID,
});

/* eventually, this whole if section is going to be replaced
when all the users naturaly migrated to the new identification mechanism */
const prop = hasUuid ? { uuid: savedUUID } : { legacyId: legacyId.toString() };
const hasLegacyId = legacyId !== -1;
const hasUuid = savedUUID !== '';
if (!hasLegacyId && !hasUuid) {
const result = await fetchDevice({ deviceIdentifier: data });
return await handleFetchDeviceResult(result);
}

const deviceResult = await fetchDeviceLegacyAndMigrate(prop);
return await handleFetchDeviceResult(deviceResult);
/* eventually, this whole if section is going to be replaced
when all the users naturaly migrated to the new identification mechanism */
const prop = hasUuid ? { uuid: savedUUID } : { legacyId: legacyId.toString() };

const deviceResult = await fetchDeviceLegacyAndMigrate(prop);
return await handleFetchDeviceResult(deviceResult);
} catch (error) {
const unknownError = error instanceof Error ? error : new Error('Unexpected error in getOrCreateDevice');
logger.error({
tag: 'BACKUPS',
msg: '[DEVICE] Unexpected error in getOrCreateDevice',
error: unknownError,
});
addUnknownDeviceIssue(unknownError);
return { error: unknownError };
}
}
Loading