diff --git a/src/rest/creator.js b/src/rest/creator.js index 9090a21e70..84b1fbc70a 100644 --- a/src/rest/creator.js +++ b/src/rest/creator.js @@ -27,10 +27,10 @@ module.exports = class RestSessionCreator { this.cwd = cwd; } - async createSessionRange(usernames, password) { + async createSessionRange(usernames, password, groupName) { const sessionPromises = usernames.map((username) => this.createSession(username, password)); const sessions = await Promise.all(sessionPromises); - return new RestMultiSession(sessions); + return new RestMultiSession(sessions, groupName); } async createSession(username, password) { diff --git a/src/rest/multi.js b/src/rest/multi.js index 12ebe9d4ab..3d24245ddf 100644 --- a/src/rest/multi.js +++ b/src/rest/multi.js @@ -17,14 +17,16 @@ limitations under the License. const request = require('request-promise-native'); const RestRoom = require('./room'); const {approveConsent} = require('./consent'); +const Logger = require('../logger'); module.exports = class RestMultiSession { - constructor(sessions) { + constructor(sessions, groupName) { + this.log = new Logger(groupName); this.sessions = sessions; } - slice(start, end) { - return new RestMultiSession(this.sessions.slice(start, end)); + slice(groupName, start, end) { + return new RestMultiSession(this.sessions.slice(start, end), groupName); } pop(userName) { @@ -37,25 +39,52 @@ module.exports = class RestMultiSession { } async setDisplayName(fn) { - await Promise.all(this.sessions.map((s) => s.setDisplayName(fn(s)))); + this.log.step("set their display name") + await Promise.all(this.sessions.map(async (s) => { + s.log.mute(); + await s.setDisplayName(fn(s)); + s.log.unmute(); + })); + this.log.done(); } - async join(roomId) { - const rooms = await Promise.all(this.sessions.map((s) => s.join(roomId))); - return new RestMultiRoom(rooms); + async join(roomIdOrAlias) { + this.log.step(`join ${roomIdOrAlias}`) + const rooms = await Promise.all(this.sessions.map(async (s) => { + s.log.mute(); + const room = await s.join(roomIdOrAlias); + s.log.unmute(); + return room; + })); + this.log.done(); + return new RestMultiRoom(rooms, roomIdOrAlias, this.log); } } class RestMultiRoom { - constructor(rooms) { + constructor(rooms, roomIdOrAlias, log) { this.rooms = rooms; + this.roomIdOrAlias = roomIdOrAlias; + this.log = log; } async talk(message) { - await Promise.all(this.rooms.map((r) => r.talk(message))); + this.log.step(`say "${message}" in ${this.roomIdOrAlias}`) + await Promise.all(this.rooms.map(async (r) => { + r.log.mute(); + await r.talk(message); + r.log.unmute(); + })); + this.log.done(); } async leave() { - await Promise.all(this.rooms.map((r) => r.leave())); + this.log.step(`leave ${this.roomIdOrAlias}`) + await Promise.all(this.rooms.map(async (r) => { + r.log.mute(); + await r.leave(message); + r.log.unmute(); + })); + this.log.done(); } } diff --git a/src/rest/room.js b/src/rest/room.js index d8de958a27..a7f40af594 100644 --- a/src/rest/room.js +++ b/src/rest/room.js @@ -18,22 +18,27 @@ const uuidv4 = require('uuid/v4'); /* no pun intented */ module.exports = class RestRoom { - constructor(session, roomId) { + constructor(session, roomId, log) { this.session = session; this._roomId = roomId; + this.log = log; } async talk(message) { + this.log.step(`says "${message}" in ${this._roomId}`) const txId = uuidv4(); await this.session._put(`/rooms/${this._roomId}/send/m.room.message/${txId}`, { "msgtype": "m.text", "body": message }); + this.log.done(); return txId; } async leave() { + this.log.step(`leaves ${this._roomId}`) await this.session._post(`/rooms/${this._roomId}/leave`); + this.log.done(); } roomId() { diff --git a/src/rest/session.js b/src/rest/session.js index ece04f3352..21922a69f1 100644 --- a/src/rest/session.js +++ b/src/rest/session.js @@ -15,11 +15,13 @@ limitations under the License. */ const request = require('request-promise-native'); +const Logger = require('../logger'); const RestRoom = require('./room'); const {approveConsent} = require('./consent'); module.exports = class RestSession { constructor(credentials) { + this.log = new Logger(credentials.userId); this._credentials = credentials; this._displayName = null; } @@ -37,18 +39,23 @@ module.exports = class RestSession { } async setDisplayName(displayName) { + this.log.step(`sets their display name to ${displayName}`); this._displayName = displayName; await this._put(`/profile/${this._credentials.userId}/displayname`, { displayname: displayName }); + this.log.done(); } async join(roomIdOrAlias) { + this.log.step(`joins ${roomIdOrAlias}`); const {room_id} = await this._post(`/join/${encodeURIComponent(roomIdOrAlias)}`); - return new RestRoom(this, room_id); + this.log.done(); + return new RestRoom(this, room_id, this.log); } async createRoom(name, options) { + this.log.step(`creates room ${name}`); const body = { name, }; @@ -68,7 +75,8 @@ module.exports = class RestSession { } const {room_id} = await this._post(`/createRoom`, body); - return new RestRoom(this, room_id); + this.log.done(); + return new RestRoom(this, room_id, this.log); } _post(csApiPath, body) { diff --git a/src/scenario.js b/src/scenario.js index f0b4ad988b..12cff7d498 100644 --- a/src/scenario.js +++ b/src/scenario.js @@ -41,7 +41,7 @@ module.exports = async function scenario(createSession, restCreator) { async function createRestUsers(restCreator) { const usernames = range(1, 10).map((i) => `charly-${i}`); - const charlies = await restCreator.createSessionRange(usernames, 'testtest'); + const charlies = await restCreator.createSessionRange(usernames, "testtest", "charly-1..10"); await charlies.setDisplayName((s) => `Charly #${s.userName().split('-')[1]}`); return charlies; } diff --git a/src/scenarios/lazy-loading.js b/src/scenarios/lazy-loading.js index bd7c1d1507..c33e83215c 100644 --- a/src/scenarios/lazy-loading.js +++ b/src/scenarios/lazy-loading.js @@ -31,9 +31,15 @@ const assert = require('assert'); module.exports = async function lazyLoadingScenarios(alice, bob, charlies) { console.log(" creating a room for lazy loading member scenarios:"); await enableLazyLoading(alice); - await setupRoomWithBobAliceAndCharlies(alice, bob, charlies); - await checkPaginatedDisplayNames(alice, charlies); - await checkMemberList(alice, charlies); + const charly1to5 = charlies.slice("charly-1..5", 0, 5); + const charly6to10 = charlies.slice("charly-6..10", 5); + assert(charly1to5.sessions.length, 5); + assert(charly6to10.sessions.length, 5); + await setupRoomWithBobAliceAndCharlies(alice, bob, charly1to5); + await checkPaginatedDisplayNames(alice, charly1to5); + await checkMemberList(alice, charly1to5); + await joinCharliesWhileAliceIsOffline(alice, charly6to10); + await checkMemberList(alice, charly6to10); } const room = "Lazy Loading Test"; @@ -70,11 +76,11 @@ async function checkPaginatedDisplayNames(alice, charlies) { }); }, messages); }, []); - await checkTimelineContains(alice, expectedMessages, "Charly #1-10"); + await checkTimelineContains(alice, expectedMessages, charlies.log.username); } async function checkMemberList(alice, charlies) { - alice.log.step("checks the memberlist contains herself, bob and all charlies"); + alice.log.step(`checks the memberlist contains herself, bob and ${charlies.log.username}`); const displayNames = (await getMembersInMemberlist(alice)).map((m) => m.displayName); assert(displayNames.includes("alice")); assert(displayNames.includes("bob")); @@ -85,3 +91,19 @@ async function checkMemberList(alice, charlies) { }); alice.log.done(); } + +async function joinCharliesWhileAliceIsOffline(alice, charly6to10) { + await alice.setOffline(true); + await delay(1000); + const members6to10 = await charly6to10.join(alias); + const member6 = members6to10.rooms[0]; + member6.log.step("sends 20 messages").mute(); + for(let i = 20; i >= 1; --i) { + await member6.talk("where is charly?"); + } + member6.log.unmute().done(); + const catchupPromise = alice.waitForNextSuccessfulSync(); + await alice.setOffline(false); + await catchupPromise; + await delay(2000); +} diff --git a/src/session.js b/src/session.js index 3f233ee8f2..7ea980bd32 100644 --- a/src/session.js +++ b/src/session.js @@ -161,6 +161,33 @@ module.exports = class RiotSession { }); } + waitForSyncResponseWith(predicate) { + return this.page.waitForResponse(async (response) => { + if (response.request().url().indexOf("/sync") === -1) { + return false; + } + return predicate(response); + }); + } + + /** wait for a /sync request started after this call that gets a 200 response */ + async waitForNextSuccessfulSync() { + const syncUrls = []; + function onRequest(request) { + if (request.url().indexOf("/sync") !== -1) { + syncUrls.push(request.url()); + } + } + + this.page.on('request', onRequest); + + await this.page.waitForResponse((response) => { + return syncUrls.includes(response.request().url()) && response.status() === 200; + }); + + this.page.removeListener('request', onRequest); + } + goto(url) { return this.page.goto(url); } @@ -173,6 +200,13 @@ module.exports = class RiotSession { return delay(ms); } + async setOffline(enabled) { + const description = enabled ? "offline" : "back online"; + this.log.step(`goes ${description}`); + await this.page.setOfflineMode(enabled); + this.log.done(); + } + close() { return this.browser.close(); } diff --git a/src/usecases/timeline.js b/src/usecases/timeline.js index 466d7fb222..dce0203660 100644 --- a/src/usecases/timeline.js +++ b/src/usecases/timeline.js @@ -64,10 +64,7 @@ module.exports.receiveMessage = async function(session, expectedMessage) { if (isExpectedMessage) { assertMessage(lastMessage, expectedMessage); } else { - await session.page.waitForResponse(async (response) => { - if (response.request().url().indexOf("/sync") === -1) { - return false; - } + await session.waitForSyncResponseWith(async (response) => { const body = await response.text(); if (expectedMessage.encrypted) { return body.indexOf(expectedMessage.sender) !== -1 && diff --git a/synapse/install.sh b/synapse/install.sh index 3d8172a9f6..37dfd7d7e2 100755 --- a/synapse/install.sh +++ b/synapse/install.sh @@ -1,6 +1,6 @@ #!/bin/bash # config -SYNAPSE_BRANCH=master +SYNAPSE_BRANCH=develop INSTALLATION_NAME=consent SERVER_DIR=installations/$INSTALLATION_NAME CONFIG_TEMPLATE=consent