Skip to content

Commit 2783c57

Browse files
committed
Added exception handling to the model
1 parent ea19423 commit 2783c57

File tree

3 files changed

+97
-37
lines changed

3 files changed

+97
-37
lines changed

service/models.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,13 @@ def create(self):
8585
logger.info("Creating %s", self.name)
8686
# id must be none to generate next primary key
8787
self.id = None # pylint: disable=invalid-name
88-
db.session.add(self)
89-
db.session.commit()
88+
try:
89+
db.session.add(self)
90+
db.session.commit()
91+
except Exception as e:
92+
db.session.rollback()
93+
logger.error("Error creating record: %s", self)
94+
raise DataValidationError(e) from e
9095

9196
def update(self):
9297
"""
@@ -95,13 +100,23 @@ def update(self):
95100
logger.info("Saving %s", self.name)
96101
if not self.id:
97102
raise DataValidationError("Update called with empty ID field")
98-
db.session.commit()
103+
try:
104+
db.session.commit()
105+
except Exception as e:
106+
db.session.rollback()
107+
logger.error("Error updating record: %s", self)
108+
raise DataValidationError(e) from e
99109

100110
def delete(self):
101111
"""Removes a Pet from the data store"""
102112
logger.info("Deleting %s", self.name)
103-
db.session.delete(self)
104-
db.session.commit()
113+
try:
114+
db.session.delete(self)
115+
db.session.commit()
116+
except Exception as e:
117+
db.session.rollback()
118+
logger.error("Error deleting record: %s", self)
119+
raise DataValidationError(e) from e
105120

106121
def serialize(self) -> dict:
107122
"""Serializes a Pet into a dictionary"""
@@ -111,7 +126,7 @@ def serialize(self) -> dict:
111126
"category": self.category,
112127
"available": self.available,
113128
"gender": self.gender.name, # convert enum to string
114-
"birthday": self.birthday.isoformat()
129+
"birthday": self.birthday.isoformat(),
115130
}
116131

117132
def deserialize(self, data: dict):
@@ -135,7 +150,9 @@ def deserialize(self, data: dict):
135150
except AttributeError as error:
136151
raise DataValidationError("Invalid attribute: " + error.args[0]) from error
137152
except KeyError as error:
138-
raise DataValidationError("Invalid pet: missing " + error.args[0]) from error
153+
raise DataValidationError(
154+
"Invalid pet: missing " + error.args[0]
155+
) from error
139156
except TypeError as error:
140157
raise DataValidationError(
141158
"Invalid pet: body of request contained bad or no data " + str(error)

tests/test_models.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import os
1919
import logging
2020
from unittest import TestCase
21+
from unittest.mock import patch
2122
from datetime import date
2223
from wsgi import app
2324
from service.models import Pet, Gender, DataValidationError, db
@@ -218,6 +219,34 @@ def test_deserialize_bad_gender(self):
218219
self.assertRaises(DataValidationError, pet.deserialize, data)
219220

220221

222+
######################################################################
223+
# T E S T E X C E P T I O N H A N D L E R S
224+
######################################################################
225+
class TestExceptionHandlers(TestCaseBase):
226+
"""Pet Model Exception Handlers"""
227+
228+
@patch("service.models.db.session.commit")
229+
def test_create_exception(self, exception_mock):
230+
"""It should catch a create exception"""
231+
exception_mock.side_effect = Exception()
232+
pet = PetFactory()
233+
self.assertRaises(DataValidationError, pet.create)
234+
235+
@patch("service.models.db.session.commit")
236+
def test_update_exception(self, exception_mock):
237+
"""It should catch a update exception"""
238+
exception_mock.side_effect = Exception()
239+
pet = PetFactory()
240+
self.assertRaises(DataValidationError, pet.update)
241+
242+
@patch("service.models.db.session.commit")
243+
def test_delete_exception(self, exception_mock):
244+
"""It should catch a delete exception"""
245+
exception_mock.side_effect = Exception()
246+
pet = PetFactory()
247+
self.assertRaises(DataValidationError, pet.delete)
248+
249+
221250
######################################################################
222251
# Q U E R Y T E S T C A S E S
223252
######################################################################

tests/test_routes.py

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# from unittest.mock import MagicMock, patch
2424
from urllib.parse import quote_plus
2525
from wsgi import app
26+
2627
# from service import create_app
2728
from service.common import status
2829
from service.models import Pet, db
@@ -79,7 +80,9 @@ def _create_pets(self, count):
7980
test_pet = PetFactory()
8081
response = self.client.post(BASE_URL, json=test_pet.serialize())
8182
self.assertEqual(
82-
response.status_code, status.HTTP_201_CREATED, "Could not create test pet"
83+
response.status_code,
84+
status.HTTP_201_CREATED,
85+
"Could not create test pet",
8386
)
8487
new_pet = response.get_json()
8588
test_pet.id = new_pet["id"]
@@ -189,8 +192,7 @@ def test_query_pet_list_by_category(self):
189192
test_category = pets[0].category
190193
category_pets = [pet for pet in pets if pet.category == test_category]
191194
response = self.client.get(
192-
BASE_URL,
193-
query_string=f"category={quote_plus(test_category)}"
195+
BASE_URL, query_string=f"category={quote_plus(test_category)}"
194196
)
195197
self.assertEqual(response.status_code, status.HTTP_200_OK)
196198
data = response.get_json()
@@ -200,9 +202,46 @@ def test_query_pet_list_by_category(self):
200202
self.assertEqual(pet["category"], test_category)
201203

202204
######################################################################
203-
# T E S T S A D P A T H S
205+
# T E S T A C T I O N S
204206
######################################################################
205207

208+
def test_purchase_a_pet(self):
209+
"""It should Purchase a Pet"""
210+
pets = self._create_pets(10)
211+
available_pets = [pet for pet in pets if pet.available is True]
212+
pet = available_pets[0]
213+
response = self.client.put(f"{BASE_URL}/{pet.id}/purchase")
214+
self.assertEqual(response.status_code, status.HTTP_200_OK)
215+
response = self.client.get(f"{BASE_URL}/{pet.id}")
216+
self.assertEqual(response.status_code, status.HTTP_200_OK)
217+
data = response.get_json()
218+
logging.debug("Response data: %s", data)
219+
self.assertEqual(data["available"], False)
220+
221+
def test_purchase_not_available(self):
222+
"""It should not Purchase a Pet that is not available"""
223+
pets = self._create_pets(10)
224+
unavailable_pets = [pet for pet in pets if pet.available is False]
225+
pet = unavailable_pets[0]
226+
response = self.client.put(f"{BASE_URL}/{pet.id}/purchase")
227+
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
228+
229+
230+
######################################################################
231+
# T E S T S A D P A T H S
232+
######################################################################
233+
class TestSadPaths(TestCase):
234+
"""Test REST Exception Handling"""
235+
236+
def setUp(self):
237+
"""Runs before each test"""
238+
self.client = app.test_client()
239+
240+
def test_method_not_allowed(self):
241+
"""It should not allow update without a pet id"""
242+
response = self.client.put(BASE_URL)
243+
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
244+
206245
def test_create_pet_no_data(self):
207246
"""It should not Create a Pet with missing data"""
208247
response = self.client.post(BASE_URL, json={})
@@ -233,35 +272,10 @@ def test_create_pet_bad_gender(self):
233272
logging.debug(pet)
234273
# change gender to a bad string
235274
test_pet = pet.serialize()
236-
test_pet["gender"] = "male" # wrong case
275+
test_pet["gender"] = "male" # wrong case
237276
response = self.client.post(BASE_URL, json=test_pet)
238277
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
239278

240-
######################################################################
241-
# T E S T A C T I O N S
242-
######################################################################
243-
244-
def test_purchase_a_pet(self):
245-
"""It should Purchase a Pet"""
246-
pets = self._create_pets(10)
247-
available_pets = [pet for pet in pets if pet.available is True]
248-
pet = available_pets[0]
249-
response = self.client.put(f"{BASE_URL}/{pet.id}/purchase")
250-
self.assertEqual(response.status_code, status.HTTP_200_OK)
251-
response = self.client.get(f"{BASE_URL}/{pet.id}")
252-
self.assertEqual(response.status_code, status.HTTP_200_OK)
253-
data = response.get_json()
254-
logging.debug("Response data: %s", data)
255-
self.assertEqual(data["available"], False)
256-
257-
def test_purchase_not_available(self):
258-
"""It should not Purchase a Pet that is not available"""
259-
pets = self._create_pets(10)
260-
unavailable_pets = [pet for pet in pets if pet.available is False]
261-
pet = unavailable_pets[0]
262-
response = self.client.put(f"{BASE_URL}/{pet.id}/purchase")
263-
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
264-
265279
######################################################################
266280
# T E S T M O C K S
267281
######################################################################

0 commit comments

Comments
 (0)