Compare commits
29 Commits
develop
...
collab-tes
Author | SHA1 | Date |
---|---|---|
John McLear | f33bd821ee | |
John McLear | 58f0000ed4 | |
John McLear | 211264c6de | |
John McLear | 05d8ba2f5a | |
John McLear | a6d59e004c | |
John McLear | 6e4f3f8fab | |
John McLear | 1b4b243736 | |
John McLear | 4876cf7313 | |
John McLear | 9478418984 | |
John McLear | e0dbacf86f | |
John McLear | 5550912d81 | |
John McLear | 4910396f40 | |
John McLear | d3d9ec095a | |
John McLear | db2d097d5a | |
John McLear | adfe7e51ae | |
John McLear | 844c787bbf | |
John McLear | 01d4bfc753 | |
John McLear | 4e38c5714f | |
John McLear | 754aa8363b | |
John McLear | 4da826dd0c | |
John McLear | 98a83462d2 | |
John McLear | 230336add3 | |
John McLear | 586e4a13b6 | |
John McLear | 28c6170cd7 | |
John McLear | 918e642501 | |
John McLear | d8baf7a1a7 | |
John McLear | 47475bada6 | |
John McLear | 5aa8d9ca5f | |
John McLear | a0c57b9c11 |
|
@ -0,0 +1,54 @@
|
||||||
|
# Leave the powered by Sauce Labs bit in as this means we get additional concurrency
|
||||||
|
name: "Frontend Collaboration tests powered by Sauce Labs"
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
withoutplugins:
|
||||||
|
name: without plugins
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Generate Sauce Labs strings
|
||||||
|
id: sauce_strings
|
||||||
|
run: |
|
||||||
|
printf %s\\n '::set-output name=name::${{ github.workflow }} - ${{ github.job }}'
|
||||||
|
printf %s\\n '::set-output name=tunnel_id::${{ github.run_id }}-${{ github.run_number }}-${{ github.job }}'
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 12
|
||||||
|
|
||||||
|
- name: Install all dependencies and symlink for ep_etherpad-lite
|
||||||
|
run: src/bin/installDeps.sh
|
||||||
|
|
||||||
|
- name: export GIT_HASH to env
|
||||||
|
id: environment
|
||||||
|
run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})"
|
||||||
|
|
||||||
|
- name: Create settings.json
|
||||||
|
run: cp settings.json.template settings.json
|
||||||
|
|
||||||
|
- name: Disable import/export rate limiting
|
||||||
|
run: |
|
||||||
|
sed -e '/^ *"importExportRateLimiting":/,/^ *\}/ s/"max":.*/"max": 0/' -i settings.json
|
||||||
|
|
||||||
|
- uses: saucelabs/sauce-connect-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.SAUCE_USERNAME }}
|
||||||
|
accessKey: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||||
|
tunnelIdentifier: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||||
|
|
||||||
|
- name: Run the frontend tests
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
||||||
|
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||||
|
SAUCE_NAME: ${{ steps.sauce_strings.outputs.name }}
|
||||||
|
TRAVIS_JOB_NUMBER: ${{ steps.sauce_strings.outputs.tunnel_id }}
|
||||||
|
GIT_HASH: ${{ steps.environment.outputs.sha_short }}
|
||||||
|
run: |
|
||||||
|
src/tests/frontend/travis/collabrunner.sh
|
|
@ -1,91 +1,56 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// Wait helper function, for simulating words per minute.
|
||||||
|
const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||||
|
|
||||||
// Test for https://github.com/ether/etherpad-lite/issues/1763
|
// Test for https://github.com/ether/etherpad-lite/issues/1763
|
||||||
|
describe('Responsiveness of Editor', function () {
|
||||||
// This test fails in Opera, IE and Safari
|
|
||||||
// Opera fails due to a weird way of handling the order of execution,
|
|
||||||
// yet actual performance seems fine
|
|
||||||
// Safari fails due the delay being too great yet the actual performance seems fine
|
|
||||||
// Firefox might panic that the script is taking too long so will fail
|
|
||||||
// IE will fail due to running out of memory as it can't fit 2M chars in memory.
|
|
||||||
|
|
||||||
// Just FYI Google Docs crashes on large docs whilst trying to Save,
|
|
||||||
// it's likely the limitations we are
|
|
||||||
// experiencing are more to do with browser limitations than improper implementation.
|
|
||||||
// A ueber fix for this would be to have a separate lower cpu priority
|
|
||||||
// thread that handles operations that aren't
|
|
||||||
// visible to the user.
|
|
||||||
|
|
||||||
// Adapted from John McLear's original test case.
|
|
||||||
|
|
||||||
xdescribe('Responsiveness of Editor', function () {
|
|
||||||
// create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function (cb) {
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb, 'TEST_PAD_collab');
|
||||||
this.timeout(6000);
|
this.timeout(1200000);
|
||||||
});
|
});
|
||||||
// JM commented out on 8th Sep 2020 for a release, after release this needs uncommenting
|
|
||||||
// And the test needs to be fixed to work in Firefox 52 on Windows 7.
|
|
||||||
// I am not sure why it fails on this specific platform
|
|
||||||
// The errors show this.timeout... then crash the browser but
|
|
||||||
// I am sure something is actually causing the stack trace and
|
|
||||||
// I just need to narrow down what, offers to help accepted.
|
|
||||||
it('Fast response to keypress in pad with large amount of contents', function (done) {
|
|
||||||
// skip on Windows Firefox 52.0
|
|
||||||
if (window.bowser &&
|
|
||||||
window.bowser.windows && window.bowser.firefox && window.bowser.version === '52.0') {
|
|
||||||
this.skip();
|
|
||||||
}
|
|
||||||
const inner$ = helper.padInner$;
|
|
||||||
const chars = '0000000000'; // row of placeholder chars
|
|
||||||
const amount = 200000; // number of blocks of chars we will insert
|
|
||||||
const length = (amount * (chars.length) + 1); // include a counter for each space
|
|
||||||
let text = ''; // the text we're gonna insert
|
|
||||||
this.timeout(amount * 150); // Changed from 100 to 150 to allow Mac OSX Safari to be slow.
|
|
||||||
|
|
||||||
// get keys to send
|
it('Fast response to keypress in pad with large amount of contents', async function () {
|
||||||
const keyMultiplier = 10; // multiplier * 10 == total number of key events
|
this.timeout(1200000);
|
||||||
let keysToSend = '';
|
if (top.window.location.search.indexOf('&collab=true') === -1) this.skip();
|
||||||
for (let i = 0; i <= keyMultiplier; i++) {
|
const numberOfEdits = 3000; // creates 700+ lines
|
||||||
keysToSend += chars;
|
const allowableLatency = 100; // allow 100 ms of latency to see our edit
|
||||||
|
|
||||||
|
// wait a minute for everyone to connect, this is skipped if &test=true is in the url
|
||||||
|
// so that it's easier to do local debug/testing without lots of users connected
|
||||||
|
if (top.window.location.search.indexOf('&test=true') === -1) {
|
||||||
|
await helper.waitForPromise(
|
||||||
|
() => parseInt(helper.padChrome$('#online_count').text()) >= 4, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
const textElement = inner$('div');
|
let i = 0;
|
||||||
textElement.sendkeys('{selectall}'); // select all
|
while (i < numberOfEdits) {
|
||||||
textElement.sendkeys('{del}'); // clear the pad text
|
helper.padOuter$('#outerdocbody').scrollTop(helper.padOuter$('#outerdocbody').height());
|
||||||
|
// move the caret to increase randomness of span lengths and increase likelihood that this
|
||||||
for (let i = 0; i <= amount; i++) {
|
// authors content is within another authors span.
|
||||||
text = `${text + chars} `; // add the chars and space to the text contents
|
helper.padInner$('div').last().sendkeys('{rightarrow}');
|
||||||
|
helper.padInner$('div').last().sendkeys('{rightarrow}');
|
||||||
|
helper.padInner$('div').last().sendkeys('{rightarrow}');
|
||||||
|
helper.padInner$('div').last().sendkeys('{rightarrow}');
|
||||||
|
// Put the text contents into the pad
|
||||||
|
// intentional white space at end of string
|
||||||
|
helper.padInner$('div').last().sendkeys(`${i}: ${Math.random().toString(36).substring(7)} `);
|
||||||
|
// 5% chance for every word we will do an enter
|
||||||
|
if (Math.random() < 0.05) {
|
||||||
|
helper.padInner$('div').last().sendkeys('{leftarrow}'); // To force enter on Chrome?
|
||||||
|
helper.padInner$('div').last().sendkeys('{enter}');
|
||||||
}
|
}
|
||||||
inner$('div').first().text(text); // Put the text contents into the pad
|
// wait 1500 milliseconds to simulate 40wpm if you have 20 authors you would do this
|
||||||
|
// but to speed up the test and as we only have 5 authors, we can do things ~7 times faster
|
||||||
// Wait for the new contents to be on the pad
|
await wait(200);
|
||||||
helper.waitFor(() => inner$('div').text().length > length).done(() => {
|
i++;
|
||||||
// has the text changed?
|
|
||||||
expect(inner$('div').text().length).to.be.greaterThan(length);
|
|
||||||
const start = Date.now(); // get the start time
|
|
||||||
|
|
||||||
// send some new text to the screen (ensure all 3 key events are sent)
|
|
||||||
const el = inner$('div').first();
|
|
||||||
for (let i = 0; i < keysToSend.length; ++i) {
|
|
||||||
const x = keysToSend.charCodeAt(i);
|
|
||||||
['keyup', 'keypress', 'keydown'].forEach((type) => {
|
|
||||||
const e = new $.Event(type);
|
|
||||||
e.keyCode = x;
|
|
||||||
el.trigger(e);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.waitFor(() => { // Wait for the ability to process
|
// do an edit, ensure it's on the screen within x ms.
|
||||||
const el = inner$('body');
|
const rand = Math.random().toString(36).substring(7);
|
||||||
if (el[0].textContent.length > amount) return true;
|
helper.padInner$('div').last().sendkeys(`finaledit: ${rand}`);
|
||||||
}).done(() => {
|
await helper.waitForPromise(
|
||||||
const end = Date.now(); // get the current time
|
() => helper.padInner$('div').text().indexOf(rand) !== -1, allowableLatency);
|
||||||
const delay = end - start; // get the delay as the current time minus the start time
|
|
||||||
|
|
||||||
expect(delay).to.be.below(600);
|
|
||||||
done();
|
|
||||||
}, 5000);
|
|
||||||
}, 10000);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
pecho() { printf %s\\n "$*"; }
|
||||||
|
log() { pecho "$@"; }
|
||||||
|
error() { log "ERROR: $@" >&2; }
|
||||||
|
fatal() { error "$@"; exit 1; }
|
||||||
|
try() { "$@" || fatal "'$@' failed"; }
|
||||||
|
|
||||||
|
# Move to the Etherpad base directory.
|
||||||
|
MY_DIR=$(try cd "${0%/*}" && try pwd -P) || exit 1
|
||||||
|
try cd "${MY_DIR}/../../../.."
|
||||||
|
|
||||||
|
log "Assuming src/bin/installDeps.sh has already been run"
|
||||||
|
node src/node/server.js --experimental-worker "${@}" &
|
||||||
|
ep_pid=$!
|
||||||
|
|
||||||
|
log "Waiting for Etherpad to accept connections (http://localhost:9001)..."
|
||||||
|
connected=false
|
||||||
|
can_connect() {
|
||||||
|
curl -sSfo /dev/null http://localhost:9001/ || return 1
|
||||||
|
connected=true
|
||||||
|
}
|
||||||
|
now() { date +%s; }
|
||||||
|
start=$(now)
|
||||||
|
while [ $(($(now) - $start)) -le 15 ] && ! can_connect; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
[ "$connected" = true ] \
|
||||||
|
|| fatal "Timed out waiting for Etherpad to accept connections"
|
||||||
|
log "Successfully connected to Etherpad on http://localhost:9001"
|
||||||
|
|
||||||
|
# start the remote runner
|
||||||
|
try cd "${MY_DIR}"
|
||||||
|
log "Starting the remote runner..."
|
||||||
|
node remote_runner.js collab
|
||||||
|
exit_code=$?
|
||||||
|
|
||||||
|
kill "$ep_pid" && wait "$ep_pid"
|
||||||
|
log "Done."
|
||||||
|
exit "$exit_code"
|
|
@ -11,6 +11,7 @@ const config = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAdminRunner = process.argv[2] === 'admin';
|
const isAdminRunner = process.argv[2] === 'admin';
|
||||||
|
const isCollabRunner = process.argv[2] === 'collab';
|
||||||
|
|
||||||
let allTestsPassed = true;
|
let allTestsPassed = true;
|
||||||
// overwrite the default exit code
|
// overwrite the default exit code
|
||||||
|
@ -37,8 +38,14 @@ const sauceTestWorker = async.queue((testSettings, callback) => {
|
||||||
// don't know how to print them into output of the tests
|
// don't know how to print them into output of the tests
|
||||||
testSettings.extendedDebugging = true;
|
testSettings.extendedDebugging = true;
|
||||||
testSettings.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
testSettings.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||||
|
let testURL;
|
||||||
|
if (isCollabRunner) {
|
||||||
|
testURL = 'http://localhost:9001/tests/frontend/index.html?grep=responsiveness%5C.js&collab=true';
|
||||||
|
} else {
|
||||||
|
testURL = 'http://localhost:9001/tests/frontend/';
|
||||||
|
}
|
||||||
|
|
||||||
browser.init(testSettings).get('http://localhost:9001/tests/frontend/', () => {
|
browser.init(testSettings).get(testURL, () => {
|
||||||
const url = `https://saucelabs.com/jobs/${browser.sessionID}`;
|
const url = `https://saucelabs.com/jobs/${browser.sessionID}`;
|
||||||
console.log(`Remote sauce test '${name}' started! ${url}`);
|
console.log(`Remote sauce test '${name}' started! ${url}`);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue