@@ -639,16 +639,25 @@ void main() {
639
639
check (store.userSettings! .twentyFourHourTime).isTrue ();
640
640
}));
641
641
642
- void checkReload (void Function () prepareError) {
642
+ void checkReload (FutureOr <void > Function () prepareError, {
643
+ bool expectBackoff = true ,
644
+ }) {
643
645
awaitFakeAsync ((async ) async {
644
646
await preparePoll ();
645
647
check (globalStore.perAccountSync (store.accountId)).identicalTo (store);
646
648
647
- prepareError ();
649
+ await prepareError ();
648
650
updateMachine.debugAdvanceLoop ();
649
651
async .elapse (Duration .zero);
650
652
check (store).isLoading.isTrue ();
651
653
654
+ if (expectBackoff) {
655
+ // The reload doesn't happen immediately; there's a timer.
656
+ check (globalStore.perAccountSync (store.accountId)).identicalTo (store);
657
+ check (async .pendingTimers).length.equals (1 );
658
+ async .flushTimers ();
659
+ }
660
+
652
661
// The global store has a new store.
653
662
check (globalStore.perAccountSync (store.accountId)).not ((it) => it.identicalTo (store));
654
663
updateFromGlobalStore ();
@@ -700,6 +709,10 @@ void main() {
700
709
701
710
// These cases are ordered by how far the request got before it failed.
702
711
712
+ void prepareUnexpectedLoopError () {
713
+ updateMachine.debugPrepareLoopError (eg.nullCheckError ());
714
+ }
715
+
703
716
void prepareNetworkExceptionSocketException () {
704
717
connection.prepare (exception: const SocketException ('failed' ));
705
718
}
@@ -753,6 +766,23 @@ void main() {
753
766
});
754
767
}
755
768
769
+ Future <void > prepareHandleEventError () async {
770
+ final stream = eg.stream ();
771
+ await store.addStream (stream);
772
+ // Set up a situation that breaks our data structures' invariants:
773
+ // a stream/channel found in the by-ID map is missing in the by-name map.
774
+ store.streamsByName.remove (stream.name);
775
+ // Then prepare an event on which handleEvent will throw
776
+ // because it hits that broken invariant.
777
+ connection.prepare (json: GetEventsResult (events: [
778
+ ChannelDeleteEvent (id: 1 , streams: [stream]),
779
+ ], queueId: null ).toJson ());
780
+ }
781
+
782
+ test ('reloads on unexpected error within loop' , () {
783
+ checkReload (prepareUnexpectedLoopError);
784
+ });
785
+
756
786
test ('retries on NetworkException from SocketException' , () {
757
787
// We skip reporting errors on these; check we retry them all the same.
758
788
checkRetry (prepareNetworkExceptionSocketException);
@@ -786,8 +816,12 @@ void main() {
786
816
checkRetry (prepareZulipApiExceptionBadRequest);
787
817
});
788
818
789
- test ('reloads on expired queue' , () {
790
- checkReload (prepareExpiredEventQueue);
819
+ test ('reloads immediately on expired queue' , () {
820
+ checkReload (expectBackoff: false , prepareExpiredEventQueue);
821
+ });
822
+
823
+ test ('reloads on handleEvent error' , () {
824
+ checkReload (prepareHandleEventError);
791
825
});
792
826
793
827
test ('expired queue disposes registered MessageListView instances' , () => awaitFakeAsync ((async ) async {
@@ -828,18 +862,20 @@ void main() {
828
862
await preparePoll (lastEventId: 1 );
829
863
}
830
864
831
- void pollAndFail (FakeAsync async ) {
865
+ void pollAndFail (FakeAsync async , { bool shouldCheckRequest = true } ) {
832
866
updateMachine.debugAdvanceLoop ();
833
867
async .elapse (Duration .zero);
834
- checkLastRequest (lastEventId: 1 );
868
+ if (shouldCheckRequest) checkLastRequest (lastEventId: 1 );
835
869
check (store).isLoading.isTrue ();
836
870
}
837
871
838
872
Subject <String > checkReported (void Function () prepareError) {
839
873
return awaitFakeAsync ((async ) async {
840
874
await prepare ();
841
875
prepareError ();
842
- pollAndFail (async );
876
+ // No need to check on the request; there's no later step of this test
877
+ // for it to be needed as setup for.
878
+ pollAndFail (async , shouldCheckRequest: false );
843
879
return check (takeLastReportedError ()).isNotNull ();
844
880
});
845
881
}
@@ -892,6 +928,10 @@ void main() {
892
928
});
893
929
}
894
930
931
+ test ('report unexpected error within loop' , () {
932
+ checkReported (prepareUnexpectedLoopError);
933
+ });
934
+
895
935
test ('ignore NetworkException from SocketException' , () {
896
936
checkNotReported (prepareNetworkExceptionSocketException);
897
937
});
@@ -941,6 +981,12 @@ void main() {
941
981
test ('ignore expired queue' , () {
942
982
checkNotReported (prepareExpiredEventQueue);
943
983
});
984
+
985
+ test ('report handleEvent error' , () {
986
+ checkReported (prepareHandleEventError).startsWith (
987
+ "Error connecting to Zulip. Retrying…\n "
988
+ "Error connecting to Zulip at" );
989
+ });
944
990
});
945
991
});
946
992
0 commit comments