@@ -131,17 +131,25 @@ void main() {
131131 }));
132132
133133 test ('GlobalStore.perAccount account is logged out while loading; then fails with HTTP status code 401' , () => awaitFakeAsync ((async ) async {
134- final globalStore = LoadingTestGlobalStore (accounts: [eg.selfAccount]);
134+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
135+ globalStore.prepareRegisterQueueResponse = (connection) =>
136+ connection.prepare (
137+ delay: TestGlobalStore .removeAccountDuration + Duration (seconds: 1 ),
138+ apiException: eg.apiExceptionUnauthorized ());
139+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
135140 final future = globalStore.perAccount (eg.selfAccount.id);
141+ check (connection.takeRequests ()).length.equals (1 ); // register request
136142
137143 await logOutAccount (globalStore, eg.selfAccount.id);
138144 check (globalStore.takeDoRemoveAccountCalls ())
139145 .single.equals (eg.selfAccount.id);
140146
141- globalStore.completers[eg.selfAccount.id]!
142- .single.completeError (eg.apiExceptionUnauthorized ());
143147 await check (future).throws <AccountNotFoundException >();
144148 check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
149+ // no poll, server-emoji-data, or register-token requests
150+ check (connection.takeRequests ()).isEmpty ();
151+ // TODO(#1354) uncomment
152+ // check(connection).isOpen.isFalse();
145153 }));
146154
147155 // TODO test insertAccount
@@ -239,11 +247,20 @@ void main() {
239247 });
240248
241249 test ('when store loading' , () async {
242- final globalStore = LoadingTestGlobalStore (accounts: [eg.selfAccount]);
250+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
243251 checkGlobalStore (globalStore, eg.selfAccount.id,
244252 expectAccount: true , expectStore: false );
245253
246- // don't await; we'll complete/await it manually after removeAccount
254+ // assert(globalStore.useCachedApiConnections);
255+ // Cache a connection and get this reference to it,
256+ // so we can check later that it gets closed.
257+ // final connection = globalStore.apiConnectionFromAccount(eg.selfAccount) as FakeApiConnection;
258+
259+ globalStore.prepareRegisterQueueResponse = (connection) {
260+ connection.prepare (
261+ delay: TestGlobalStore .removeAccountDuration + Duration (seconds: 1 ),
262+ json: eg.initialSnapshot ().toJson ());
263+ };
247264 final loadingFuture = globalStore.perAccount (eg.selfAccount.id);
248265
249266 checkGlobalStore (globalStore, eg.selfAccount.id,
@@ -257,13 +274,14 @@ void main() {
257274 expectAccount: false , expectStore: false );
258275 check (notifyCount).equals (1 );
259276
260- globalStore.completers[eg.selfAccount.id]! .single
261- .complete (eg.store (account: eg.selfAccount, initialSnapshot: eg.initialSnapshot ()));
262- // TODO test that the never-used store got disposed and its connection closed
263- await check (loadingFuture).throws <AccountNotFoundException >();
277+ // Actually throws a null-check error; that's the bug #1354.
278+ // TODO(#1354) should specifically throw AccountNotFoundException
279+ await check (loadingFuture).throws ();
264280 checkGlobalStore (globalStore, eg.selfAccount.id,
265281 expectAccount: false , expectStore: false );
266282 check (notifyCount).equals (1 ); // no extra notify
283+ // TODO(#1354) uncomment
284+ // check(connection).isOpen.isFalse();
267285
268286 check (globalStore.debugNumPerAccountStoresLoading).equals (0 );
269287 });
@@ -966,41 +984,42 @@ void main() {
966984 });
967985
968986 group ('UpdateMachine.poll reload failure' , () {
969- late LoadingTestGlobalStore globalStore;
987+ late UpdateMachineTestGlobalStore globalStore;
970988
971- List <Completer <PerAccountStore >> completers () =>
972- globalStore.completers[eg.selfAccount.id]! ;
989+ Future <void > prepareReload (FakeAsync async , {
990+ required void Function (FakeApiConnection ) prepareRegisterQueueResponse,
991+ }) async {
992+ globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
973993
974- Future <void > prepareReload (FakeAsync async ) async {
975- globalStore = LoadingTestGlobalStore (accounts: [eg.selfAccount]);
976- final future = globalStore.perAccount (eg.selfAccount.id);
977- final store = eg.store (globalStore: globalStore, account: eg.selfAccount);
978- completers ().single.complete (store);
979- await future;
980- completers ().clear ();
981- final updateMachine = globalStore.updateMachines[eg.selfAccount.id] =
982- UpdateMachine .fromInitialSnapshot (
983- store: store, initialSnapshot: eg.initialSnapshot ());
984- updateMachine.debugPauseLoop ();
994+ final store = await globalStore.perAccount (eg.selfAccount.id);
995+ final updateMachine = store.updateMachine! ;
985996 updateMachine.poll ();
986997
987- (store.connection as FakeApiConnection ).prepare (
998+ final connection = store.connection as FakeApiConnection ;
999+ connection.prepare (
9881000 apiException: eg.apiExceptionBadEventQueueId ());
1001+ globalStore.clearCachedApiConnections ();
1002+ globalStore.prepareRegisterQueueResponse = (newConnection) {
1003+ // Assert this is actually a new connection, not the one on
1004+ // globalStore._perAccountStores, which at least one test will close
1005+ // via logOutAccount.
1006+ assert (! identical (connection, newConnection));
1007+ prepareRegisterQueueResponse (newConnection);
1008+ };
9891009 updateMachine.debugAdvanceLoop ();
9901010 async .elapse (Duration .zero);
9911011 check (store).isLoading.isTrue ();
9921012 }
9931013
9941014 test ('user logged out before new store is loaded' , () => awaitFakeAsync ((async ) async {
995- await prepareReload (async );
996- check (completers ()).single.isCompleted.isFalse ();
1015+ await prepareReload (async ,
1016+ prepareRegisterQueueResponse: (newConnection) {
1017+ newConnection.prepare (
1018+ delay: TestGlobalStore .removeAccountDuration + Duration (seconds: 1 ),
1019+ json: eg.initialSnapshot ().toJson ());
1020+ });
9971021
998- // [PerAccountStore.fromInitialSnapshot] requires the account
999- // to be in the global store when called; do so before logging out.
1000- final newStore = eg.store (globalStore: globalStore, account: eg.selfAccount);
10011022 await logOutAccount (globalStore, eg.selfAccount.id);
1002- completers ().single.complete (newStore);
1003- check (completers ()).single.isCompleted.isTrue ();
10041023 check (globalStore.takeDoRemoveAccountCalls ()).single.equals (eg.selfAccount.id);
10051024
10061025 async .elapse (TestGlobalStore .removeAccountDuration);
@@ -1009,15 +1028,20 @@ void main() {
10091028 async .flushTimers ();
10101029 // Reload never succeeds and there are no unhandled errors.
10111030 check (globalStore.perAccountSync (eg.selfAccount.id)).isNull ();
1012- }));
1031+ }),
1032+ // An unhandled error is actually the bug #1354, so skip for now
1033+ // TODO(#1354) unskip
1034+ skip: true );
10131035
10141036 test ('new store is not loaded, gets HTTP 401 error instead' , () => awaitFakeAsync ((async ) async {
1015- await prepareReload (async );
1016- check (completers ()).single.isCompleted.isFalse ();
1037+ await prepareReload (async ,
1038+ prepareRegisterQueueResponse: (newConnection) {
1039+ newConnection.prepare (
1040+ delay: Duration (seconds: 1 ),
1041+ apiException: eg.apiExceptionUnauthorized ());
1042+ });
10171043
1018- completers ().single.completeError (eg.apiExceptionUnauthorized ());
1019- async .elapse (Duration .zero);
1020- check (completers ()).single.isCompleted.isTrue ();
1044+ async .elapse (const Duration (seconds: 1 ));
10211045 check (globalStore.takeDoRemoveAccountCalls ()).single.equals (eg.selfAccount.id);
10221046
10231047 async .elapse (TestGlobalStore .removeAccountDuration);
0 commit comments