"""Tests for the missions module.""" import functools import json import os.path from auvsi_suas.models.aerial_position import AerialPosition from auvsi_suas.models.gps_position import GpsPosition from auvsi_suas.models.mission_config import MissionConfig from auvsi_suas.models.odlc import Odlc from auvsi_suas.models.waypoint import Waypoint from auvsi_suas.proto import interop_api_pb2 from django.conf import settings from django.contrib.auth.models import User from django.core.files.images import ImageFile from django.test import TestCase from django.urls import reverse odlcs_url = reverse('auvsi_suas:odlcs') odlcs_id_url = functools.partial(reverse, 'auvsi_suas:odlcs_id') odlcs_id_image_url = functools.partial(reverse, 'auvsi_suas:odlcs_id_image') odlcs_review_url = reverse('auvsi_suas:odlcs_review') odlcs_review_id_url = functools.partial(reverse, 'auvsi_suas:odlcs_review_id') class TestOdlcsCommon(TestCase): """Common functionality for ODLC tests.""" def setUp(self): # Mission pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() wpt = Waypoint() wpt.order = 10 wpt.latitude = 10 wpt.longitude = 100 wpt.altitude_msl = 0 wpt.save() self.mission = MissionConfig() self.mission.home_pos = pos self.mission.lost_comms_pos = pos self.mission.emergent_last_known_pos = pos self.mission.off_axis_odlc_pos = pos self.mission.map_center_pos = pos self.mission.map_height_ft = 1 self.mission.air_drop_pos = pos self.mission.ugv_drive_pos = pos self.mission.save() self.mission.mission_waypoints.add(wpt) self.mission.search_grid_points.add(wpt) self.mission.save() # Mission 2 self.mission2 = MissionConfig() self.mission2.home_pos = pos self.mission2.lost_comms_pos = pos self.mission2.emergent_last_known_pos = pos self.mission2.off_axis_odlc_pos = pos self.mission2.map_center_pos = pos self.mission2.map_height_ft = 1 self.mission2.air_drop_pos = pos self.mission2.ugv_drive_pos = pos self.mission2.save() self.mission2.mission_waypoints.add(wpt) self.mission2.search_grid_points.add(wpt) self.mission2.save() class TestOdlcsLoggedOut(TestOdlcsCommon): """Tests logged out odlcs.""" def test_not_authenticated(self): """Unauthenticated requests should fail.""" odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'latitude': 38, 'longitude': -76, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(403, response.status_code) response = self.client.get(odlcs_url) self.assertEqual(403, response.status_code) class TestGetOdlc(TestOdlcsCommon): """Tests GETing the odlcs view.""" def setUp(self): """Creates user and logs in.""" super(TestGetOdlc, self).setUp() self.user = User.objects.create_user('testuser', 'testemail@x.com', 'testpass') self.client.force_login(self.user) def test_no_odlcs(self): """We get back an empty list if we have no odlcs.""" response = self.client.get(odlcs_url) self.assertEqual(200, response.status_code) self.assertEqual([], json.loads(response.content)) def test_get_odlcs(self): """We get back the odlcs we own.""" t1 = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t1.save() t2 = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t2.save() t3 = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.EMERGENT) t3.save() t4 = Odlc(mission=self.mission2, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t4.save() get_id = lambda x: x['id'] response = self.client.get(odlcs_url) self.assertEqual(200, response.status_code) self.assertEqual( sorted([ { 'id': t4.pk, 'mission': self.mission2.pk, 'type': 'STANDARD', 'autonomous': False, }, { 'id': t3.pk, 'mission': self.mission.pk, 'type': 'EMERGENT', 'autonomous': False, }, { 'id': t2.pk, 'mission': self.mission.pk, 'type': 'STANDARD', 'autonomous': False, }, { 'id': t1.pk, 'mission': self.mission.pk, 'type': 'STANDARD', 'autonomous': False, }, ], key=get_id), sorted(json.loads(response.content), key=get_id)) response = self.client.get(odlcs_url + '?mission=%d' % self.mission2.pk) self.assertEqual(200, response.status_code) self.assertEqual([ { 'id': t4.pk, 'mission': self.mission2.pk, 'type': 'STANDARD', 'autonomous': False, }, ], json.loads(response.content)) def test_not_others(self): """We don't get odlcs owned by other users.""" user2 = User.objects.create_user('testuser2', 'testemail@x.com', 'testpass') mine = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) mine.save() theirs = Odlc(mission=self.mission, user=user2, odlc_type=interop_api_pb2.Odlc.STANDARD) theirs.save() response = self.client.get(odlcs_url) self.assertEqual(200, response.status_code) self.assertEqual([ { 'id': mine.pk, 'mission': self.mission.pk, 'type': 'STANDARD', 'autonomous': False, }, ], json.loads(response.content)) class TestPostOdlc(TestOdlcsCommon): """Tests POSTing the odlcs view.""" def setUp(self): """Creates user and logs in.""" super(TestPostOdlc, self).setUp() self.user = User.objects.create_user('testuser', 'testemail@x.com', 'testpass') self.user.save() self.client.force_login(self.user) def test_complete(self): """Send complete odlc with all fields.""" odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'latitude': 38, 'longitude': -76, 'orientation': 'N', 'shape': 'SQUARE', 'shapeColor': 'WHITE', 'alphanumeric': 'A', 'alphanumericColor': 'BLACK', 'description': 'Best odlc', 'autonomous': False, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(200, response.status_code) # Check that returned odlc matches created = json.loads(response.content) self.assertIn('id', created) self.assertIn('mission', created) self.assertEqual(self.mission.pk, created['mission']) self.assertEqual(odlc['type'], created['type']) self.assertEqual(odlc['latitude'], created['latitude']) self.assertEqual(odlc['longitude'], created['longitude']) self.assertEqual(odlc['orientation'], created['orientation']) self.assertEqual(odlc['shape'], created['shape']) self.assertEqual(odlc['shapeColor'], created['shapeColor']) self.assertEqual(odlc['alphanumeric'], created['alphanumeric']) self.assertEqual(odlc['alphanumericColor'], created['alphanumericColor']) self.assertEqual(odlc['description'], created['description']) self.assertEqual(odlc['autonomous'], created['autonomous']) def test_minimal(self): """Send odlc minimal fields.""" odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(200, response.status_code) # Check that returned odlc matches created = json.loads(response.content) self.assertIn('id', created) self.assertEqual(odlc['type'], created['type']) self.assertNotIn('latitude', created) self.assertNotIn('longitude', created) self.assertNotIn('orientation', created) self.assertNotIn('shape', created) self.assertNotIn('shapeColor', created) self.assertNotIn('alphanumeric', created) self.assertNotIn('alphanumericColor', created) self.assertNotIn('description', created) self.assertEqual(False, created['autonomous']) def test_missing_type(self): """Odlc type required.""" odlc = { 'mission': self.mission.pk, 'latitude': 38, 'longitude': -76, 'orientation': 'N', 'shape': 'SQUARE', 'shapeColor': 'WHITE', 'alphanumeric': 'A', 'alphanumericColor': 'BLACK', 'description': 'Best odlc', } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_json(self): """Request body must contain valid JSON.""" response = self.client.post(odlcs_url, data='type=STANDARD&longitude=-76', content_type='multipart/form-data') self.assertEqual(400, response.status_code) def test_invalid_mission(self): """Mission ID must correspond to an actual mission.""" odlc = { 'mission': self.mission2.pk + 1, 'type': 'STANDARD', } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_missing_latitude(self): """Odlc latitude required if longitude specified.""" odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'longitude': -76 } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_missing_longitude(self): """Odlc longitude required if latitude specified.""" odlc = {'type': 'STANDARD', 'latitude': 38} response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_type(self): """Send bad odlc type.""" bad = ['foo', 'STANDARD nonsense', 42] for b in bad: odlc = { 'mission': self.mission.pk, 'type': b, 'latitude': 38, 'longitude': -76 } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_latitude(self): """Send bad odlc latitude.""" bad = ['string', 120, -120] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'latitude': b, 'longitude': -76 } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_longitude(self): """Send bad odlc longitude.""" bad = ['string', 200, -200] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'latitude': 38, 'longitude': b } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_shape(self): """Send bad odlc shape.""" bad = ['square circle', 'dodecahedron', 42] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'shape': b, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_shape_color(self): """Send bad odlc background color.""" bad = ['white black', 'mahogany', 42] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'shapeColor': b, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_alphanumeric(self): """Send bad alphanumerics.""" bad = ['a', '10', 'AA'] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'alphanumeric': b, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_alphanumeric_color(self): """Send bad odlc alphanumeric color.""" bad = ['white black', 'mahogany', 42] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'alphanumericColor': b, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_orientation(self): """Send bad odlc orientation.""" bad = ['NNE', 'north', 42] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'orientation': b, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_invalid_autonomous(self): """Send bad odlc autonomous.""" bad = ['true', 1, 'Yes'] for b in bad: odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', 'autonomous': b, } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) def test_too_many(self): """Too many uploads.""" too_many = 50 # Uploaded too many for mission 1. for _ in range(too_many): odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', } self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') # Upload past too many should fail. odlc = { 'mission': self.mission.pk, 'type': 'STANDARD', } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(400, response.status_code) # An upload for mission 2 should succeed. odlc = { 'mission': self.mission2.pk, 'type': 'STANDARD', } response = self.client.post(odlcs_url, data=json.dumps(odlc), content_type='application/json') self.assertEqual(200, response.status_code) class TestOdlcsIdLoggedOut(TestOdlcsCommon): """Tests logged out odlcs_id.""" def test_not_authenticated(self): """Unauthenticated requests should fail.""" response = self.client.get(odlcs_id_url(args=[1])) self.assertEqual(403, response.status_code) class TestOdlcId(TestOdlcsCommon): """Tests GET/PUT/DELETE specific odlcs.""" def setUp(self): """Creates user and logs in.""" super(TestOdlcId, self).setUp() self.user = User.objects.create_user('testuser', 'testemail@x.com', 'testpass') self.client.force_login(self.user) def test_get_nonexistent(self): """Test GETting a odlc that doesn't exist.""" response = self.client.get(odlcs_id_url(args=[999])) self.assertEqual(404, response.status_code) def test_get_other_user(self): """Test GETting a odlc owned by a different user.""" user2 = User.objects.create_user('testuser2', 'testemail@x.com', 'testpass') t = Odlc(mission=self.mission, user=user2, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() response = self.client.get(odlcs_id_url(args=[t.pk])) self.assertEqual(403, response.status_code) def test_get_own(self): """Test GETting a odlc owned by the correct user.""" t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() response = self.client.get(odlcs_id_url(args=[t.pk])) self.assertEqual(200, response.status_code) self.assertEqual( { 'mission': self.mission.pk, 'id': t.pk, 'type': 'STANDARD', 'autonomous': False, }, json.loads(response.content)) def test_put_append(self): """PUT sets a new field that wasn't set before.""" t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() data = { 'mission': self.mission.pk, 'type': 'STANDARD', 'description': 'Hello' } response = self.client.put(odlcs_id_url(args=[t.pk]), data=json.dumps(data)) self.assertEqual(200, response.status_code) t.refresh_from_db() self.assertEqual('Hello', t.description) def test_put_changes_last_modified(self): """PUT sets a new field that wasn't set before.""" t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() orig_last_modified = t.last_modified_time data = { 'mission': self.mission.pk, 'type': 'STANDARD', 'description': 'Hello' } response = self.client.put(odlcs_id_url(args=[t.pk]), data=json.dumps(data)) self.assertEqual(200, response.status_code) t.refresh_from_db() self.assertNotEqual(orig_last_modified, t.last_modified_time) def test_put_updates_fields(self): """PUT updates fields.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD, location=l, orientation=interop_api_pb2.Odlc.S, shape=interop_api_pb2.Odlc.SQUARE, shape_color=interop_api_pb2.Odlc.WHITE, alphanumeric='ABC', alphanumeric_color=interop_api_pb2.Odlc.BLACK, description='Test odlc') t.save() updated = { 'mission': self.mission.pk, 'type': 'STANDARD', 'latitude': 39, 'longitude': -77, 'orientation': 'N', 'shape': 'CIRCLE', 'shapeColor': 'BLACK', 'alphanumeric': 'A', 'alphanumericColor': 'GREEN', 'description': 'Best odlc', 'autonomous': False, } response = self.client.put(odlcs_id_url(args=[t.pk]), data=json.dumps(updated)) self.assertEqual(200, response.status_code) t.refresh_from_db() t.location.refresh_from_db() self.assertEqual(self.user, t.user) self.assertEqual(interop_api_pb2.Odlc.STANDARD, t.odlc_type) self.assertEqual(39, t.location.latitude) self.assertEqual(-77, t.location.longitude) self.assertEqual(interop_api_pb2.Odlc.N, t.orientation) self.assertEqual(interop_api_pb2.Odlc.CIRCLE, t.shape) self.assertEqual(interop_api_pb2.Odlc.BLACK, t.shape_color) self.assertEqual('A', t.alphanumeric) self.assertEqual(interop_api_pb2.Odlc.GREEN, t.alphanumeric_color) self.assertEqual('Best odlc', t.description) def test_put_clear_shape(self): """PUT clear a field with None.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD, location=l, orientation=interop_api_pb2.Odlc.S, shape=interop_api_pb2.Odlc.SQUARE, shape_color=interop_api_pb2.Odlc.WHITE, alphanumeric='ABC', alphanumeric_color=interop_api_pb2.Odlc.BLACK, description='Test odlc') t.save() updated = { 'mission': self.mission.pk, 'type': 'STANDARD', } response = self.client.put(odlcs_id_url(args=[t.pk]), data=json.dumps(updated)) self.assertEqual(200, response.status_code) t.refresh_from_db() self.assertEqual(self.user, t.user) self.assertEqual(interop_api_pb2.Odlc.STANDARD, t.odlc_type) self.assertIsNone(t.location) self.assertIsNone(t.orientation) self.assertIsNone(t.shape) self.assertIsNone(t.shape_color) self.assertEqual('', t.alphanumeric) self.assertIsNone(t.alphanumeric_color) self.assertEqual('', t.description) def test_delete_own(self): """Test DELETEing a odlc owned by the correct user.""" t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() pk = t.pk self.assertTrue(Odlc.objects.get(pk=pk)) response = self.client.delete(odlcs_id_url(args=[pk])) self.assertEqual(200, response.status_code) with self.assertRaises(Odlc.DoesNotExist): Odlc.objects.get(pk=pk) def test_delete_other(self): """Test DELETEing a odlc owned by another user.""" user2 = User.objects.create_user('testuser2', 'testemail@x.com', 'testpass') t = Odlc(mission=self.mission, user=user2, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() response = self.client.delete(odlcs_id_url(args=[t.pk])) self.assertEqual(403, response.status_code) def test_get_after_delete_own(self): """Test GETting a odlc after DELETE.""" t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() pk = t.pk response = self.client.delete(odlcs_id_url(args=[pk])) self.assertEqual(200, response.status_code) response = self.client.get(odlcs_id_url(args=[pk])) self.assertEqual(404, response.status_code) def test_delete_thumb(self): """Test DELETEing a odlc with thumbnail.""" t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() pk = t.pk with open(test_image("A.jpg"), 'rb') as f: response = self.client.post(odlcs_id_image_url(args=[pk]), data=f.read(), content_type="image/jpeg") self.assertEqual(200, response.status_code) t.refresh_from_db() thumb = t.thumbnail.path self.assertTrue(os.path.exists(thumb)) response = self.client.delete(odlcs_id_url(args=[pk])) self.assertEqual(200, response.status_code) self.assertFalse(os.path.exists(thumb)) def test_image(name): """Compute path of test image""" return os.path.join(settings.BASE_DIR, 'auvsi_suas/testdata', name) class TestOdlcIdImage(TestOdlcsCommon): """Tests GET/PUT/DELETE odlc image.""" def setUp(self): """Creates user and logs in.""" super(TestOdlcIdImage, self).setUp() self.user = User.objects.create_user('testuser', 'testemail@x.com', 'testpass') self.client.force_login(self.user) # Create a odlc response = self.client.post(odlcs_url, data=json.dumps({ 'mission': self.mission.pk, 'type': 'STANDARD' }), content_type='application/json') self.assertEqual(200, response.status_code) self.odlc_id = json.loads(response.content)['id'] self.odlc = Odlc.objects.get(pk=self.odlc_id) def test_get_no_image(self): """404 when GET image before upload.""" response = self.client.get(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(404, response.status_code) def test_delete_no_image(self): """404 when DELETE image before upload.""" response = self.client.delete( odlcs_id_image_url(args=[self.odlc_id])) # yapf: disable self.assertEqual(404, response.status_code) def test_get_other_user(self): """Test GETting a thumbnail owned by a different user.""" user2 = User.objects.create_user('testuser2', 'testemail@x.com', 'testpass') t = Odlc(mission=self.mission, user=user2, odlc_type=interop_api_pb2.Odlc.STANDARD) t.save() response = self.client.get(odlcs_id_image_url(args=[t.pk])) self.assertEqual(403, response.status_code) def test_post_bad_image(self): """Try to upload bad image""" response = self.client.post(odlcs_id_image_url(args=[self.odlc_id]), data='Hahaha', content_type='image/jpeg') self.assertEqual(400, response.status_code) def upload_image(self, name, method='POST', content_type='image/jpeg'): """Upload image, assert that it worked""" # Read image to upload. data = None with open(test_image(name), 'rb') as f: data = f.read() # Upload image. response = None if method == 'POST': response = self.client.post( odlcs_id_image_url(args=[self.odlc_id]), data=data, content_type=content_type) else: response = self.client.put(odlcs_id_image_url(args=[self.odlc_id]), data=data, content_type=content_type) self.assertEqual(200, response.status_code) # Validate can retrieve image with uploaded contents. response = self.client.get(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(200, response.status_code) resp_data = b''.join(response.streaming_content) self.assertEqual(data, resp_data) def test_post_jpg(self): """Successfully upload jpg""" self.upload_image('S.jpg') def test_post_png(self): """Successfully upload png""" self.upload_image('A.png', content_type='image/png') def test_post_gif(self): """GIF upload not allowed""" with open(test_image('A.gif'), 'rb') as f: response = self.client.post( odlcs_id_image_url(args=[self.odlc_id]), data=f.read(), content_type='image/gif') self.assertEqual(400, response.status_code) def test_get_image(self): """Successfully GET uploaded image""" self.upload_image('S.jpg') response = self.client.get(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(200, response.status_code) self.assertEqual('image/jpeg', response['Content-Type']) data = b''.join(response.streaming_content) # Did we get back what we uploaded? with open(test_image('S.jpg'), 'rb') as f: self.assertEqual(f.read(), data) def test_replace_image(self): """Successfully replace uploaded image""" self.upload_image('S.jpg') self.upload_image('A.jpg') def test_put_image(self): """PUT works just like POST""" self.upload_image('S.jpg', method='PUT') def test_update_invalidates_thumbnail_review(self): """Test that update invalidates thumbnail field.""" self.odlc.thumbnail_approved = True self.odlc.save() # POST self.upload_image('A.jpg') self.odlc.refresh_from_db() self.assertIsNone(self.odlc.thumbnail_approved) self.odlc.thumbnail_approved = True self.odlc.description_approved = True self.odlc.save() # PUT self.upload_image('A.jpg', method='PUT') self.odlc.refresh_from_db() self.assertIsNone(self.odlc.thumbnail_approved) self.odlc.thumbnail_approved = True self.odlc.description_approved = True self.odlc.save() # DELETE response = self.client.delete(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(200, response.status_code) self.odlc.refresh_from_db() self.assertIsNone(self.odlc.thumbnail_approved) def test_post_delete_old(self): """Old image deleted when new doesn't overwrite.""" self.upload_image('A.jpg') t = Odlc.objects.get(pk=self.odlc_id) jpg_path = t.thumbnail.path self.assertTrue(os.path.exists(jpg_path)) self.upload_image('A.png', content_type='image/png') self.assertFalse(os.path.exists(jpg_path)) def test_delete(self): """Image deleted on DELETE""" self.upload_image('A.jpg') t = Odlc.objects.get(pk=self.odlc_id) jpg_path = t.thumbnail.path self.assertTrue(os.path.exists(jpg_path)) response = self.client.delete(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(200, response.status_code) self.assertFalse(os.path.exists(jpg_path)) def test_get_after_delete(self): """GET returns 404 after DELETE""" self.upload_image('A.jpg') response = self.client.delete(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(200, response.status_code) response = self.client.get(odlcs_id_image_url(args=[self.odlc_id])) self.assertEqual(404, response.status_code) class TestOdlcsAdminReviewNotAdmin(TestOdlcsCommon): """Tests admin review when not logged in as admin.""" def test_not_authenticated(self): """Unauthenticated requests should fail.""" response = self.client.get(odlcs_review_url) self.assertEqual(403, response.status_code) response = self.client.put(odlcs_review_id_url(args=[1])) self.assertEqual(403, response.status_code) def test_not_admin(self): """Unauthenticated requests should fail.""" self.user = User.objects.create_user('testuser', 'testemail@x.com', 'testpass') self.client.force_login(self.user) response = self.client.get(odlcs_review_url) self.assertEqual(403, response.status_code) response = self.client.put(odlcs_review_id_url(args=[1])) self.assertEqual(403, response.status_code) class TestOdlcsAdminReview(TestOdlcsCommon): """Tests GET/PUT admin review of odlcs.""" def setUp(self): """Creates user and logs in.""" super(TestOdlcsAdminReview, self).setUp() self.user = User.objects.create_superuser('testuser', 'testemail@x.com', 'testpass') self.team = User.objects.create_user('testuser2', 'testemail@x.com', 'testpass') self.client.force_login(self.user) def test_get_none(self): """Test GET when there are no odlcs.""" response = self.client.get(odlcs_review_url) self.assertEqual(200, response.status_code) self.assertEqual([], json.loads(response.content)) def test_get_without_thumbnail(self): """Test GET when there are odlcs without thumbnail.""" odlc = Odlc(mission=self.mission, user=self.team, odlc_type=interop_api_pb2.Odlc.STANDARD) odlc.save() response = self.client.get(odlcs_review_url) self.assertEqual(200, response.status_code) data = json.loads(response.content) self.assertEqual(0, len(data)) def test_get(self): """Test GET when there are odlcs.""" odlc = Odlc(mission=self.mission, user=self.team, odlc_type=interop_api_pb2.Odlc.STANDARD) odlc.save() with open(test_image('A.jpg'), 'rb') as f: odlc.thumbnail.save('%d.%s' % (odlc.pk, 'jpg'), ImageFile(f)) odlc.save() response = self.client.get(odlcs_review_url) self.assertEqual(200, response.status_code) data = json.loads(response.content) self.assertEqual(1, len(data)) self.assertIn('odlc', data[0]) self.assertIn('type', data[0]['odlc']) self.assertEqual('STANDARD', data[0]['odlc']['type']) def test_put_review_no_approved(self): """Test PUT review with no approved field.""" odlc = Odlc(mission=self.mission, user=self.team, odlc_type=interop_api_pb2.Odlc.STANDARD) odlc.save() response = self.client.put(odlcs_review_id_url(args=[odlc.pk])) self.assertEqual(400, response.status_code) def test_put_invalid_pk(self): """Test PUT reivew with invalid pk.""" response = self.client.put(odlcs_review_id_url(args=[1]), data=json.dumps({ 'thumbnailApproved': True, 'descriptionApproved': True, })) self.assertEqual(404, response.status_code) def test_put_review(self): """Test PUT review is saved.""" odlc = Odlc(mission=self.mission, user=self.team, odlc_type=interop_api_pb2.Odlc.STANDARD) odlc.save() response = self.client.put(odlcs_review_id_url(args=[odlc.pk]), data=json.dumps({ 'thumbnailApproved': True, 'descriptionApproved': True, })) self.assertEqual(200, response.status_code) data = json.loads(response.content) self.assertIn('odlc', data) self.assertIn('id', data['odlc']) self.assertEqual(odlc.pk, data['odlc']['id']) self.assertIn('thumbnailApproved', data) self.assertTrue(data['thumbnailApproved']) self.assertTrue(data['descriptionApproved']) odlc.refresh_from_db() self.assertTrue(odlc.thumbnail_approved) self.assertTrue(odlc.description_approved)