Merge branch 'hotfix/21.56.9' into master
[gitter.git] / modules / rooms / test / room-membership-service-test.js
blob6a1db264d405aaecb2dd7a3b51dfea254de911b1
1 'use strict';
3 var fixtureLoader = require('gitter-web-test-utils/lib/test-fixtures');
4 var assert = require('assert');
5 var Promise = require('bluebird');
6 var sinon = require('sinon');
7 var roomMembershipFlags = require('../lib/room-membership-flags');
8 var roomMembershipService = require('../lib/room-membership-service');
9 var persistence = require('gitter-web-persistence');
11 function mongoIdEqualPredicate(value) {
12   var strValue = String(value);
13   return function(x) {
14     return String(x) === strValue;
15   };
18 describe('room-membership-service', function() {
19   describe('integration tests #slow', function() {
20     var fixture = fixtureLoader.setup({
21       user1: {},
22       user2: {},
23       user3: {},
24       troupe1: {},
25       troupe2: {},
26       troupe3: {}
27     });
29     describe('addRoomMember', function() {
30       beforeEach(function() {
31         return roomMembershipService.removeRoomMembers(fixture.troupe3._id, [
32           fixture.user1.id,
33           fixture.user2.id,
34           fixture.user3.id
35         ]);
36       });
38       it('should add a single user to a room', function() {
39         var troupeId3 = fixture.troupe3._id;
40         var userId1 = fixture.user1._id;
41         var flags = roomMembershipFlags.MODES.all;
43         return roomMembershipService
44           .addRoomMember(troupeId3, userId1, flags)
45           .then(function() {
46             return roomMembershipService.countMembersInRoom(troupeId3);
47           })
48           .then(function(count) {
49             assert.strictEqual(count, 1);
50             return roomMembershipService.findMembersForRoom(troupeId3);
51           })
52           .then(function(members) {
53             assert.deepEqual(members, [userId1]);
55             return roomMembershipService.findRoomIdsForUser(userId1);
56           })
57           .then(function(roomIds) {
58             assert(roomIds.length >= 1);
59             assert(roomIds.some(mongoIdEqualPredicate(troupeId3)));
61             return persistence.TroupeUser.findOne({ troupeId: troupeId3, userId: userId1 }).exec();
62           })
63           .then(function(troupeUser) {
64             assert.strictEqual(troupeUser.flags, flags);
65           });
66       });
68       it('should handle different flags', function() {
69         var troupeId3 = fixture.troupe3._id;
70         var userId1 = fixture.user1._id;
71         var userId2 = fixture.user2._id;
72         var userId3 = fixture.user3._id;
74         return Promise.join(
75           roomMembershipService.addRoomMember(troupeId3, userId1, roomMembershipFlags.MODES.all),
76           roomMembershipService.addRoomMember(
77             troupeId3,
78             userId2,
79             roomMembershipFlags.MODES.announcement
80           ),
81           roomMembershipService.addRoomMember(troupeId3, userId3, roomMembershipFlags.MODES.mute)
82         )
83           .then(function() {
84             return roomMembershipService.findMembersForRoomWithLurk(troupeId3);
85           })
86           .then(function(result) {
87             var expected = {};
88             expected[userId1] = false;
89             expected[userId2] = false;
90             expected[userId3] = true;
91             assert.deepEqual(result, expected);
93             return roomMembershipService.getMembershipDetails(userId1, troupeId3);
94           })
95           .then(function(result) {
96             assert.strictEqual(result.flags, roomMembershipFlags.MODES.all);
97             return roomMembershipService.getMembershipDetails(userId2, troupeId3);
98           })
99           .then(function(result) {
100             assert.strictEqual(result.flags, roomMembershipFlags.MODES.announcement);
101             return roomMembershipService.getMembershipDetails(userId3, troupeId3);
102           })
103           .then(function(result) {
104             assert.strictEqual(result.flags, roomMembershipFlags.MODES.mute);
105           });
106       });
107     });
109     describe('removeRoomMembers', function() {
110       it('should allow users to be removed from a room', function() {
111         var flags = roomMembershipFlags.MODES.all;
113         return Promise.join(
114           roomMembershipService.addRoomMember(fixture.troupe2.id, fixture.user1.id, flags),
115           roomMembershipService.addRoomMember(fixture.troupe2.id, fixture.user2.id, flags)
116         )
117           .then(function() {
118             return persistence.Troupe.findById(fixture.troupe2.id).exec();
119           })
120           .then(function(troupe) {
121             assert.strictEqual(troupe.userCount, 2);
122             return roomMembershipService.removeRoomMembers(fixture.troupe2.id, [fixture.user1.id]);
123           })
124           .then(function() {
125             return roomMembershipService.countMembersInRoom(fixture.troupe2.id);
126           })
127           .then(function(count) {
128             assert.strictEqual(count, 1);
129             return persistence.Troupe.findById(fixture.troupe2.id).exec();
130           })
131           .then(function(troupe) {
132             assert.strictEqual(troupe.userCount, 1);
134             return roomMembershipService.checkRoomMembership(fixture.troupe2.id, fixture.user2.id);
135           })
136           .then(function(member) {
137             assert(member);
138             return roomMembershipService.checkRoomMembership(fixture.troupe2.id, fixture.user1.id);
139           })
140           .then(function(member) {
141             assert(!member);
142           });
143       });
144     });
146     describe('membership modes', function() {
147       beforeEach(function() {
148         this.onMembersLurkChange = sinon.spy();
150         roomMembershipService.events.on('members.lurk.change', this.onMembersLurkChange);
151       });
153       afterEach(function() {
154         roomMembershipService.events.removeListener(
155           'members.lurk.change',
156           this.onMembersLurkChange
157         );
158       });
160       it('should handle lurk status alongside membership mode mute', function() {
161         var troupeId2 = fixture.troupe2.id;
162         var userId1 = fixture.user1.id;
164         return roomMembershipService
165           .removeRoomMember(troupeId2, userId1)
166           .bind(this)
167           .then(function() {
168             return roomMembershipService.addRoomMember(
169               troupeId2,
170               userId1,
171               roomMembershipFlags.MODES.all
172             );
173           })
174           .then(function() {
175             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'mute');
176           })
177           .then(function() {
178             // Check that the event emitter fired
179             assert.strictEqual(1, this.onMembersLurkChange.callCount);
180             var spyCall = this.onMembersLurkChange.getCall(0);
182             assert.strictEqual(troupeId2, spyCall.args[0]);
183             assert.deepEqual([userId1], spyCall.args[1]);
184             assert.strictEqual(true, spyCall.args[2]);
186             return roomMembershipService.getMembershipDetails(userId1, troupeId2);
187           })
188           .then(function(modeExtended) {
189             assert.deepEqual(modeExtended, {
190               mode: 'mute',
191               lurk: true,
192               flags: parseInt('110', 2),
193               unread: false,
194               activity: true,
195               announcement: false,
196               mention: true,
197               desktop: false,
198               mobile: false,
199               default: false
200             });
201             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
202           })
203           .then(function(lurking) {
204             assert.strictEqual(lurking, true);
205           });
206       });
208       it('should handle lurk status alongside membership mode announcement', function() {
209         var troupeId2 = fixture.troupe2.id;
210         var userId1 = fixture.user1.id;
212         return roomMembershipService
213           .removeRoomMember(troupeId2, userId1)
214           .bind(this)
215           .then(function() {
216             return roomMembershipService.addRoomMember(
217               troupeId2,
218               userId1,
219               roomMembershipFlags.MODES.all
220             );
221           })
222           .then(function() {
223             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'announcement');
224           })
225           .then(function() {
226             // Check that the event emitter fired
227             assert.strictEqual(0, this.onMembersLurkChange.callCount);
228             return roomMembershipService.getMembershipMode(userId1, troupeId2);
229           })
230           .then(function(mode) {
231             assert.strictEqual(mode, 'announcement');
232             return roomMembershipService.getMembershipDetails(userId1, troupeId2);
233           })
234           .then(function(modeExtended) {
235             assert.deepEqual(modeExtended, {
236               mode: 'announcement',
237               lurk: false,
238               flags: parseInt('1101', 2),
239               unread: true,
240               activity: false,
241               announcement: true,
242               mention: true,
243               desktop: false,
244               mobile: false,
245               default: false
246             });
248             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
249           })
250           .then(function(lurking) {
251             assert.strictEqual(lurking, false);
252             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'mute');
253           })
254           .then(function() {
255             // Check that the event emitter fired
256             assert.strictEqual(1, this.onMembersLurkChange.callCount);
257             var spyCall = this.onMembersLurkChange.getCall(0);
259             assert.strictEqual(troupeId2, spyCall.args[0]);
260             assert.deepEqual([userId1], spyCall.args[1]);
261             assert.strictEqual(true, spyCall.args[2]);
263             return roomMembershipService.getMembershipMode(userId1, troupeId2);
264           })
265           .then(function(mode) {
266             assert.strictEqual(mode, 'mute');
267             return roomMembershipService.getMembershipDetails(userId1, troupeId2);
268           })
269           .then(function(modeExtended) {
270             assert.deepEqual(modeExtended, {
271               mode: 'mute',
272               lurk: true,
273               flags: parseInt('0110', 2),
274               unread: false,
275               activity: true,
276               announcement: false,
277               mention: true,
278               desktop: false,
279               mobile: false,
280               default: false
281             });
283             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
284           })
285           .then(function(lurking) {
286             assert.strictEqual(lurking, true);
287           });
288       });
290       it('should handle lurk status alongside membership mode all', function() {
291         var troupeId2 = fixture.troupe2.id;
292         var userId1 = fixture.user1.id;
294         return roomMembershipService
295           .removeRoomMember(troupeId2, userId1)
296           .bind(this)
297           .then(function() {
298             return roomMembershipService.addRoomMember(
299               troupeId2,
300               userId1,
301               roomMembershipFlags.MODES.all
302             );
303           })
304           .then(function() {
305             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'all');
306           })
307           .then(function() {
308             assert.strictEqual(0, this.onMembersLurkChange.callCount);
310             return roomMembershipService.getMembershipMode(userId1, troupeId2);
311           })
312           .then(function(mode) {
313             assert.strictEqual(mode, 'all');
314             return roomMembershipService.getMembershipDetails(userId1, troupeId2);
315           })
316           .then(function(modeExtended) {
317             assert.deepEqual(modeExtended, {
318               mode: 'all',
319               lurk: false,
320               flags: parseInt('1101101', 2),
321               unread: true,
322               activity: false,
323               announcement: true,
324               mention: true,
325               desktop: true,
326               mobile: true,
327               default: false
328             });
329             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
330           })
331           .then(function(lurking) {
332             assert.strictEqual(lurking, false);
333           });
334       });
336       it('should handle transitions to and from lurk mode', function() {
337         var troupeId2 = fixture.troupe2.id;
338         var userId1 = fixture.user1.id;
340         return roomMembershipService
341           .removeRoomMember(troupeId2, userId1)
342           .bind(this)
343           .then(function() {
344             return roomMembershipService.addRoomMember(
345               troupeId2,
346               userId1,
347               roomMembershipFlags.MODES.all
348             );
349           })
350           .then(function() {
351             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'all');
352           })
353           .then(function() {
354             assert.strictEqual(0, this.onMembersLurkChange.callCount);
356             return roomMembershipService.getMembershipMode(userId1, troupeId2);
357           })
358           .then(function(mode) {
359             assert.strictEqual(mode, 'all');
360             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
361           })
362           .then(function(lurking) {
363             assert.strictEqual(lurking, false);
364             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'mute');
365           })
366           .then(function() {
367             // Check that the event emitter fired
368             assert.strictEqual(1, this.onMembersLurkChange.callCount);
369             var spyCall = this.onMembersLurkChange.getCall(0);
371             assert.strictEqual(troupeId2, spyCall.args[0]);
372             assert.deepEqual([userId1], spyCall.args[1]);
373             assert.strictEqual(true, spyCall.args[2]);
375             return roomMembershipService.getMembershipMode(userId1, troupeId2);
376           })
377           .then(function(mode) {
378             assert.strictEqual(mode, 'mute');
379             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
380           })
381           .then(function(lurking) {
382             assert.strictEqual(lurking, true);
383             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'all');
384           })
385           .then(function() {
386             // Check that the event emitter fired
387             assert.strictEqual(2, this.onMembersLurkChange.callCount);
388             var spyCall = this.onMembersLurkChange.getCall(1);
390             assert.strictEqual(troupeId2, spyCall.args[0]);
391             assert.deepEqual([userId1], spyCall.args[1]);
392             assert.strictEqual(false, spyCall.args[2]);
394             return roomMembershipService.getMembershipMode(userId1, troupeId2);
395           })
396           .then(function(mode) {
397             assert.strictEqual(mode, 'all');
398             return roomMembershipService.getMembershipDetails(userId1, troupeId2);
399           })
400           .then(function(modeExtended) {
401             assert.deepEqual(modeExtended, {
402               mode: 'all',
403               lurk: false,
404               flags: parseInt('1101101', 2),
405               unread: true,
406               activity: false,
407               announcement: true,
408               mention: true,
409               desktop: true,
410               mobile: true,
411               default: false
412             });
414             return roomMembershipService.getMemberLurkStatus(troupeId2, userId1);
415           })
416           .then(function(lurking) {
417             assert.strictEqual(lurking, false);
418             return roomMembershipService.setMembershipMode(userId1, troupeId2, 'all');
419           });
420       });
421     });
423     describe('findMembersForRoom', function() {
424       it('findMembersForRoom should handle skip and limit', function() {
425         var troupeId2 = fixture.troupe2.id;
426         var userId1 = fixture.user1.id;
427         var userId2 = fixture.user2.id;
429         var flags = roomMembershipFlags.MODES.all;
431         return Promise.join(
432           roomMembershipService.addRoomMember(troupeId2, userId1, flags),
433           roomMembershipService.addRoomMember(troupeId2, userId2, flags)
434         ).then(function() {
435           return Promise.join(
436             roomMembershipService.findMembersForRoom(troupeId2, { limit: 1 }),
437             roomMembershipService.findMembersForRoom(troupeId2, { skip: 1, limit: 1 }),
438             function(find1, find2) {
439               assert.strictEqual(find1.length, 1);
440               assert.strictEqual(find2.length, 1);
442               assert(
443                 find1.some(mongoIdEqualPredicate(userId1)) ||
444                   find2.some(mongoIdEqualPredicate(userId1))
445               );
446               assert(
447                 find1.some(mongoIdEqualPredicate(userId2)) ||
448                   find2.some(mongoIdEqualPredicate(userId2))
449               );
450             }
451           );
452         });
453       });
454     });
456     describe('findRoomIdsForUserWithLurk', function() {
457       it('should return the correct values', function() {
458         var troupeId2 = fixture.troupe2.id;
459         var userId1 = fixture.user1.id;
460         var userId2 = fixture.user2.id;
461         var userId3 = fixture.user3.id;
463         return Promise.join(
464           roomMembershipService.addRoomMember(troupeId2, userId1, roomMembershipFlags.MODES.all),
465           roomMembershipService.addRoomMember(
466             troupeId2,
467             userId2,
468             roomMembershipFlags.MODES.announcement
469           ),
470           roomMembershipService.addRoomMember(troupeId2, userId3, roomMembershipFlags.MODES.mute)
471         )
472           .then(function() {
473             return roomMembershipService.findRoomIdsForUserWithLurk(userId1);
474           })
475           .then(function(result) {
476             assert(typeof result === 'object');
477             assert(!!result);
478             assert(result.hasOwnProperty(troupeId2));
479             assert.strictEqual(result[troupeId2], false);
481             return roomMembershipService.findRoomIdsForUserWithLurk(userId2);
482           })
483           .then(function(result) {
484             assert(typeof result === 'object');
485             assert(result.hasOwnProperty(troupeId2));
486             assert.strictEqual(result[troupeId2], false);
488             return roomMembershipService.findRoomIdsForUserWithLurk(userId3);
489           })
490           .then(function(result) {
491             assert(typeof result === 'object');
492             assert(result.hasOwnProperty(troupeId2));
493             assert.strictEqual(result[troupeId2], true);
494           });
495       });
496     });
498     describe('findLurkingRoomIdsForUserId', function() {
499       it('should return rooms in which a user is lurking', function() {
500         var troupeId1 = fixture.troupe1.id;
501         var troupeId2 = fixture.troupe2.id;
502         var troupeId3 = fixture.troupe3.id;
503         var userId1 = fixture.user1.id;
505         return Promise.join(
506           roomMembershipService.removeRoomMember(troupeId1, userId1),
507           roomMembershipService.removeRoomMember(troupeId2, userId1),
508           roomMembershipService.removeRoomMember(troupeId3, userId1)
509         )
510           .then(function() {
511             return Promise.join(
512               roomMembershipService.addRoomMember(
513                 troupeId1,
514                 userId1,
515                 roomMembershipFlags.MODES.all
516               ),
517               roomMembershipService.addRoomMember(
518                 troupeId2,
519                 userId1,
520                 roomMembershipFlags.MODES.announcement
521               ),
522               roomMembershipService.addRoomMember(
523                 troupeId3,
524                 userId1,
525                 roomMembershipFlags.MODES.mute
526               )
527             );
528           })
529           .then(function() {
530             return roomMembershipService.findLurkingRoomIdsForUserId(userId1);
531           })
532           .then(function(troupeIds) {
533             assert.strictEqual(troupeIds.length, 1);
534             assert.strictEqual(String(troupeIds[0]), troupeId3);
535           });
536       });
537     });
539     describe('addRoomMember', function() {
540       it('should add a new member to a room', function() {
541         var troupeId = fixture.troupe2.id;
542         var userId = fixture.user1.id;
544         var called = 0;
545         function listener(pTroupeId, members) {
546           assert.strictEqual(pTroupeId, troupeId);
547           assert.deepEqual(members, [userId]);
548           called++;
549         }
551         return roomMembershipService
552           .removeRoomMember(troupeId, userId)
553           .then(function() {
554             roomMembershipService.events.on('members.added', listener);
555             return roomMembershipService.addRoomMember(
556               troupeId,
557               userId,
558               roomMembershipFlags.MODES.all
559             );
560           })
561           .then(function(result) {
562             assert.strictEqual(result, true);
563             assert.strictEqual(called, 1);
564           })
565           .finally(function() {
566             roomMembershipService.events.removeListener('members.added', listener);
567           });
568       });
570       it('should be idempotent', function() {
571         var troupeId = fixture.troupe2.id;
572         var userId = fixture.user1.id;
574         var called = 0;
575         function listener() {
576           called++;
577         }
579         return roomMembershipService
580           .addRoomMember(troupeId, userId, roomMembershipFlags.MODES.all)
581           .then(function() {
582             roomMembershipService.events.on('members.added', listener);
583             return roomMembershipService.addRoomMember(
584               troupeId,
585               userId,
586               roomMembershipFlags.MODES.all
587             );
588           })
589           .then(function(result) {
590             assert.strictEqual(result, false);
591             assert.strictEqual(called, 0);
592           })
593           .finally(function() {
594             roomMembershipService.events.removeListener('members.added', listener);
595           });
596       });
597     });
599     describe('findUserMembershipInRooms', function() {
600       it('should return some users', function() {
601         var troupeId1 = fixture.troupe1.id;
602         var troupeId2 = fixture.troupe2.id;
603         var userId = fixture.user1.id;
605         return Promise.join(
606           roomMembershipService.removeRoomMember(troupeId1, userId),
607           roomMembershipService.addRoomMember(troupeId2, userId, roomMembershipFlags.MODES.all),
608           function() {
609             return roomMembershipService.findUserMembershipInRooms(userId, [troupeId1, troupeId2]);
610           }
611         ).then(function(result) {
612           assert.strictEqual(result.length, 1);
613           assert.equal(result[0], troupeId2);
614         });
615       });
616     });
618     describe('findMembershipForUsersInRoom', function() {
619       it('should return some users', function() {
620         var troupeId = fixture.troupe1.id;
621         var userId1 = fixture.user1.id;
622         var userId2 = fixture.user2.id;
624         return Promise.join(
625           roomMembershipService.removeRoomMember(troupeId, userId1),
626           roomMembershipService.addRoomMember(troupeId, userId2, roomMembershipFlags.MODES.all),
627           function() {
628             return roomMembershipService.findMembershipForUsersInRoom(troupeId, [userId1, userId2]);
629           }
630         ).then(function(result) {
631           assert(Array.isArray(result));
632           assert.strictEqual(result.length, 1);
633           assert.equal(result[0], userId2);
634         });
635       });
637       it('should return some users when a single user is added', function() {
638         var troupeId = fixture.troupe1.id;
639         var userId1 = fixture.user1.id;
640         var userId2 = fixture.user2.id;
642         return Promise.join(
643           roomMembershipService.removeRoomMember(troupeId, userId1),
644           roomMembershipService.addRoomMember(troupeId, userId2, roomMembershipFlags.MODES.all),
645           function() {
646             return roomMembershipService.findMembershipForUsersInRoom(troupeId, [userId2]);
647           }
648         ).then(function(result) {
649           assert(Array.isArray(result));
650           assert.strictEqual(result.length, 1);
651           assert.equal(result[0], userId2);
652         });
653       });
654     });
656     describe('findMembersForRoomWithLurk', function() {
657       it('should return some users with lurk', function() {
658         var troupeId = fixture.troupe1.id;
659         var userId1 = fixture.user1.id;
660         var userId2 = fixture.user2.id;
661         var userId3 = fixture.user3.id;
663         return Promise.join(
664           roomMembershipService.removeRoomMember(troupeId, userId1),
665           roomMembershipService.addRoomMember(troupeId, userId2, roomMembershipFlags.MODES.all),
666           roomMembershipService.addRoomMember(troupeId, userId3, roomMembershipFlags.MODES.all),
667           function() {
668             return [
669               roomMembershipService.setMembershipMode(userId2, troupeId, 'all'),
670               roomMembershipService.setMembershipMode(userId3, troupeId, 'mute')
671             ];
672           }
673         )
674           .spread(function() {
675             return roomMembershipService.findMembersForRoomWithLurk(troupeId, [
676               userId1,
677               userId2,
678               userId3
679             ]);
680           })
681           .then(function(result) {
682             var expected = {};
683             expected[userId2] = false;
684             expected[userId3] = true;
685             assert.deepEqual(result, expected);
686           });
687       });
688     });
690     describe('removeRoomMember', function() {
691       it('should remove a member from a room', function() {
692         var troupeId = fixture.troupe2.id;
693         var userId = fixture.user1.id;
695         var called = 0;
696         function listener(pTroupeId, members) {
697           assert.strictEqual(pTroupeId, troupeId);
698           assert.deepEqual(members, [userId]);
699           called++;
700         }
702         return roomMembershipService
703           .addRoomMember(troupeId, userId, roomMembershipFlags.MODES.all)
704           .then(function() {
705             roomMembershipService.events.on('members.removed', listener);
707             return roomMembershipService.removeRoomMember(troupeId, userId);
708           })
709           .then(function(result) {
710             assert.strictEqual(result, true);
711             assert.strictEqual(called, 1);
712           })
713           .finally(function() {
714             roomMembershipService.events.removeListener('members.removed', listener);
715           });
716       });
718       it('should be idempotent', function() {
719         var troupeId = fixture.troupe2.id;
720         var userId = fixture.user1.id;
722         var called = 0;
723         function listener() {
724           called++;
725         }
727         return roomMembershipService
728           .removeRoomMember(troupeId, userId)
729           .then(function() {
730             roomMembershipService.events.on('members.removed', listener);
731             return roomMembershipService.removeRoomMember(troupeId, userId);
732           })
733           .then(function(result) {
734             assert.strictEqual(result, false);
735             assert.strictEqual(called, 0);
736           })
737           .finally(function() {
738             roomMembershipService.events.removeListener('members.removed', listener);
739           });
740       });
741     });
743     describe('findAllMembersForRooms', function() {
744       it('should return some users', function() {
745         var troupeId1 = fixture.troupe1.id;
746         var troupeId2 = fixture.troupe2.id;
747         var userId1 = fixture.user1.id;
748         var userId2 = fixture.user2.id;
749         var userId3 = fixture.user3.id;
751         return Promise.join(
752           roomMembershipService.removeRoomMember(troupeId1, userId3),
753           roomMembershipService.removeRoomMember(troupeId2, userId3),
754           roomMembershipService.addRoomMember(troupeId1, userId1, roomMembershipFlags.MODES.all),
755           roomMembershipService.addRoomMember(
756             troupeId1,
757             userId2,
758             roomMembershipFlags.MODES.announcement
759           ),
760           roomMembershipService.addRoomMember(troupeId2, userId1, roomMembershipFlags.MODES.mute),
761           function() {
762             return roomMembershipService.findAllMembersForRooms([troupeId1, troupeId2]);
763           }
764         ).then(function(result) {
765           assert.strictEqual(result.length, 2);
766           assert(result.some(mongoIdEqualPredicate(userId1)));
767           assert(result.some(mongoIdEqualPredicate(userId2)));
768           assert(!result.some(mongoIdEqualPredicate(userId3)));
769         });
770       });
771     });
773     describe('findMembersForRoomMulti', function() {
774       it('should return some users', function() {
775         var troupeId1 = fixture.troupe1.id;
776         var troupeId2 = fixture.troupe2.id;
777         var userId1 = fixture.user1.id;
778         var userId2 = fixture.user2.id;
779         var userId3 = fixture.user3.id;
781         return Promise.join(
782           roomMembershipService.removeRoomMember(troupeId1, userId3),
783           roomMembershipService.removeRoomMember(troupeId2, userId3),
784           roomMembershipService.addRoomMember(troupeId1, userId1, roomMembershipFlags.MODES.all),
785           roomMembershipService.addRoomMember(
786             troupeId1,
787             userId2,
788             roomMembershipFlags.MODES.announcement
789           ),
790           roomMembershipService.addRoomMember(troupeId2, userId1, roomMembershipFlags.MODES.mute),
791           roomMembershipService.removeRoomMember(troupeId2, userId2),
792           function() {
793             return roomMembershipService.findMembersForRoomMulti([troupeId1, troupeId2]);
794           }
795         ).then(function(result) {
796           assert.strictEqual(Object.keys(result).length, 2);
797           var t1 = result[troupeId1];
798           var t2 = result[troupeId2];
799           assert(Array.isArray(t1));
800           assert(Array.isArray(t2));
802           assert(t1.some(mongoIdEqualPredicate(userId1)));
803           assert(t1.some(mongoIdEqualPredicate(userId2)));
804           assert(!t1.some(mongoIdEqualPredicate(userId3)));
806           assert(t2.some(mongoIdEqualPredicate(userId1)));
807           assert(!t2.some(mongoIdEqualPredicate(userId2)));
808           assert(!t2.some(mongoIdEqualPredicate(userId3)));
809         });
810       });
811     });
813     describe('setMembershipModeForUsersInRoom', function() {
814       it('should return some users', function() {
815         var troupeId1 = fixture.troupe1.id;
816         var userId1 = fixture.user1.id;
817         var userId2 = fixture.user2.id;
819         return Promise.join(
820           roomMembershipService.addRoomMember(troupeId1, userId1, roomMembershipFlags.MODES.mute),
821           roomMembershipService.addRoomMember(troupeId1, userId2, roomMembershipFlags.MODES.mute),
822           function() {
823             return roomMembershipService.setMembershipModeForUsersInRoom(
824               troupeId1,
825               [userId1, userId2],
826               'all'
827             );
828           }
829         )
830           .then(function() {
831             return roomMembershipService.findMembershipModeForUsersInRoom(troupeId1, [
832               userId1,
833               userId2
834             ]);
835           })
836           .then(function(result) {
837             var expected = {};
838             expected[userId1] = 'all';
839             expected[userId2] = 'all';
840             assert.deepEqual(result, expected);
842             return roomMembershipService.setMembershipModeForUsersInRoom(
843               troupeId1,
844               [userId1],
845               'announcement'
846             );
847           })
848           .then(function() {
849             return roomMembershipService.findMembershipModeForUsersInRoom(troupeId1, [
850               userId1,
851               userId2
852             ]);
853           })
854           .then(function(result) {
855             var expected = {};
856             expected[userId1] = 'announcement';
857             expected[userId2] = 'all';
858             assert.deepEqual(result, expected);
860             return roomMembershipService.setMembershipModeForUsersInRoom(
861               troupeId1,
862               [userId2],
863               'mute'
864             );
865           })
866           .then(function() {
867             return roomMembershipService.findMembershipModeForUsersInRoom(troupeId1, [
868               userId1,
869               userId2
870             ]);
871           })
872           .then(function(result) {
873             var expected = {};
874             expected[userId1] = 'announcement';
875             expected[userId2] = 'mute';
876             assert.deepEqual(result, expected);
878             return roomMembershipService.setMembershipModeForUsersInRoom(
879               troupeId1,
880               [userId1, userId2],
881               'all'
882             );
883           })
884           .then(function() {
885             return roomMembershipService.findMembershipModeForUsersInRoom(troupeId1, [
886               userId1,
887               userId2
888             ]);
889           })
890           .then(function(result) {
891             var expected = {};
892             expected[userId1] = 'all';
893             expected[userId2] = 'all';
894             assert.deepEqual(result, expected);
895           });
896       });
897     });
899     describe('findMembersForRoomForNotify', function() {
900       var troupeId1, userId1, userId2, userId3;
902       function roomForNotifySort(a, b) {
903         var u1 = a.userId;
904         var u2 = b.userId;
905         if (u1 === u2) {
906           return 0;
907         } else {
908           return u1 > u2 ? 1 : -1;
909         }
910       }
912       function equivalentValues(array, expected) {
913         var keys = Object.keys(expected);
914         assert.strictEqual(
915           array.length,
916           keys.length,
917           'Expected ' + keys.length + ' items, got ' + array.length
918         );
919         array.forEach(function(item) {
920           var expectedItem = expected[item.userId];
921           assert(expectedItem !== undefined, 'Item for user ' + item.userId + ' does not exist');
922           assert.strictEqual(item.flags, expectedItem);
923         });
924       }
926       before(function() {
927         troupeId1 = fixture.troupe1.id;
928         userId1 = fixture.user1._id;
929         userId2 = fixture.user2._id;
930         userId3 = fixture.user3._id;
932         return Promise.join(
933           roomMembershipService.addRoomMember(troupeId1, userId1, roomMembershipFlags.MODES.all),
934           roomMembershipService.addRoomMember(
935             troupeId1,
936             userId2,
937             roomMembershipFlags.MODES.announcement
938           ),
939           roomMembershipService.addRoomMember(troupeId1, userId3, roomMembershipFlags.MODES.mute),
940           function() {
941             return Promise.join(
942               roomMembershipService.setMembershipModeForUsersInRoom(troupeId1, [userId1], 'all'),
943               roomMembershipService.setMembershipModeForUsersInRoom(
944                 troupeId1,
945                 [userId2],
946                 'announcement'
947               ),
948               roomMembershipService.setMembershipModeForUsersInRoom(troupeId1, [userId3], 'mute')
949             );
950           }
951         );
952       });
954       it('should return notify users', function() {
955         // No announcement, no
956         return roomMembershipService
957           .findMembersForRoomForNotify(troupeId1, null)
958           .then(function(result) {
959             result.sort(roomForNotifySort);
960             var expected = {};
961             expected[userId1] = roomMembershipFlags.MODES.all;
962             expected[userId2] = roomMembershipFlags.MODES.announcement;
963             expected[userId3] = roomMembershipFlags.MODES.mute;
965             equivalentValues(result, expected);
966           });
967       });
969       it('should not return the sender', function() {
970         // No announcement, no
971         return roomMembershipService
972           .findMembersForRoomForNotify(troupeId1, userId1)
973           .then(function(result) {
974             result.sort(roomForNotifySort);
975             var expected = {};
976             expected[userId2] = roomMembershipFlags.MODES.announcement;
977             expected[userId3] = roomMembershipFlags.MODES.mute;
979             equivalentValues(result, expected);
980           });
981       });
983       it('should return notify users and announce users', function() {
984         return roomMembershipService
985           .findMembersForRoomForNotify(troupeId1, null, true)
986           .then(function(result) {
987             var expected = {};
988             expected[userId1] = roomMembershipFlags.MODES.all;
989             expected[userId2] = roomMembershipFlags.MODES.announcement;
990             expected[userId3] = roomMembershipFlags.MODES.mute;
992             equivalentValues(result, expected);
993           });
994       });
996       it('should return notify users and mention users who are already notify users', function() {
997         return roomMembershipService
998           .findMembersForRoomForNotify(troupeId1, null, false, [userId1])
999           .then(function(result) {
1000             var expected = {};
1001             expected[userId1] = roomMembershipFlags.MODES.all;
1002             expected[userId2] = roomMembershipFlags.MODES.announcement;
1003             expected[userId3] = roomMembershipFlags.MODES.mute;
1005             equivalentValues(result, expected);
1006           });
1007       });
1009       it('should return notify users and mention users who are announcement users', function() {
1010         return roomMembershipService
1011           .findMembersForRoomForNotify(troupeId1, null, false, [userId2])
1012           .then(function(result) {
1013             var expected = {};
1014             expected[userId1] = roomMembershipFlags.MODES.all;
1015             expected[userId2] = roomMembershipFlags.MODES.announcement;
1016             expected[userId3] = roomMembershipFlags.MODES.mute;
1018             equivalentValues(result, expected);
1019           });
1020       });
1022       it('should return notify users and mention users who are announcement users', function() {
1023         return roomMembershipService
1024           .findMembersForRoomForNotify(troupeId1, null, false, [userId3])
1025           .then(function(result) {
1026             var expected = {};
1027             expected[userId1] = roomMembershipFlags.MODES.all;
1028             expected[userId2] = roomMembershipFlags.MODES.announcement;
1029             expected[userId3] = roomMembershipFlags.MODES.mute;
1031             equivalentValues(result, expected);
1032           });
1033       });
1035       it('should return notify users and mention users who are mute users', function() {
1036         return roomMembershipService
1037           .findMembersForRoomForNotify(troupeId1, null, true, [userId3])
1038           .then(function(result) {
1039             var expected = {};
1040             expected[userId1] = roomMembershipFlags.MODES.all;
1041             expected[userId2] = roomMembershipFlags.MODES.announcement;
1042             expected[userId3] = roomMembershipFlags.MODES.mute;
1044             equivalentValues(result, expected);
1045           });
1046       });
1047     });
1049     describe('groupMembership change notification', function() {
1050       var fixture = fixtureLoader.setup({
1051         user1: {},
1052         user2: {},
1053         user3: {},
1054         user4: {},
1055         user5: {},
1056         user6: {},
1057         group1: {},
1058         troupe1: { security: 'PUBLIC', group: 'group1', users: ['user3', 'user5', 'user6'] },
1059         troupe2: { security: 'PUBLIC', group: 'group1', users: ['user2', 'user4', 'user5'] }
1060       });
1061       var _onAdded;
1062       var onAdded;
1063       var _onRemoved;
1064       var onRemoved;
1066       beforeEach(function() {
1067         _onAdded = function() {
1068           if (onAdded) {
1069             return onAdded.apply(null, arguments);
1070           }
1072           assert.ok(false, 'Unexpected add');
1073         };
1075         _onRemoved = function() {
1076           if (onRemoved) {
1077             return onRemoved.apply(null, arguments);
1078           }
1080           assert.ok(false, 'Unexpected remove');
1081         };
1083         roomMembershipService.events.on('group.members.added', _onAdded);
1084         roomMembershipService.events.on('group.members.removed', _onRemoved);
1085       });
1087       afterEach(function() {
1088         roomMembershipService.events.removeListener('group.members.added', _onAdded);
1089         roomMembershipService.events.removeListener('group.members.removed', _onRemoved);
1090         onAdded = null;
1091         onRemoved = null;
1092       });
1094       it('should notify when a user joins a new group', function() {
1095         var troupeId = fixture.troupe1._id;
1096         var userId = fixture.user1._id;
1097         var groupId = fixture.group1._id;
1099         var p = new Promise(function(resolve) {
1100           onAdded = function(pGroupId, pUserIds) {
1101             assert.strictEqual(pGroupId, groupId);
1102             assert.deepEqual(pUserIds, [userId]);
1103             resolve();
1104           };
1105         });
1107         return roomMembershipService
1108           .addRoomMember(troupeId, userId, roomMembershipFlags.MODES.all, groupId)
1109           .then(function() {
1110             return p;
1111           });
1112       });
1114       it('should not notify when a user joins a new room for a group they are already in', function() {
1115         var troupeId = fixture.troupe1._id;
1116         var userId = fixture.user2._id;
1117         var groupId = fixture.group1._id;
1119         return roomMembershipService
1120           .addRoomMember(troupeId, userId, roomMembershipFlags.MODES.all, groupId)
1121           .delay(10); // Give the caller time to fire the event
1122       });
1124       it('should notify when a user leaves a room and its the last room in that group theyre a member of', function() {
1125         var troupeId = fixture.troupe1._id;
1126         var userId = fixture.user3._id;
1127         var groupId = fixture.group1._id;
1129         var p = new Promise(function(resolve) {
1130           onRemoved = function(pGroupId, pUserIds) {
1131             assert.strictEqual(pGroupId, groupId);
1132             assert.deepEqual(pUserIds, [userId]);
1133             resolve();
1134           };
1135         });
1137         return roomMembershipService.removeRoomMember(troupeId, userId, groupId).then(function() {
1138           return p;
1139         });
1140       });
1142       it('should not notify when a user leaves a room and its not the last room in that group theyre a member of', function() {
1143         var troupeId = fixture.troupe1._id;
1144         var userId = fixture.user4._id;
1145         var groupId = fixture.group1._id;
1147         return roomMembershipService.removeRoomMember(troupeId, userId, groupId).delay(10); // Give the caller time to fire the event
1148       });
1150       it('should emit events when multiple room members are removed at once', function() {
1151         var troupeId = fixture.troupe1._id;
1152         var userId5 = fixture.user5._id;
1153         var userId6 = fixture.user6._id;
1154         var groupId = fixture.group1._id;
1156         var p = new Promise(function(resolve) {
1157           onRemoved = function(pGroupId, pUserIds) {
1158             assert.strictEqual(pGroupId, groupId);
1159             assert.deepEqual(pUserIds, [userId6]);
1160             resolve();
1161           };
1162         });
1164         return roomMembershipService
1165           .removeRoomMembers(troupeId, [userId5, userId6], groupId)
1166           .then(function() {
1167             return p;
1168           });
1169       });
1170     });
1172     describe('findPrivateRoomIdsForUser', function() {
1173       var fixture = fixtureLoader.setup({
1174         user1: {},
1175         user2: {},
1176         troupe1: {
1177           securityDescriptor: {
1178             public: false
1179           },
1180           users: ['user1']
1181         },
1182         troupe2: {
1183           securityDescriptor: {
1184             public: true
1185           },
1186           users: ['user2', 'user1']
1187         },
1188         troupe3: {
1189           securityDescriptor: {
1190             public: false
1191           },
1192           users: ['user1']
1193         }
1194       });
1196       function contains(ids, expectedIds) {
1197         return expectedIds.every(function(expectedId) {
1198           return ids.some(function(x) {
1199             return String(expectedId) === String(x);
1200           });
1201         });
1202       }
1204       it('should find private rooms', function() {
1205         var userId1 = fixture.user1.id;
1207         return roomMembershipService.findPrivateRoomIdsForUser(userId1).then(function(roomIds) {
1208           assert.strictEqual(roomIds.length, 2);
1209           assert(contains(roomIds, [fixture.troupe1.id, fixture.troupe3.id]));
1210         });
1211       });
1213       it('should handle users without private rooms', function() {
1214         var userId1 = fixture.user2.id;
1216         return roomMembershipService.findPrivateRoomIdsForUser(userId1).then(function(roomIds) {
1217           assert.deepEqual(roomIds, []);
1218         });
1219       });
1220     });
1221   });