From e3bec37253814e7ed5c67d26fd5b53339c4fcabc Mon Sep 17 00:00:00 2001 From: Daewoong Date: Sat, 14 Dec 2019 05:07:37 +0900 Subject: [PATCH] feat: add exception handling code and tests to api gateway views --- .../tests/test_carpool_request_controller.py | 63 ++++++++++++- .../carpool_request_endpoint/views.py | 54 +++++------- .../tests/test_group_controller.py | 68 ++++++++++++-- backend/api_gateway/group_endpoint/views.py | 33 +++---- .../tests/test_user_controller.py | 88 ++++++++++++++++++- backend/api_gateway/user_endpoint/views.py | 16 +--- .../carpool_request_application_service.py | 14 +-- ...est_carpool_request_application_service.py | 20 ++--- .../carpool_request/domain/carpool_request.py | 20 ++++- frontend/src/App.js | 8 +- .../components/DriverDetail/DriverDetail.js | 5 +- .../DriverDetail/DriverDetail.test.js | 6 +- .../src/components/DriverFinal/DriverFinal.js | 16 ++-- .../DriverFinal/DriverFinal.test.js | 6 +- .../RequestCallSection.test.js | 4 +- .../src/components/RiderDetail/RiderDetail.js | 4 +- .../RiderDetail/RiderDetail.test.js | 4 +- .../src/components/RiderFinal/RiderFinal.js | 36 ++++---- .../components/RiderFinal/RiderFinal.test.js | 7 +- .../DriverDetailContainer.js | 17 ++-- .../DriverDetailContainer.test.js | 4 +- .../DriverFinalContainer.js | 13 ++- .../containers/DriverFinalContainer/index.js | 2 +- .../RiderDetailContainer.js | 17 ++-- .../RiderDetailContainer.test.js | 6 +- .../containers/RiderDetailContainer/index.js | 2 +- .../RiderFinalContainer.js | 20 ++--- .../RiderFinalContainer.test.js | 2 +- .../containers/RiderFinalContainer/index.js | 2 +- frontend/src/lib/api/user/user.js | 4 +- frontend/src/lib/api/user/user.test.js | 2 +- frontend/src/modules/user/user.js | 24 +++-- frontend/src/modules/user/user.test.js | 16 ++-- .../DriverDetailPage/DriverDetailPage.test.js | 8 +- .../DriverFinalPage/DriverFinalPage.test.js | 5 +- .../RiderDetailPage/RiderDetailPage.test.js | 12 ++- .../pages/RiderFinalPage/RiderFinalPage.js | 5 +- .../RiderFinalPage/RiderFinalPage.test.js | 7 +- frontend/src/types/__mock__/group.js | 9 +- 39 files changed, 412 insertions(+), 237 deletions(-) diff --git a/backend/api_gateway/carpool_request_endpoint/tests/test_carpool_request_controller.py b/backend/api_gateway/carpool_request_endpoint/tests/test_carpool_request_controller.py index 9636028..93f9531 100644 --- a/backend/api_gateway/carpool_request_endpoint/tests/test_carpool_request_controller.py +++ b/backend/api_gateway/carpool_request_endpoint/tests/test_carpool_request_controller.py @@ -1,4 +1,14 @@ from django.test import TestCase, Client +from unittest.mock import patch +from backend.common.rpc.infra.adapter.redis.redis_rpc_client \ + import RedisRpcClient +from backend.common.rpc.rpc_response import RpcResponse +from backend.common.command.carpool_request_create_command \ + import CARPOOL_REQUEST_CREATE_COMMAND +from backend.common.command.carpool_request_delete_command \ + import CARPOOL_REQUEST_DELETE_COMMAND +from backend.carpool_request_service.carpool_request.domain.carpool_request \ + import CarpoolRequest class CarpoolRequestControllerTestCase(TestCase): @@ -6,7 +16,58 @@ class CarpoolRequestControllerTestCase(TestCase): def setUp(self): self.client = Client() - def test_create_when_method_is_not_post_response_with_405(self): + + def test_create_carpool_request_wrong_api(self): response = self.client.get('/api/v1/carpool_request/', content_type='application/json') self.assertEqual(response.status_code, 405) + + + @patch.object(RedisRpcClient, 'call') + def test_create_carpool_request_success(self, call_fn): + request = { + 'from_location': 'here', + 'to_location': 'there', + 'minimum_passenger': 4, + 'rider_id': 1 + } + call_fn.return_value = RpcResponse( + result={ + 'from_location': 'here', + 'to_location': 'there', + 'minimum_passenger': 4, + 'rider_id': 1 + }, + id=1, + ) + response = self.client.post( + '/api/v1/carpool_request/', + request, + content_type='application/json' + ) + + args, kwargs = call_fn.call_args + self.assertEqual(args[0], CARPOOL_REQUEST_CREATE_COMMAND) + self.assertEqual(response.status_code, 204) + + @patch.object(RedisRpcClient, 'call') + def test_delete_carpool_request_success(self, call_fn): + mock_carpool_request = CarpoolRequest.objects.create(id=1) + request = { + 'request_id': 1 + } + call_fn.return_value = RpcResponse( + result={ + 'request_id': 1 + }, + id=1, + ) + response = self.client.delete( + '/api/v1/carpool_request/1', + request, + content_type='application/json' + ) + + args, kwargs = call_fn.call_args + self.assertEqual(args[0], CARPOOL_REQUEST_DELETE_COMMAND) + self.assertEqual(response.status_code, 204) diff --git a/backend/api_gateway/carpool_request_endpoint/views.py b/backend/api_gateway/carpool_request_endpoint/views.py index e72bb3e..6d78915 100644 --- a/backend/api_gateway/carpool_request_endpoint/views.py +++ b/backend/api_gateway/carpool_request_endpoint/views.py @@ -1,6 +1,6 @@ import json from django.http \ - import HttpResponseNotAllowed, JsonResponse + import HttpResponseNotAllowed, HttpResponseBadRequest, JsonResponse from backend.common.command.carpool_request_create_command \ import CarpoolRequestCreateCommand, CARPOOL_REQUEST_CREATE_COMMAND from backend.common.command.carpool_request_delete_command \ @@ -9,15 +9,6 @@ import RedisRpcClient -""" -TODO: add exception controller -""" - - -def with_json_response(status, data): - return JsonResponse(data=json.dumps(data), status=status, safe=False) - - def carpool_request(request): if request.method == 'POST': return __create_carpool_request(request) @@ -28,30 +19,27 @@ def carpool_request(request): def __create_carpool_request(request): - body = json.loads(request.body.decode()) - # TODO: check KeyError - command = CarpoolRequestCreateCommand( - from_location=body['from_location'], - to_location=body['to_location'], - minimum_passenger=body['minimum_passenger'], - rider_id=body['rider_id'], - ) - - result = RedisRpcClient().call(CARPOOL_REQUEST_CREATE_COMMAND, command) - data = {'jsonrpc': result.jsonrpc, - 'id': result.id, 'result': result.result} + try: + body = json.loads(request.body.decode()) + command = CarpoolRequestCreateCommand( + from_location=body['from_location'], + to_location=body['to_location'], + minimum_passenger=body['minimum_passenger'], + rider_id=body['rider_id'], + ) + except(KeyError, JSONDecodeError) as e: + return HttpResponseBadRequest(e) - # TODO: handling exception - return with_json_response(status=204, data=data) + rpc_response = RedisRpcClient().call(CARPOOL_REQUEST_CREATE_COMMAND, command) + return JsonResponse(data=rpc_response.result, status=204, safe=False) def __delete_carpool_request(request): - body = json.loads(request.body.decode()) - # TODO: check KeyError - command = CarpoolRequestDeleteCommand(request_id=body['request_id']) - result = RedisRpcClient().call(CARPOOL_REQUEST_DELETE_COMMAND, command) - data = {'jsonrpc': result.jsonrpc, - 'id': result.id, 'result': result.result} - - # TODO: handling exception - return with_json_response(status=204, data=data) + try: + body = json.loads(request.body.decode()) + command = CarpoolRequestDeleteCommand(request_id=body['request_id']) + except(KeyError, JSONDecodeError) as e: + return HttpResponseBadRequest(e) + + rpc_response = RedisRpcClient().call(CARPOOL_REQUEST_DELETE_COMMAND, command) + return JsonResponse(data=rpc_response.result, status=204, safe=False) diff --git a/backend/api_gateway/group_endpoint/tests/test_group_controller.py b/backend/api_gateway/group_endpoint/tests/test_group_controller.py index 4011750..3c39fda 100644 --- a/backend/api_gateway/group_endpoint/tests/test_group_controller.py +++ b/backend/api_gateway/group_endpoint/tests/test_group_controller.py @@ -1,6 +1,11 @@ from django.test import TestCase, Client - -# Needs editing +from unittest.mock import patch +from backend.common.rpc.infra.adapter.redis.redis_rpc_client \ + import RedisRpcClient +from backend.common.rpc.rpc_response import RpcResponse +from backend.common.command.group_create_command import GROUP_CREATE_COMMAND +from backend.common.command.group_update_command import GROUP_UPDATE_COMMAND +from backend.group_service.group.domain.group import Group class GroupControllerTestCase(TestCase): @@ -8,8 +13,61 @@ class GroupControllerTestCase(TestCase): def setUp(self): self.client = Client() - def test_group(self): - response = self.client.get( - '/api/v1/group/', content_type='application/json') + def test_create_group_wrong_api(self): + response = self.client.get( + '/api/v1/group/', + content_type='application/json' + ) self.assertEqual(response.status_code, 405) + + + @patch.object(RedisRpcClient, 'call') + def test_create_group_success(self, call_fn): + request = { + 'rider_id_list': [1,2,3,4], + 'from_location': 'here', + 'to_location': 'there' + } + call_fn.return_value = RpcResponse( + result={ + 'rider_id_list': [1,2,3,4], + 'from_location': 'here', + 'to_location': 'there' + }, + id=1, + ) + response = self.client.post( + '/api/v1/group/', + request, + content_type='application/json' + ) + + args, kwargs = call_fn.call_args + self.assertEqual(args[0], GROUP_CREATE_COMMAND) + self.assertEqual(response.status_code, 204) + + + @patch.object(RedisRpcClient, 'call') + def test_update_group_sucess(self, call_fn): + mock_group = Group.objects.create(id=1) + request = { + 'driverId': 1, + 'groupId': 2, + } + call_fn.return_value = RpcResponse( + result={ + 'driver_id': 1, + 'group_id': 2, + }, + id=1, + ) + response = self.client.put( + '/api/v1/group/1', + request, + content_type='application/json' + ) + + args, kwargs = call_fn.call_args + self.assertEqual(args[0], GROUP_UPDATE_COMMAND) + self.assertEqual(response.status_code, 204) diff --git a/backend/api_gateway/group_endpoint/views.py b/backend/api_gateway/group_endpoint/views.py index c2fc4c7..1d68b95 100644 --- a/backend/api_gateway/group_endpoint/views.py +++ b/backend/api_gateway/group_endpoint/views.py @@ -1,4 +1,5 @@ import json +from json import JSONDecodeError from django.http \ import HttpResponseNotAllowed, JsonResponse @@ -11,14 +12,6 @@ from backend.common.rpc.infra.adapter.redis.redis_rpc_client \ import RedisRpcClient -""" -TODO: add exception controller -""" - - -def with_json_response(status, data): - return JsonResponse(data=json.dumps(data), status=status, safe=False) - def group(request): if request.method == 'POST': @@ -28,18 +21,18 @@ def group(request): def __create_group(request): - body = json.loads(request.body.decode()) - # TODO: check KeyError - command = GroupCreateCommand( - from_location=body['from_location'], - to_location=body['to_location']) - - result = RedisRpcClient().call(GROUP_CREATE_COMMAND, command) - data = {'jsonrpc': result.jsonrpc, - 'id': result.id, 'result': result.result} - - # TODO: handling exception - return with_json_response(status=204, data=data) + try: + body = json.loads(request.body.decode()) + command = GroupCreateCommand( + rider_id_list=body['rider_id_list'], + from_location=body['from_location'], + to_location=body['to_location'] + ) + except (KeyError, JSONDecodeError) as e: + return HttpResponseBadRequest(e) + + rpc_response = RedisRpcClient().call(GROUP_CREATE_COMMAND, command) + return JsonResponse(data=rpc_response.result, status=204, safe=False) def update_driver(request, group_id): diff --git a/backend/api_gateway/user_endpoint/tests/test_user_controller.py b/backend/api_gateway/user_endpoint/tests/test_user_controller.py index 1982328..c16726a 100644 --- a/backend/api_gateway/user_endpoint/tests/test_user_controller.py +++ b/backend/api_gateway/user_endpoint/tests/test_user_controller.py @@ -1,4 +1,13 @@ from django.test import TestCase, Client +from unittest.mock import patch +from backend.common.rpc.infra.adapter.redis.redis_rpc_client \ + import RedisRpcClient +from backend.common.rpc.rpc_response import RpcResponse +from backend.common.command.user_create_command \ + import USER_CREATE_COMMAND +from backend.common.event.user_login_event \ + import USER_LOGIN_EVENT +from django.contrib.auth import get_user_model class UserControllerTestCase(TestCase): @@ -6,24 +15,101 @@ class UserControllerTestCase(TestCase): def setUp(self): self.client = Client() - def test_register_user_when_method_is_not_post_response_with_405(self): + def test_register_user_wrong_api(self): response = self.client.get('/api/v1/user/register', content_type='application/json') self.assertEqual(response.status_code, 405) + + @patch.object(RedisRpcClient, 'call') + def test_register_user_rider_success(self, call_fn): + request = { + 'email': 'swpp@swpp.com', + 'password': 'pleaseNotC', + 'userType': 'rider', + 'carType': '', + 'plateNo': '' + } + call_fn.return_value = RpcResponse( + result={ + 'email': 'swpp@swpp.com', + 'password': 'pleaseNotC', + 'user_type': 'rider', + 'car_type': '', + 'plate_no': '' + }, + id=1, + ) + response = self.client.post( + '/api/v1/user/register', + request, + content_type='application/json' + ) + + args, kwargs = call_fn.call_args + self.assertEqual(args[0], USER_CREATE_COMMAND) + self.assertEqual(response.status_code, 200) + + + @patch.object(RedisRpcClient, 'call') + def test_register_user_driver_success(self, call_fn): + request = { + 'email': 'swpp@swpp.com', + 'password': 'pleaseNotC', + 'userType': 'driver', + 'carType': 'BMW', + 'plateNo': '01a 1234' + } + call_fn.return_value = RpcResponse( + result={ + 'email': 'swpp@swpp.com', + 'password': 'pleaseNotC', + 'user_type': 'driver', + 'car_type': 'BMW', + 'plate_no': '01a 1234' + }, + id=1, + ) + response = self.client.post( + '/api/v1/user/register', + request, + content_type='application/json' + ) + + args, kwargs = call_fn.call_args + self.assertEqual(args[0], USER_CREATE_COMMAND) + self.assertEqual(response.status_code, 200) + + + @patch.object(RedisRpcClient, 'call') + def test_check_user_success(self, call_fn): + mock_user = get_user_model().objects.create(id=1) + call_fn.return_value = RpcResponse( + result={}, + id=1, + ) + response = self.client.get( + '/api/v1/user/1', + content_type='application/json' + ) + self.assertEqual(response.status_code, 200) + + def test_login_user_when_method_is_not_post_response_with_405(self): response = self.client.get('/api/v1/user/login', content_type='application/json') self.assertEqual(response.status_code, 405) + def test_logout_user_when_method_is_not_post_response_with_405(self): response = self.client.get('/api/v1/user/logout', content_type='application/json') self.assertEqual(response.status_code, 401) + def test_check_when_not_get(self): response = self.client.post('/api/v1/user/1', content_type='application/json') diff --git a/backend/api_gateway/user_endpoint/views.py b/backend/api_gateway/user_endpoint/views.py index e3602c6..8f3995e 100644 --- a/backend/api_gateway/user_endpoint/views.py +++ b/backend/api_gateway/user_endpoint/views.py @@ -18,15 +18,6 @@ import RedisRpcClient -""" -TODO: add exception controller -""" - - -def with_json_response(status, data): - return JsonResponse(data=json.dumps(data), status=status, safe=False) - - def register_user(request): if request.method == 'POST': return __register_user(request) @@ -37,7 +28,6 @@ def register_user(request): def __register_user(request): try: body = json.loads(request.body.decode()) - # TODO: check KeyError command = UserCreateCommand( email=body['email'], password=body['password'], @@ -80,8 +70,9 @@ def __point_user(request, id): def __check_user(request, id): try: user = get_user_model().objects.get(id=id) - except Exception: - return HttpResponseBadRequest + except KeyError as e: + return HttpResponseBadRequest(e) + login(request, user) event = UserLoginEvent(user_id=user.id) rpc_response = RedisRpcClient().call(USER_LOGIN_EVENT, event) @@ -102,6 +93,7 @@ def __login_user(request): password = body['password'] except(KeyError, JSONDecodeError) as e: return HttpResponseBadRequest(e) + user = authenticate(email=email, password=password) if user is not None: login(request, user) diff --git a/backend/carpool_request_service/carpool_request/app/carpool_request_application_service.py b/backend/carpool_request_service/carpool_request/app/carpool_request_application_service.py index 8a80ef8..1cbf0e6 100644 --- a/backend/carpool_request_service/carpool_request/app/carpool_request_application_service.py +++ b/backend/carpool_request_service/carpool_request/app/carpool_request_application_service.py @@ -1,6 +1,6 @@ from backend.user_service.user.domain.rider import Rider from backend.carpool_request_service.carpool_request.domain.carpool_request \ - import CarpoolRequest + import CarpoolRequest, CarpoolRequestSerializer from backend.common.messaging.infra.redis.redis_message_publisher \ import RedisMessagePublisher from backend.common.command.group_create_command import GroupCreateCommand @@ -8,8 +8,11 @@ class CarpoolRequestApplicationService(): def create(self, from_location, to_location, minimum_passenger, rider_id): - # TODO: handle NotFound exception - rider = Rider.objects.get(pk=rider_id) + try: + rider = Rider.objects.get(pk=rider_id) + except KeyError as e: + print('No such rider exists') + return e result = CarpoolRequest.objects.create( from_location=from_location, @@ -35,10 +38,11 @@ def create(self, from_location, to_location, minimum_passenger, rider_id): to_location=to_location ) RedisMessagePublisher().publish_message(command) - return result + return CarpoolRequestSerializer(result).data def delete(self, request_id): return CarpoolRequest.objects.filter(pk=request_id).delete() def get(self, request_id): - return CarpoolRequest.objects.get(pk=request_id) + result = CarpoolRequest.objects.get(pk=request_id) + return CarpoolRequestSerializer(result).data diff --git a/backend/carpool_request_service/carpool_request/app/tests/test_carpool_request_application_service.py b/backend/carpool_request_service/carpool_request/app/tests/test_carpool_request_application_service.py index 9b0012a..4256e56 100644 --- a/backend/carpool_request_service/carpool_request/app/tests/test_carpool_request_application_service.py +++ b/backend/carpool_request_service/carpool_request/app/tests/test_carpool_request_application_service.py @@ -26,10 +26,10 @@ def test_create(self): result = self.carpool_request_application_service.create( from_location, to_location, minimum_passenger, self.rider.id ) - self.assertEqual(result.from_location, from_location) - self.assertEqual(result.to_location, to_location) - self.assertEqual(result.minimum_passenger, minimum_passenger) - self.assertEqual(result.rider_id, self.rider.id) + self.assertEqual(result['from_location'], from_location) + self.assertEqual(result['to_location'], to_location) + self.assertEqual(result['minimum_passenger'], minimum_passenger) + self.assertEqual(result['rider']['id'], self.rider.id) def test_del(self): from_location = "TEST_FROM" @@ -40,7 +40,7 @@ def test_del(self): from_location, to_location, minimum_passenger, self.rider.id ) result = self.carpool_request_application_service.delete( - request_id=carpool_request.id + request_id=carpool_request['id'] ) self.assertEqual(result[0], 1) @@ -53,10 +53,10 @@ def test_get(self): from_location, to_location, minimum_passenger, self.rider.id ) result = self.carpool_request_application_service.get( - request_id=carpool_request.id + request_id=carpool_request['id'] ) - self.assertEqual(result.from_location, from_location) - self.assertEqual(result.to_location, to_location) - self.assertEqual(result.minimum_passenger, minimum_passenger) - self.assertEqual(result.rider_id, self.rider.id) + self.assertEqual(result['from_location'], from_location) + self.assertEqual(result['to_location'], to_location) + self.assertEqual(result['minimum_passenger'], minimum_passenger) + self.assertEqual(result['rider']['id'], self.rider.id) diff --git a/backend/carpool_request_service/carpool_request/domain/carpool_request.py b/backend/carpool_request_service/carpool_request/domain/carpool_request.py index 315a025..e46eae3 100644 --- a/backend/carpool_request_service/carpool_request/domain/carpool_request.py +++ b/backend/carpool_request_service/carpool_request/domain/carpool_request.py @@ -1,7 +1,9 @@ from django.db import models - +from rest_framework import serializers +from backend.user_service.user.domain.rider import RiderSerializer class CarpoolRequest(models.Model): + class Meta: app_label = 'carpool_request' @@ -20,3 +22,19 @@ class Meta: def __str__(self): return 'rider_id={},from={},to={}'\ .format(self.rider_id, self.from_location, self.to_location) + + +class CarpoolRequestSerializer(serializers.ModelSerializer): + + rider = RiderSerializer(many=False, read_only=True) + + class Meta: + model = CarpoolRequest + fields = ( + 'id', 'status', 'from_location', + 'to_location', 'minimum_passenger', 'rider' + ) + read_only_fields = ( + 'id', 'status', 'from_location', + 'to_location', 'minimum_passenger' + ) diff --git a/frontend/src/App.js b/frontend/src/App.js index 995f9dd..f0a5ecb 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -9,10 +9,10 @@ import DetailPage from './pages/DetailPage/DetailPage'; import FinalPage from './pages/FinalPage/FinalPage'; import RegisterPage from './pages/RegisterPage/RegisterPage'; import LoginPage from './pages/LoginPage/LoginPage'; -import DriverDetailPage from './pages/DriverDetailPage/DriverDetailPage' -import RiderDetailPage from './pages/RiderDetailPage/RiderDetailPage' -import DriverFinalPage from './pages/DriverFinalPage/DriverFinalPage' -import RiderFinalPage from './pages/RiderFinalPage/RiderFinalPage' +import DriverDetailPage from './pages/DriverDetailPage/DriverDetailPage'; +import RiderDetailPage from './pages/RiderDetailPage/RiderDetailPage'; +import DriverFinalPage from './pages/DriverFinalPage/DriverFinalPage'; +import RiderFinalPage from './pages/RiderFinalPage/RiderFinalPage'; function App() { return ( diff --git a/frontend/src/components/DriverDetail/DriverDetail.js b/frontend/src/components/DriverDetail/DriverDetail.js index c7c6d30..85df3e9 100644 --- a/frontend/src/components/DriverDetail/DriverDetail.js +++ b/frontend/src/components/DriverDetail/DriverDetail.js @@ -15,7 +15,7 @@ function DriverDetail({ user, group, onClickConfirm }) { const [totalCost, setTotalCost] = useState(0); const userId = user.id; const groupId = group.groupId; - + return ( onClickConfirm({userId, groupId, totalCost})} + onClick={() => onClickConfirm({ userId, groupId, totalCost })} /> - ); } diff --git a/frontend/src/components/DriverDetail/DriverDetail.test.js b/frontend/src/components/DriverDetail/DriverDetail.test.js index 0ae1308..acb7eba 100644 --- a/frontend/src/components/DriverDetail/DriverDetail.test.js +++ b/frontend/src/components/DriverDetail/DriverDetail.test.js @@ -3,11 +3,11 @@ import { render } from '@testing-library/react'; import DriverDetail from './DriverDetail'; describe('', () => { - it('SHOULD match with snapshot', async () => { + it('SHOULD match with snapshot', async () => { const { container } = render( {}} />, ); diff --git a/frontend/src/components/DriverFinal/DriverFinal.js b/frontend/src/components/DriverFinal/DriverFinal.js index 8aba5f8..797bdee 100644 --- a/frontend/src/components/DriverFinal/DriverFinal.js +++ b/frontend/src/components/DriverFinal/DriverFinal.js @@ -15,14 +15,14 @@ DriverFinal.propTypes = { function DriverFinal({ earning, point, onClickGoToMain }) { return ( - Total Earning: {earning} - Current Point: {point} -