mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 09:23:21 +01:00
Introduce action metrics for mv3 service worker restart (#18346)
* fix dapp interaction e2e test * wip * add sentry post request mock * fix console errors * fix scripting console error and remove e2e test unnecessary check * clean up * remove e2e test * stop skipping test * fixing build mv3 job * fixing unit tests * fixing unit tests * fixing unit tests * update coverages * revert skip mv3 e2e test * remove IN_TEST on the npm script * remove console.log * revert aria label changes * revert aria label changes * revert permission changes * revert permission changes * implement sw restart delay tracking * fix rebase
This commit is contained in:
parent
18a21ca57e
commit
fbd68d4a3f
@ -556,6 +556,10 @@ export function setupController(initState, initLangCode, overrides) {
|
||||
if (message.name === WORKER_KEEP_ALIVE_MESSAGE) {
|
||||
// To test un-comment this line and wait for 1 minute. An error should be shown on MetaMask UI.
|
||||
remotePort.postMessage({ name: ACK_KEEP_ALIVE_MESSAGE });
|
||||
|
||||
controller.appStateController.setServiceWorkerLastActiveTime(
|
||||
Date.now(),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ export default class AppStateController extends EventEmitter {
|
||||
'0x5': true,
|
||||
'0x539': true,
|
||||
},
|
||||
serviceWorkerLastActiveTime: 0,
|
||||
});
|
||||
this.timer = null;
|
||||
|
||||
@ -362,4 +363,10 @@ export default class AppStateController extends EventEmitter {
|
||||
getCurrentPopupId() {
|
||||
return this.store.getState().currentPopupId;
|
||||
}
|
||||
|
||||
setServiceWorkerLastActiveTime(serviceWorkerLastActiveTime) {
|
||||
this.store.updateState({
|
||||
serviceWorkerLastActiveTime,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ import { isMain, isFlask } from '../../shared/constants/environment';
|
||||
// eslint-disable-next-line import/order
|
||||
import { DesktopController } from '@metamask/desktop/dist/controllers/desktop';
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
import { ACTION_QUEUE_METRICS_E2E_TEST } from '../../shared/constants/test-flags';
|
||||
import {
|
||||
onMessageReceived,
|
||||
checkForMultipleVersionsRunning,
|
||||
@ -695,6 +696,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.keyringController.memStore.subscribe((state) =>
|
||||
this._onKeyringControllerUpdate(state),
|
||||
);
|
||||
|
||||
this.keyringController.on('unlock', () => this._onUnlock());
|
||||
this.keyringController.on('lock', () => this._onLock());
|
||||
|
||||
@ -1190,6 +1192,25 @@ export default class MetamaskController extends EventEmitter {
|
||||
},
|
||||
);
|
||||
|
||||
if (isManifestV3 && globalThis.isFirstTimeProfileLoaded === false) {
|
||||
const { serviceWorkerLastActiveTime } =
|
||||
this.appStateController.store.getState();
|
||||
const metametricsPayload = {
|
||||
category: EVENT.SOURCE.SERVICE_WORKERS,
|
||||
event: EVENT_NAMES.SERVICE_WORKER_RESTARTED,
|
||||
properties: {
|
||||
service_worker_restarted_time:
|
||||
Date.now() - serviceWorkerLastActiveTime,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
this.metaMetricsController.trackEvent(metametricsPayload);
|
||||
} catch (e) {
|
||||
log.warn('Failed to track service worker restart metric:', e);
|
||||
}
|
||||
}
|
||||
|
||||
this.metamaskMiddleware = createMetamaskMiddleware({
|
||||
static: {
|
||||
eth_syncing: false,
|
||||
@ -2627,7 +2648,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
try {
|
||||
// Automatic login via config password
|
||||
const password = process.env.CONF?.PASSWORD;
|
||||
if (password) {
|
||||
if (password && !process.env.IN_TEST) {
|
||||
await this.submitPassword(password);
|
||||
}
|
||||
// Automatic login via storage encryption key
|
||||
@ -2960,6 +2981,13 @@ export default class MetamaskController extends EventEmitter {
|
||||
* @returns {} keyState
|
||||
*/
|
||||
async addNewAccount(accountCount) {
|
||||
const isActionMetricsQueueE2ETest =
|
||||
this.appStateController.store.getState()[ACTION_QUEUE_METRICS_E2E_TEST];
|
||||
|
||||
if (process.env.IN_TEST && isActionMetricsQueueE2ETest) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 5_000));
|
||||
}
|
||||
|
||||
const [primaryKeyring] = this.keyringController.getKeyringsByType(
|
||||
KeyringType.hdKeyTree,
|
||||
);
|
||||
|
@ -21,6 +21,7 @@
|
||||
"build:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build test",
|
||||
"build:test:flask": "yarn build test --build-type flask",
|
||||
"build:test:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build test",
|
||||
"build:test:dev:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build:dev testDev --apply-lavamoat=false",
|
||||
"test": "yarn lint && yarn test:unit && yarn test:unit:jest",
|
||||
"dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080",
|
||||
"dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'",
|
||||
@ -32,6 +33,7 @@
|
||||
"test:unit:mocha": "node ./test/run-unit-tests.js --mocha",
|
||||
"test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js",
|
||||
"test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps",
|
||||
"test:e2e:chrome:mv3": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mv3",
|
||||
"test:e2e:firefox": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js",
|
||||
"test:e2e:firefox:snaps": "SELENIUM_BROWSER=firefox node test/e2e/run-all.js --snaps",
|
||||
"test:e2e:single": "node test/e2e/run-e2e-test.js",
|
||||
|
@ -374,6 +374,7 @@ export const EVENT_NAMES = {
|
||||
ONBOARDING_WALLET_IMPORT_ATTEMPTED: 'Wallet Import Attempted',
|
||||
ONBOARDING_WALLET_VIDEO_PLAY: 'SRP Intro Video Played',
|
||||
ONBOARDING_TWITTER_CLICK: 'External Link Clicked',
|
||||
SERVICE_WORKER_RESTARTED: 'Service Worker Restarted',
|
||||
};
|
||||
|
||||
export const EVENT = {
|
||||
@ -447,6 +448,7 @@ export const EVENT = {
|
||||
DAPP: 'dapp',
|
||||
USER: 'user',
|
||||
},
|
||||
SERVICE_WORKERS: 'service_workers',
|
||||
},
|
||||
LOCATION: {
|
||||
TOKEN_DETAILS: 'token_details',
|
||||
|
1
shared/constants/test-flags.js
Normal file
1
shared/constants/test-flags.js
Normal file
@ -0,0 +1 @@
|
||||
export const ACTION_QUEUE_METRICS_E2E_TEST = 'action_queue_metrics_e2e_test';
|
@ -4,6 +4,9 @@ const {
|
||||
} = require('@metamask/snaps-utils');
|
||||
const { merge } = require('lodash');
|
||||
const { CHAIN_IDS } = require('../../shared/constants/network');
|
||||
const {
|
||||
ACTION_QUEUE_METRICS_E2E_TEST,
|
||||
} = require('../../shared/constants/test-flags');
|
||||
const { SMART_CONTRACTS } = require('./seeder/smart-contracts');
|
||||
|
||||
function defaultFixture() {
|
||||
@ -309,6 +312,7 @@ function onboardingFixture() {
|
||||
[CHAIN_IDS.GOERLI]: true,
|
||||
[CHAIN_IDS.LOCALHOST]: true,
|
||||
},
|
||||
[ACTION_QUEUE_METRICS_E2E_TEST]: false,
|
||||
},
|
||||
NetworkController: {
|
||||
networkId: '1337',
|
||||
|
@ -12,6 +12,7 @@ describe('MV3 - Dapp interactions', function () {
|
||||
balance: convertToHexValue(25000000000000000000),
|
||||
},
|
||||
],
|
||||
concurrent: { port: 8546, chainId: 1338 },
|
||||
};
|
||||
it('should continue to support dapp interactions after service worker re-start', async function () {
|
||||
await withFixtures(
|
||||
|
@ -428,10 +428,6 @@ class Driver {
|
||||
const artifactDir = `./test-artifacts/${this.browser}/${title}`;
|
||||
const filepathBase = `${artifactDir}/test-failure`;
|
||||
await fs.mkdir(artifactDir, { recursive: true });
|
||||
const isPageError = await this.isElementPresent('.error-page__details');
|
||||
if (isPageError) {
|
||||
await this.clickElement('.error-page__details');
|
||||
}
|
||||
const screenshot = await this.driver.takeScreenshot();
|
||||
await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, {
|
||||
encoding: 'base64',
|
||||
@ -482,20 +478,22 @@ class Driver {
|
||||
// 4Byte
|
||||
'Failed to load resource: the server responded with a status of 502 (Bad Gateway)',
|
||||
];
|
||||
|
||||
const { errors } = this;
|
||||
const cdpConnection = await this.driver.createCDPConnection('page');
|
||||
await this.driver.onLogEvent(cdpConnection, (event) => {
|
||||
if (event.type === 'error') {
|
||||
const eventDescription = event.args.filter(
|
||||
const eventDescriptions = event.args.filter(
|
||||
(err) => err.description !== undefined,
|
||||
);
|
||||
const [{ description }] = eventDescription;
|
||||
|
||||
const [eventDescription] = eventDescriptions;
|
||||
const ignore = ignoredErrorMessages.some((message) =>
|
||||
description.includes(message),
|
||||
eventDescription?.description.includes(message),
|
||||
);
|
||||
if (!ignore) {
|
||||
errors.push(description);
|
||||
logBrowserError(failOnConsoleError, description);
|
||||
errors.push(eventDescription?.description);
|
||||
logBrowserError(failOnConsoleError, eventDescription?.description);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -41,6 +41,7 @@ describe('ActionQueue', () => {
|
||||
expect(background.backgroundFunction.called).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('submitRequestToBackground', () => {
|
||||
it('calls promisified background method if the stream is connected', async () => {
|
||||
const background = {
|
||||
@ -74,6 +75,7 @@ describe('ActionQueue', () => {
|
||||
readable: false,
|
||||
},
|
||||
backgroundFunction3: sinon.stub().yields(),
|
||||
trackMetaMetricsEvent: sinon.stub().yields(),
|
||||
};
|
||||
_setBackgroundConnection(background);
|
||||
const requestPromise = submitRequestToBackground('backgroundFunction3');
|
||||
@ -133,6 +135,7 @@ describe('ActionQueue', () => {
|
||||
trace.secondStarted = Date.now();
|
||||
setTimeout(() => cb(null, 'second'), 10);
|
||||
},
|
||||
trackMetaMetricsEvent: sinon.stub().yields(),
|
||||
};
|
||||
_setBackgroundConnection(background);
|
||||
const scheduled = Promise.all([
|
||||
@ -159,6 +162,7 @@ describe('ActionQueue', () => {
|
||||
trace.secondStarted = Date.now();
|
||||
setTimeout(() => cb(null, 'second'), 10);
|
||||
},
|
||||
trackMetaMetricsEvent: sinon.stub().yields(),
|
||||
};
|
||||
_setBackgroundConnection(background);
|
||||
const scheduled = Promise.all([
|
||||
@ -189,6 +193,7 @@ describe('ActionQueue', () => {
|
||||
trace.secondStarted = Date.now();
|
||||
setTimeout(() => cb(null, 'second'), 10);
|
||||
},
|
||||
trackMetaMetricsEvent: sinon.stub().yields(),
|
||||
};
|
||||
_setBackgroundConnection(background);
|
||||
const scheduled = Promise.all([
|
||||
@ -217,6 +222,7 @@ describe('ActionQueue', () => {
|
||||
}, 5);
|
||||
},
|
||||
second: sinon.stub().yields(),
|
||||
trackMetaMetricsEvent: sinon.stub().yields(),
|
||||
};
|
||||
_setBackgroundConnection(background);
|
||||
const scheduled = Promise.race([
|
||||
@ -251,6 +257,7 @@ describe('ActionQueue', () => {
|
||||
setTimeout(() => cb(null, 'second'), 10);
|
||||
},
|
||||
third: sinon.stub().yields(),
|
||||
trackMetaMetricsEvent: sinon.stub().yields(),
|
||||
};
|
||||
flowControl.triggerRaceCondition = () => {
|
||||
flowControl.waitFor = submitRequestToBackground('third');
|
||||
|
@ -1,5 +1,8 @@
|
||||
import pify from 'pify';
|
||||
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
|
||||
import { isManifestV3 } from '../../../shared/modules/mv3.utils';
|
||||
import { trackMetaMetricsEvent } from '../actions';
|
||||
|
||||
// // A simplified pify maybe?
|
||||
// function pify(apiObject) {
|
||||
// return Object.keys(apiObject).reduce((promisifiedAPI, key) => {
|
||||
@ -187,6 +190,20 @@ async function processActionRetryQueue() {
|
||||
}
|
||||
processingQueue = true;
|
||||
try {
|
||||
if (actionRetryQueue.length > 0) {
|
||||
const metametricsPayload = {
|
||||
category: EVENT.SOURCE.SERVICE_WORKERS,
|
||||
event: EVENT_NAMES.SERVICE_WORKER_RESTARTED,
|
||||
properties: {
|
||||
service_worker_action_queue_methods: actionRetryQueue.map(
|
||||
(action) => action.request.method,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
trackMetaMetricsEvent(metametricsPayload);
|
||||
}
|
||||
|
||||
while (
|
||||
background?.connectionStream.readable &&
|
||||
actionRetryQueue.length > 0
|
||||
|
Loading…
Reference in New Issue
Block a user