Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for running WebPageReplay using non Dockerized runners #79

Merged
merged 4 commits into from
Aug 30, 2024
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
2 changes: 1 addition & 1 deletion testrunner/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const compat = new FlatCompat({

export default [
{
ignores: ['sitespeed-result/*', 'default/*']
ignores: ['sitespeed-result/*', 'default/*', 'wpr/*']
},
...compat.extends('eslint:recommended', 'plugin:unicorn/recommended'),
{
Expand Down
10 changes: 8 additions & 2 deletions testrunner/npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion testrunner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"src",
"package.json",
"npm-shrinkwrap.json",
"config"
"config",
"wpr"
],
"scripts": {
"start": "node ./app.js",
Expand All @@ -58,6 +59,7 @@
"bull": "4.15.1",
"nconf": "0.12.1",
"execa": "9.3.0",
"lodash.get": "4.4.2",
"intel": "1.2.0",
"joi" : "17.13.3",
"js-yaml": "4.1.0"
Expand Down
27 changes: 24 additions & 3 deletions testrunner/src/testrunners/testrunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from 'node:os';
import { execa } from 'execa';
import log from 'intel';
import nconf from 'nconf';
import get from 'lodash.get';

import { queueHandler } from '../queue/queuehandler.js';
import { getBaseFilePath } from '../util.js';
Expand Down Expand Up @@ -116,7 +117,6 @@ function prepareSitespeedConfig(job) {
nconf.get('sitespeedioConfigFile') === undefined
? getBaseFilePath('./config/sitespeedDefault.json')
: path.resolve(nconf.get('sitespeedioConfigFile'));

return jobConfig;
}

Expand All @@ -126,10 +126,31 @@ async function runTest(job, workingDirectory, configFileName, logger) {
workingDirectory,
configFileName
);
const binary = nconf.get('executable');

let binary = nconf.get('executable');
let environment = {};
if (
(job.data.extras && job.data.extras.includes('--webpagereplay')) ||
job.data.config.webpagereplay
) {
binary = './wpr/replay.sh';
environment = {
env: {
ANDROID: true
}
};
const deviceId =
get(job.data.config, 'browsertime.firefox.android.deviceSerial') ||
get(job.data.config, 'browsertime.chrome.android.deviceSerial');

if (deviceId) {
environment.env.DEVICE_SERIAL = deviceId;
}
}

let exitCode = 0;
try {
const process = execa(binary, parameters);
const process = execa(binary, parameters, environment);
process.stdout.on('data', chunk => {
logger.debug(chunk.toString());
job.log(chunk.toString());
Expand Down
70 changes: 70 additions & 0 deletions testrunner/wpr/deterministic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

(function () {
var random_count = 0;
var random_count_threshold = 25;
var random_seed = 0.462;
Math.random = function() {
random_count++;
if (random_count > random_count_threshold){
random_seed += 0.1;
random_count = 1;
}
return (random_seed % 1);
};
if (typeof(crypto) == 'object' &&
typeof(crypto.getRandomValues) == 'function') {
crypto.getRandomValues = function(arr) {
var scale = Math.pow(256, arr.BYTES_PER_ELEMENT);
for (var i = 0; i < arr.length; i++) {
arr[i] = Math.floor(Math.random() * scale);
}
return arr;
};
}
})();
(function () {
var date_count = 0;
var date_count_threshold = 25;
var orig_date = Date;
// Time since epoch in milliseconds. This is replaced by script injector with
// the date when the recording is done.
var time_seed = {{WPR_TIME_SEED_TIMESTAMP}};
Date = function() {
if (this instanceof Date) {
date_count++;
if (date_count > date_count_threshold){
time_seed += 50;
date_count = 1;
}
switch (arguments.length) {
case 0: return new orig_date(time_seed);
case 1: return new orig_date(arguments[0]);
default: return new orig_date(arguments[0], arguments[1],
arguments.length >= 3 ? arguments[2] : 1,
arguments.length >= 4 ? arguments[3] : 0,
arguments.length >= 5 ? arguments[4] : 0,
arguments.length >= 6 ? arguments[5] : 0,
arguments.length >= 7 ? arguments[6] : 0);
}
}
return new Date().toString();
};
Date.__proto__ = orig_date;
Date.prototype = orig_date.prototype;
Date.prototype.constructor = Date;
orig_date.now = function() {
return new Date().getTime();
};
orig_date.prototype.getTimezoneOffset = function() {
var dst2010Start = 1268560800000;
var dst2010End = 1289120400000;
if (this.getTime() >= dst2010Start && this.getTime() < dst2010End)
return 420;
return 480;
};
})();
87 changes: 87 additions & 0 deletions testrunner/wpr/replay.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/bin/bash
set -eu

## Script to run your Android device against WebPageReplay

# You need to install sitespeed.io globally: npm install sitespeed.io -g
BROWSERTIME=sitespeed.io-wpr
SITESPEEDIO=sitespeed.io

# WebPageReplay setup
WPR_BINARY=wpr
WPR_CERT_FILE=./wpr/wpr_cert.pem
WPR_KEY_FILE=./wpr/wpr_key.pem
WPR_SCRIPTS=./wpr/deterministic.js
WPR_HTTP_PORT=8085
WPR_HTTPS_PORT=8086
WPR_ARCHIVE=/tmp/archive.wprgo
WPR_RECORD_LOG=/tmp/wpr-record.log
WPR_REPLAY_LOG=/tmp/wpr-replay.log

# If you want to run the tests on a Android phone, add
RUN_ON_ANDROID=${ANDROID:-false}

# Special setup when yoy run on an Android devic
if [ "$RUN_ON_ANDROID" = true ]
then
FIRST_DEVICE=$(adb devices | grep -v "List" | awk 'NR==1{print $1}')
FIRST_DEVICE=${FIRST_DEVICE:-'no_device'}
if [ "$FIRST_DEVICE" == "no_device" ]
then
echo "Could not find a phone connected to the computer. Try with adb devices"
exit 1
fi

DEVICE_SERIAL=${DEVICE_SERIAL:-$FIRST_DEVICE}

# Reverse the traffic for the android device back to the computer
adb -s "$DEVICE_SERIAL" reverse tcp:"$WPR_HTTP_PORT" tcp:"$WPR_HTTP_PORT"
adb -s "$DEVICE_SERIAL" reverse tcp:"$WPR_HTTPS_PORT" tcp:"$WPR_HTTPS_PORT"
fi

# Parameters used to start WebPageReplay
WPR_PARAMS="--http_port $WPR_HTTP_PORT --https_port $WPR_HTTPS_PORT --https_cert_file $WPR_CERT_FILE --https_key_file $WPR_KEY_FILE --inject_scripts $WPR_SCRIPTS $WPR_ARCHIVE"

# First step is recording your page
declare -i RESULT=0
echo "Start WebPageReplay record"
$WPR_BINARY record $WPR_PARAMS > "$WPR_RECORD_LOG" 2>&1 &
RECORD_PID=$!
RESULT+=$?
sleep 3
"$BROWSERTIME" "$@" --browsertime.chrome.webPageReplayHostResolver --browsertime.chrome.webPageReplayHTTPPort $WPR_HTTP_PORT --browsertime.chrome.webPageReplayHTTPSPort $WPR_HTTPS_PORT --browsertime.chrome.webPageReplayRecord true --browsertime.firefox.preference network.dns.forceResolve:127.0.0.1
RESULT+=$?

kill -2 $RECORD_PID
RESULT+=$?
wait $RECORD_PID
echo 'Stopped WebPageReplay record'

# If everything worked fine, replay the page
if [ $RESULT -eq 0 ]
then
echo 'Start WebPageReplay replay'
"$WPR_BINARY" replay $WPR_PARAMS > "$WPR_REPLAY_LOG" 2>&1 &
REPLAY_PID=$!
if [ $? -eq 0 ]
then
echo 'Run the test against WebPageReplay'
"$SITESPEEDIO" "$@" --browsertime.firefox.preference security.OCSP.enabled:0 --browsertime.firefox.preference network.dns.forceResolve:127.0.0.1 --browsertime.chrome.webPageReplayHostResolver --browsertime.chrome.webPageReplayHTTPPort $WPR_HTTP_PORT --browsertime.chrome.webPageReplayHTTPSPort $WPR_HTTPS_PORT --replay &
SITESPEEDIO_PID=$!
wait $SITESPEEDIO_PID
if kill -0 $REPLAY_PID 2>/dev/null; then
kill -2 $REPLAY_PID
wait $REPLAY_PID
fi
echo 'Stopped WebPageReplay replay'
else
echo "Replay server didn't start correctly, check the logs $WPR_REPLAY_LOG" >&2
fi
else
echo "Recording or accessing the URL failed, will not replay" >&2
fi

if [ "$RUN_ON_ANDROID" = true ]
then
adb -s "$DEVICE_SERIAL" reverse --remove-all
fi
13 changes: 13 additions & 0 deletions testrunner/wpr/wpr_cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIICDDCCAXUCFDpoMKg9jdABK5CDWJvb9ZPgiY0tMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjAwNjE5MTgyODQ4WhcNMjMwMzE2MTgy
ODQ4WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQCyzqGNRDTe/HTLzt97UhJXXWmjxVeKKFySmwqlrBLq5CiY7aB8Z64u
eK4DTi0lODvGkMrVhPc6uhIv3Kiu3ZelKmYmbcJOB1awS+/OnFSpYKT5IXJxvhDH
Q8cvz8jA9/IzbUzTCS4sG8YmajKN742f+PtVy3TYrAFkwy2lnl8ZmwIDAQABMA0G
CSqGSIb3DQEBCwUAA4GBAD4AXGQ7eaIdnnI9SJMkgEJIpJMJNOl4kN/kESMmJE9G
GFJ4oiP6VzXPVMTW4xeqmuIIqX8ZovO8SA+C2e1yqcz6X8WN7EDD0UJVGiru9yaT
C7AbTTK8NsKxKKGzGF6qnnnwtKc8ZIypw4/00yw8vZOwMwLOV+ffvkUX9uW9Ws8z
-----END CERTIFICATE-----
16 changes: 16 additions & 0 deletions testrunner/wpr/wpr_key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALLOoY1ENN78dMvO
33tSElddaaPFV4ooXJKbCqWsEurkKJjtoHxnri54rgNOLSU4O8aQytWE9zq6Ei/c
qK7dl6UqZiZtwk4HVrBL786cVKlgpPkhcnG+EMdDxy/PyMD38jNtTNMJLiwbxiZq
Mo3vjZ/4+1XLdNisAWTDLaWeXxmbAgMBAAECgYAadwLqScIZjvwqfkANnKQiUi0k
lDzUsgyhllkJFGLoaUSo/eLXBvF851e6HYQJEj2msh+TYs7E3m16sAo3d4zOIdnz
VwOF0SVuUveqJz6K1/k6nPxck+dPj8Mi+gBm3Fd0+0wcozjWaxhx3f462HCUb6b+
ZpJRBsbyvzu6rn7iQQJBAOlWhtfL8r9+Kl0vxRD1XukaJwlxPv24JhfKOU4z8WlJ
WX7Wr8ws+xKS+CtfFnjkf/iFJPpTb8jxpQyWMJzYZIkCQQDELE5hGnBFVQArMAOp
VbwYordTrVY3AagO4tDJ6T3a7GEXE28ol16/i02+4FLd65vubL21IuX0exH/eRvZ
Q4wDAkEAub/qyiEOFkjOWq5rd0uNiY0LJGYlWf7dPDT8l3ecJ09/0gv/mE76c9fR
fV1N22EzSlhbjncbVuCenj11Z3aP2QJAILtfzJXzu63GHG6jfcKfYuDrg9u9Mepl
1y4DNl1jg77DKG2Gs5gmKAGfVETrrrmcR/j+4lVTVyqdwym6+tJpbwJBAN3vixxc
5N9pUMDfFnHrx/x9QPd0JgSAT21KSIB+PndlbD7QO6nwFhQNNcTYt2D4VWPVo1vg
lOraHyFakb7NqEA=
-----END PRIVATE KEY-----