sharedb 7.0.0 → 7.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  var Backend = require('../../../lib/backend');
2
+ var logger = require('../../../lib/logger');
2
3
  var PresencePauser = require('./presence-pauser');
3
4
  var expect = require('chai').expect;
4
5
  var async = require('async');
@@ -685,6 +686,32 @@ describe('Presence', function() {
685
686
  ], done);
686
687
  });
687
688
 
689
+ it('ignores presence from another client with the same ID as its local presence', function(done) {
690
+ var connection3 = backend.connect();
691
+ var localPresence3 = connection3.getPresence('test-channel').create('presence-1');
692
+ var localPresence1 = presence1.create('presence-1');
693
+ var hasReceivedOwnPresence = false;
694
+ presence1.on('receive', function(id) {
695
+ done(new Error('Unexpected presence received: ' + id));
696
+ });
697
+
698
+ async.series([
699
+ presence1.subscribe.bind(presence1),
700
+ function(next) {
701
+ connection1.on('receive', function(request) {
702
+ if (request.data.src === connection1.id) hasReceivedOwnPresence = true;
703
+ if (request.data.src !== connection3.id) return;
704
+ localPresence1.submit({index: 1}, function(error) {
705
+ if (error) return done(error);
706
+ expect(hasReceivedOwnPresence).to.be.true;
707
+ next();
708
+ });
709
+ });
710
+ localPresence3.submit({index: 9}, errorHandler(done));
711
+ }
712
+ ], done);
713
+ });
714
+
688
715
  it('adds itself back onto the connection after a destroy and a resubscribe', function(done) {
689
716
  async.series([
690
717
  presence1.destroy.bind(presence1),
@@ -718,6 +745,513 @@ describe('Presence', function() {
718
745
  ], done);
719
746
  });
720
747
 
748
+ it('broadcasts a null presence when a connection that never subscribed is disconnected', function(done) {
749
+ var localPresence1 = presence1.create('presence-1');
750
+ async.series([
751
+ presence2.subscribe.bind(presence2),
752
+ function(next) {
753
+ localPresence1.submit({index: 3}, errorHandler(done));
754
+ presence2.once('receive', function() {
755
+ next();
756
+ });
757
+ },
758
+ function(next) {
759
+ presence2.once('receive', function(id, presence) {
760
+ expect(id).to.equal('presence-1');
761
+ expect(presence).to.be.null;
762
+ next();
763
+ });
764
+ connection1.close();
765
+ }
766
+ ], done);
767
+ });
768
+
769
+ it('broadcasts a null presence for presence in flight when the connection is disconnected', function(done) {
770
+ var localPresence1 = presence1.create('presence-1');
771
+
772
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
773
+ if (context.presence.p === null) return next();
774
+ connection1.agent.stream.once('end', function() {
775
+ next();
776
+ });
777
+ connection1.close();
778
+ });
779
+
780
+ async.series([
781
+ presence2.subscribe.bind(presence2),
782
+ function(next) {
783
+ presence2.once('receive', function(id, presence) {
784
+ expect(id).to.equal('presence-1');
785
+ expect(presence).to.be.null;
786
+ next();
787
+ });
788
+ localPresence1.submit({index: 3}, errorHandler(done));
789
+ }
790
+ ], done);
791
+ });
792
+
793
+ it('broadcasts a null presence for presence in flight when unsubscribing', function(done) {
794
+ var localPresence1 = presence1.create('presence-1');
795
+
796
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
797
+ if (context.presence.p === null) return next();
798
+ presence1.unsubscribe(function(error) {
799
+ if (error) return done(error);
800
+ next();
801
+ });
802
+ });
803
+
804
+ async.series([
805
+ presence1.subscribe.bind(presence1),
806
+ presence2.subscribe.bind(presence2),
807
+ function(next) {
808
+ async.parallel([
809
+ function(cb) {
810
+ presence2.once('receive', function(id, presence) {
811
+ expect(id).to.equal('presence-1');
812
+ expect(presence).to.be.null;
813
+ cb();
814
+ });
815
+ },
816
+ function(cb) {
817
+ localPresence1.submit({index: 3}, cb);
818
+ }
819
+ ], next);
820
+ }
821
+ ], done);
822
+ });
823
+
824
+ it('broadcasts presence submitted after unsubscribing while earlier presence was in flight', function(done) {
825
+ var localPresence1 = presence1.create('presence-1');
826
+ var localPresence2 = presence1.create('presence-2');
827
+ var received = {};
828
+
829
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
830
+ if (context.presence.id !== 'presence-1' || context.presence.p === null) return next();
831
+ presence1.unsubscribe(function(error) {
832
+ if (error) return done(error);
833
+ localPresence2.submit({index: 2}, function(error) {
834
+ if (error) return done(error);
835
+ next();
836
+ });
837
+ });
838
+ });
839
+
840
+ async.series([
841
+ presence1.subscribe.bind(presence1),
842
+ presence2.subscribe.bind(presence2),
843
+ function(next) {
844
+ presence2.on('receive', function(id, presence) {
845
+ received[id] = presence;
846
+ if (Object.keys(received).length === 2) next();
847
+ });
848
+ localPresence1.submit({index: 1}, errorHandler(done));
849
+ },
850
+ function(next) {
851
+ expect(received).to.eql({'presence-1': null, 'presence-2': {index: 2}});
852
+ next();
853
+ }
854
+ ], done);
855
+ });
856
+
857
+ it('broadcasts a null presence for presence held in receive middleware when disconnected', function(done) {
858
+ var localPresence1 = presence1.create('presence-1');
859
+
860
+ backend.use(backend.MIDDLEWARE_ACTIONS.receive, function(context, next) {
861
+ if (context.agent !== connection1.agent || context.data.a !== 'p') return next();
862
+ connection1.agent.stream.once('end', function() {
863
+ next();
864
+ });
865
+ connection1.close();
866
+ });
867
+
868
+ async.series([
869
+ presence2.subscribe.bind(presence2),
870
+ function(next) {
871
+ presence2.once('receive', function(id, presence) {
872
+ expect(id).to.equal('presence-1');
873
+ expect(presence).to.be.null;
874
+ next();
875
+ });
876
+ localPresence1.submit({index: 3}, errorHandler(done));
877
+ }
878
+ ], done);
879
+ });
880
+
881
+ it('does not rewrite a null presence again when middleware fills it in on disconnect', function(done) {
882
+ var localPresence1 = presence1.create('presence-1');
883
+ var nullPresenceCount = 0;
884
+
885
+ async.series([
886
+ presence2.subscribe.bind(presence2),
887
+ function(next) {
888
+ localPresence1.submit({index: 3}, errorHandler(done));
889
+ presence2.once('receive', function() {
890
+ next();
891
+ });
892
+ },
893
+ function(next) {
894
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, callback) {
895
+ if (context.presence.p !== null) return callback();
896
+ if (++nullPresenceCount > 1) return done(new Error('Rewrote a null presence more than once'));
897
+ context.presence.p = {index: 0};
898
+ callback();
899
+ });
900
+ presence2.once('receive', function(id) {
901
+ expect(id).to.equal('presence-1');
902
+ expect(nullPresenceCount).to.equal(1);
903
+ next();
904
+ });
905
+ connection1.close();
906
+ }
907
+ ], done);
908
+ });
909
+
910
+ it('logs an error when the leave for presence in flight fails', function(done) {
911
+ var localPresence1 = presence1.create('presence-1');
912
+ var agent1 = connection1.agent;
913
+
914
+ sinon.stub(logger, 'error').callsFake(function(message, channel, id, src, error) {
915
+ expect(message).to.equal('Error broadcasting disconnect presence');
916
+ expect([channel, id, src]).to.eql(['test-channel', 'presence-1', agent1._src()]);
917
+ expect(error.message).to.equal('bad!');
918
+ done();
919
+ });
920
+
921
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
922
+ if (context.presence.p === null) return next(new Error('bad!'));
923
+ agent1.stream.once('end', function() {
924
+ next();
925
+ });
926
+ connection1.close();
927
+ });
928
+
929
+ localPresence1.submit({index: 3}, errorHandler(done));
930
+ });
931
+
932
+ it('does not broadcast presence that gets through middleware after its own leave', function(done) {
933
+ var localPresence1 = presence1.create('presence-1');
934
+ var localPresence2 = presence1.create('presence-2');
935
+ var releasePresence;
936
+
937
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
938
+ var isFirstPresence = context.presence.id === 'presence-1' && context.presence.pv === 0;
939
+ if (!isFirstPresence || releasePresence) return next();
940
+ releasePresence = next;
941
+ });
942
+
943
+ async.series([
944
+ presence2.subscribe.bind(presence2),
945
+ function(next) {
946
+ localPresence1.submit({index: 1}, errorHandler(done));
947
+ localPresence1.submit({index: 2}, errorHandler(done));
948
+ presence2.once('receive', function(id, presence) {
949
+ expect(presence).to.eql({index: 2});
950
+ next();
951
+ });
952
+ },
953
+ function(next) {
954
+ localPresence1.submit(null, errorHandler(done));
955
+ presence2.once('receive', function(id, presence) {
956
+ expect(presence).to.be.null;
957
+ next();
958
+ });
959
+ },
960
+ function(next) {
961
+ releasePresence();
962
+ localPresence2.submit({index: 3}, errorHandler(done));
963
+ presence2.once('receive', function(id) {
964
+ expect(id).to.equal('presence-2');
965
+ next();
966
+ });
967
+ },
968
+ function(next) {
969
+ expect(presence2.remotePresences).to.eql({'presence-2': {index: 3}});
970
+ next();
971
+ }
972
+ ], done);
973
+ });
974
+
975
+ it('broadcasts presence in flight when its leave is rejected', function(done) {
976
+ var localPresence1 = presence1.create('presence-1');
977
+ var releasePresence;
978
+
979
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
980
+ if (context.presence.p === null) return next(new Error('bad!'));
981
+ releasePresence = next;
982
+ });
983
+
984
+ async.series([
985
+ presence2.subscribe.bind(presence2),
986
+ function(next) {
987
+ localPresence1.submit({index: 1}, errorHandler(done));
988
+ localPresence1.submit(null, function(error) {
989
+ expect(error.message).to.contain('bad!');
990
+ next();
991
+ });
992
+ },
993
+ function(next) {
994
+ presence2.once('receive', function(id, presence) {
995
+ expect(id).to.equal('presence-1');
996
+ expect(presence).to.eql({index: 1});
997
+ next();
998
+ });
999
+ releasePresence();
1000
+ }
1001
+ ], done);
1002
+ });
1003
+
1004
+ it('broadcasts presence that overtakes its older leave in receive middleware', function(done) {
1005
+ var localPresence1 = presence1.create('presence-1');
1006
+ var releaseLeave;
1007
+ var releasePresence;
1008
+
1009
+ backend.use(backend.MIDDLEWARE_ACTIONS.receive, function(context, next) {
1010
+ var isLeave = context.agent === connection1.agent && context.data.a === 'p' && context.data.p === null;
1011
+ if (!isLeave) return next();
1012
+ releaseLeave = next;
1013
+ });
1014
+
1015
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
1016
+ if (context.presence.p === null) return next();
1017
+ releasePresence = next;
1018
+ releaseLeave();
1019
+ });
1020
+
1021
+ async.series([
1022
+ presence2.subscribe.bind(presence2),
1023
+ function(next) {
1024
+ presence2.once('receive', function(id, presence) {
1025
+ expect(presence).to.be.null;
1026
+ next();
1027
+ });
1028
+ localPresence1.submit(null, errorHandler(done));
1029
+ localPresence1.submit({index: 1}, errorHandler(done));
1030
+ },
1031
+ function(next) {
1032
+ presence2.once('receive', function(id, presence) {
1033
+ expect(id).to.equal('presence-1');
1034
+ expect(presence).to.eql({index: 1});
1035
+ next();
1036
+ });
1037
+ releasePresence();
1038
+ }
1039
+ ], done);
1040
+ });
1041
+
1042
+ it('broadcasts presence re-created with the same id while its old leave is in middleware', function(done) {
1043
+ var localPresence1 = presence1.create('presence-1');
1044
+ var releaseLeave;
1045
+ var releasePresence;
1046
+
1047
+ async.series([
1048
+ presence2.subscribe.bind(presence2),
1049
+ function(next) {
1050
+ localPresence1.submit({index: 1}, errorHandler(done));
1051
+ presence2.once('receive', function() {
1052
+ next();
1053
+ });
1054
+ },
1055
+ function(next) {
1056
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, callback) {
1057
+ if (releaseLeave && releasePresence) return callback();
1058
+ if (context.presence.p === null) releaseLeave = callback;
1059
+ else releasePresence = callback;
1060
+ if (releaseLeave && releasePresence) next();
1061
+ });
1062
+ localPresence1.submit(null);
1063
+ presence1.create('presence-1').submit({index: 2}, errorHandler(done));
1064
+ },
1065
+ function(next) {
1066
+ presence2.once('receive', function(id, presence) {
1067
+ expect(presence).to.be.null;
1068
+ next();
1069
+ });
1070
+ releaseLeave();
1071
+ },
1072
+ function(next) {
1073
+ presence2.once('receive', function(id, presence) {
1074
+ expect(id).to.equal('presence-1');
1075
+ expect(presence).to.eql({index: 2});
1076
+ next();
1077
+ });
1078
+ releasePresence();
1079
+ }
1080
+ ], done);
1081
+ });
1082
+
1083
+ it('broadcasts presence submitted after unsubscribing while an older one is still in middleware', function(done) {
1084
+ var localPresence1 = presence1.create('presence-1');
1085
+ var heldPresences = [];
1086
+ var onHeld;
1087
+
1088
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
1089
+ if (context.presence.p === null) return next();
1090
+ heldPresences.push(next);
1091
+ onHeld();
1092
+ });
1093
+
1094
+ async.series([
1095
+ presence1.subscribe.bind(presence1),
1096
+ presence2.subscribe.bind(presence2),
1097
+ function(next) {
1098
+ onHeld = next;
1099
+ localPresence1.submit({index: 1}, errorHandler(done));
1100
+ },
1101
+ presence1.unsubscribe.bind(presence1),
1102
+ function(next) {
1103
+ onHeld = next;
1104
+ localPresence1.submit({index: 2}, errorHandler(done));
1105
+ },
1106
+ function(next) {
1107
+ heldPresences[0]();
1108
+ presence2.once('receive', function(id, presence) {
1109
+ expect(id).to.equal('presence-1');
1110
+ expect(presence).to.be.null;
1111
+ next();
1112
+ });
1113
+ },
1114
+ function(next) {
1115
+ heldPresences[1]();
1116
+ presence2.once('receive', function(id, presence) {
1117
+ expect(id).to.equal('presence-1');
1118
+ expect(presence).to.eql({index: 2});
1119
+ next();
1120
+ });
1121
+ }
1122
+ ], done);
1123
+ });
1124
+
1125
+ it('broadcasts presence re-created with the same id, and its leave on disconnect', function(done) {
1126
+ var localPresence1 = presence1.create('presence-1');
1127
+
1128
+ async.series([
1129
+ presence2.subscribe.bind(presence2),
1130
+ function(next) {
1131
+ localPresence1.submit({index: 1}, errorHandler(done));
1132
+ presence2.once('receive', function() {
1133
+ next();
1134
+ });
1135
+ },
1136
+ function(next) {
1137
+ localPresence1.destroy(errorHandler(done));
1138
+ presence2.once('receive', function(id, presence) {
1139
+ expect(presence).to.be.null;
1140
+ next();
1141
+ });
1142
+ },
1143
+ function(next) {
1144
+ presence1.create('presence-1').submit({index: 2}, errorHandler(done));
1145
+ presence2.once('receive', function(id, presence) {
1146
+ expect(id).to.equal('presence-1');
1147
+ expect(presence).to.eql({index: 2});
1148
+ next();
1149
+ });
1150
+ },
1151
+ function(next) {
1152
+ connection1.close();
1153
+ presence2.once('receive', function(id, presence) {
1154
+ expect(id).to.equal('presence-1');
1155
+ expect(presence).to.be.null;
1156
+ next();
1157
+ });
1158
+ }
1159
+ ], done);
1160
+ });
1161
+
1162
+ it('broadcasts presence re-created with the same id after destroying the channel presence', function(done) {
1163
+ async.series([
1164
+ presence1.subscribe.bind(presence1),
1165
+ presence2.subscribe.bind(presence2),
1166
+ function(next) {
1167
+ presence1.create('presence-1').submit({index: 1}, errorHandler(done));
1168
+ presence2.once('receive', function() {
1169
+ next();
1170
+ });
1171
+ },
1172
+ function(next) {
1173
+ var leaveCount = 0;
1174
+ presence1.destroy(errorHandler(done));
1175
+ presence2.on('receive', function receiveLeave(id, presence) {
1176
+ expect(id).to.equal('presence-1');
1177
+ expect(presence).to.be.null;
1178
+ leaveCount++;
1179
+ if (leaveCount < 2) return;
1180
+ presence2.off('receive', receiveLeave);
1181
+ next();
1182
+ });
1183
+ },
1184
+ function(next) {
1185
+ connection1.getPresence('test-channel').create('presence-1').submit({index: 2}, errorHandler(done));
1186
+ presence2.once('receive', function(id, presence) {
1187
+ expect(id).to.equal('presence-1');
1188
+ expect(presence).to.eql({index: 2});
1189
+ next();
1190
+ });
1191
+ },
1192
+ function(next) {
1193
+ connection1.close();
1194
+ presence2.once('receive', function(id, presence) {
1195
+ expect(id).to.equal('presence-1');
1196
+ expect(presence).to.be.null;
1197
+ next();
1198
+ });
1199
+ }
1200
+ ], done);
1201
+ });
1202
+
1203
+ it('broadcasts a null presence when unsubscribing', function(done) {
1204
+ var localPresence1 = presence1.create('presence-1');
1205
+ async.series([
1206
+ presence1.subscribe.bind(presence1),
1207
+ presence2.subscribe.bind(presence2),
1208
+ function(next) {
1209
+ localPresence1.submit({index: 3}, errorHandler(done));
1210
+ presence2.once('receive', function() {
1211
+ next();
1212
+ });
1213
+ },
1214
+ function(next) {
1215
+ presence2.once('receive', function(id, presence) {
1216
+ expect(id).to.equal('presence-1');
1217
+ expect(presence).to.be.null;
1218
+ next();
1219
+ });
1220
+ presence1.unsubscribe(errorHandler(done));
1221
+ }
1222
+ ], done);
1223
+ });
1224
+
1225
+ it('does not broadcast a null presence again when disconnecting after unsubscribing', function(done) {
1226
+ var localPresence1 = presence1.create('presence-1');
1227
+ var agent1 = connection1.agent;
1228
+ async.series([
1229
+ presence1.subscribe.bind(presence1),
1230
+ presence2.subscribe.bind(presence2),
1231
+ function(next) {
1232
+ localPresence1.submit({index: 3}, errorHandler(done));
1233
+ presence2.once('receive', function() {
1234
+ next();
1235
+ });
1236
+ },
1237
+ function(next) {
1238
+ presence2.once('receive', function() {
1239
+ next();
1240
+ });
1241
+ presence1.unsubscribe(errorHandler(done));
1242
+ },
1243
+ function(next) {
1244
+ sinon.spy(agent1, '_broadcastPresence');
1245
+ agent1.stream.once('end', next);
1246
+ connection1.close();
1247
+ },
1248
+ function(next) {
1249
+ expect(agent1._broadcastPresence).not.to.have.been.called;
1250
+ next();
1251
+ }
1252
+ ], done);
1253
+ });
1254
+
721
1255
  describe('middleware', function() {
722
1256
  describe('receivePresence', function() {
723
1257
  it('provides the presence in the middleware', function(done) {
@@ -732,7 +1266,7 @@ describe('Presence', function() {
732
1266
 
733
1267
  it('can mutate the presence in the middleware', function(done) {
734
1268
  backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
735
- context.presence.p.index++;
1269
+ if (context.presence.p) context.presence.p.index++;
736
1270
  next();
737
1271
  });
738
1272
 
@@ -767,8 +1301,34 @@ describe('Presence', function() {
767
1301
  localPresence1.submit({index: 5}, function(error) {
768
1302
  expect(error.message).to.contain('bad!');
769
1303
  expect(connection1.agent.presenceRequests['test-channel']).not.to.be.ok;
1304
+ expect(connection1.agent._pendingPresenceBroadcasts).to.be.empty;
1305
+ next();
1306
+ });
1307
+ }
1308
+ ], done);
1309
+ });
1310
+
1311
+ it('still broadcasts presence in flight when another presence on the channel is rejected', function(done) {
1312
+ var localPresence1 = presence1.create('presence-1');
1313
+ var localPresence2 = presence1.create('presence-2');
1314
+
1315
+ backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
1316
+ if (context.presence.id === 'presence-2') return next(new Error('bad!'));
1317
+ localPresence2.submit({index: 2}, function(error) {
1318
+ expect(error.message).to.contain('bad!');
1319
+ next();
1320
+ });
1321
+ });
1322
+
1323
+ async.series([
1324
+ presence2.subscribe.bind(presence2),
1325
+ function(next) {
1326
+ presence2.once('receive', function(id, presence) {
1327
+ expect(id).to.equal('presence-1');
1328
+ expect(presence).to.eql({index: 1});
770
1329
  next();
771
1330
  });
1331
+ localPresence1.submit({index: 1}, errorHandler(done));
772
1332
  }
773
1333
  ], done);
774
1334
  });
@@ -795,6 +1355,27 @@ describe('Presence', function() {
795
1355
  ], done);
796
1356
  });
797
1357
 
1358
+ it('emits an error for a presence with the same ID on the presence, not its local presence', function(done) {
1359
+ var localPresence1 = presence1.create('presence-1');
1360
+ var localPresence2 = presence2.create('presence-1');
1361
+ localPresence2.on('error', done);
1362
+
1363
+ backend.use(backend.MIDDLEWARE_ACTIONS.sendPresence, function(context, next) {
1364
+ next(new Error('uh-oh!'));
1365
+ });
1366
+
1367
+ async.series([
1368
+ presence2.subscribe.bind(presence2),
1369
+ function(next) {
1370
+ localPresence1.submit({index: 3}, errorHandler(done));
1371
+ presence2.once('error', function(error) {
1372
+ expect(error.message).to.equal('uh-oh!');
1373
+ next();
1374
+ });
1375
+ }
1376
+ ], done);
1377
+ });
1378
+
798
1379
  it('emits errors on the server instead of sending to the client', function(done) {
799
1380
  var localPresence1 = presence1.create('presence-1');
800
1381
 
@@ -430,6 +430,31 @@ function commonTests(options) {
430
430
  });
431
431
  });
432
432
 
433
+ it('subscribed query results catch up on ops missed while disconnected', function(done) {
434
+ var backend = this.backend;
435
+ var connection = backend.connect();
436
+ var doc2 = backend.connect().get('dogs', 'fido').on('error', done);
437
+ var matchAllDbQuery = this.matchAllDbQuery;
438
+ doc2.create({age: 3}, function(err) {
439
+ if (err) return done(err);
440
+ var query = connection.createSubscribeQuery('dogs', matchAllDbQuery, null, function(err, results) {
441
+ if (err) return done(err);
442
+ var doc = results[0];
443
+ connection.close();
444
+ doc2.submitOp({p: ['age'], na: 1}, function(err) {
445
+ if (err) return done(err);
446
+ backend.connect(connection);
447
+ query.once('ready', function() {
448
+ expect(doc.version).to.equal(2);
449
+ expect(doc.data).to.eql({age: 4});
450
+ done();
451
+ });
452
+ });
453
+ });
454
+ query.on('error', done);
455
+ });
456
+ });
457
+
433
458
  it('subscribed query gets simultaneous insert and remove after reconnecting', function(done) {
434
459
  var backend = this.backend;
435
460
  var connection = backend.connect();