Skip to content

Commit faa87f5

Browse files
committed
store test [nfc]: Pull out prepare-error helpers
This lets us share this setup code between the tests of how the logic responds (retry, reload, or otherwise) and how it reports errors to the user (or doesn't), while keeping separate test cases so that test failures of one kind don't obscure the story with the other.
1 parent 372b882 commit faa87f5

File tree

1 file changed

+59
-40
lines changed

1 file changed

+59
-40
lines changed

test/model/store_test.dart

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -671,30 +671,6 @@ void main() {
671671
});
672672
}
673673

674-
test('expired queue disposes registered MessageListView instances', () => awaitFakeAsync((async) async {
675-
// Regression test for: https://github.com/zulip/zulip-flutter/issues/810
676-
await preparePoll();
677-
678-
// Make sure there are [MessageListView]s in the message store.
679-
MessageListView.init(store: store, narrow: const MentionsNarrow());
680-
MessageListView.init(store: store, narrow: const StarredMessagesNarrow());
681-
check(store.debugMessageListViews).length.equals(2);
682-
683-
// Let the server expire the event queue.
684-
connection.prepare(httpStatus: 400, json: {
685-
'result': 'error', 'code': 'BAD_EVENT_QUEUE_ID',
686-
'queue_id': updateMachine.queueId,
687-
'msg': 'Bad event queue ID: ${updateMachine.queueId}',
688-
});
689-
updateMachine.debugAdvanceLoop();
690-
async.flushMicrotasks();
691-
await Future<void>.delayed(Duration.zero);
692-
693-
// The old store's [MessageListView]s have been disposed.
694-
// (And no exception was thrown; that was #810.)
695-
check(store.debugMessageListViews).isEmpty();
696-
}));
697-
698674
void checkRetry(void Function() prepareError) {
699675
awaitFakeAsync((async) async {
700676
await preparePoll(lastEventId: 1);
@@ -727,31 +703,75 @@ void main() {
727703

728704
// These cases are ordered by how far the request got before it failed.
729705

706+
void prepareNetworkExceptionSocketException() {
707+
connection.prepare(exception: const SocketException('failed'));
708+
}
709+
710+
void prepareNetworkException() {
711+
connection.prepare(exception: Exception("failed"));
712+
}
713+
714+
void prepareServer5xxException() {
715+
connection.prepare(httpStatus: 500, body: 'splat');
716+
}
717+
718+
void prepareMalformedServerResponseException() {
719+
connection.prepare(httpStatus: 200, body: 'nonsense');
720+
}
721+
722+
void prepareZulipApiExceptionBadRequest() {
723+
connection.prepare(httpStatus: 400, json: {
724+
'result': 'error', 'code': 'BAD_REQUEST', 'msg': 'Bad request'});
725+
}
726+
727+
void prepareExpiredEventQueue() {
728+
connection.prepare(httpStatus: 400, json: {
729+
'result': 'error', 'code': 'BAD_EVENT_QUEUE_ID',
730+
'queue_id': updateMachine.queueId,
731+
'msg': 'Bad event queue ID: ${updateMachine.queueId}',
732+
});
733+
}
734+
730735
test('retries on NetworkException', () {
731-
checkRetry(() => connection.prepare(exception: Exception("failed")));
736+
checkRetry(prepareNetworkException);
732737
});
733738

734739
test('retries on Server5xxException', () {
735-
checkRetry(() => connection.prepare(httpStatus: 500, body: 'splat'));
740+
checkRetry(prepareServer5xxException);
736741
});
737742

738743
test('retries on MalformedServerResponseException', () {
739-
checkRetry(() => connection.prepare(httpStatus: 200, body: 'nonsense'));
744+
checkRetry(prepareMalformedServerResponseException);
740745
});
741746

742747
test('retries on generic ZulipApiException', () {
743-
checkRetry(() => connection.prepare(httpStatus: 400, json: {
744-
'result': 'error', 'code': 'BAD_REQUEST', 'msg': 'Bad request'}));
748+
checkRetry(prepareZulipApiExceptionBadRequest);
745749
});
746750

747751
test('reloads on expired queue', () {
748-
checkReload(() => connection.prepare(httpStatus: 400, json: {
749-
'result': 'error', 'code': 'BAD_EVENT_QUEUE_ID',
750-
'queue_id': updateMachine.queueId,
751-
'msg': 'Bad event queue ID: ${updateMachine.queueId}',
752-
}));
752+
checkReload(prepareExpiredEventQueue);
753753
});
754754

755+
test('expired queue disposes registered MessageListView instances', () => awaitFakeAsync((async) async {
756+
// Regression test for: https://github.com/zulip/zulip-flutter/issues/810
757+
await preparePoll();
758+
759+
// Make sure there are [MessageListView]s in the message store.
760+
MessageListView.init(store: store, narrow: const MentionsNarrow());
761+
MessageListView.init(store: store, narrow: const StarredMessagesNarrow());
762+
check(store.debugMessageListViews).length.equals(2);
763+
764+
// Let the server expire the event queue.
765+
prepareExpiredEventQueue();
766+
updateMachine.debugAdvanceLoop();
767+
async.flushMicrotasks();
768+
await Future<void>.delayed(Duration.zero);
769+
770+
// The old store's [MessageListView]s have been disposed.
771+
// (And no exception was thrown; that was #810.)
772+
check(store.debugMessageListViews).isEmpty();
773+
}));
774+
755775
group('report error', () {
756776
String? lastReportedError;
757777
String? takeLastReportedError() {
@@ -781,8 +801,7 @@ void main() {
781801
test('report non-transient errors', () => awaitFakeAsync((async) async {
782802
await prepare();
783803

784-
connection.prepare(httpStatus: 400, json: {
785-
'result': 'error', 'code': 'BAD_REQUEST', 'msg': 'Bad request'});
804+
prepareZulipApiExceptionBadRequest();
786805
pollAndFail(async);
787806
check(takeLastReportedError()).isNotNull().startsWith(
788807
"Error connecting to Zulip. Retrying…\n"
@@ -794,14 +813,14 @@ void main() {
794813

795814
// There should be no user visible error messages during these retries.
796815
for (int i = 0; i < UpdateMachine.transientFailureCountNotifyThreshold; i++) {
797-
connection.prepare(httpStatus: 500, body: 'splat');
816+
prepareServer5xxException();
798817
pollAndFail(async);
799818
check(takeLastReportedError()).isNull();
800819
// This skips the pending polling backoff.
801820
async.flushTimers();
802821
}
803822

804-
connection.prepare(httpStatus: 500, body: 'splat');
823+
prepareServer5xxException();
805824
pollAndFail(async);
806825
check(takeLastReportedError()).isNotNull().startsWith(
807826
"Error connecting to Zulip. Retrying…\n"
@@ -812,14 +831,14 @@ void main() {
812831
await prepare();
813832

814833
for (int i = 0; i < UpdateMachine.transientFailureCountNotifyThreshold; i++) {
815-
connection.prepare(exception: const SocketException('failed'));
834+
prepareNetworkExceptionSocketException();
816835
pollAndFail(async);
817836
check(takeLastReportedError()).isNull();
818837
// This skips the pending polling backoff.
819838
async.flushTimers();
820839
}
821840

822-
connection.prepare(exception: const SocketException('failed'));
841+
prepareNetworkExceptionSocketException();
823842
pollAndFail(async);
824843
// Normally we start showing user visible error messages for transient
825844
// errors after enough number of retries.

0 commit comments

Comments
 (0)