1 | "use strict";
|
2 | import 'source-map-support/register';
|
3 | const sdk = require("../..");
|
4 | const HttpBackend = require("matrix-mock-request");
|
5 | const publicGlobals = require("../../lib/matrix");
|
6 | const Room = publicGlobals.Room;
|
7 | const MemoryStore = publicGlobals.MemoryStore;
|
8 | const Filter = publicGlobals.Filter;
|
9 | const utils = require("../test-utils");
|
10 | const MockStorageApi = require("../MockStorageApi");
|
11 |
|
12 | import expect from 'expect';
|
13 |
|
14 | describe("MatrixClient", function() {
|
15 | const baseUrl = "http://localhost.or.something";
|
16 | let client = null;
|
17 | let httpBackend = null;
|
18 | let store = null;
|
19 | let sessionStore = null;
|
20 | const userId = "@alice:localhost";
|
21 | const accessToken = "aseukfgwef";
|
22 |
|
23 | beforeEach(function() {
|
24 | utils.beforeEach(this);
|
25 | httpBackend = new HttpBackend();
|
26 | store = new MemoryStore();
|
27 |
|
28 | const mockStorage = new MockStorageApi();
|
29 | sessionStore = new sdk.WebStorageSessionStore(mockStorage);
|
30 |
|
31 | sdk.request(httpBackend.requestFn);
|
32 | client = sdk.createClient({
|
33 | baseUrl: baseUrl,
|
34 | userId: userId,
|
35 | deviceId: "aliceDevice",
|
36 | accessToken: accessToken,
|
37 | store: store,
|
38 | sessionStore: sessionStore,
|
39 | });
|
40 | });
|
41 |
|
42 | afterEach(function() {
|
43 | httpBackend.verifyNoOutstandingExpectation();
|
44 | return httpBackend.stop();
|
45 | });
|
46 |
|
47 | describe("uploadContent", function() {
|
48 | const buf = new Buffer('hello world');
|
49 | it("should upload the file", function(done) {
|
50 | httpBackend.when(
|
51 | "POST", "/_matrix/media/r0/upload",
|
52 | ).check(function(req) {
|
53 | expect(req.rawData).toEqual(buf);
|
54 | expect(req.queryParams.filename).toEqual("hi.txt");
|
55 | if (!(req.queryParams.access_token == accessToken ||
|
56 | req.headers["Authorization"] == "Bearer " + accessToken)) {
|
57 | expect(true).toBe(false);
|
58 | }
|
59 | expect(req.headers["Content-Type"]).toEqual("text/plain");
|
60 | expect(req.opts.json).toBeFalsy();
|
61 | expect(req.opts.timeout).toBe(undefined);
|
62 | }).respond(200, "content", true);
|
63 |
|
64 | const prom = client.uploadContent({
|
65 | stream: buf,
|
66 | name: "hi.txt",
|
67 | type: "text/plain",
|
68 | });
|
69 |
|
70 | expect(prom).toBeTruthy();
|
71 |
|
72 | const uploads = client.getCurrentUploads();
|
73 | expect(uploads.length).toEqual(1);
|
74 | expect(uploads[0].promise).toBe(prom);
|
75 | expect(uploads[0].loaded).toEqual(0);
|
76 |
|
77 | prom.then(function(response) {
|
78 |
|
79 | expect(response).toEqual("content");
|
80 |
|
81 | const uploads = client.getCurrentUploads();
|
82 | expect(uploads.length).toEqual(0);
|
83 | }).nodeify(done);
|
84 |
|
85 | httpBackend.flush();
|
86 | });
|
87 |
|
88 | it("should parse the response if rawResponse=false", function(done) {
|
89 | httpBackend.when(
|
90 | "POST", "/_matrix/media/r0/upload",
|
91 | ).check(function(req) {
|
92 | expect(req.opts.json).toBeFalsy();
|
93 | }).respond(200, { "content_uri": "uri" });
|
94 |
|
95 | client.uploadContent({
|
96 | stream: buf,
|
97 | name: "hi.txt",
|
98 | type: "text/plain",
|
99 | }, {
|
100 | rawResponse: false,
|
101 | }).then(function(response) {
|
102 | expect(response.content_uri).toEqual("uri");
|
103 | }).nodeify(done);
|
104 |
|
105 | httpBackend.flush();
|
106 | });
|
107 |
|
108 | it("should parse errors into a MatrixError", function(done) {
|
109 | httpBackend.when(
|
110 | "POST", "/_matrix/media/r0/upload",
|
111 | ).check(function(req) {
|
112 | expect(req.rawData).toEqual(buf);
|
113 | expect(req.opts.json).toBeFalsy();
|
114 | }).respond(400, {
|
115 | "errcode": "M_SNAFU",
|
116 | "error": "broken",
|
117 | });
|
118 |
|
119 | client.uploadContent({
|
120 | stream: buf,
|
121 | name: "hi.txt",
|
122 | type: "text/plain",
|
123 | }).then(function(response) {
|
124 | throw Error("request not failed");
|
125 | }, function(error) {
|
126 | expect(error.httpStatus).toEqual(400);
|
127 | expect(error.errcode).toEqual("M_SNAFU");
|
128 | expect(error.message).toEqual("broken");
|
129 | }).nodeify(done);
|
130 |
|
131 | httpBackend.flush();
|
132 | });
|
133 |
|
134 | it("should return a promise which can be cancelled", function(done) {
|
135 | const prom = client.uploadContent({
|
136 | stream: buf,
|
137 | name: "hi.txt",
|
138 | type: "text/plain",
|
139 | });
|
140 |
|
141 | const uploads = client.getCurrentUploads();
|
142 | expect(uploads.length).toEqual(1);
|
143 | expect(uploads[0].promise).toBe(prom);
|
144 | expect(uploads[0].loaded).toEqual(0);
|
145 |
|
146 | prom.then(function(response) {
|
147 | throw Error("request not aborted");
|
148 | }, function(error) {
|
149 | expect(error).toEqual("aborted");
|
150 |
|
151 | const uploads = client.getCurrentUploads();
|
152 | expect(uploads.length).toEqual(0);
|
153 | }).nodeify(done);
|
154 |
|
155 | const r = client.cancelUpload(prom);
|
156 | expect(r).toBe(true);
|
157 | });
|
158 | });
|
159 |
|
160 | describe("joinRoom", function() {
|
161 | it("should no-op if you've already joined a room", function() {
|
162 | const roomId = "!foo:bar";
|
163 | const room = new Room(roomId, userId);
|
164 | room.addLiveEvents([
|
165 | utils.mkMembership({
|
166 | user: userId, room: roomId, mship: "join", event: true,
|
167 | }),
|
168 | ]);
|
169 | store.storeRoom(room);
|
170 | client.joinRoom(roomId);
|
171 | httpBackend.verifyNoOutstandingRequests();
|
172 | });
|
173 | });
|
174 |
|
175 | describe("getFilter", function() {
|
176 | const filterId = "f1lt3r1d";
|
177 |
|
178 | it("should return a filter from the store if allowCached", function(done) {
|
179 | const filter = Filter.fromJson(userId, filterId, {
|
180 | event_format: "client",
|
181 | });
|
182 | store.storeFilter(filter);
|
183 | client.getFilter(userId, filterId, true).done(function(gotFilter) {
|
184 | expect(gotFilter).toEqual(filter);
|
185 | done();
|
186 | });
|
187 | httpBackend.verifyNoOutstandingRequests();
|
188 | });
|
189 |
|
190 | it("should do an HTTP request if !allowCached even if one exists",
|
191 | function(done) {
|
192 | const httpFilterDefinition = {
|
193 | event_format: "federation",
|
194 | };
|
195 |
|
196 | httpBackend.when(
|
197 | "GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
|
198 | ).respond(200, httpFilterDefinition);
|
199 |
|
200 | const storeFilter = Filter.fromJson(userId, filterId, {
|
201 | event_format: "client",
|
202 | });
|
203 | store.storeFilter(storeFilter);
|
204 | client.getFilter(userId, filterId, false).done(function(gotFilter) {
|
205 | expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
|
206 | done();
|
207 | });
|
208 |
|
209 | httpBackend.flush();
|
210 | });
|
211 |
|
212 | it("should do an HTTP request if nothing is in the cache and then store it",
|
213 | function(done) {
|
214 | const httpFilterDefinition = {
|
215 | event_format: "federation",
|
216 | };
|
217 | expect(store.getFilter(userId, filterId)).toBe(null);
|
218 |
|
219 | httpBackend.when(
|
220 | "GET", "/user/" + encodeURIComponent(userId) + "/filter/" + filterId,
|
221 | ).respond(200, httpFilterDefinition);
|
222 | client.getFilter(userId, filterId, true).done(function(gotFilter) {
|
223 | expect(gotFilter.getDefinition()).toEqual(httpFilterDefinition);
|
224 | expect(store.getFilter(userId, filterId)).toBeTruthy();
|
225 | done();
|
226 | });
|
227 |
|
228 | httpBackend.flush();
|
229 | });
|
230 | });
|
231 |
|
232 | describe("createFilter", function() {
|
233 | const filterId = "f1llllllerid";
|
234 |
|
235 | it("should do an HTTP request and then store the filter", function(done) {
|
236 | expect(store.getFilter(userId, filterId)).toBe(null);
|
237 |
|
238 | const filterDefinition = {
|
239 | event_format: "client",
|
240 | };
|
241 |
|
242 | httpBackend.when(
|
243 | "POST", "/user/" + encodeURIComponent(userId) + "/filter",
|
244 | ).check(function(req) {
|
245 | expect(req.data).toEqual(filterDefinition);
|
246 | }).respond(200, {
|
247 | filter_id: filterId,
|
248 | });
|
249 |
|
250 | client.createFilter(filterDefinition).done(function(gotFilter) {
|
251 | expect(gotFilter.getDefinition()).toEqual(filterDefinition);
|
252 | expect(store.getFilter(userId, filterId)).toEqual(gotFilter);
|
253 | done();
|
254 | });
|
255 |
|
256 | httpBackend.flush();
|
257 | });
|
258 | });
|
259 |
|
260 | describe("searching", function() {
|
261 | const response = {
|
262 | search_categories: {
|
263 | room_events: {
|
264 | count: 24,
|
265 | results: {
|
266 | "$flibble:localhost": {
|
267 | rank: 0.1,
|
268 | result: {
|
269 | type: "m.room.message",
|
270 | user_id: "@alice:localhost",
|
271 | room_id: "!feuiwhf:localhost",
|
272 | content: {
|
273 | body: "a result",
|
274 | msgtype: "m.text",
|
275 | },
|
276 | },
|
277 | },
|
278 | },
|
279 | },
|
280 | },
|
281 | };
|
282 |
|
283 | it("searchMessageText should perform a /search for room_events", function(done) {
|
284 | client.searchMessageText({
|
285 | query: "monkeys",
|
286 | });
|
287 | httpBackend.when("POST", "/search").check(function(req) {
|
288 | expect(req.data).toEqual({
|
289 | search_categories: {
|
290 | room_events: {
|
291 | search_term: "monkeys",
|
292 | },
|
293 | },
|
294 | });
|
295 | }).respond(200, response);
|
296 |
|
297 | httpBackend.flush().done(function() {
|
298 | done();
|
299 | });
|
300 | });
|
301 | });
|
302 |
|
303 |
|
304 | describe("downloadKeys", function() {
|
305 | if (!sdk.CRYPTO_ENABLED) {
|
306 | return;
|
307 | }
|
308 |
|
309 | beforeEach(function() {
|
310 | return client.initCrypto();
|
311 | });
|
312 |
|
313 | it("should do an HTTP request and then store the keys", function(done) {
|
314 | const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
|
315 |
|
316 | const borisKeys = {
|
317 | dev1: {
|
318 | algorithms: ["1"],
|
319 | device_id: "dev1",
|
320 | keys: { "ed25519:dev1": ed25519key },
|
321 | signatures: {
|
322 | boris: {
|
323 | "ed25519:dev1":
|
324 | "RAhmbNDq1efK3hCpBzZDsKoGSsrHUxb25NW5/WbEV9R" +
|
325 | "JVwLdP032mg5QsKt/pBDUGtggBcnk43n3nBWlA88WAw",
|
326 | },
|
327 | },
|
328 | unsigned: { "abc": "def" },
|
329 | user_id: "boris",
|
330 | },
|
331 | };
|
332 | const chazKeys = {
|
333 | dev2: {
|
334 | algorithms: ["2"],
|
335 | device_id: "dev2",
|
336 | keys: { "ed25519:dev2": ed25519key },
|
337 | signatures: {
|
338 | chaz: {
|
339 | "ed25519:dev2":
|
340 | "FwslH/Q7EYSb7swDJbNB5PSzcbEO1xRRBF1riuijqvL" +
|
341 | "EkrK9/XVN8jl4h7thGuRITQ01siBQnNmMK9t45QfcCQ",
|
342 | },
|
343 | },
|
344 | unsigned: { "ghi": "def" },
|
345 | user_id: "chaz",
|
346 | },
|
347 | };
|
348 |
|
349 | |
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 | httpBackend.when("POST", "/keys/query").check(function(req) {
|
364 | expect(req.data).toEqual({device_keys: {
|
365 | 'boris': {},
|
366 | 'chaz': {},
|
367 | }});
|
368 | }).respond(200, {
|
369 | device_keys: {
|
370 | boris: borisKeys,
|
371 | chaz: chazKeys,
|
372 | },
|
373 | });
|
374 |
|
375 | client.downloadKeys(["boris", "chaz"]).then(function(res) {
|
376 | assertObjectContains(res.boris.dev1, {
|
377 | verified: 0,
|
378 | keys: { "ed25519:dev1": ed25519key },
|
379 | algorithms: ["1"],
|
380 | unsigned: { "abc": "def" },
|
381 | });
|
382 |
|
383 | assertObjectContains(res.chaz.dev2, {
|
384 | verified: 0,
|
385 | keys: { "ed25519:dev2": ed25519key },
|
386 | algorithms: ["2"],
|
387 | unsigned: { "ghi": "def" },
|
388 | });
|
389 | }).nodeify(done);
|
390 |
|
391 | httpBackend.flush();
|
392 | });
|
393 | });
|
394 |
|
395 | describe("deleteDevice", function() {
|
396 | const auth = {a: 1};
|
397 | it("should pass through an auth dict", function(done) {
|
398 | httpBackend.when(
|
399 | "DELETE", "/_matrix/client/r0/devices/my_device",
|
400 | ).check(function(req) {
|
401 | expect(req.data).toEqual({auth: auth});
|
402 | }).respond(200);
|
403 |
|
404 | client.deleteDevice(
|
405 | "my_device", auth,
|
406 | ).nodeify(done);
|
407 |
|
408 | httpBackend.flush();
|
409 | });
|
410 | });
|
411 | });
|
412 |
|
413 | function assertObjectContains(obj, expected) {
|
414 | for (const k in expected) {
|
415 | if (expected.hasOwnProperty(k)) {
|
416 | expect(obj[k]).toEqual(expected[k]);
|
417 | }
|
418 | }
|
419 | }
|