generated from ttipo/project-base
fix(flutter): 모양이 틀린 로그인 응답의 토큰 · 다시 확인 재사용 창 · 기다리던 다시 맞추기를 고친다
앱 기반 3차 확인에서 나온 낮음 넷이다. - 토큰은 실렸는데 모양이 틀린 로그인 응답은 응답을 뺀 실패로 던지고, 읽을 수 있는 토큰으로 조용히 logout 한다(비밀 요청의 실패 예외는 응답 본문도 비운다) - 확인하지 못한(unknown) 다시 확인 결과는 처음 물은 때부터 5초만 다시 쓴다 - 로그아웃 · 다른 계정 · 세션 끝 때 기다리던 다시 맞추기에 stale 로 답한다 — 새 로그인의 오류가 앞 세션의 me 를 기다리지 않게 - postAppLogout 주석을 사실대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -971,4 +971,31 @@ void main() {
|
||||
expect(api.server.received('GET', _mailState), hasLength(1));
|
||||
});
|
||||
});
|
||||
|
||||
group('3차 — 다시 쓰는 결과의 창', () {
|
||||
test(
|
||||
'확인하지 못한(unknown) 결과는 새로 물은 때부터 5초만 다시 쓴다(다시 쓴 결과로 창이 늘지 않는다)',
|
||||
() async {
|
||||
await api.signIn();
|
||||
api.recheckAnswer = RestrictionCheck.unknown;
|
||||
api.server.on(
|
||||
'GET',
|
||||
_mailState,
|
||||
(_) => FakeResponse.fail(403, 'AUTH_010'),
|
||||
);
|
||||
|
||||
await errorOf(api.dio.get<Object?>(_mailState));
|
||||
expect(api.recheckCount, 1);
|
||||
|
||||
api.clock.advance(const Duration(seconds: 3));
|
||||
await errorOf(api.dio.get<Object?>(_mailState));
|
||||
expect(api.recheckCount, 1);
|
||||
|
||||
// 처음 물은 때부터 6초 — 3초에 다시 쓴 것으로 창이 늘었다면 여기서도 묻지 않았을 것이다
|
||||
api.clock.advance(const Duration(seconds: 3));
|
||||
await errorOf(api.dio.get<Object?>(_mailState));
|
||||
expect(api.recheckCount, 2);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -660,4 +660,90 @@ void main() {
|
||||
expect(h.store.hasSession, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('3차 — 남은 비밀 · 기다림', () {
|
||||
test(
|
||||
'signedIn 에 토큰은 실렸는데 모양이 틀리면 응답을 뺀 실패로 던지고 그 서버 세션을 조용히 끝낸다',
|
||||
() async {
|
||||
await start();
|
||||
await settled();
|
||||
h.server.on(
|
||||
'POST',
|
||||
ApiPaths.appLogin,
|
||||
(_) => FakeResponse.ok(<String, Object?>{
|
||||
'status': 'signedIn',
|
||||
'email': 'ara.kim@arasystem.it.kr',
|
||||
'tokens': tokensJson(1),
|
||||
}),
|
||||
);
|
||||
h.server.on('POST', ApiPaths.appLogout, (_) => FakeResponse.ok());
|
||||
|
||||
final Object error = await errorOf(
|
||||
notifier().signIn(email: 'ara.kim@arasystem.it.kr', password: 'pw'),
|
||||
);
|
||||
|
||||
final DioException failure = error as DioException;
|
||||
expect(apiErrorOf(failure).code, 'SYS_001');
|
||||
expect(failure.response, isNull);
|
||||
expect(failure.requestOptions.data, isNull);
|
||||
expect(h.store.hasSession, isFalse);
|
||||
await pumpEventsUntil(() => logouts().isNotEmpty, reason: '조용한 로그아웃');
|
||||
expect(logouts().single.data, <String, Object?>{
|
||||
'refreshToken': 'refresh-1',
|
||||
});
|
||||
expect(bearerTokenOf(logouts().single), 'access-1');
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'다시 맞추기를 기다리는 동안 로그아웃하면 stale 로 답해 막힌 요청을 놓아주고, 새 로그인 오류가 그 뒤에서 기다리지 않는다',
|
||||
() async {
|
||||
await start(refreshToken: 'refresh-1');
|
||||
refreshGives(2);
|
||||
final Completer<void> slowMe = Completer<void>();
|
||||
int meCalls = 0;
|
||||
h.server.on('GET', ApiPaths.me, (_) async {
|
||||
meCalls++;
|
||||
if (meCalls > 1) await slowMe.future;
|
||||
return FakeResponse.ok(sessionJson());
|
||||
});
|
||||
h.server.on('POST', ApiPaths.appLogout, (_) => FakeResponse.ok());
|
||||
h.server.on(
|
||||
'GET',
|
||||
'/mailboxes',
|
||||
(_) => FakeResponse.fail(403, 'AUTH_010'),
|
||||
);
|
||||
h.server.on(
|
||||
'POST',
|
||||
ApiPaths.appLogin,
|
||||
(_) => FakeResponse.fail(401, 'AUTH_004'),
|
||||
);
|
||||
expect(await settled(), isA<SignedIn>());
|
||||
|
||||
final Future<Object> blocked = errorOf(
|
||||
container.read(dioProvider).get<Object?>('/mailboxes'),
|
||||
);
|
||||
await pumpEventsUntil(
|
||||
() => meCalls == 2,
|
||||
reason: '다시 맞추기의 me 가 서버에 닿기',
|
||||
);
|
||||
|
||||
await notifier().switchAccount();
|
||||
|
||||
// 앞 세션의 me 는 아직 끝나지 않았지만 막힌 요청은 조용히 끝난다
|
||||
expect(apiErrorOf(await blocked).code, 'AUTH_010');
|
||||
expect(h.notifier.shownCodes, isEmpty);
|
||||
// 다른 계정의 새 로그인 오류도 기다리지 않고 온다
|
||||
final Object loginError = await errorOf(
|
||||
notifier().signIn(email: 'other@arasystem.it.kr', password: 'wrong'),
|
||||
);
|
||||
expect(apiErrorOf(loginError).code, 'AUTH_004');
|
||||
expect(slowMe.isCompleted, isFalse);
|
||||
|
||||
slowMe.complete();
|
||||
await pumpEventsUntil(() => true);
|
||||
expect(current(), const SignedOut(reason: SignOutReason.switchAccount));
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user