1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 09:23:21 +01:00

Adding artifacts (#15145)

This commit is contained in:
Jyoti Puri 2022-07-20 19:33:16 +04:00 committed by GitHub
parent df646a03eb
commit 45cecf385d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 9339 additions and 30 deletions

View File

@ -136,6 +136,9 @@ workflows:
- benchmark:
requires:
- prep-build-test
- stats-module-load-init:
requires:
- prep-build-test-mv3
- job-publish-prerelease:
requires:
- prep-deps
@ -143,7 +146,9 @@ workflows:
- prep-build-beta
- prep-build-flask
- prep-build-storybook
- prep-build-test-mv3
- benchmark
- stats-module-load-init
- all-tests-pass
- job-publish-release:
filters:
@ -596,6 +601,40 @@ jobs:
paths:
- test-artifacts
stats-module-load-init:
executor: node-browsers-medium-plus
steps:
- checkout
- run:
name: Re-Install Chrome
command: ./.circleci/scripts/chrome-install.sh
- attach_workspace:
at: .
- run:
name: Move test build to dist
command: mv ./dist-test-mv3 ./dist
- run:
name: Move test zips to builds
command: mv ./builds-test-mv3 ./builds
- run:
name: Run page load benchmark
command: |
mkdir -p test-artifacts/chrome/mv3
cp -R development/charts/flamegraph test-artifacts/chrome/mv3/initialisation
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/background
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/ui
cp -R development/charts/table test-artifacts/chrome/mv3/load_time
- run:
name: Run page load benchmark
command: yarn mv3:stats:chrome --out test-artifacts/chrome/mv3
- store_artifacts:
path: test-artifacts
destination: test-artifacts
- persist_to_workspace:
root: .
paths:
- test-artifacts
job-publish-prerelease:
executor: node-browsers
steps:

View File

@ -8,6 +8,7 @@ module.exports = {
'app/vendor/**',
'builds/**/*',
'development/chromereload.js',
'development/charts/**',
'dist/**/*',
'node_modules/**/*',
],

View File

@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>
<link rel="stylesheet" type="text/css" href="../lib/d3-flamegraph.css" />
<style>
/* Space out content a bit */
body {
padding-top: 20px;
padding-bottom: 20px;
}
/* Custom page header */
.header {
padding-bottom: 20px;
padding-right: 15px;
padding-left: 15px;
border-bottom: 1px solid #e5e5e5;
}
/* Make the masthead heading the same height as the navigation */
.header h3 {
margin-top: 0;
margin-bottom: 0;
line-height: 40px;
}
/* Customize container */
.container {
max-width: 990px;
}
</style>
<title>Performance Measurements</title>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="header clearfix">
<nav>
<div class="pull-right">
<form class="form-inline" id="form">
<a class="btn" href="javascript: resetZoom();">Reset zoom</a>
<a class="btn" href="javascript: clear();">Clear</a>
<div class="form-group">
<input type="text" class="form-control" id="term" />
</div>
<a class="btn btn-primary" href="javascript: search();">Search</a>
</form>
</div>
</nav>
<h3 class="text-muted">d3-flame-graph</h3>
</div>
<div id="chart"></div>
<hr />
<div id="details"></div>
</div>
<!-- D3.js -->
<script src="https://d3js.org/d3.v7.js" charset="utf-8"></script>
<!-- d3-flamegraph -->
<script type="text/javascript" src="../lib/d3-flamegraph.js"></script>
<script
type="text/javascript"
src="../lib/d3-flamegraph-tooltip.js"
></script>
<script type="text/javascript">
var chart = flamegraph()
.width(960)
.cellHeight(18)
.transitionDuration(750)
.minFrameSize(5)
.transitionEase(d3.easeCubic)
.sort(true)
//Example to sort in reverse order
//.sort(function(a,b){ return d3.descending(a.name, b.name);})
.title('')
.onClick(onClick)
.selfValue(false)
.setColorMapper((d, originalColor) =>
d.highlight ? '#6aff8f' : originalColor,
);
// Example on how to use custom a tooltip.
var tip = flamegraph.tooltip
.defaultFlamegraphTooltip()
.text((d) => 'name: ' + d.data.name + ', value: ' + d.data.value);
chart.tooltip(tip);
var details = document.getElementById('details');
chart.setDetailsElement(details);
// Example on how to use searchById() function in flamegraph.
// To invoke this function after loading the graph itself, this function should be registered in d3 datum(data).call()
// (See d3.json invocation in this file)
function invokeFind() {
var searchId = parseInt(location.hash.substring(1), 10);
if (searchId) {
find(searchId);
}
}
// Example on how to use custom labels
// var label = function(d) {
// return "name: " + d.name + ", value: " + d.value;
// }
// chart.label(label);
// Example of how to set fixed chart height
// chart.height(540);
d3.json('stacks.json')
.then((data) => {
d3.select('#chart').datum(data).call(chart).call(invokeFind);
})
.catch((error) => {
return console.warn(error);
});
document
.getElementById('form')
.addEventListener('submit', function (event) {
event.preventDefault();
search();
});
function search() {
var term = document.getElementById('term').value;
chart.search(term);
}
function find(id) {
var elem = chart.findById(id);
if (elem) {
console.log(elem);
chart.zoomTo(elem);
}
}
function clear() {
document.getElementById('term').value = '';
chart.clear();
}
function resetZoom() {
chart.resetZoom();
}
function onClick(d) {
console.info(`Clicked on ${d.data.name}, id: "${d.id}"`);
history.pushState({ id: d.id }, d.data.name, `#${d.id}`);
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
.d3-flame-graph rect {
stroke: #EEEEEE;
fill-opacity: .8;
}
.d3-flame-graph rect:hover {
stroke: #474747;
stroke-width: 0.5;
cursor: pointer;
}
.d3-flame-graph-label {
pointer-events: none;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 12px;
font-family: Verdana;
margin-left: 4px;
margin-right: 4px;
line-height: 1.5;
padding: 0 0 0;
font-weight: 400;
color: black;
text-align: left;
}
.d3-flame-graph .fade {
opacity: 0.6 !important;
}
.d3-flame-graph .title {
font-size: 20px;
font-family: Verdana;
}
.d3-flame-graph-tip {
background-color: black;
border: none;
border-radius: 3px;
padding: 5px 10px 5px 10px;
min-width: 250px;
text-align: left;
color: white;
z-index: 10;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
<html>
<head>
<script type="text/javascript" src="./jquery.min.js"></script>
<style>
table {
border: 1px solid black;
border-collapse: collapse;
}
tr {
border: 1px solid black;
}
</style>
<script>
$(function () {
var loadTime = [];
$.getJSON('stats.json', function (data) {
$.each(data.children, function (index, datum) {
if (datum.name) {
var tblRow =
'<tr>' +
'<td>' +
index +
'</td>' +
'<td>' +
datum.name +
'</td>' +
'<td>' +
datum.value +
'</td>' +
'</tr>';
$(tblRow).appendTo('#loaddata tbody');
}
});
$(
'<tr>' +
'<td>' +
'Total' +
'</td>' +
'<td>' +
'--' +
'</td>' +
'<td>' +
data.value +
'</td>' +
'</tr>',
).appendTo('#loaddata tbody');
});
});
</script>
</head>
<body>
<div class="wrapper">
<div class="profile">
<table id="loaddata">
<thead>
<th>S.No</th>
<th>Name</th>
<th>TotalTime</th>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</body>
</html>

18
development/charts/table/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -94,6 +94,12 @@ async function start() {
// links to bundle browser builds
const depVizUrl = `${BUILD_LINK_BASE}/build-artifacts/build-viz/index.html`;
const depVizLink = `<a href="${depVizUrl}">Build System</a>`;
const moduleInitStatsBackgroundUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/initialisation/background/index.html`;
const moduleInitStatsBackgroundLink = `<a href="${moduleInitStatsBackgroundUrl}">MV3 Background Module Init Stats</a>`;
const moduleInitStatsUIUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/initialisation/ui/index.html`;
const moduleInitStatsUILink = `<a href="${moduleInitStatsUIUrl}">MV3 UI Init Stats</a>`;
const moduleLoadStatsUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/load_time/index.html`;
const moduleLoadStatsLink = `<a href="${moduleLoadStatsUrl}">Module Load Stats</a>`;
// link to artifacts
const allArtifactsUrl = `https://circleci.com/gh/MetaMask/metamask-extension/${CIRCLE_BUILD_NUM}#artifacts/containers/0`;
@ -103,6 +109,9 @@ async function start() {
`builds (beta): ${betaBuildLinks}`,
`builds (flask): ${flaskBuildLinks}`,
`build viz: ${depVizLink}`,
`mv3: ${moduleInitStatsBackgroundLink}`,
`mv3: ${moduleInitStatsUILink}`,
`mv3: ${moduleLoadStatsLink}`,
`code coverage: ${coverageLink}`,
`storybook: ${storybookLink}`,
`<a href="${allArtifactsUrl}">all artifacts</a>`,

View File

@ -1,12 +1,16 @@
#!/usr/bin/env node
const path = require('path');
const { promises: fs, constants: fsConstants } = require('fs');
const { promises: fs } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const ttest = require('ttest');
const { retry } = require('../../development/lib/retry');
const { exitWithError } = require('../../development/lib/exit-with-error');
const {
isWritable,
getFirstParentDirectoryThatExists,
} = require('../helpers/file');
const { withFixtures, tinyDelayMs } = require('./helpers');
const { PAGES } = require('./webdriver/driver');
@ -108,35 +112,6 @@ async function profilePageLoad(pages, numSamples, retries) {
return results;
}
async function isWritable(directory) {
try {
await fs.access(directory, fsConstants.W_OK);
return true;
} catch (error) {
if (error.code !== 'EACCES') {
throw error;
}
return false;
}
}
async function getFirstParentDirectoryThatExists(directory) {
let nextDirectory = directory;
for (;;) {
try {
await fs.access(nextDirectory, fsConstants.F_OK);
return nextDirectory;
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
} else if (nextDirectory === path.dirname(nextDirectory)) {
throw new Error('Failed to find parent directory that exists');
}
nextDirectory = path.dirname(nextDirectory);
}
}
}
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',

111
test/e2e/mv3-stats.js Normal file
View File

@ -0,0 +1,111 @@
#!/usr/bin/env node
/* eslint-disable node/shebang */
const path = require('path');
const { promises: fs } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const { exitWithError } = require('../../development/lib/exit-with-error');
const {
isWritable,
getFirstParentDirectoryThatExists,
} = require('../helpers/file');
const { withFixtures, tinyDelayMs } = require('./helpers');
/**
* The e2e test case is used to capture load and initialisation time statistics for extension in MV3 environment.
*/
async function profilePageLoad() {
const parsedLogs = {};
try {
await withFixtures({ fixtures: 'imported-account' }, async ({ driver }) => {
await driver.delay(tinyDelayMs);
await driver.navigate();
await driver.delay(1000);
const logs = await driver.checkBrowserForLavamoatLogs();
let logString = '';
let logType = '';
logs.forEach((log) => {
if (log.indexOf('"version": 1') >= 0) {
// log end here
logString += log;
parsedLogs[logType] = JSON.parse(`{${logString}}`);
logString = '';
logType = '';
} else if (logType) {
// log string continues
logString += log;
} else if (
log.search(/"name": ".*app\/scripts\/background.js",/u) >= 0
) {
// background log starts
logString += log;
logType = 'background';
} else if (log.search(/"name": ".*app\/scripts\/ui.js",/u) >= 0) {
// ui log starts
logString += log;
logType = 'ui';
} else if (log.search(/"name": "Total"/u) >= 0) {
// load time log starts
logString += log;
logType = 'loadTime';
}
});
});
} catch (error) {
console.log('Error in trying to parse logs.');
}
return parsedLogs;
}
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',
'Run a page load benchmark',
(_yargs) =>
_yargs.option('out', {
description:
'Output filename. Output printed to STDOUT of this is omitted.',
type: 'string',
normalize: true,
}),
);
const results = await profilePageLoad();
const { out } = argv;
const logCategories = [
{ key: 'background', dirPath: 'initialisation/background/stacks.json' },
{ key: 'ui', dirPath: 'initialisation/ui/stacks.json' },
{ key: 'loadTime', dirPath: 'load_time/stats.json' },
];
if (out) {
logCategories.forEach(async ({ key, dirPath }) => {
if (results[key]) {
const outPath = `${out}/${dirPath}`;
const outputDirectory = path.dirname(outPath);
const existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error('Specified output file directory is not writable');
}
if (outputDirectory !== existingParentDirectory) {
await fs.mkdir(outputDirectory, { recursive: true });
}
await fs.writeFile(outPath, JSON.stringify(results[key], null, 2));
}
});
} else {
console.log(JSON.stringify(results, null, 2));
}
}
main().catch((error) => {
exitWithError(error);
});

37
test/helpers/file.js Normal file
View File

@ -0,0 +1,37 @@
/* eslint-disable node/shebang */
const path = require('path');
const { promises: fs, constants: fsConstants } = require('fs');
async function isWritable(directory) {
try {
await fs.access(directory, fsConstants.W_OK);
return true;
} catch (error) {
if (error.code !== 'EACCES') {
throw error;
}
return false;
}
}
async function getFirstParentDirectoryThatExists(directory) {
let nextDirectory = directory;
for (;;) {
try {
await fs.access(nextDirectory, fsConstants.F_OK);
return nextDirectory;
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
} else if (nextDirectory === path.dirname(nextDirectory)) {
throw new Error('Failed to find parent directory that exists');
}
nextDirectory = path.dirname(nextDirectory);
}
}
}
module.exports = {
isWritable,
getFirstParentDirectoryThatExists,
};