@@ -6,6 +6,7 @@ import 'package:fake_async/fake_async.dart';
6
6
import 'package:flutter/foundation.dart' ;
7
7
import 'package:http/http.dart' as http;
8
8
import 'package:test/scaffolding.dart' ;
9
+ import 'package:zulip/api/backoff.dart' ;
9
10
import 'package:zulip/api/core.dart' ;
10
11
import 'package:zulip/api/model/events.dart' ;
11
12
import 'package:zulip/api/model/model.dart' ;
@@ -130,6 +131,27 @@ void main() {
130
131
await check (future).throws <AccountNotFoundException >();
131
132
}));
132
133
134
+ test ('GlobalStore.perAccount account is logged out while loading; then succeeds' , () => awaitFakeAsync ((async ) async {
135
+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
136
+ globalStore.prepareRegisterQueueResponse = (connection) =>
137
+ connection.prepare (
138
+ delay: TestGlobalStore .removeAccountDuration + Duration (seconds: 1 ),
139
+ json: eg.initialSnapshot ().toJson ());
140
+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
141
+ final future = globalStore.perAccount (eg.selfAccount.id);
142
+ check (connection.takeRequests ()).length.equals (1 ); // register request
143
+
144
+ await logOutAccount (globalStore, eg.selfAccount.id);
145
+ check (globalStore.takeDoRemoveAccountCalls ())
146
+ .single.equals (eg.selfAccount.id);
147
+
148
+ await check (future).throws <AccountNotFoundException >();
149
+ check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
150
+ // no poll, server-emoji-data, or register-token requests
151
+ check (connection.takeRequests ()).isEmpty ();
152
+ check (connection).isOpen.isFalse ();
153
+ }));
154
+
133
155
test ('GlobalStore.perAccount account is logged out while loading; then fails with HTTP status code 401' , () => awaitFakeAsync ((async ) async {
134
156
final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
135
157
globalStore.prepareRegisterQueueResponse = (connection) =>
@@ -148,8 +170,31 @@ void main() {
148
170
check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
149
171
// no poll, server-emoji-data, or register-token requests
150
172
check (connection.takeRequests ()).isEmpty ();
151
- // TODO(#1354) uncomment
152
- // check(connection).isOpen.isFalse();
173
+ check (connection).isOpen.isFalse ();
174
+ }));
175
+
176
+ test ('GlobalStore.perAccount account is logged out during transient-error backoff' , () => awaitFakeAsync ((async ) async {
177
+ final globalStore = UpdateMachineTestGlobalStore (accounts: [eg.selfAccount]);
178
+ globalStore.prepareRegisterQueueResponse = (connection) =>
179
+ connection.prepare (
180
+ delay: Duration (seconds: 1 ),
181
+ httpException: http.ClientException ('Oops' ));
182
+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
183
+ final future = globalStore.perAccount (eg.selfAccount.id);
184
+ BackoffMachine .debugDuration = Duration (seconds: 1 );
185
+ async .elapse (Duration (milliseconds: 1500 ));
186
+ check (connection.takeRequests ()).length.equals (1 ); // register request
187
+
188
+ assert (TestGlobalStore .removeAccountDuration < Duration (milliseconds: 500 ));
189
+ await logOutAccount (globalStore, eg.selfAccount.id);
190
+ check (globalStore.takeDoRemoveAccountCalls ())
191
+ .single.equals (eg.selfAccount.id);
192
+
193
+ await check (future).throws <AccountNotFoundException >();
194
+ check (globalStore.takeDoRemoveAccountCalls ()).isEmpty ();
195
+ // no retry-register, poll, server-emoji-data, or register-token requests
196
+ check (connection.takeRequests ()).isEmpty ();
197
+ check (connection).isOpen.isFalse ();
153
198
}));
154
199
155
200
// TODO test insertAccount
@@ -251,10 +296,10 @@ void main() {
251
296
checkGlobalStore (globalStore, eg.selfAccount.id,
252
297
expectAccount: true , expectStore: false );
253
298
254
- // assert(globalStore.useCachedApiConnections);
299
+ assert (globalStore.useCachedApiConnections);
255
300
// Cache a connection and get this reference to it,
256
301
// so we can check later that it gets closed.
257
- // final connection = globalStore.apiConnectionFromAccount(eg.selfAccount) as FakeApiConnection;
302
+ final connection = globalStore.apiConnectionFromAccount (eg.selfAccount) as FakeApiConnection ;
258
303
259
304
globalStore.prepareRegisterQueueResponse = (connection) {
260
305
connection.prepare (
@@ -274,14 +319,11 @@ void main() {
274
319
expectAccount: false , expectStore: false );
275
320
check (notifyCount).equals (1 );
276
321
277
- // Actually throws a null-check error; that's the bug #1354.
278
- // TODO(#1354) should specifically throw AccountNotFoundException
279
- await check (loadingFuture).throws ();
322
+ await check (loadingFuture).throws <AccountNotFoundException >();
280
323
checkGlobalStore (globalStore, eg.selfAccount.id,
281
324
expectAccount: false , expectStore: false );
282
325
check (notifyCount).equals (1 ); // no extra notify
283
- // TODO(#1354) uncomment
284
- // check(connection).isOpen.isFalse();
326
+ check (connection).isOpen.isFalse ();
285
327
286
328
check (globalStore.debugNumPerAccountStoresLoading).equals (0 );
287
329
});
@@ -1027,10 +1069,7 @@ void main() {
1027
1069
async .flushTimers ();
1028
1070
// Reload never succeeds and there are no unhandled errors.
1029
1071
check (globalStore.perAccountSync (eg.selfAccount.id)).isNull ();
1030
- }),
1031
- // An unhandled error is actually the bug #1354, so skip for now
1032
- // TODO(#1354) unskip
1033
- skip: true );
1072
+ }));
1034
1073
1035
1074
test ('new store is not loaded, gets HTTP 401 error instead' , () => awaitFakeAsync ((async ) async {
1036
1075
await prepareReload (async ,
0 commit comments