Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
proximity and outbreak test (#1716)
Browse files Browse the repository at this point in the history
  • Loading branch information
timarney authored Jun 21, 2021
1 parent b1ef8ff commit 28c745b
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 52 deletions.
55 changes: 3 additions & 52 deletions src/screens/exposureHistory/ExposureHistoryScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React, {useCallback, useState} from 'react';
import {StyleSheet, Alert} from 'react-native';
import {useI18n, I18n} from 'locale';
import {
CombinedExposureHistoryData,
ExposureType,
getNonIgnoredFromHistoryOutbreakHistory,
OutbreakHistoryItem,
OutbreakSeverity,
} from 'shared/qr';
import {useI18n} from 'locale';
import {getNonIgnoredFromHistoryOutbreakHistory} from 'shared/qr';
import {useNavigation} from '@react-navigation/native';
import {Box, Text, ToolbarWithClose, Button} from 'components';
import {SafeAreaView} from 'react-native-safe-area-context';
Expand All @@ -16,7 +10,6 @@ import {useOutbreakService} from 'services/OutbreakService';
import {getCurrentDate} from 'shared/date-fns';
import {
useDisplayExposureHistory,
ProximityExposureHistoryItem,
useClearExposedStatus,
useExposureStatus,
} from 'services/ExposureNotificationService';
Expand All @@ -25,49 +18,7 @@ import {FilteredMetricsService, EventTypeMetric} from 'services/MetricsService';

import {ExposureList} from './views/ExposureList';
import {NoExposureHistoryScreen} from './views/NoExposureHistoryScreen';

const severityText = ({severity, i18n}: {severity: OutbreakSeverity; i18n: I18n}) => {
switch (severity) {
case OutbreakSeverity.SelfIsolate:
return i18n.translate('QRCode.OutbreakExposed.SelfIsolate.Title');
case OutbreakSeverity.SelfMonitor:
return i18n.translate('QRCode.OutbreakExposed.SelfMonitor.Title');
}
};

const toOutbreakExposureHistoryData = ({
history,
i18n,
}: {
history: OutbreakHistoryItem[];
i18n: I18n;
}): CombinedExposureHistoryData[] => {
return history.map(outbreak => {
return {
exposureType: ExposureType.Outbreak,
subtitle: severityText({severity: Number(outbreak.severity), i18n}),
notificationTimestamp: outbreak.notificationTimestamp,
historyItem: outbreak,
};
});
};

const toProximityExposureHistoryData = ({
proximityExposureHistory,
i18n,
}: {
proximityExposureHistory: ProximityExposureHistoryItem[];
i18n: I18n;
}): CombinedExposureHistoryData[] => {
return proximityExposureHistory.map(item => {
return {
exposureType: ExposureType.Proximity,
subtitle: i18n.translate('QRCode.ProximityExposure'),
notificationTimestamp: item.notificationTimestamp,
historyItem: item,
};
});
};
import {toOutbreakExposureHistoryData, toProximityExposureHistoryData} from './utils';

export const ExposureHistoryScreenState = {
exposureHistoryClearedDate: getCurrentDate(),
Expand Down
46 changes: 46 additions & 0 deletions src/screens/exposureHistory/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {CombinedExposureHistoryData, ExposureType, OutbreakHistoryItem, OutbreakSeverity} from 'shared/qr';
import {ProximityExposureHistoryItem} from 'services/ExposureNotificationService';
import {I18n} from 'locale';

const severityText = ({severity, i18n}: {severity: OutbreakSeverity; i18n: I18n}) => {
switch (severity) {
case OutbreakSeverity.SelfIsolate:
return i18n.translate('QRCode.OutbreakExposed.SelfIsolate.Title');
case OutbreakSeverity.SelfMonitor:
return i18n.translate('QRCode.OutbreakExposed.SelfMonitor.Title');
}
};

export const toOutbreakExposureHistoryData = ({
history,
i18n,
}: {
history: OutbreakHistoryItem[];
i18n: I18n;
}): CombinedExposureHistoryData[] => {
return history.map(outbreak => {
return {
exposureType: ExposureType.Outbreak,
subtitle: severityText({severity: Number(outbreak.severity), i18n}),
notificationTimestamp: outbreak.notificationTimestamp,
historyItem: outbreak,
};
});
};

export const toProximityExposureHistoryData = ({
proximityExposureHistory,
i18n,
}: {
proximityExposureHistory: ProximityExposureHistoryItem[];
i18n: I18n;
}): CombinedExposureHistoryData[] => {
return proximityExposureHistory.map(item => {
return {
exposureType: ExposureType.Proximity,
subtitle: i18n.translate('QRCode.ProximityExposure'),
notificationTimestamp: item.notificationTimestamp,
historyItem: item,
};
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import {
ProximityExposureHistoryItem,
} from '../ExposureNotificationService';
import {HOURS_PER_PERIOD} from '../../../shared/config';
// eslint-disable-next-line @shopify/strict-component-boundaries
import {checkIns, toSeconds, subtractHours, addHours} from '../../OutbreakService/tests/utils';
import {OutbreakService} from '../../OutbreakService';
import {toOutbreakExposureHistoryData, toProximityExposureHistoryData} from '../../../screens/exposureHistory/utils';

jest.mock('react-native-permissions', () => {
return {checkNotifications: jest.fn().mockReturnValue(Promise.reject()), requestNotifications: jest.fn()};
Expand Down Expand Up @@ -83,6 +87,7 @@ const bridge: any = {
getTemporaryExposureKeyHistory: jest.fn().mockResolvedValue({}),
getStatus: jest.fn().mockResolvedValue('active'),
getPendingExposureSummary: jest.fn().mockResolvedValue(undefined),
retrieveOutbreakEvents: jest.fn(),
};

const storageService: StorageService = {
Expand Down Expand Up @@ -1229,6 +1234,98 @@ describe('ExposureNotificationService', () => {
expect(displayExposureHistoryItems).toHaveLength(0);
});

//

it('recent exposures handles outbreak and proximity exposures', async () => {
MockDate.set('2021-02-01T12:00Z');

const storage = new StorageServiceMock();

// create a new EN service using the StorageServiceMock so we can check the saved values
const enService = new ExposureNotificationService(server, i18n, storage, bridge, filteredMetricsService);

// create Outbreak service using the same storage
const outbreakService = new OutbreakService(i18n, bridge, storage, [], []);

jest.spyOn(outbreakService, 'extractOutbreakEventsFromZipFiles').mockImplementation(async () => {
return outbreakService.convertOutbreakEvents([
{
locationId: checkIns[0].id,
startTime: {seconds: toSeconds(subtractHours(checkIns[0].timestamp, 12))},
endTime: {seconds: toSeconds(addHours(checkIns[0].timestamp, 12))},
severity: 1,
},
]);
});

const period = periodSinceEpoch(today, HOURS_PER_PERIOD);
const nextSummary = {
daysSinceLastExposure: 7,
lastExposureTimestamp: today.getTime() - 7 * 3600 * 24 * 1000,
matchedKeyCount: 1,
maximumRiskScore: 1,
attenuationDurations: [1200, 0, 0],
};
bridge.detectExposure.mockResolvedValueOnce([nextSummary]);
enService.exposureStatus.set({
type: ExposureStatusType.Monitoring,
lastChecked: {
period,
timestamp: today.getTime() - PERIODIC_TASK_INTERVAL_IN_MINUTES * 60 * 1000 - 3600 * 1000,
},
});

await enService.updateExposureStatus();

// ensure we have an exposed item
expect(enService.exposureStatus.get()).toStrictEqual(
expect.objectContaining({
type: ExposureStatusType.Exposed,
summary: nextSummary,
}),
);

const displayExposureHistoryItems: ProximityExposureHistoryItem[] = enService.displayExposureHistory.get();

expect(displayExposureHistoryItems[0]).toStrictEqual(
expect.objectContaining({
isIgnoredFromHistory: false,
isExpired: false,
}),
);

expect(displayExposureHistoryItems).toHaveLength(1);

jest.spyOn(outbreakService, 'extractOutbreakEventsFromZipFiles').mockImplementation(async () => {
return outbreakService.convertOutbreakEvents([
{
locationId: checkIns[0].id,
startTime: {seconds: toSeconds(subtractHours(checkIns[0].timestamp, 2))},
endTime: {seconds: toSeconds(addHours(checkIns[0].timestamp, 4))},
severity: 1,
},
]);
});

// setup an outbreak
await outbreakService.addCheckIn(checkIns[0]);
await outbreakService.addCheckIn(checkIns[1]);
await outbreakService.checkForOutbreaks();

const outbreakHistory = outbreakService.outbreakHistory.get();
expect(outbreakHistory).toHaveLength(1);

// combine the history as it would be for ExposureHistoryScreen
const mergedArray = [
...toOutbreakExposureHistoryData({history: outbreakHistory, i18n}),
...toProximityExposureHistoryData({proximityExposureHistory: displayExposureHistoryItems, i18n}),
];

expect(mergedArray).toHaveLength(2);
expect(mergedArray[0].exposureType).toStrictEqual('outbreak');
expect(mergedArray[1].exposureType).toStrictEqual('proximity');
});

describe('testing metrics component', () => {
it('updateExposureStatusInBackground publishes BackgroundProcess metric with succeeded state set to true if process has finished successfully', async () => {
await service.updateExposureStatusInBackground();
Expand Down

0 comments on commit 28c745b

Please sign in to comment.