def setUp(self): """ create test data 1 User 1 Thermometer 1 `context` dictionary """ self.user = get_user_model().objects.create_user( username="******", password="******", email="*****@*****.**" ) self.thermometer = Thermometer( display_name='therm' ) self.temps = [] for i in range(50): self.temps.append( TemperatureReading( thermometer=self.thermometer, degrees_c=i ) ) self.assertEqual(50, len(self.temps)) with transaction.atomic(): self.user.save() self.thermometer.register(self.user) for temp in self.temps: temp.save() self.context = {'request': None}
def setUp(self): """ Set up thermometer record for class tests """ self.user = get_user_model().objects.create_user(username="******", password="******") self.thermometer = Thermometer(display_name="test therm") self.thermometer.register(self.user)
def test_single_user_multiple_therms(self): """ One user should be able to own many thermometers """ therms = [] for i in range(20): therm = Thermometer(display_name=f"therm{i}") with transaction.atomic(): therm.register(self.user) self.assertIs(self.user, therm.owner) therms.append(therm) self.assertEqual(len(self.user.thermometers.all()), 20)
def test_new_therm_properties(self): """ New therms should have uuid autogenerated. They should not have owners, should not be registered, and should not have a registration date. """ therm = Thermometer(display_name="test thermometer") therm.save() self.assertTrue(therm.therm_id) self.assertFalse(therm.registered) self.assertIsNone(therm.registration_date) self.assertEquals(therm.display_name, "test thermometer") self.assertEquals(therm.created_date, datetime.date.today()) self.assertIsNone(therm.owner)
def test_authenticated_patch_invalid_data(self): """ PATCH requests with invalid data should return 400 """ url = reverse('thermometer-detail', args=[self.therm.pk]) new_therm = Thermometer(therm_id='1') def patch_invalid_data(data): request = self.factory.patch(url, data=data, format='json') force_authenticate(request, user=self.normal_user) response = self.detailview(request, data=data, pk=self.therm.pk) self.assertEquals(response.status_code, 400) datasets = [{ 'therm_id': 'apweoriulsadk falk4;l43aklk jea;lkj34leskrjng lksjn435lka345asdn lksjd' }, { 'display_name': 'thisnameiswaytoolongandwonteverbeacceptedbecausethelongestallowedis75characters' }, { 'therm_id': '1' }, { 'temperatures': [{ 'degrees_c': 123456789012334567 }] }] for data in datasets: patch_invalid_data(data)
def test_authenticated_get(self): """ Users should be able to see their own temperature readings Staff should be able to see all temperature readings """ # owner should see all temps created url = reverse('temperaturereading-list') request = self.factory.get(url) force_authenticate(request, user=self.user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), len(TemperatureReading.objects.all())) # new user should see no temps user = get_user_model().objects.create_user(username='******', password='******', email='*****@*****.**') request = self.factory.get(url) force_authenticate(request, user=user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 0) # giving new user a thermometer with a temp should get 1 temp on get therm = Thermometer() therm.register(user) temp = TemperatureReading(thermometer=therm, degrees_c=1) with transaction.atomic(): temp.save() request = self.factory.get(url) force_authenticate(request, user=user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 1) superuser = get_user_model().objects.create_superuser( username='******', password='******', email='*****@*****.**') request = self.factory.get(url) force_authenticate(request, user=superuser) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 11)
def test_authenticated_get(self): """ Regular users should be able to see their own thermometers Staff should be able to see all thermometers """ other_user = get_user_model().objects.create_user(username="******", password="******", email="*****@*****.**") normal_user_therms = [] for i in range(4): therm = Thermometer() therm.register(self.normal_user) normal_user_therms.append(therm) other_user_therms = [] for i in range(4): therm = Thermometer() therm.register(other_user) other_user_therms = [] normal_user_therms.append(self.therm) # Test list view url = reverse('thermometer-list') request = self.factory.get(url) force_authenticate(request, user=self.normal_user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 5) for therm_data in response.data: therm = Thermometer.objects.get(therm_id=therm_data['therm_id']) self.assertIn(therm, normal_user_therms) request = self.factory.get(url) force_authenticate(request, user=self.super_user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 9) # Test detail view url = reverse('thermometer-detail', args=[self.therm.pk]) request = self.factory.get(url) force_authenticate(request, self.normal_user) response = self.detailview(request, pk=self.therm.pk) self.assertEquals(response.status_code, 200) self.assertEquals(response.data['owner'][-2], str(self.normal_user.pk)) request = self.factory.get(url) force_authenticate(request, self.super_user) response = self.detailview(request, pk=self.therm.pk) self.assertEquals(response.status_code, 200) self.assertEquals(response.data['owner'][-2], str(self.normal_user.pk))
def setUp(self): """ create test data """ self.normal_user = get_user_model().objects.create_user( username='******', password='******', email='*****@*****.**') self.super_user = get_user_model().objects.create_superuser( username='******', password='******', email='*****@*****.**') self.therm = Thermometer(display_name='test thermometer') self.therm.register(self.normal_user) self.factory = APIRequestFactory() self.listview = ThermometerViewset.as_view({ 'get': 'list', 'post': 'create' }) self.detailview = ThermometerViewset.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' })
class TemperatureReadingModelTests(TestCase): """Tests for TemperatureReading class Methods: create_many_temperature_records: Create a bunch of temperature records, ensuring they can be saved as expected, and that deleting the user associated with the thermometer cascades into deleting the temperatures as well temperature_conversion: Test conversion of C to F temperatures """ def setUp(self): """ Set up thermometer record for class tests """ self.user = get_user_model().objects.create_user(username="******", password="******") self.thermometer = Thermometer(display_name="test therm") self.thermometer.register(self.user) def tearDown(self): """ Clear test database after tests run """ self.user.delete() self.assertEquals(len(Thermometer.objects.all()), 0) self.assertEquals(len(TemperatureReading.objects.all()), 0) self.assertEquals(len(get_user_model().objects.all()), 0) def test_create_many_temperature_records(self): """ Create a bunch of temperature records and ensure they can be saved/retrieved as expected """ for i in range(1000): temp = TemperatureReading(degrees_c=i / 10, thermometer=self.thermometer) temp.save() self.assertEquals(len(self.thermometer.temperatures.all()), 1000)
def test_duplicate_id_rejected(self): """ UUIDs need to be unique, so attempting to re-use one should fail """ therm_one = Thermometer(display_name="one") therm_one.save() try: therm_two = Thermometer(display_name="two", therm_id=therm_one.therm_id) therm_two.save() self.fail( "Should not be able to save thermometer with repeat uuid") except Exception as e: self.assertEquals( str(e), 'UNIQUE constraint failed: temperature_thermometer.therm_id')
def test_register_thermometer(self): """ Registering a thermometer should associated a user with it. Attempting to register an already registered thermometer should fail. """ therm = Thermometer(display_name="registration test") self.assertIsNone(therm.owner) therm.register(self.user) self.assertIs(self.user, therm.owner) self.assertTrue(therm.registered) self.assertEquals(therm.registration_date, datetime.date.today()) other_user = get_user_model().objects.create_user( username="******", password="******", email="*****@*****.**") try: therm.register(other_user) self.fail("Attempting to register second thermometer should fail") except ThermometerRegistrationError as tre: self.assertEquals(str(tre), "Thermometer Already Registered")
class ThermometerViewsetTests(APITestCase): """Tests for Thermometer Viewset Methods: setUp: Create test data tearDown: Empty test database test_unauthenticated_requests: All unauthenticated requests should fail test_authenticated_get: Regular users should be able to see only their own thermometers. Staff should see all thermometers test_authenticated_post_valid: POST requests should create a new thermometer record registered to the authenticated user test_authenticated_post_invalid_data: POST requests with invalid data should return http code 400 bad request test_authenticated_put_valid_data: PUT requests should update all fields on an existing model test_authenticated_put_invalid_data: Invalid data in PUT requests should return 400 test_authenticated_path_valid_data: PATCH requests should update the correct fields test_authenticated_path_invalid_data: PATCH requests with invalid data should return 400 """ def setUp(self): """ create test data """ self.normal_user = get_user_model().objects.create_user( username='******', password='******', email='*****@*****.**') self.super_user = get_user_model().objects.create_superuser( username='******', password='******', email='*****@*****.**') self.therm = Thermometer(display_name='test thermometer') self.therm.register(self.normal_user) self.factory = APIRequestFactory() self.listview = ThermometerViewset.as_view({ 'get': 'list', 'post': 'create' }) self.detailview = ThermometerViewset.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }) def tearDown(self): """ empty test database """ with transaction.atomic(): for user in get_user_model().objects.all(): user.delete() self.assertEquals(len(get_user_model().objects.all()), 0) self.assertEquals(len(Thermometer.objects.all()), 0) self.assertEquals(len(TemperatureReading.objects.all()), 0) def test_unauthenticated_requests(self): """ This viewset should reject all unauthenticated requests """ self.client.logout() # ListView requests url = reverse('thermometer-list') request = self.factory.get(url) response = self.listview(request) self.assertEquals(response.status_code, 403) data = {'display_name': 'fred'} requet = self.factory.post(url, data) response = self.listview(request) self.assertEquals(response.status_code, 403) # DetailView requests url = reverse('thermometer-detail', args=[self.therm.pk]) request = self.factory.get(url) response = self.detailview(request, pk=self.therm.pk) self.assertEquals(response.status_code, 403) data = {'display_name': 'forky'} request = self.factory.patch(url, data=data, partial=True) response = self.detailview(request) self.assertEquals(response.status_code, 403) data['therm_id'] = 'sausage' request = self.factory.put(url, pk=self.therm.pk, data=data) response = self.detailview(request) self.assertEquals(response.status_code, 403) request = self.factory.delete(url, pk=self.therm.pk) response = self.detailview(request) self.assertEquals(response.status_code, 403) def test_authenticated_get(self): """ Regular users should be able to see their own thermometers Staff should be able to see all thermometers """ other_user = get_user_model().objects.create_user(username="******", password="******", email="*****@*****.**") normal_user_therms = [] for i in range(4): therm = Thermometer() therm.register(self.normal_user) normal_user_therms.append(therm) other_user_therms = [] for i in range(4): therm = Thermometer() therm.register(other_user) other_user_therms = [] normal_user_therms.append(self.therm) # Test list view url = reverse('thermometer-list') request = self.factory.get(url) force_authenticate(request, user=self.normal_user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 5) for therm_data in response.data: therm = Thermometer.objects.get(therm_id=therm_data['therm_id']) self.assertIn(therm, normal_user_therms) request = self.factory.get(url) force_authenticate(request, user=self.super_user) response = self.listview(request) self.assertEquals(response.status_code, 200) self.assertEquals(len(response.data), 9) # Test detail view url = reverse('thermometer-detail', args=[self.therm.pk]) request = self.factory.get(url) force_authenticate(request, self.normal_user) response = self.detailview(request, pk=self.therm.pk) self.assertEquals(response.status_code, 200) self.assertEquals(response.data['owner'][-2], str(self.normal_user.pk)) request = self.factory.get(url) force_authenticate(request, self.super_user) response = self.detailview(request, pk=self.therm.pk) self.assertEquals(response.status_code, 200) self.assertEquals(response.data['owner'][-2], str(self.normal_user.pk)) def test_authenticated_post_valid(self): """ POST requests should create a new thermometer registered to the current user """ def make_assertions_about_data(data, user): url = reverse('thermometer-list') request = self.factory.post(url, data=data, format='json') force_authenticate(request, user=user) response = self.listview(request) self.assertEquals(response.status_code, 201) self.assertEquals(int(response.data['owner'][-2]), user.pk) self.assertEquals(response.data['display_name'], data['display_name']) self.assertEquals(response.data['therm_id'], str(data['therm_id'])) data = {'display_name': 'new thermometer', 'therm_id': uuid.uuid4()} make_assertions_about_data(data, self.normal_user) data = {'display_name': 'newer thermometer', 'therm_id': uuid.uuid4()} make_assertions_about_data(data, self.super_user) def test_authenticated_post_invalid_data(self): """ POST requests with invalid data should return error code """ def make_assertions_with_data(data): url = reverse('thermometer-list') request = self.factory.post(url, data=data, format='json') force_authenticate(request, user=self.normal_user) response = self.listview(request) self.assertEquals(response.status_code, 400) data_sets = [{ 'temperatures': [{ 'degrees_c': 91 }] }, { 'display_name': 'thisnameiswaytoolongandwonteverbeacceptedbecausethelongestallowedis75characters' }, { 'display_name': 'valid', 'temperatures': [{ 'degrees_c': 40 }] }] for data in data_sets: make_assertions_with_data(data) def test_authenticated_put_valid_data(self): """ Authenticated put requests with valid data should overwrite existing records with new values """ def validate_put_request(data): url = reverse('thermometer-detail', args=[self.therm.pk]) request = self.factory.put(url, data=data, format='json') force_authenticate(request, self.normal_user) response = self.detailview(request, data=data, pk=self.therm.pk) self.therm = Thermometer.objects.get(pk=self.therm.pk) self.assertEquals(response.status_code, 200) if 'temperatures' in data.keys(): for temp in data['temperatures']: temp = TemperatureReading.objects.get( degrees_c=temp['degrees_c']) self.assertIsNotNone(temp) self.assertEquals(temp.thermometer.pk, self.therm.pk) del data['temperatures'] for key, value in data.items(): self.assertEquals(getattr(self.therm, key), value) self.assertIn(key, response.data) data_sets = [{ 'display_name': 'new display name', 'therm_id': uuid.uuid4() }, { 'display_name': 'newer display name', 'therm_id': uuid.uuid4() }, { 'display_name': 'newest display name', 'therm_id': uuid.uuid4() }, { 'temperatures': [ { 'degrees_c': 1 }, { 'degrees_c': 2 }, { 'degrees_c': 4 }, { 'degrees_c': 5 }, ] }] for data in data_sets: validate_put_request(data) def test_authenticated_put_invalid_data(self): """ PUT requests with invalid data should return 400 """ url = reverse('thermometer-detail', args=[self.therm.pk]) new_therm = Thermometer(therm_id='1') def put_invalid_data(data): request = self.factory.put(url, data=data, format='json') force_authenticate(request, user=self.normal_user) response = self.detailview(request, data=data, pk=self.therm.pk) self.assertEquals(response.status_code, 400) datasets = [{ 'therm_id': 'apweoriulsadk falk4;l43aklk jea;lkj34leskrjng lksjn435lka345asdn lksjd' }, { 'display_name': 'thisnameiswaytoolongandwonteverbeacceptedbecausethelongestallowedis75characters' }, { 'therm_id': '1' }, { 'temperatures': [{ 'degrees_c': 123456789012334567 }] }] for data in datasets: put_invalid_data(data) def test_authenticated_patch_valid_data(self): """ Authenticated patch requests with valid data should overwrite existing records with new values """ def validate_patch_request(data): url = reverse('thermometer-detail', args=[self.therm.pk]) request = self.factory.patch(url, data=data, format='json') force_authenticate(request, self.normal_user) response = self.detailview(request, data=data, pk=self.therm.pk) self.therm = Thermometer.objects.get(pk=self.therm.pk) self.assertEquals(response.status_code, 200) if 'temperatures' in data.keys(): for temp in data['temperatures']: temp = TemperatureReading.objects.get( degrees_c=temp['degrees_c']) self.assertIsNotNone(temp) self.assertEquals(temp.thermometer.pk, self.therm.pk) del data['temperatures'] for key, value in data.items(): self.assertEquals(getattr(self.therm, key), value) self.assertIn(key, response.data) data_sets = [{ 'display_name': 'new display name', }, { 'therm_id': uuid.uuid4() }, { 'display_name': 'newest display name', 'therm_id': uuid.uuid4() }, { 'temperatures': [ { 'degrees_c': 1 }, { 'degrees_c': 2 }, { 'degrees_c': 4 }, { 'degrees_c': 5 }, ] }] for data in data_sets: validate_patch_request(data) def test_authenticated_patch_invalid_data(self): """ PATCH requests with invalid data should return 400 """ url = reverse('thermometer-detail', args=[self.therm.pk]) new_therm = Thermometer(therm_id='1') def patch_invalid_data(data): request = self.factory.patch(url, data=data, format='json') force_authenticate(request, user=self.normal_user) response = self.detailview(request, data=data, pk=self.therm.pk) self.assertEquals(response.status_code, 400) datasets = [{ 'therm_id': 'apweoriulsadk falk4;l43aklk jea;lkj34leskrjng lksjn435lka345asdn lksjd' }, { 'display_name': 'thisnameiswaytoolongandwonteverbeacceptedbecausethelongestallowedis75characters' }, { 'therm_id': '1' }, { 'temperatures': [{ 'degrees_c': 123456789012334567 }] }] for data in datasets: patch_invalid_data(data) def test_delete(self): """ Normal users should be able to delete their thermometers. Superusers should be able to delete anyone's thermometers """ second_therm = Thermometer.objects.create() second_therm.register(self.normal_user) # normal user delete their own thermometer url = reverse('thermometer-detail', args=[second_therm.pk]) request = self.factory.delete(url) force_authenticate(request, self.normal_user) response = self.detailview(request, pk=second_therm.pk) self.assertEquals(response.status_code, 204) try: Thermometer.objects.get(pk=second_therm.pk) self.fail("Query should fail, as oject should no longer exist") except Thermometer.DoesNotExist as dne: self.assertEquals(str(dne), "Thermometer matching query does not exist.") # normal user delete others thermometer second_therm = Thermometer.objects.create() second_therm.register(self.super_user) url = reverse('thermometer-detail', args=[second_therm.pk]) request = self.factory.delete(url) force_authenticate(request, self.normal_user) response = self.detailview(request, pk=second_therm.pk) self.assertEquals(response.status_code, 404) self.assertEquals( Thermometer.objects.get(owner=self.super_user).pk, second_therm.pk) # superuser delete other's thermometer url = reverse('thermometer-detail', args=[self.therm.pk]) request = self.factory.delete(url) force_authenticate(request, self.super_user) response = self.detailview(request, pk=self.therm.pk) self.assertEquals(response.status_code, 204) try: Thermometer.objects.get(pk=self.therm.pk) self.fail("Query should fail, as oject should no longer exist") except Thermometer.DoesNotExist as dne: self.assertEquals(str(dne), "Thermometer matching query does not exist.") # superuser delete own thermometer url = reverse('thermometer-detail', args=[second_therm.pk]) request = self.factory.delete(url) force_authenticate(request, self.super_user) response = self.detailview(request, pk=second_therm.pk) self.assertEquals(response.status_code, 204) try: Thermometer.objects.get(pk=second_therm.pk) self.fail("Query should fail, as oject should no longer exist") except Thermometer.DoesNotExist as dne: self.assertEquals(str(dne), "Thermometer matching query does not exist.")
class TemperatureReadingSerializerTests(APITestCase): """Tests for Temperature Reading Serializer Methods: setUp: create test data tearDown: clear test database test_serializer_valid_data: when given valid data, serializer should create a new temperature reading record """ def setUp(self): """ create test data 1 User 1 Thermometer 1 `context` dictionary """ self.user = get_user_model().objects.create_user( username="******", password="******", email="*****@*****.**" ) self.thermometer = Thermometer( display_name='therm' ) self.temps = [] for i in range(50): self.temps.append( TemperatureReading( thermometer=self.thermometer, degrees_c=i ) ) self.assertEqual(50, len(self.temps)) with transaction.atomic(): self.user.save() self.thermometer.register(self.user) for temp in self.temps: temp.save() self.context = {'request': None} def tearDown(self): """ clear test database """ with transaction.atomic(): self.user.delete() self.assertEqual(0, len(TemperatureReading.objects.all())) self.assertEqual(0, len(get_user_model().objects.all())) self.assertEqual(0, len(Thermometer.objects.all())) def test_temperature_reading_serialized_correctly(self): """ Serialized readings should include all fields specified """ temp = TemperatureReading( degrees_c=1.23456, thermometer=self.thermometer ) with transaction.atomic(): temp.save() serializer = TemperatureReadingSerializer( temp, context=self.context ) self.assertEqual(temp.id, serializer.data['id']) self.assertEqual(temp.degrees_c, float(serializer.data['degrees_c'])) self.assertEqual(temp.thermometer.display_name, serializer.data['thermometer']) def test_update_raises_type_error(self): """ Update method should always raise type error. """ temp = self.temps[0] valid_data = { 'degrees_c': 101 } valid_data_bigger = { 'degrees_c': 100, 'thermometer': 'display' } invalid_data = { 'degrees_c': 'snacks', 'thermometer': 'invalid' } serializer = TemperatureReadingSerializer( temp, data=valid_data, context=self.context, partial=True ) self.assertTrue(serializer.is_valid()) try: serializer.save() self.fail("Saving update should fail - valid data") except TypeError as te: exp = "Updating Temperature Readings via API not allowed. " + \ "Contact a system administrator for assistance." self.assertEquals(exp, str(te)) serializer = TemperatureReadingSerializer( temp, data=valid_data_bigger, context=self.context, partial=True ) self.assertTrue(serializer.is_valid()) try: serializer.save() self.fail("Saving update should fail - valid data") except TypeError as te: exp = "Updating Temperature Readings via API not allowed. " + \ "Contact a system administrator for assistance." self.assertEquals(exp, str(te)) serializer = TemperatureReadingSerializer( temp, data=invalid_data, context=self.context, partial=True ) self.assertFalse(serializer.is_valid())