From 6c04cb342dd933a0c55ceddf65df6c5ee478080d Mon Sep 17 00:00:00 2001 From: AyadLaouissi Date: Thu, 18 Apr 2024 12:38:33 +0200 Subject: [PATCH 1/5] feat: adds reset api call --- api/routes/game/reset_streak.dart | 29 +++++++ api/test/routes/game/reset_streak_test.dart | 81 +++++++++++++++++++ .../src/resources/leaderboard_resource.dart | 16 ++++ .../resources/leaderboard_resource_test.dart | 37 +++++++++ 4 files changed, 163 insertions(+) create mode 100644 api/routes/game/reset_streak.dart create mode 100644 api/test/routes/game/reset_streak_test.dart diff --git a/api/routes/game/reset_streak.dart b/api/routes/game/reset_streak.dart new file mode 100644 index 000000000..4f7a464d2 --- /dev/null +++ b/api/routes/game/reset_streak.dart @@ -0,0 +1,29 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:dart_frog/dart_frog.dart'; +import 'package:jwt_middleware/jwt_middleware.dart'; +import 'package:leaderboard_repository/leaderboard_repository.dart'; +import 'package:logging/logging.dart'; + +FutureOr onRequest(RequestContext context) async { + if (context.request.method == HttpMethod.post) { + return _onPost(context); + } + return Response(statusCode: HttpStatus.methodNotAllowed); +} + +Future _onPost(RequestContext context) async { + final leaderboardRepository = context.read(); + + final user = context.read(); + + try { + await leaderboardRepository.resetStreak(user.id); + } catch (e, s) { + context.read().severe('Error creating a player score', e, s); + rethrow; + } + + return Response(statusCode: HttpStatus.created); +} diff --git a/api/test/routes/game/reset_streak_test.dart b/api/test/routes/game/reset_streak_test.dart new file mode 100644 index 000000000..cbd4a645e --- /dev/null +++ b/api/test/routes/game/reset_streak_test.dart @@ -0,0 +1,81 @@ +// ignore_for_file: prefer_const_constructors + +import 'dart:io'; + +import 'package:dart_frog/dart_frog.dart'; +import 'package:jwt_middleware/jwt_middleware.dart'; +import 'package:leaderboard_repository/leaderboard_repository.dart'; +import 'package:logging/logging.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +import '../../../routes/game/reset_streak.dart' as route; + +class _MockLeaderboardRepository extends Mock + implements LeaderboardRepository {} + +class _MockRequest extends Mock implements Request {} + +class _MockRequestContext extends Mock implements RequestContext {} + +class _MockLogger extends Mock implements Logger {} + +void main() { + late LeaderboardRepository leaderboardRepository; + late Request request; + late RequestContext context; + late Logger logger; + + setUp(() { + leaderboardRepository = _MockLeaderboardRepository(); + request = _MockRequest(); + logger = _MockLogger(); + + context = _MockRequestContext(); + when(() => context.request).thenReturn(request); + when(() => context.read()) + .thenReturn(leaderboardRepository); + when(() => context.read()).thenReturn(logger); + when(() => context.read()) + .thenReturn(AuthenticatedUser('id')); + }); + + group('POST', () { + test( + 'responds with a HttpStatus.created status when reset is correct', + () async { + when(() => request.method).thenReturn(HttpMethod.post); + when(() => leaderboardRepository.resetStreak('id')) + .thenAnswer((_) async {}); + + final response = await route.onRequest(context); + expect(response.statusCode, equals(HttpStatus.created)); + }, + ); + + test( + 'calls resetStreak with the user id', + () async { + when(() => request.method).thenReturn(HttpMethod.post); + when(() => leaderboardRepository.resetStreak('id')) + .thenAnswer((_) async {}); + + await route.onRequest(context); + + verify(() => leaderboardRepository.resetStreak('id')).called(1); + }, + ); + + test( + 'throws error when resetStreak throws exception', + () async { + when(() => request.method).thenReturn(HttpMethod.post); + when(() => leaderboardRepository.resetStreak('id')) + .thenThrow(Exception()); + + final response = route.onRequest(context); + expect(response, throwsA(isA())); + }, + ); + }); +} diff --git a/packages/api_client/lib/src/resources/leaderboard_resource.dart b/packages/api_client/lib/src/resources/leaderboard_resource.dart index dcf30a151..f137a336b 100644 --- a/packages/api_client/lib/src/resources/leaderboard_resource.dart +++ b/packages/api_client/lib/src/resources/leaderboard_resource.dart @@ -68,4 +68,20 @@ class LeaderboardResource { ); } } + + /// Post /game/reset_streak + Future resetStreak() async { + final response = await _apiClient.post( + '/game/reset_streak', + ); + + if (response.statusCode != HttpStatus.created) { + throw ApiClientError( + 'POST /game/reset_streak returned status ' + '${response.statusCode} with the following response: ' + '"${response.body}"', + StackTrace.current, + ); + } + } } diff --git a/packages/api_client/test/src/resources/leaderboard_resource_test.dart b/packages/api_client/test/src/resources/leaderboard_resource_test.dart index 1717adadd..a01050423 100644 --- a/packages/api_client/test/src/resources/leaderboard_resource_test.dart +++ b/packages/api_client/test/src/resources/leaderboard_resource_test.dart @@ -132,5 +132,42 @@ void main() { ); }); }); + + group('resetStreak', () { + setUp(() { + when(() => apiClient.post(any())).thenAnswer((_) async => response); + }); + + test('makes the correct call', () async { + when(() => response.statusCode).thenReturn(HttpStatus.created); + await resource.resetStreak(); + + verify( + () => apiClient.post( + '/game/reset_streak', + ), + ).called(1); + }); + + test('throws ApiClientError when request fails', () async { + when(() => response.statusCode) + .thenReturn(HttpStatus.internalServerError); + when(() => response.body).thenReturn('Oops'); + + await expectLater( + () => resource.resetStreak(), + throwsA( + isA().having( + (e) => e.cause, + 'cause', + equals( + 'POST /game/reset_streak returned status 500 ' + 'with the following response: "Oops"', + ), + ), + ), + ); + }); + }); }); } From 2fc038ece2086caa5d2e0e9ef17ac3f5ea2df521 Mon Sep 17 00:00:00 2001 From: AyadLaouissi Date: Thu, 18 Apr 2024 15:27:58 +0200 Subject: [PATCH 2/5] updated reset_streak_test.dart --- api/test/routes/game/reset_streak_test.dart | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/api/test/routes/game/reset_streak_test.dart b/api/test/routes/game/reset_streak_test.dart index cbd4a645e..a5863d4bd 100644 --- a/api/test/routes/game/reset_streak_test.dart +++ b/api/test/routes/game/reset_streak_test.dart @@ -40,6 +40,20 @@ void main() { .thenReturn(AuthenticatedUser('id')); }); + for (final method in HttpMethod.values.toList()..remove(HttpMethod.post)) { + test( + 'responds with a ${HttpStatus.methodNotAllowed} status with $method', + () async { + when(() => request.method).thenReturn(method); + when(() => leaderboardRepository.resetStreak('id')) + .thenAnswer((_) async {}); + + final response = await route.onRequest(context); + expect(response.statusCode, equals(HttpStatus.methodNotAllowed)); + }, + ); + } + group('POST', () { test( 'responds with a HttpStatus.created status when reset is correct', From ad92a1925bdd988b048e27cba7ebfe3956f274d5 Mon Sep 17 00:00:00 2001 From: Ayad Laaouissi Jones <42848220+AyadLaouissi@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:08:06 +0200 Subject: [PATCH 3/5] Update api/routes/game/reset_streak.dart Co-authored-by: Jaime <52668514+jsgalarraga@users.noreply.github.com> --- api/routes/game/reset_streak.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/routes/game/reset_streak.dart b/api/routes/game/reset_streak.dart index 4f7a464d2..8ee38f0b5 100644 --- a/api/routes/game/reset_streak.dart +++ b/api/routes/game/reset_streak.dart @@ -21,7 +21,7 @@ Future _onPost(RequestContext context) async { try { await leaderboardRepository.resetStreak(user.id); } catch (e, s) { - context.read().severe('Error creating a player score', e, s); + context.read().severe('Error resetting the streak', e, s); rethrow; } From 14b5b045dafed24fc79e0040e1ace83ec7b4f60c Mon Sep 17 00:00:00 2001 From: AyadLaouissi Date: Thu, 18 Apr 2024 16:12:45 +0200 Subject: [PATCH 4/5] updated PR suggestion --- api/routes/game/reset_streak.dart | 2 +- api/test/routes/game/reset_streak_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/routes/game/reset_streak.dart b/api/routes/game/reset_streak.dart index 8ee38f0b5..3c3bb6aa2 100644 --- a/api/routes/game/reset_streak.dart +++ b/api/routes/game/reset_streak.dart @@ -25,5 +25,5 @@ Future _onPost(RequestContext context) async { rethrow; } - return Response(statusCode: HttpStatus.created); + return Response(); } diff --git a/api/test/routes/game/reset_streak_test.dart b/api/test/routes/game/reset_streak_test.dart index a5863d4bd..5032b4eb7 100644 --- a/api/test/routes/game/reset_streak_test.dart +++ b/api/test/routes/game/reset_streak_test.dart @@ -63,7 +63,7 @@ void main() { .thenAnswer((_) async {}); final response = await route.onRequest(context); - expect(response.statusCode, equals(HttpStatus.created)); + expect(response.statusCode, equals(HttpStatus.ok)); }, ); From 41f153443c5b6b4e543bd65a26270cf1d2ac3052 Mon Sep 17 00:00:00 2001 From: AyadLaouissi Date: Thu, 18 Apr 2024 16:16:42 +0200 Subject: [PATCH 5/5] updated leaderboard_resource.dart --- packages/api_client/lib/src/resources/leaderboard_resource.dart | 2 +- .../test/src/resources/leaderboard_resource_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api_client/lib/src/resources/leaderboard_resource.dart b/packages/api_client/lib/src/resources/leaderboard_resource.dart index f137a336b..d1b7e289c 100644 --- a/packages/api_client/lib/src/resources/leaderboard_resource.dart +++ b/packages/api_client/lib/src/resources/leaderboard_resource.dart @@ -75,7 +75,7 @@ class LeaderboardResource { '/game/reset_streak', ); - if (response.statusCode != HttpStatus.created) { + if (response.statusCode != HttpStatus.ok) { throw ApiClientError( 'POST /game/reset_streak returned status ' '${response.statusCode} with the following response: ' diff --git a/packages/api_client/test/src/resources/leaderboard_resource_test.dart b/packages/api_client/test/src/resources/leaderboard_resource_test.dart index a01050423..800b89af1 100644 --- a/packages/api_client/test/src/resources/leaderboard_resource_test.dart +++ b/packages/api_client/test/src/resources/leaderboard_resource_test.dart @@ -139,7 +139,7 @@ void main() { }); test('makes the correct call', () async { - when(() => response.statusCode).thenReturn(HttpStatus.created); + when(() => response.statusCode).thenReturn(HttpStatus.ok); await resource.resetStreak(); verify(