@@ -6,6 +6,7 @@ import 'package:fake_async/fake_async.dart';
66import 'package:flutter/foundation.dart' ;
77import 'package:http/http.dart' as http;
88import 'package:test/scaffolding.dart' ;
9+ import 'package:zulip/api/backoff.dart' ;
910import 'package:zulip/api/core.dart' ;
1011import 'package:zulip/api/model/events.dart' ;
1112import 'package:zulip/api/model/model.dart' ;
@@ -157,6 +158,42 @@ void main() {
157158 await check (future).throws <AccountNotFoundException >();
158159 }));
159160
161+ test ('GlobalStore.perAccount loading succeeds' , () => awaitFakeAsync ((async ) async {
162+ NotificationService .instance.token = ValueNotifier ('asdf' );
163+ addTearDown (NotificationService .debugReset);
164+
165+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
166+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
167+ final future = globalStore.perAccount (eg.selfAccount.id);
168+ check (connection.takeRequests ()).length.equals (1 ); // register request
169+
170+ await future;
171+ // poll, server-emoji-data, register-token requests
172+ check (connection.takeRequests ()).length.equals (3 );
173+ check (connection).isOpen.isTrue ();
174+ }));
175+
176+ test ('GlobalStore.perAccount account is logged out while loading; then succeeds' , () => awaitFakeAsync ((async ) async {
177+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
178+ globalStore.prepareRegisterQueueResponse = (connection) =>
179+ connection.prepare (
180+ delay: TestGlobalStore .removeAccountDuration + Duration (seconds: 1 ),
181+ json: eg.initialSnapshot ().toJson ());
182+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
183+ final future = globalStore.perAccount (eg.selfAccount.id);
184+ check (connection.takeRequests ()).length.equals (1 ); // register request
185+
186+ await logOutAccount (globalStore, eg.selfAccount.id);
187+ check (globalStore.takeDoRemoveAccountCalls ())
188+ .single.equals (eg.selfAccount.id);
189+
190+ await check (future).throws <AccountNotFoundException >();
191+ check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
192+ // no poll, server-emoji-data, or register-token requests
193+ check (connection.takeRequests ()).isEmpty ();
194+ check (connection).isOpen.isFalse ();
195+ }));
196+
160197 test ('GlobalStore.perAccount account is logged out while loading; then fails with HTTP status code 401' , () => awaitFakeAsync ((async ) async {
161198 final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
162199 globalStore.prepareRegisterQueueResponse = (connection) =>
@@ -175,8 +212,31 @@ void main() {
175212 check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
176213 // no poll, server-emoji-data, or register-token requests
177214 check (connection.takeRequests ()).isEmpty ();
178- // TODO(#1354) uncomment
179- // check(connection).isOpen.isFalse();
215+ check (connection).isOpen.isFalse ();
216+ }));
217+
218+ test ('GlobalStore.perAccount account is logged out during transient-error backoff' , () => awaitFakeAsync ((async ) async {
219+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
220+ globalStore.prepareRegisterQueueResponse = (connection) =>
221+ connection.prepare (
222+ delay: Duration (seconds: 1 ),
223+ httpException: http.ClientException ('Oops' ));
224+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
225+ final future = globalStore.perAccount (eg.selfAccount.id);
226+ BackoffMachine .debugDuration = Duration (seconds: 1 );
227+ async .elapse (Duration (milliseconds: 1500 ));
228+ check (connection.takeRequests ()).length.equals (1 ); // register request
229+
230+ assert (TestGlobalStore .removeAccountDuration < Duration (milliseconds: 500 ));
231+ await logOutAccount (globalStore, eg.selfAccount.id);
232+ check (globalStore.takeDoRemoveAccountCalls ())
233+ .single.equals (eg.selfAccount.id);
234+
235+ await check (future).throws <AccountNotFoundException >();
236+ check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
237+ // no retry-register, poll, server-emoji-data, or register-token requests
238+ check (connection.takeRequests ()).isEmpty ();
239+ check (connection).isOpen.isFalse ();
180240 }));
181241
182242 // TODO test insertAccount
@@ -278,10 +338,10 @@ void main() {
278338 checkGlobalStore (globalStore, eg.selfAccount.id,
279339 expectAccount: true , expectStore: false );
280340
281- // assert(globalStore.useCachedApiConnections);
341+ assert (globalStore.useCachedApiConnections);
282342 // Cache a connection and get this reference to it,
283343 // so we can check later that it gets closed.
284- // final connection = globalStore.apiConnectionFromAccount(eg.selfAccount) as FakeApiConnection;
344+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
285345
286346 globalStore.prepareRegisterQueueResponse = (connection) {
287347 connection.prepare (
@@ -301,14 +361,11 @@ void main() {
301361 expectAccount: false , expectStore: false );
302362 check (notifyCount).equals (1 );
303363
304- // Actually throws a null-check error; that's the bug #1354.
305- // TODO(#1354) should specifically throw AccountNotFoundException
306- await check (loadingFuture).throws ();
364+ await check (loadingFuture).throws <AccountNotFoundException >();
307365 checkGlobalStore (globalStore, eg.selfAccount.id,
308366 expectAccount: false , expectStore: false );
309367 check (notifyCount).equals (1 ); // no extra notify
310- // TODO(#1354) uncomment
311- // check(connection).isOpen.isFalse();
368+ check (connection).isOpen.isFalse ();
312369
313370 check (globalStore.debugNumPerAccountStoresLoading).equals (0 );
314371 });
@@ -1051,10 +1108,7 @@ void main() {
10511108 async .flushTimers ();
10521109 // Reload never succeeds and there are no unhandled errors.
10531110 check (globalStore.perAccountSync (eg.selfAccount.id)).isNull ();
1054- }),
1055- // An unhandled error is actually the bug #1354, so skip for now
1056- // TODO(#1354) unskip
1057- skip: true );
1111+ }));
10581112
10591113 test ('new store is not loaded, gets HTTP 401 error instead' , () => awaitFakeAsync ((async ) async {
10601114 await prepareReload (async , prepareRegisterQueueResponse: (connection) {
0 commit comments