From 98aafd6abbe63748886e198bca0ed044d8bb86de Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 14:37:36 +0200 Subject: [PATCH 01/18] add rest/non-browser session, which we can create a lot more off --- package.json | 6 +++- src/rest/consent.js | 30 ++++++++++++++++ src/rest/factory.js | 77 +++++++++++++++++++++++++++++++++++++++ src/rest/room.js | 42 ++++++++++++++++++++++ src/rest/session.js | 88 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 src/rest/consent.js create mode 100644 src/rest/factory.js create mode 100644 src/rest/room.js create mode 100644 src/rest/session.js diff --git a/package.json b/package.json index 8035fbb508..f3c47ac491 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "author": "", "license": "ISC", "dependencies": { + "cheerio": "^1.0.0-rc.2", "commander": "^2.17.1", - "puppeteer": "^1.6.0" + "puppeteer": "^1.6.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "uuid": "^3.3.2" } } diff --git a/src/rest/consent.js b/src/rest/consent.js new file mode 100644 index 0000000000..1e36f541a3 --- /dev/null +++ b/src/rest/consent.js @@ -0,0 +1,30 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const request = require('request-promise-native'); +const cheerio = require('cheerio'); +const url = require("url"); + +module.exports.approveConsent = async function(consentUrl) { + const body = await request.get(consentUrl); + const doc = cheerio.load(body); + const v = doc("input[name=v]").val(); + const u = doc("input[name=u]").val(); + const h = doc("input[name=h]").val(); + const formAction = doc("form").attr("action"); + const absAction = url.resolve(consentUrl, formAction); + await request.post(absAction).form({v, u, h}); +}; diff --git a/src/rest/factory.js b/src/rest/factory.js new file mode 100644 index 0000000000..2df6624ef9 --- /dev/null +++ b/src/rest/factory.js @@ -0,0 +1,77 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const util = require('util'); +const exec = util.promisify(require('child_process').exec); +const request = require('request-promise-native'); +const RestSession = require('./session'); + +module.exports = class RestSessionFactory { + constructor(synapseSubdir, hsUrl, cwd) { + this.synapseSubdir = synapseSubdir; + this.hsUrl = hsUrl; + this.cwd = cwd; + } + + async createSession(username, password) { + await this._register(username, password); + const authResult = await this._authenticate(username, password); + return new RestSession(authResult); + } + + _register(username, password) { + const registerArgs = [ + '-c homeserver.yaml', + `-u ${username}`, + `-p ${password}`, + // '--regular-user', + '-a', //until PR gets merged + this.hsUrl + ]; + const registerCmd = `./scripts/register_new_matrix_user ${registerArgs.join(' ')}`; + const allCmds = [ + `cd ${this.synapseSubdir}`, + "source env/bin/activate", + registerCmd + ].join(';'); + + return exec(allCmds, {cwd: this.cwd, encoding: 'utf-8'}).catch((result) => { + const lines = result.stdout.trim().split('\n'); + const failureReason = lines[lines.length - 1]; + throw new Error(`creating user ${username} failed: ${failureReason}`); + }); + } + + async _authenticate(username, password) { + const requestBody = { + "type": "m.login.password", + "identifier": { + "type": "m.id.user", + "user": username + }, + "password": password + }; + const url = `${this.hsUrl}/_matrix/client/r0/login`; + const responseBody = await request.post({url, json: true, body: requestBody}); + return { + accessToken: responseBody.access_token, + homeServer: responseBody.home_server, + userId: responseBody.user_id, + deviceId: responseBody.device_id, + hsUrl: this.hsUrl, + }; + } +} diff --git a/src/rest/room.js b/src/rest/room.js new file mode 100644 index 0000000000..b7da1789ff --- /dev/null +++ b/src/rest/room.js @@ -0,0 +1,42 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const uuidv4 = require('uuid/v4'); + +/* no pun intented */ +module.exports = class RestRoom { + constructor(session, roomId) { + this.session = session; + this.roomId = roomId; + } + + async talk(message) { + const txId = uuidv4(); + await this.session._put(`/rooms/${this.roomId}/send/m.room.message/${txId}`, { + "msgtype": "m.text", + "body": message + }); + return txId; + } + + async leave() { + await this.session._post(`/rooms/${this.roomId}/leave`); + } + + id() { + return this.roomId; + } +} diff --git a/src/rest/session.js b/src/rest/session.js new file mode 100644 index 0000000000..f57d0467f5 --- /dev/null +++ b/src/rest/session.js @@ -0,0 +1,88 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const request = require('request-promise-native'); +const RestRoom = require('./room'); +const {approveConsent} = require('./consent'); + +module.exports = class RestSession { + constructor(credentials) { + this.credentials = credentials; + } + + _post(csApiPath, body) { + return this._request("POST", csApiPath, body); + } + + _put(csApiPath, body) { + return this._request("PUT", csApiPath, body); + } + + async _request(method, csApiPath, body) { + try { + const responseBody = await request({ + url: `${this.credentials.hsUrl}/_matrix/client/r0${csApiPath}`, + method, + headers: { + "Authorization": `Bearer ${this.credentials.accessToken}` + }, + json: true, + body + }); + return responseBody; + + } catch(err) { + const responseBody = err.response.body; + if (responseBody.errcode === 'M_CONSENT_NOT_GIVEN') { + await approveConsent(responseBody.consent_uri); + return this._request(method, csApiPath, body); + } else if(responseBody && responseBody.error) { + throw new Error(`${method} ${csApiPath}: ${responseBody.error}`); + } else { + throw new Error(`${method} ${csApiPath}: ${err.response.statusCode}`); + } + } + } + + async join(roomId) { + const {room_id} = await this._post(`/rooms/${roomId}/join`); + return new RestRoom(this, room_id); + } + + + async createRoom(name, options) { + const body = { + name, + }; + if (options.invite) { + body.invite = options.invite; + } + if (options.public) { + body.visibility = "public"; + } else { + body.visibility = "private"; + } + if (options.dm) { + body.is_direct = true; + } + if (options.topic) { + body.topic = options.topic; + } + + const {room_id} = await this._post(`/createRoom`, body); + return new RestRoom(this, room_id); + } +} From afc678fea066e8d5e75461bb078c0dacb2401eee Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 14:46:25 +0200 Subject: [PATCH 02/18] pass rest session creator to scenario --- src/scenario.js | 2 +- start.js | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/scenario.js b/src/scenario.js index f7229057a8..f774a8649d 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -28,7 +28,7 @@ const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-cons const getE2EDeviceFromSettings = require('./tests/e2e-device'); const verifyDeviceForUser = require("./tests/verify-device"); -module.exports = async function scenario(createSession) { +module.exports = async function scenario(createSession, createRestSession) { async function createUser(username) { const session = await createSession(username); await signup(session, session.username, 'testtest'); diff --git a/start.js b/start.js index ac9a2f8684..c21fcd0a2d 100644 --- a/start.js +++ b/start.js @@ -17,6 +17,7 @@ limitations under the License. const assert = require('assert'); const RiotSession = require('./src/session'); const scenario = require('./src/scenario'); +const RestSessionFactory = require('./src/rest/factory'); const program = require('commander'); program @@ -40,6 +41,16 @@ async function runTests() { options.executablePath = path; } + const restFactory = new RestSessionFactory( + 'synapse/installations/consent', + 'http://localhost:5005', + __dirname + ); + + function createRestSession(username, password) { + return restFactory.createSession(username, password); + } + async function createSession(username) { const session = await RiotSession.create(username, options, program.riotUrl); sessions.push(session); @@ -48,7 +59,7 @@ async function runTests() { let failure = false; try { - await scenario(createSession); + await scenario(createSession, createRestSession); } catch(err) { failure = true; console.log('failure: ', err); From 3c5e73d64414e69a46cf1624c4cb91254570a2e5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 14:54:14 +0200 Subject: [PATCH 03/18] support setting the display name on rest session --- src/rest/session.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rest/session.js b/src/rest/session.js index f57d0467f5..caa10a430b 100644 --- a/src/rest/session.js +++ b/src/rest/session.js @@ -57,12 +57,17 @@ module.exports = class RestSession { } } + async setDisplayName(displayName) { + await this._put(`/profile/${this.credentials.userId}/displayname`, { + displayname: displayName + }); + } + async join(roomId) { const {room_id} = await this._post(`/rooms/${roomId}/join`); return new RestRoom(this, room_id); } - async createRoom(name, options) { const body = { name, From 48d95c228a2e4f483c4602f31fb12d55e7e0da2c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 15:02:02 +0200 Subject: [PATCH 04/18] creator instead of factory, as it does registration and authentication --- src/rest/{factory.js => creator.js} | 2 +- start.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/rest/{factory.js => creator.js} (98%) diff --git a/src/rest/factory.js b/src/rest/creator.js similarity index 98% rename from src/rest/factory.js rename to src/rest/creator.js index 2df6624ef9..05976552d0 100644 --- a/src/rest/factory.js +++ b/src/rest/creator.js @@ -19,7 +19,7 @@ const exec = util.promisify(require('child_process').exec); const request = require('request-promise-native'); const RestSession = require('./session'); -module.exports = class RestSessionFactory { +module.exports = class RestSessionCreator { constructor(synapseSubdir, hsUrl, cwd) { this.synapseSubdir = synapseSubdir; this.hsUrl = hsUrl; diff --git a/start.js b/start.js index c21fcd0a2d..e39681f71b 100644 --- a/start.js +++ b/start.js @@ -17,7 +17,7 @@ limitations under the License. const assert = require('assert'); const RiotSession = require('./src/session'); const scenario = require('./src/scenario'); -const RestSessionFactory = require('./src/rest/factory'); +const RestSessionCreator = require('./src/rest/creator'); const program = require('commander'); program @@ -41,14 +41,14 @@ async function runTests() { options.executablePath = path; } - const restFactory = new RestSessionFactory( + const restCreator = new RestSessionCreator( 'synapse/installations/consent', 'http://localhost:5005', __dirname ); function createRestSession(username, password) { - return restFactory.createSession(username, password); + return restCreator.createSession(username, password); } async function createSession(username) { From 827e6365bbe4779c89fe9a1ea87856a9f76cb4c3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 16:18:27 +0200 Subject: [PATCH 05/18] add wrapper around multiple rest sessions --- src/rest/creator.js | 7 +++++ src/rest/multi.js | 61 ++++++++++++++++++++++++++++++++++++++++ src/rest/room.js | 10 +++---- src/rest/session.js | 68 +++++++++++++++++++++++++-------------------- 4 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 src/rest/multi.js diff --git a/src/rest/creator.js b/src/rest/creator.js index 05976552d0..9090a21e70 100644 --- a/src/rest/creator.js +++ b/src/rest/creator.js @@ -18,6 +18,7 @@ const util = require('util'); const exec = util.promisify(require('child_process').exec); const request = require('request-promise-native'); const RestSession = require('./session'); +const RestMultiSession = require('./multi'); module.exports = class RestSessionCreator { constructor(synapseSubdir, hsUrl, cwd) { @@ -26,6 +27,12 @@ module.exports = class RestSessionCreator { this.cwd = cwd; } + async createSessionRange(usernames, password) { + const sessionPromises = usernames.map((username) => this.createSession(username, password)); + const sessions = await Promise.all(sessionPromises); + return new RestMultiSession(sessions); + } + async createSession(username, password) { await this._register(username, password); const authResult = await this._authenticate(username, password); diff --git a/src/rest/multi.js b/src/rest/multi.js new file mode 100644 index 0000000000..12ebe9d4ab --- /dev/null +++ b/src/rest/multi.js @@ -0,0 +1,61 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const request = require('request-promise-native'); +const RestRoom = require('./room'); +const {approveConsent} = require('./consent'); + +module.exports = class RestMultiSession { + constructor(sessions) { + this.sessions = sessions; + } + + slice(start, end) { + return new RestMultiSession(this.sessions.slice(start, end)); + } + + pop(userName) { + const idx = this.sessions.findIndex((s) => s.userName() === userName); + if(idx === -1) { + throw new Error(`user ${userName} not found`); + } + const session = this.sessions.splice(idx, 1)[0]; + return session; + } + + async setDisplayName(fn) { + await Promise.all(this.sessions.map((s) => s.setDisplayName(fn(s)))); + } + + async join(roomId) { + const rooms = await Promise.all(this.sessions.map((s) => s.join(roomId))); + return new RestMultiRoom(rooms); + } +} + +class RestMultiRoom { + constructor(rooms) { + this.rooms = rooms; + } + + async talk(message) { + await Promise.all(this.rooms.map((r) => r.talk(message))); + } + + async leave() { + await Promise.all(this.rooms.map((r) => r.leave())); + } +} diff --git a/src/rest/room.js b/src/rest/room.js index b7da1789ff..d8de958a27 100644 --- a/src/rest/room.js +++ b/src/rest/room.js @@ -20,12 +20,12 @@ const uuidv4 = require('uuid/v4'); module.exports = class RestRoom { constructor(session, roomId) { this.session = session; - this.roomId = roomId; + this._roomId = roomId; } async talk(message) { const txId = uuidv4(); - await this.session._put(`/rooms/${this.roomId}/send/m.room.message/${txId}`, { + await this.session._put(`/rooms/${this._roomId}/send/m.room.message/${txId}`, { "msgtype": "m.text", "body": message }); @@ -33,10 +33,10 @@ module.exports = class RestRoom { } async leave() { - await this.session._post(`/rooms/${this.roomId}/leave`); + await this.session._post(`/rooms/${this._roomId}/leave`); } - id() { - return this.roomId; + roomId() { + return this._roomId; } } diff --git a/src/rest/session.js b/src/rest/session.js index caa10a430b..44be15c3ff 100644 --- a/src/rest/session.js +++ b/src/rest/session.js @@ -23,38 +23,12 @@ module.exports = class RestSession { this.credentials = credentials; } - _post(csApiPath, body) { - return this._request("POST", csApiPath, body); + userId() { + return this.credentials.userId; } - _put(csApiPath, body) { - return this._request("PUT", csApiPath, body); - } - - async _request(method, csApiPath, body) { - try { - const responseBody = await request({ - url: `${this.credentials.hsUrl}/_matrix/client/r0${csApiPath}`, - method, - headers: { - "Authorization": `Bearer ${this.credentials.accessToken}` - }, - json: true, - body - }); - return responseBody; - - } catch(err) { - const responseBody = err.response.body; - if (responseBody.errcode === 'M_CONSENT_NOT_GIVEN') { - await approveConsent(responseBody.consent_uri); - return this._request(method, csApiPath, body); - } else if(responseBody && responseBody.error) { - throw new Error(`${method} ${csApiPath}: ${responseBody.error}`); - } else { - throw new Error(`${method} ${csApiPath}: ${err.response.statusCode}`); - } - } + userName() { + return this.credentials.userId.split(":")[0].substr(1); } async setDisplayName(displayName) { @@ -90,4 +64,38 @@ module.exports = class RestSession { const {room_id} = await this._post(`/createRoom`, body); return new RestRoom(this, room_id); } + + _post(csApiPath, body) { + return this._request("POST", csApiPath, body); + } + + _put(csApiPath, body) { + return this._request("PUT", csApiPath, body); + } + + async _request(method, csApiPath, body) { + try { + const responseBody = await request({ + url: `${this.credentials.hsUrl}/_matrix/client/r0${csApiPath}`, + method, + headers: { + "Authorization": `Bearer ${this.credentials.accessToken}` + }, + json: true, + body + }); + return responseBody; + + } catch(err) { + const responseBody = err.response.body; + if (responseBody.errcode === 'M_CONSENT_NOT_GIVEN') { + await approveConsent(responseBody.consent_uri); + return this._request(method, csApiPath, body); + } else if(responseBody && responseBody.error) { + throw new Error(`${method} ${csApiPath}: ${responseBody.error}`); + } else { + throw new Error(`${method} ${csApiPath}: ${err.response.statusCode}`); + } + } + } } From 4a4b1f65aa2d418d8c616b2501b25ceb49f74a5e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:28:50 +0200 Subject: [PATCH 06/18] wait for the message to be sent --- src/scenario.js | 9 +++++++-- src/session.js | 23 ++++++++++++++++++++--- src/tests/e2e-device.js | 31 ------------------------------- src/tests/send-message.js | 4 +++- start.js | 6 ++++-- synapse/install.sh | 4 +++- 6 files changed, 37 insertions(+), 40 deletions(-) delete mode 100644 src/tests/e2e-device.js diff --git a/src/scenario.js b/src/scenario.js index b468cad823..3145c9471a 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -25,13 +25,13 @@ const receiveMessage = require('./tests/receive-message'); const createRoom = require('./tests/create-room'); const changeRoomSettings = require('./tests/room-settings'); const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-consent'); -const getE2EDeviceFromSettings = require('./tests/e2e-device'); +const {enableLazyLoading, getE2EDeviceFromSettings} = require('./tests/settings'); const verifyDeviceForUser = require("./tests/verify-device"); module.exports = async function scenario(createSession, createRestSession) { async function createUser(username) { const session = await createSession(username); - await signup(session, session.username, 'testtest'); + await signup(session, session.username, 'testtest', session.hsUrl); await acceptServerNoticesInviteAndConsent(session); return session; } @@ -83,3 +83,8 @@ async function createE2ERoomAndTalk(alice, bob) { await sendMessage(bob, bobMessage); await receiveMessage(alice, {sender: "bob", body: bobMessage, encrypted: true}); } + +async function aLLtest(alice, bob) { + await enableLazyLoading(alice); + +} diff --git a/src/session.js b/src/session.js index bcccc9d6cc..60cbfa9099 100644 --- a/src/session.js +++ b/src/session.js @@ -58,9 +58,10 @@ class Logger { } module.exports = class RiotSession { - constructor(browser, page, username, riotserver) { + constructor(browser, page, username, riotserver, hsUrl) { this.browser = browser; this.page = page; + this.hsUrl = hsUrl; this.riotserver = riotserver; this.username = username; this.consoleLog = new LogBuffer(page, "console", (msg) => `${msg.text()}\n`); @@ -72,14 +73,14 @@ module.exports = class RiotSession { this.log = new Logger(this.username); } - static async create(username, puppeteerOptions, riotserver) { + static async create(username, puppeteerOptions, riotserver, hsUrl) { const browser = await puppeteer.launch(puppeteerOptions); const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); - return new RiotSession(browser, page, username, riotserver); + return new RiotSession(browser, page, username, riotserver, hsUrl); } async tryGetInnertext(selector) { @@ -161,6 +162,22 @@ module.exports = class RiotSession { return await this.queryAll(selector); } + waitForReload(timeout = 5000) { + return new Promise((resolve, reject) => { + const timeoutHandle = setTimeout(() => { + this.browser.removeEventListener('domcontentloaded', callback); + reject(new Error(`timeout of ${timeout}ms for waitForReload elapsed`)); + }, timeout); + + const callback = async () => { + clearTimeout(timeoutHandle); + resolve(); + }; + + this.page.once('domcontentloaded', callback); + }); + } + waitForNewPage(timeout = 5000) { return new Promise((resolve, reject) => { const timeoutHandle = setTimeout(() => { diff --git a/src/tests/e2e-device.js b/src/tests/e2e-device.js deleted file mode 100644 index 4be6677396..0000000000 --- a/src/tests/e2e-device.js +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -const assert = require('assert'); - -module.exports = async function getE2EDeviceFromSettings(session) { - session.log.step(`gets e2e device/key from settings`); - const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); - await settingsButton.click(); - const deviceAndKey = await session.waitAndQueryAll(".mx_UserSettings_section.mx_UserSettings_cryptoSection code", 1000); - assert.equal(deviceAndKey.length, 2); - const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue(); - const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue(); - const closeButton = await session.query(".mx_RoomHeader_cancelButton"); - await closeButton.click(); - session.log.done(); - return {id, key}; -} diff --git a/src/tests/send-message.js b/src/tests/send-message.js index eb70f5ce23..5bf289b03a 100644 --- a/src/tests/send-message.js +++ b/src/tests/send-message.js @@ -25,5 +25,7 @@ module.exports = async function sendMessage(session, message) { const text = await session.innerText(composer); assert.equal(text.trim(), message.trim()); await composer.press("Enter"); + // wait for the message to appear sent + await session.waitAndQuery(".mx_EventTile_last:not(.mx_EventTile_sending)"); session.log.done(); -} \ No newline at end of file +} diff --git a/start.js b/start.js index 5f6681519b..62ec29d6a1 100644 --- a/start.js +++ b/start.js @@ -26,6 +26,8 @@ program .option('--riot-url [url]', "riot url to test", "http://localhost:5000") .parse(process.argv); +const hsUrl = 'http://localhost:5005'; + async function runTests() { let sessions = []; console.log("running tests ..."); @@ -43,7 +45,7 @@ async function runTests() { const restCreator = new RestSessionCreator( 'synapse/installations/consent', - 'http://localhost:5005', + hsUrl, __dirname ); @@ -52,7 +54,7 @@ async function runTests() { } async function createSession(username) { - const session = await RiotSession.create(username, options, program.riotUrl); + const session = await RiotSession.create(username, options, program.riotUrl, hsUrl); sessions.push(session); return session; } diff --git a/synapse/install.sh b/synapse/install.sh index 3d8172a9f6..a438ea5dc2 100755 --- a/synapse/install.sh +++ b/synapse/install.sh @@ -31,9 +31,11 @@ python -m synapse.app.homeserver \ --generate-config \ --report-stats=no # apply configuration +REGISTRATION_SHARED_SECRET=$(uuidgen) cp -r $BASE_DIR/config-templates/$CONFIG_TEMPLATE/. ./ sed -i "s#{{SYNAPSE_ROOT}}#$(pwd)/#g" homeserver.yaml sed -i "s#{{SYNAPSE_PORT}}#${PORT}#g" homeserver.yaml sed -i "s#{{FORM_SECRET}}#$(uuidgen)#g" homeserver.yaml -sed -i "s#{{REGISTRATION_SHARED_SECRET}}#$(uuidgen)#g" homeserver.yaml +sed -i "s#{{REGISTRATION_SHARED_SECRET}}#${REGISTRATION_SHARED_SECRET}#g" homeserver.yaml sed -i "s#{{MACAROON_SECRET_KEY}}#$(uuidgen)#g" homeserver.yaml +echo REGISTRATION_SHARED_SECRET=$REGISTRATION_SHARED_SECRET= From be4c1cb899e7f9e50e29d3a54aa6f569ce34447e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:29:05 +0200 Subject: [PATCH 07/18] support setting the room alias --- src/tests/room-settings.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tests/room-settings.js b/src/tests/room-settings.js index 9f802da711..95c7538431 100644 --- a/src/tests/room-settings.js +++ b/src/tests/room-settings.js @@ -76,6 +76,13 @@ module.exports = async function changeRoomSettings(session, settings) { session.log.done(); } + if (settings.alias) { + session.log.step(`sets alias to ${settings.alias}`); + const aliasField = await session.waitAndQuery(".mx_RoomSettings .mx_EditableItemList .mx_EditableItem_editable"); + await session.replaceInputText(aliasField, settings.alias); + session.log.done(); + } + const saveButton = await session.query(".mx_RoomHeader_wrapper .mx_RoomHeader_textButton"); await saveButton.click(); From 2be413ba6d025813e18ee1f6766ae710b8147439 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:29:52 +0200 Subject: [PATCH 08/18] allow clients to send messages faster, in order to speed up the test --- synapse/config-templates/consent/homeserver.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synapse/config-templates/consent/homeserver.yaml b/synapse/config-templates/consent/homeserver.yaml index 38aa4747b5..9fa16ebe5f 100644 --- a/synapse/config-templates/consent/homeserver.yaml +++ b/synapse/config-templates/consent/homeserver.yaml @@ -207,10 +207,10 @@ log_config: "{{SYNAPSE_ROOT}}localhost.log.config" ## Ratelimiting ## # Number of messages a client can send per second -rc_messages_per_second: 0.2 +rc_messages_per_second: 100 # Number of message a client can send before being throttled -rc_message_burst_count: 10.0 +rc_message_burst_count: 20.0 # The federation window size in milliseconds federation_rc_window_size: 1000 From ff20bc783dc77e61ad21d024fe72c09be6ae2323 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:30:17 +0200 Subject: [PATCH 09/18] support joining with a room alias for rest session --- src/rest/session.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rest/session.js b/src/rest/session.js index 44be15c3ff..846e83cc84 100644 --- a/src/rest/session.js +++ b/src/rest/session.js @@ -37,8 +37,8 @@ module.exports = class RestSession { }); } - async join(roomId) { - const {room_id} = await this._post(`/rooms/${roomId}/join`); + async join(roomIdOrAlias) { + const {room_id} = await this._post(`/join/${encodeURIComponent(roomIdOrAlias)}`); return new RestRoom(this, room_id); } From abc7c4c3acb334d6b300a1baa10f7338e0c3e89c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:30:57 +0200 Subject: [PATCH 10/18] join use cases that touch settings in one file, as selectors are similar --- src/tests/settings.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/tests/settings.js diff --git a/src/tests/settings.js b/src/tests/settings.js new file mode 100644 index 0000000000..5649671e7a --- /dev/null +++ b/src/tests/settings.js @@ -0,0 +1,43 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const assert = require('assert'); + +module.exports.enableLazyLoading = async function(session) { + session.log.step(`enables lazy loading of members in the lab settings`); + const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); + await settingsButton.click(); + const llCheckbox = await session.waitAndQuery("#feature_lazyloading"); + await llCheckbox.click(); + await session.waitForReload(); + const closeButton = await session.waitAndQuery(".mx_RoomHeader_cancelButton"); + await closeButton.click(); + session.log.done(); +} + +module.exports.getE2EDeviceFromSettings = async function(session) { + session.log.step(`gets e2e device/key from settings`); + const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); + await settingsButton.click(); + const deviceAndKey = await session.waitAndQueryAll(".mx_UserSettings_section.mx_UserSettings_cryptoSection code"); + assert.equal(deviceAndKey.length, 2); + const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue(); + const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue(); + const closeButton = await session.query(".mx_RoomHeader_cancelButton"); + await closeButton.click(); + session.log.done(); + return {id, key}; +} From 3db32c93d427ae082cf625d17d02109647f5e946 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:32:18 +0200 Subject: [PATCH 11/18] past rest creator to scenario to also be able to call createSessionRange --- start.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/start.js b/start.js index 62ec29d6a1..3367787905 100644 --- a/start.js +++ b/start.js @@ -49,10 +49,6 @@ async function runTests() { __dirname ); - function createRestSession(username, password) { - return restCreator.createSession(username, password); - } - async function createSession(username) { const session = await RiotSession.create(username, options, program.riotUrl, hsUrl); sessions.push(session); @@ -61,7 +57,7 @@ async function runTests() { let failure = false; try { - await scenario(createSession, createRestSession); + await scenario(createSession, restCreator); } catch(err) { failure = true; console.log('failure: ', err); From dcf96e146167db46fe348ebe5c13eb9762479d45 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 11 Sep 2018 18:32:32 +0200 Subject: [PATCH 12/18] WIP for LL test --- src/scenario.js | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/scenario.js b/src/scenario.js index 3145c9471a..24983d8cbf 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -28,7 +28,7 @@ const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-cons const {enableLazyLoading, getE2EDeviceFromSettings} = require('./tests/settings'); const verifyDeviceForUser = require("./tests/verify-device"); -module.exports = async function scenario(createSession, createRestSession) { +module.exports = async function scenario(createSession, restCreator) { async function createUser(username) { const session = await createSession(username); await signup(session, session.username, 'testtest', session.hsUrl); @@ -38,9 +38,26 @@ module.exports = async function scenario(createSession, createRestSession) { const alice = await createUser("alice"); const bob = await createUser("bob"); + const charlies = await createRestUsers(restCreator); - await createDirectoryRoomAndTalk(alice, bob); - await createE2ERoomAndTalk(alice, bob); + // await createDirectoryRoomAndTalk(alice, bob); + // await createE2ERoomAndTalk(alice, bob); + await aLazyLoadingTest(alice, bob, charlies); +} + +function range(start, amount, step = 1) { + const r = []; + for (let i = 0; i < amount; ++i) { + r.push(start + (i * step)); + } + return r; +} + +async function createRestUsers(restCreator) { + const usernames = range(1, 10).map((i) => `charly-${i}`); + const charlies = await restCreator.createSessionRange(usernames, 'testtest'); + await charlies.setDisplayName((s) => `Charly #${s.userName().split('-')[1]}`); + return charlies; } async function createDirectoryRoomAndTalk(alice, bob) { @@ -84,7 +101,18 @@ async function createE2ERoomAndTalk(alice, bob) { await receiveMessage(alice, {sender: "bob", body: bobMessage, encrypted: true}); } -async function aLLtest(alice, bob) { +async function aLazyLoadingTest(alice, bob, charlies) { await enableLazyLoading(alice); - + const room = "Lazy Loading Test"; + const alias = "#lltest:localhost"; + await createRoom(bob, room); + await changeRoomSettings(bob, {directory: true, visibility: "public_no_guests", alias}); + // wait for alias to be set by server after clicking "save" + await bob.delay(500); + await charlies.join(alias); + const messageRange = range(1, 20); + for(let i = 20; i >= 1; --i) { + await sendMessage(bob, `I will only say this ${i} time(s)!`); + } + await join(alice, room); } From 244d5b08514f7f2f518274261e40d6352cc5c5a5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Sep 2018 09:47:57 +0200 Subject: [PATCH 13/18] dont show all 20 send messages support muting a logger and chaining calls --- src/scenario.js | 3 +++ src/session.js | 31 ++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/scenario.js b/src/scenario.js index 24983d8cbf..840cd3e0dc 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -111,8 +111,11 @@ async function aLazyLoadingTest(alice, bob, charlies) { await bob.delay(500); await charlies.join(alias); const messageRange = range(1, 20); + bob.log.step("sends 20 messages").mute(); for(let i = 20; i >= 1; --i) { await sendMessage(bob, `I will only say this ${i} time(s)!`); } + bob.log.unmute().done(); await join(alice, room); + } diff --git a/src/session.js b/src/session.js index 60cbfa9099..0bfe781e61 100644 --- a/src/session.js +++ b/src/session.js @@ -35,25 +35,46 @@ class Logger { constructor(username) { this.indent = 0; this.username = username; + this.muted = false; } startGroup(description) { - const indent = " ".repeat(this.indent * 2); - console.log(`${indent} * ${this.username} ${description}:`); + if (!this.muted) { + const indent = " ".repeat(this.indent * 2); + console.log(`${indent} * ${this.username} ${description}:`); + } this.indent += 1; + return this; } endGroup() { this.indent -= 1; + return this; } step(description) { - const indent = " ".repeat(this.indent * 2); - process.stdout.write(`${indent} * ${this.username} ${description} ... `); + if (!this.muted) { + const indent = " ".repeat(this.indent * 2); + process.stdout.write(`${indent} * ${this.username} ${description} ... `); + } + return this; } done(status = "done") { - process.stdout.write(status + "\n"); + if (!this.muted) { + process.stdout.write(status + "\n"); + } + return this; + } + + mute() { + this.muted = true; + return this; + } + + unmute() { + this.muted = false; + return this; } } From 249cf4f87efb4492ca5098b272ed3704f64dbcf2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Sep 2018 14:49:48 +0200 Subject: [PATCH 14/18] implement reading and scrolling timeline, group timeline related code --- src/scenario.js | 6 +- src/tests/receive-message.js | 49 -------------- src/tests/timeline.js | 125 +++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 50 deletions(-) delete mode 100644 src/tests/receive-message.js create mode 100644 src/tests/timeline.js diff --git a/src/scenario.js b/src/scenario.js index 840cd3e0dc..70ceae1471 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -21,7 +21,11 @@ const join = require('./tests/join'); const sendMessage = require('./tests/send-message'); const acceptInvite = require('./tests/accept-invite'); const invite = require('./tests/invite'); -const receiveMessage = require('./tests/receive-message'); +const { + receiveMessage, + checkTimelineContains, + scrollToTimelineTop +} = require('./tests/timeline'); const createRoom = require('./tests/create-room'); const changeRoomSettings = require('./tests/room-settings'); const acceptServerNoticesInviteAndConsent = require('./tests/server-notices-consent'); diff --git a/src/tests/receive-message.js b/src/tests/receive-message.js deleted file mode 100644 index afe4247181..0000000000 --- a/src/tests/receive-message.js +++ /dev/null @@ -1,49 +0,0 @@ -/* -Copyright 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -const assert = require('assert'); - -module.exports = async function receiveMessage(session, message) { - session.log.step(`receives message "${message.body}" from ${message.sender}`); - // wait for a response to come in that contains the message - // crude, but effective - await session.page.waitForResponse(async (response) => { - if (response.request().url().indexOf("/sync") === -1) { - return false; - } - const body = await response.text(); - if (message.encrypted) { - return body.indexOf(message.sender) !== -1 && - body.indexOf("m.room.encrypted") !== -1; - } else { - return body.indexOf(message.body) !== -1; - } - }); - // wait a bit for the incoming event to be rendered - await session.delay(1000); - let lastTile = await session.query(".mx_EventTile_last"); - const senderElement = await lastTile.$(".mx_SenderProfile_name"); - const bodyElement = await lastTile.$(".mx_EventTile_body"); - const sender = await(await senderElement.getProperty("innerText")).jsonValue(); - const body = await(await bodyElement.getProperty("innerText")).jsonValue(); - if (message.encrypted) { - const e2eIcon = await lastTile.$(".mx_EventTile_e2eIcon"); - assert.ok(e2eIcon); - } - assert.equal(body, message.body); - assert.equal(sender, message.sender); - session.log.done(); -} diff --git a/src/tests/timeline.js b/src/tests/timeline.js new file mode 100644 index 0000000000..1e724a2d39 --- /dev/null +++ b/src/tests/timeline.js @@ -0,0 +1,125 @@ +/* +Copyright 2018 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +const assert = require('assert'); + +module.exports.scrollToTimelineTop = async function(session) { + session.log.step(`scrolls to the top of the timeline`); + await session.page.evaluate(() => { + return Promise.resolve().then(async () => { + const timelineScrollView = document.querySelector(".mx_RoomView .gm-scroll-view"); + let timedOut = false; + let timeoutHandle = null; + // set scrollTop to 0 in a loop and check every 50ms + // if content became available (scrollTop not being 0 anymore), + // assume everything is loaded after 1000ms + do { + if (timelineScrollView.scrollTop !== 0) { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + } + timeoutHandle = setTimeout(() => timedOut = true, 1000); + timelineScrollView.scrollTop = 0; + } else { + await new Promise((resolve) => setTimeout(resolve, 50)); + } + } while (!timedOut) + }); + }) + session.log.done(); +} + +module.exports.receiveMessage = async function(session, expectedMessage) { + session.log.step(`receives message "${expectedMessage.body}" from ${expectedMessage.sender}`); + // wait for a response to come in that contains the message + // crude, but effective + await session.page.waitForResponse(async (response) => { + if (response.request().url().indexOf("/sync") === -1) { + return false; + } + const body = await response.text(); + if (expectedMessage.encrypted) { + return body.indexOf(expectedMessage.sender) !== -1 && + body.indexOf("m.room.encrypted") !== -1; + } else { + return body.indexOf(expectedMessage.body) !== -1; + } + }); + // wait a bit for the incoming event to be rendered + await session.delay(1000); + const lastTile = await getLastEventTile(session); + const foundMessage = await getMessageFromEventTile(lastTile); + assertMessage(foundMessage, expectedMessage); + session.log.done(); +} + + +module.exports.checkTimelineContains = async function (session, expectedMessages, sendersDescription) { + session.log.step(`checks timeline contains ${expectedMessages.length} ` + + `given messages${sendersDescription ? ` from ${sendersDescription}`:""}`); + const eventTiles = await getAllEventTiles(session); + let timelineMessages = await Promise.all(eventTiles.map((eventTile) => { + return getMessageFromEventTile(eventTile); + })); + //filter out tiles that were not messages + timelineMessages = timelineMessages .filter((m) => !!m); + expectedMessages.forEach((expectedMessage) => { + const foundMessage = timelineMessages.find((message) => { + return message.sender === expectedMessage.sender && + message.body === expectedMessage.body; + }); + assertMessage(foundMessage, expectedMessage); + }); + + session.log.done(); +} + +function assertMessage(foundMessage, expectedMessage) { + assert(foundMessage, `message ${JSON.stringify(expectedMessage)} not found in timeline`); + assert.equal(foundMessage.body, expectedMessage.body); + assert.equal(foundMessage.sender, expectedMessage.sender); + if (expectedMessage.hasOwnProperty("encrypted")) { + assert.equal(foundMessage.encrypted, expectedMessage.encrypted); + } +} + +function getLastEventTile(session) { + return session.query(".mx_EventTile_last"); +} + +function getAllEventTiles(session) { + return session.queryAll(".mx_RoomView_MessageList > *"); +} + +async function getMessageFromEventTile(eventTile) { + const senderElement = await eventTile.$(".mx_SenderProfile_name"); + const bodyElement = await eventTile.$(".mx_EventTile_body"); + let sender = null; + if (senderElement) { + sender = await(await senderElement.getProperty("innerText")).jsonValue(); + } + if (!bodyElement) { + return null; + } + const body = await(await bodyElement.getProperty("innerText")).jsonValue(); + const e2eIcon = await eventTile.$(".mx_EventTile_e2eIcon"); + + return { + sender, + body, + encrypted: !!e2eIcon + }; +} From 4057ec8a6accf6bdfa87f4c9e62f31b64a4f14fb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Sep 2018 14:51:00 +0200 Subject: [PATCH 15/18] store displayName on RestSession to use it in tests --- src/rest/session.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/rest/session.js b/src/rest/session.js index 846e83cc84..ece04f3352 100644 --- a/src/rest/session.js +++ b/src/rest/session.js @@ -20,19 +20,25 @@ const {approveConsent} = require('./consent'); module.exports = class RestSession { constructor(credentials) { - this.credentials = credentials; + this._credentials = credentials; + this._displayName = null; } userId() { - return this.credentials.userId; + return this._credentials.userId; } userName() { - return this.credentials.userId.split(":")[0].substr(1); + return this._credentials.userId.split(":")[0].substr(1); + } + + displayName() { + return this._displayName; } async setDisplayName(displayName) { - await this._put(`/profile/${this.credentials.userId}/displayname`, { + this._displayName = displayName; + await this._put(`/profile/${this._credentials.userId}/displayname`, { displayname: displayName }); } @@ -76,10 +82,10 @@ module.exports = class RestSession { async _request(method, csApiPath, body) { try { const responseBody = await request({ - url: `${this.credentials.hsUrl}/_matrix/client/r0${csApiPath}`, + url: `${this._credentials.hsUrl}/_matrix/client/r0${csApiPath}`, method, headers: { - "Authorization": `Bearer ${this.credentials.accessToken}` + "Authorization": `Bearer ${this._credentials.accessToken}` }, json: true, body From 29aec256df052b758a0883a397997825ed5114ed Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Sep 2018 14:53:19 +0200 Subject: [PATCH 16/18] finish basic LL test to see if display names appear from lazy loaded state --- src/scenario.js | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/scenario.js b/src/scenario.js index 70ceae1471..946a4122ef 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -44,8 +44,8 @@ module.exports = async function scenario(createSession, restCreator) { const bob = await createUser("bob"); const charlies = await createRestUsers(restCreator); - // await createDirectoryRoomAndTalk(alice, bob); - // await createE2ERoomAndTalk(alice, bob); + await createDirectoryRoomAndTalk(alice, bob); + await createE2ERoomAndTalk(alice, bob); await aLazyLoadingTest(alice, bob, charlies); } @@ -106,20 +106,36 @@ async function createE2ERoomAndTalk(alice, bob) { } async function aLazyLoadingTest(alice, bob, charlies) { + console.log(" creating a room for lazy loading member scenarios:"); await enableLazyLoading(alice); const room = "Lazy Loading Test"; const alias = "#lltest:localhost"; + const charlyMsg1 = "hi bob!"; + const charlyMsg2 = "how's it going??"; await createRoom(bob, room); await changeRoomSettings(bob, {directory: true, visibility: "public_no_guests", alias}); // wait for alias to be set by server after clicking "save" + // so the charlies can join it. await bob.delay(500); - await charlies.join(alias); - const messageRange = range(1, 20); + const charlyMembers = await charlies.join(alias); + await charlyMembers.talk(charlyMsg1); + await charlyMembers.talk(charlyMsg2); bob.log.step("sends 20 messages").mute(); for(let i = 20; i >= 1; --i) { await sendMessage(bob, `I will only say this ${i} time(s)!`); } bob.log.unmute().done(); - await join(alice, room); - + await join(alice, alias); + await scrollToTimelineTop(alice); + //alice should see 2 messages from every charly with + //the correct display name + const expectedMessages = [charlyMsg1, charlyMsg2].reduce((messages, msgText) => { + return charlies.sessions.reduce((messages, charly) => { + return messages.concat({ + sender: charly.displayName(), + body: msgText, + }); + }, messages); + }, []); + await checkTimelineContains(alice, expectedMessages, "Charly #1-10"); } From 7bcb255a2c38dcb220d67a85303d84b3fa5a503b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Sep 2018 16:47:24 +0200 Subject: [PATCH 17/18] increase timeout here in case this wouldnt be enough for the CI server --- src/tests/timeline.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/timeline.js b/src/tests/timeline.js index 1e724a2d39..beaaec5e5a 100644 --- a/src/tests/timeline.js +++ b/src/tests/timeline.js @@ -25,13 +25,13 @@ module.exports.scrollToTimelineTop = async function(session) { let timeoutHandle = null; // set scrollTop to 0 in a loop and check every 50ms // if content became available (scrollTop not being 0 anymore), - // assume everything is loaded after 1000ms + // assume everything is loaded after 3s do { if (timelineScrollView.scrollTop !== 0) { if (timeoutHandle) { clearTimeout(timeoutHandle); } - timeoutHandle = setTimeout(() => timedOut = true, 1000); + timeoutHandle = setTimeout(() => timedOut = true, 3000); timelineScrollView.scrollTop = 0; } else { await new Promise((resolve) => setTimeout(resolve, 50)); From e843d532ebe38dff7b6b934226c4f355f4689c76 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Sep 2018 16:48:40 +0200 Subject: [PATCH 18/18] these changes were not needed in the end --- synapse/install.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/synapse/install.sh b/synapse/install.sh index a438ea5dc2..3d8172a9f6 100755 --- a/synapse/install.sh +++ b/synapse/install.sh @@ -31,11 +31,9 @@ python -m synapse.app.homeserver \ --generate-config \ --report-stats=no # apply configuration -REGISTRATION_SHARED_SECRET=$(uuidgen) cp -r $BASE_DIR/config-templates/$CONFIG_TEMPLATE/. ./ sed -i "s#{{SYNAPSE_ROOT}}#$(pwd)/#g" homeserver.yaml sed -i "s#{{SYNAPSE_PORT}}#${PORT}#g" homeserver.yaml sed -i "s#{{FORM_SECRET}}#$(uuidgen)#g" homeserver.yaml -sed -i "s#{{REGISTRATION_SHARED_SECRET}}#${REGISTRATION_SHARED_SECRET}#g" homeserver.yaml +sed -i "s#{{REGISTRATION_SHARED_SECRET}}#$(uuidgen)#g" homeserver.yaml sed -i "s#{{MACAROON_SECRET_KEY}}#$(uuidgen)#g" homeserver.yaml -echo REGISTRATION_SHARED_SECRET=$REGISTRATION_SHARED_SECRET=