UNPKG

6.91 kBJavaScriptView Raw
1/*
2Copyright 2016 OpenMarket Ltd
3Copyright 2017 Vector Creations Ltd
4Copyright 2018 New Vector Ltd
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17*/
18
19"use strict";
20
21// load olm before the sdk if possible
22import './olm-loader';
23
24import sdk from '..';
25import testUtils from './test-utils';
26import MockHttpBackend from 'matrix-mock-request';
27import expect from 'expect';
28import Promise from 'bluebird';
29import LocalStorageCryptoStore from '../lib/crypto/store/localStorage-crypto-store';
30
31/**
32 * Wrapper for a MockStorageApi, MockHttpBackend and MatrixClient
33 *
34 * @constructor
35 * @param {string} userId
36 * @param {string} deviceId
37 * @param {string} accessToken
38 *
39 * @param {WebStorage=} sessionStoreBackend a web storage object to use for the
40 * session store. If undefined, we will create a MockStorageApi.
41 */
42export default function TestClient(
43 userId, deviceId, accessToken, sessionStoreBackend,
44) {
45 this.userId = userId;
46 this.deviceId = deviceId;
47
48 if (sessionStoreBackend === undefined) {
49 sessionStoreBackend = new testUtils.MockStorageApi();
50 }
51 const sessionStore = new sdk.WebStorageSessionStore(sessionStoreBackend);
52
53 // expose this so the tests can get to it
54 this.cryptoStore = new LocalStorageCryptoStore(sessionStoreBackend);
55
56 this.httpBackend = new MockHttpBackend();
57 this.client = sdk.createClient({
58 baseUrl: "http://" + userId + ".test.server",
59 userId: userId,
60 accessToken: accessToken,
61 deviceId: deviceId,
62 sessionStore: sessionStore,
63 cryptoStore: this.cryptoStore,
64 request: this.httpBackend.requestFn,
65 });
66
67 this.deviceKeys = null;
68 this.oneTimeKeys = {};
69}
70
71TestClient.prototype.toString = function() {
72 return 'TestClient[' + this.userId + ']';
73};
74
75/**
76 * start the client, and wait for it to initialise.
77 *
78 * @return {Promise}
79 */
80TestClient.prototype.start = function() {
81 console.log(this + ': starting');
82 this.httpBackend.when("GET", "/pushrules").respond(200, {});
83 this.httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
84 this.expectDeviceKeyUpload();
85
86 // we let the client do a very basic initial sync, which it needs before
87 // it will upload one-time keys.
88 this.httpBackend.when("GET", "/sync").respond(200, { next_batch: 1 });
89
90 this.client.startClient({
91 // set this so that we can get hold of failed events
92 pendingEventOrdering: 'detached',
93 });
94
95 return Promise.all([
96 this.httpBackend.flushAllExpected(),
97 testUtils.syncPromise(this.client),
98 ]).then(() => {
99 console.log(this + ': started');
100 });
101};
102
103/**
104 * stop the client
105 */
106TestClient.prototype.stop = function() {
107 this.client.stopClient();
108};
109
110/**
111 * Set up expectations that the client will upload device keys.
112 */
113TestClient.prototype.expectDeviceKeyUpload = function() {
114 const self = this;
115 this.httpBackend.when("POST", "/keys/upload").respond(200, function(path, content) {
116 expect(content.one_time_keys).toBe(undefined);
117 expect(content.device_keys).toBeTruthy();
118
119 console.log(self + ': received device keys');
120 // we expect this to happen before any one-time keys are uploaded.
121 expect(Object.keys(self.oneTimeKeys).length).toEqual(0);
122
123 self.deviceKeys = content.device_keys;
124 return {one_time_key_counts: {signed_curve25519: 0}};
125 });
126};
127
128
129/**
130 * If one-time keys have already been uploaded, return them. Otherwise,
131 * set up an expectation that the keys will be uploaded, and wait for
132 * that to happen.
133 *
134 * @returns {Promise} for the one-time keys
135 */
136TestClient.prototype.awaitOneTimeKeyUpload = function() {
137 if (Object.keys(this.oneTimeKeys).length != 0) {
138 // already got one-time keys
139 return Promise.resolve(this.oneTimeKeys);
140 }
141
142 this.httpBackend.when("POST", "/keys/upload")
143 .respond(200, (path, content) => {
144 expect(content.device_keys).toBe(undefined);
145 expect(content.one_time_keys).toBe(undefined);
146 return {one_time_key_counts: {
147 signed_curve25519: Object.keys(this.oneTimeKeys).length,
148 }};
149 });
150
151 this.httpBackend.when("POST", "/keys/upload")
152 .respond(200, (path, content) => {
153 expect(content.device_keys).toBe(undefined);
154 expect(content.one_time_keys).toBeTruthy();
155 expect(content.one_time_keys).toNotEqual({});
156 console.log('%s: received %i one-time keys', this,
157 Object.keys(content.one_time_keys).length);
158 this.oneTimeKeys = content.one_time_keys;
159 return {one_time_key_counts: {
160 signed_curve25519: Object.keys(this.oneTimeKeys).length,
161 }};
162 });
163
164 // this can take ages
165 return this.httpBackend.flush('/keys/upload', 2, 1000).then((flushed) => {
166 expect(flushed).toEqual(2);
167 return this.oneTimeKeys;
168 });
169};
170
171/**
172 * Set up expectations that the client will query device keys.
173 *
174 * We check that the query contains each of the users in `response`.
175 *
176 * @param {Object} response response to the query.
177 */
178TestClient.prototype.expectKeyQuery = function(response) {
179 this.httpBackend.when('POST', '/keys/query').respond(
180 200, (path, content) => {
181 Object.keys(response.device_keys).forEach((userId) => {
182 expect(content.device_keys[userId]).toEqual({});
183 });
184 return response;
185 });
186};
187
188
189/**
190 * get the uploaded curve25519 device key
191 *
192 * @return {string} base64 device key
193 */
194TestClient.prototype.getDeviceKey = function() {
195 const keyId = 'curve25519:' + this.deviceId;
196 return this.deviceKeys.keys[keyId];
197};
198
199
200/**
201 * get the uploaded ed25519 device key
202 *
203 * @return {string} base64 device key
204 */
205TestClient.prototype.getSigningKey = function() {
206 const keyId = 'ed25519:' + this.deviceId;
207 return this.deviceKeys.keys[keyId];
208};
209
210/**
211 * flush a single /sync request, and wait for the syncing event
212 *
213 * @returns {Promise} promise which completes once the sync has been flushed
214 */
215TestClient.prototype.flushSync = function() {
216 console.log(`${this}: flushSync`);
217 return Promise.all([
218 this.httpBackend.flush('/sync', 1),
219 testUtils.syncPromise(this.client),
220 ]).then(() => {
221 console.log(`${this}: flushSync completed`);
222 });
223};