@@ -401,25 +401,37 @@ describe("Test: Testing RoomMemberManager", function() {
401401 }
402402
403403 // Create and protect rooms.
404- // - room 0 remains unprotected, as witness;
405- // - room 1 is protected but won't be targeted directly, also as witness.
404+ //
405+ // We reserve two control rooms:
406+ // - room 0, also known as the "control unprotected room" is unprotected
407+ // (we're not calling `!mjolnir rooms add` for this room), so none
408+ // of the operations of `!mjolnir since` shoud affect it. We are
409+ // using it to control, at the end of each experiment, that none of
410+ // the `!mjolnir since` operations affect it.
411+ // - room 1, also known as the "control protected room" is protected
412+ // (we are calling `!mjolnir rooms add` for this room), but we are
413+ // never directly requesting any `!mjolnir since` action against
414+ // this room. We are using it to control, at the end of each experiment,
415+ // that none of the `!mjolnir since` operations that should target
416+ // one single other room also affect that room. It is, however, affected
417+ // by general operations that are designed to affect all protected rooms.
406418 const NUMBER_OF_ROOMS = 18 ;
407- const roomIds : string [ ] = [ ] ;
408- const roomAliases : string [ ] = [ ] ;
419+ const allRoomIds : string [ ] = [ ] ;
420+ const allRoomAliases : string [ ] = [ ] ;
409421 const mjolnirUserId = await this . mjolnir . client . getUserId ( ) ;
410422 for ( let i = 0 ; i < NUMBER_OF_ROOMS ; ++ i ) {
411423 const roomId = await this . moderator . createRoom ( {
412424 invite : [ mjolnirUserId , ...goodUserIds , ...badUserIds ] ,
413425 } ) ;
414- roomIds . push ( roomId ) ;
426+ allRoomIds . push ( roomId ) ;
415427
416428 const alias = `#since-test-${ randomUUID ( ) } :localhost:9999` ;
417429 await this . moderator . createRoomAlias ( alias , roomId ) ;
418- roomAliases . push ( alias ) ;
430+ allRoomAliases . push ( alias ) ;
419431 }
420- for ( let i = 1 ; i < roomIds . length ; ++ i ) {
421- // Protect all rooms except roomIds [0], as witness .
422- const roomId = roomIds [ i ] ;
432+ for ( let i = 1 ; i < allRoomIds . length ; ++ i ) {
433+ // Protect all rooms except allRoomIds [0], as control .
434+ const roomId = allRoomIds [ i ] ;
423435 await this . mjolnir . client . joinRoom ( roomId ) ;
424436 await this . moderator . setUserPowerLevel ( mjolnirUserId , roomId , 100 ) ;
425437 await this . moderator . sendMessage ( this . mjolnir . managementRoomId , { msgtype : 'm.text' , body : `!mjolnir rooms add ${ roomId } ` } ) ;
@@ -429,8 +441,8 @@ describe("Test: Testing RoomMemberManager", function() {
429441 do {
430442 let protectedRooms = this . mjolnir . protectedRooms ;
431443 protectedRoomsUpdated = true ;
432- for ( let i = 1 ; i < roomIds . length ; ++ i ) {
433- const roomId = roomIds [ i ] ;
444+ for ( let i = 1 ; i < allRoomIds . length ; ++ i ) {
445+ const roomId = allRoomIds [ i ] ;
434446 if ( ! ( roomId in protectedRooms ) ) {
435447 protectedRoomsUpdated = false ;
436448 await new Promise ( resolve => setTimeout ( resolve , 1_000 ) ) ;
@@ -440,7 +452,7 @@ describe("Test: Testing RoomMemberManager", function() {
440452
441453 // Good users join before cut date.
442454 for ( let user of this . goodUsers ) {
443- for ( let roomId of roomIds ) {
455+ for ( let roomId of allRoomIds ) {
444456 await user . joinRoom ( roomId ) ;
445457 }
446458 }
@@ -453,25 +465,30 @@ describe("Test: Testing RoomMemberManager", function() {
453465
454466 // Bad users join after cut date.
455467 for ( let user of this . badUsers ) {
456- for ( let roomId of roomIds ) {
468+ for ( let roomId of allRoomIds ) {
457469 await user . joinRoom ( roomId ) ;
458470 }
459471 }
460472
473+ // Finally, prepare our control rooms and separate them
474+ // from the regular rooms.
475+ const CONTROL_UNPROTECTED_ROOM_ID = allRoomIds [ 0 ] ;
476+ const CONTROL_PROTECTED_ID = allRoomIds [ 1 ] ;
477+ const roomIds = allRoomIds . slice ( 2 ) ;
478+ const roomAliases = allRoomAliases . slice ( 2 ) ;
479+
461480 enum Method {
462481 kick ,
463482 ban ,
464483 mute ,
465484 unmute ,
466485 }
467- const WITNESS_UNPROTECTED_ROOM_ID = roomIds [ 0 ] ;
468- const WITNESS_ROOM_ID = roomIds [ 1 ] ;
469486 class Experiment {
470487 // A human-readable name for the command.
471488 readonly name : string ;
472- // If `true`, this command should affect room `WITNESS_ROOM_ID `.
489+ // If `true`, this command should affect room `CONTROL_PROTECTED_ID `.
473490 // Defaults to `false`.
474- readonly shouldAffectWitnessRoom : boolean ;
491+ readonly shouldAffectControlProtected : boolean ;
475492 // The actual command-line.
476493 readonly command : ( roomId : string , roomAlias : string ) => string ;
477494 // The number of responses we expect to this command.
@@ -484,17 +501,23 @@ describe("Test: Testing RoomMemberManager", function() {
484501 // Defaults to `false`.
485502 readonly isSameRoomAsPrevious : boolean ;
486503
504+ // The index of the room on which we're acting.
505+ //
506+ // Initialized by `addTo`.
487507 roomIndex : number | undefined ;
488508
489- constructor ( { name, shouldAffectWitnessRoom , command, n, method, sameRoom} : { name : string , command : ( roomId : string , roomAlias : string ) => string , shouldAffectWitnessRoom ?: boolean , n ?: number , method : Method , sameRoom ?: boolean } ) {
509+ constructor ( { name, shouldAffectControlProtected , command, n, method, sameRoom} : { name : string , command : ( roomId : string , roomAlias : string ) => string , shouldAffectControlProtected ?: boolean , n ?: number , method : Method , sameRoom ?: boolean } ) {
490510 this . name = name ;
491- this . shouldAffectWitnessRoom = typeof shouldAffectWitnessRoom === "undefined" ? false : shouldAffectWitnessRoom ;
511+ this . shouldAffectControlProtected = typeof shouldAffectControlProtected === "undefined" ? false : shouldAffectControlProtected ;
492512 this . command = command ;
493513 this . n = typeof n === "undefined" ? 1 : n ;
494514 this . method = method ;
495515 this . isSameRoomAsPrevious = typeof sameRoom === "undefined" ? false : sameRoom ;
496516 }
497517
518+ // Add an experiment to the list of experiments.
519+ //
520+ // This is how `roomIndex` gets initialized.
498521 addTo ( experiments : Experiment [ ] ) {
499522 if ( this . isSameRoomAsPrevious ) {
500523 this . roomIndex = experiments [ experiments . length - 1 ] . roomIndex ;
@@ -586,7 +609,7 @@ describe("Test: Testing RoomMemberManager", function() {
586609 new Experiment ( {
587610 name : "kick with date and reason" ,
588611 command : ( roomId : string ) => `!mjolnir since "${ cutDate } " kick 100 ${ roomId } bad, bad user` ,
589- shouldAffectWitnessRoom : false ,
612+ shouldAffectControlProtected : false ,
590613 n : 1 ,
591614 method : Method . kick ,
592615 } ) ,
@@ -626,19 +649,35 @@ describe("Test: Testing RoomMemberManager", function() {
626649 new Experiment ( {
627650 name : "kick with date everywhere" ,
628651 command : ( ) => `!mjolnir since "${ cutDate } " kick 100 * bad, bad user` ,
629- shouldAffectWitnessRoom : true ,
652+ shouldAffectControlProtected : true ,
630653 n : NUMBER_OF_ROOMS - 1 ,
631654 method : Method . kick ,
632655 } ) ,
633656 ] ) {
634657 experiment . addTo ( EXPERIMENTS ) ;
635658 }
659+
660+ // Just-in-case health check, before starting.
661+ {
662+ const usersInUnprotectedControlProtected = await this . mjolnir . client . getJoinedRoomMembers ( CONTROL_UNPROTECTED_ROOM_ID ) ;
663+ const usersInControlProtected = await this . mjolnir . client . getJoinedRoomMembers ( CONTROL_PROTECTED_ID ) ;
664+ for ( let userId of goodUserIds ) {
665+ assert . ok ( usersInUnprotectedControlProtected . includes ( userId ) , `Initially, good user ${ userId } should be in the unprotected control room` ) ;
666+ assert . ok ( usersInControlProtected . includes ( userId ) , `Initially, good user ${ userId } should be in the control room` ) ;
667+ }
668+ for ( let userId of badUserIds ) {
669+ assert . ok ( usersInUnprotectedControlProtected . includes ( userId ) , `Initially, bad user ${ userId } should be in the unprotected control room` ) ;
670+ assert . ok ( usersInControlProtected . includes ( userId ) , `Initially, bad user ${ userId } should be in the control room` ) ;
671+ }
672+ }
673+
636674 for ( let i = 0 ; i < EXPERIMENTS . length ; ++ i ) {
637675 const experiment = EXPERIMENTS [ i ] ;
638- const index = experiment . roomIndex ! + 1 ;
639- const roomId = roomIds [ index ] ;
676+ const index = experiment . roomIndex ! ;
677+ const roomId = roomIds [ index ] ;
640678 const roomAlias = roomAliases [ index ] ;
641679 const joined = this . mjolnir . roomJoins . getUsersInRoom ( roomId , start , 100 ) ;
680+ console . debug ( `Running experiment ${ i } "${ experiment . name } " in room index ${ index } (${ roomId } / ${ roomAlias } ): \`${ experiment . command ( roomId , roomAlias ) } \`` ) ;
642681 assert . ok ( joined . length >= 2 * SAMPLE_SIZE , `In experiment ${ experiment . name } , we should have seen ${ 2 * SAMPLE_SIZE } users, saw ${ joined . length } ` ) ;
643682
644683 // Run experiment.
@@ -650,12 +689,12 @@ describe("Test: Testing RoomMemberManager", function() {
650689
651690 // Check post-conditions.
652691 const usersInRoom = await this . mjolnir . client . getJoinedRoomMembers ( roomId ) ;
653- const usersInUnprotectedWitnessRoom = await this . mjolnir . client . getJoinedRoomMembers ( WITNESS_UNPROTECTED_ROOM_ID ) ;
654- const usersInWitnessRoom = await this . mjolnir . client . getJoinedRoomMembers ( WITNESS_ROOM_ID ) ;
692+ const usersInUnprotectedControlProtected = await this . mjolnir . client . getJoinedRoomMembers ( CONTROL_UNPROTECTED_ROOM_ID ) ;
693+ const usersInControlProtected = await this . mjolnir . client . getJoinedRoomMembers ( CONTROL_PROTECTED_ID ) ;
655694 for ( let userId of goodUserIds ) {
656695 assert . ok ( usersInRoom . includes ( userId ) , `After a ${ experiment . name } , good user ${ userId } should still be in affected room` ) ;
657- assert . ok ( usersInWitnessRoom . includes ( userId ) , `After a ${ experiment . name } , good user ${ userId } should still be in witness room` ) ;
658- assert . ok ( usersInUnprotectedWitnessRoom . includes ( userId ) , `After a ${ experiment . name } , good user ${ userId } should still be in unprotected witness room` ) ;
696+ assert . ok ( usersInControlProtected . includes ( userId ) , `After a ${ experiment . name } , good user ${ userId } should still be in control room ( ${ CONTROL_PROTECTED_ID } ) ` ) ;
697+ assert . ok ( usersInUnprotectedControlProtected . includes ( userId ) , `After a ${ experiment . name } , good user ${ userId } should still be in unprotected control room ( ${ CONTROL_UNPROTECTED_ROOM_ID } ) ` ) ;
659698 }
660699 if ( experiment . method === Method . mute ) {
661700 for ( let userId of goodUserIds ) {
@@ -678,8 +717,8 @@ describe("Test: Testing RoomMemberManager", function() {
678717 } else {
679718 for ( let userId of badUserIds ) {
680719 assert . ok ( ! usersInRoom . includes ( userId ) , `After a ${ experiment . name } , bad user ${ userId } should NOT be in affected room` ) ;
681- assert . equal ( usersInWitnessRoom . includes ( userId ) , ! experiment . shouldAffectWitnessRoom , `After a ${ experiment . name } , bad user ${ userId } should ${ experiment . shouldAffectWitnessRoom ? "NOT" : "still" } be in witness room` ) ;
682- assert . ok ( usersInUnprotectedWitnessRoom . includes ( userId ) , `After a ${ experiment . name } , bad user ${ userId } should still be in unprotected witness room` ) ;
720+ assert . equal ( usersInControlProtected . includes ( userId ) , ! experiment . shouldAffectControlProtected , `After a ${ experiment . name } , bad user ${ userId } should ${ experiment . shouldAffectControlProtected ? "NOT" : "still" } be in control room` ) ;
721+ assert . ok ( usersInUnprotectedControlProtected . includes ( userId ) , `After a ${ experiment . name } , bad user ${ userId } should still be in unprotected control room` ) ;
683722 const leaveEvent = await this . mjolnir . client . getRoomStateEvent ( roomId , "m.room.member" , userId ) ;
684723 switch ( experiment . method ) {
685724 case Method . kick :
0 commit comments