Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 1 | """Test the API for crashreports, devices, heartbeats and logfiles.""" |
Franz-Xaver Geiger | 4d022d5 | 2018-03-20 13:12:49 +0100 | [diff] [blame] | 2 | import os |
| 3 | import tempfile |
| 4 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 5 | from django.contrib.auth.models import User |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 6 | from django.urls import reverse |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 7 | |
Dirk Vogt | 3663569 | 2016-10-17 12:19:10 +0200 | [diff] [blame] | 8 | from rest_framework import status |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 9 | from rest_framework.test import APIClient, APITestCase |
Dirk Vogt | f130c75 | 2016-08-23 14:45:01 +0200 | [diff] [blame] | 10 | |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 11 | from crashreports.models import Crashreport |
| 12 | |
| 13 | |
| 14 | class InvalidCrashTypeError(BaseException): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 15 | """Invalid crash type encountered. |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 16 | |
| 17 | The valid crash type values (strings) are: |
| 18 | - 'crash'; |
| 19 | - 'smpl'; |
| 20 | - 'other'. |
| 21 | |
| 22 | Args: |
| 23 | - crash_type: The invalid crash type. |
| 24 | """ |
| 25 | |
| 26 | def __init__(self, crash_type): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 27 | """Initialise the exception using the crash type to build a message. |
| 28 | |
| 29 | Args: |
| 30 | crash_type: The invalid crash type. |
| 31 | """ |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 32 | super(InvalidCrashTypeError, self).__init__( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 33 | "{} is not a valid crash type".format(crash_type) |
| 34 | ) |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 35 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 36 | |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 37 | class Dummy: |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 38 | """Dummy values for devices, heartbeats and crashreports.""" |
| 39 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 40 | DEFAULT_DUMMY_DEVICE_REGISTER_VALUES = { |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 41 | "board_date": "2015-12-15T01:23:45Z", |
| 42 | "chipset": "Qualcomm MSM8974PRO-AA", |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | DEFAULT_DUMMY_HEARTBEAT_VALUES = { |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 46 | "uuid": None, |
| 47 | "app_version": 10100, |
| 48 | "uptime": ( |
| 49 | "up time: 16 days, 21:49:56, idle time: 5 days, 20:55:04, " |
| 50 | "sleep time: 10 days, 20:46:27" |
| 51 | ), |
| 52 | "build_fingerprint": ( |
| 53 | "Fairphone/FP2/FP2:6.0.1/FP2-gms-18.03.1/FP2-gms-18.03.1:user/" |
| 54 | "release-keys" |
| 55 | ), |
| 56 | "radio_version": "4437.1-FP2-0-08", |
| 57 | "date": "2018-03-19T09:58:30.386Z", |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | DEFAULT_DUMMY_CRASHREPORTS_VALUES = DEFAULT_DUMMY_HEARTBEAT_VALUES.copy() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 61 | DEFAULT_DUMMY_CRASHREPORTS_VALUES.update( |
| 62 | { |
| 63 | "is_fake_report": 0, |
| 64 | "boot_reason": "why?", |
| 65 | "power_on_reason": "it was powered on", |
| 66 | "power_off_reason": "something happened and it went off", |
| 67 | } |
| 68 | ) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 69 | |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 70 | CRASH_TYPE_TO_BOOT_REASON_MAP = { |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 71 | "crash": Crashreport.BOOT_REASON_KEYBOARD_POWER_ON, |
| 72 | "smpl": Crashreport.BOOT_REASON_RTC_ALARM, |
| 73 | "other": "whatever", |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 74 | } |
| 75 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 76 | @staticmethod |
| 77 | def _update_copy(original, update): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 78 | """Merge fields of update into a copy of original.""" |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 79 | data = original.copy() |
| 80 | data.update(update) |
| 81 | return data |
| 82 | |
| 83 | @staticmethod |
| 84 | def device_register_data(**kwargs): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 85 | """Return the data required to register a device. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 86 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 87 | Use the values passed as keyword arguments or default to the ones |
| 88 | from `Dummy.DEFAULT_DUMMY_DEVICE_REGISTER_VALUES`. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 89 | """ |
| 90 | return Dummy._update_copy( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 91 | Dummy.DEFAULT_DUMMY_DEVICE_REGISTER_VALUES, kwargs |
| 92 | ) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 93 | |
| 94 | @staticmethod |
| 95 | def heartbeat_data(**kwargs): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 96 | """Return the data required to create a heartbeat. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 97 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 98 | Use the values passed as keyword arguments or default to the ones |
| 99 | from `Dummy.DEFAULT_DUMMY_HEARTBEAT_VALUES`. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 100 | """ |
| 101 | return Dummy._update_copy(Dummy.DEFAULT_DUMMY_HEARTBEAT_VALUES, kwargs) |
| 102 | |
| 103 | @staticmethod |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 104 | def crashreport_data(report_type=None, **kwargs): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 105 | """Return the data required to create a crashreport. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 106 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 107 | Use the values passed as keyword arguments or default to the ones |
| 108 | from `Dummy.DEFAULT_DUMMY_CRASHREPORTS_VALUES`. |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 109 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 110 | Args: |
| 111 | report_type (str, optional): A valid value from |
| 112 | `Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP.keys()` that will |
| 113 | define the boot reason if not explicitly defined in the |
| 114 | keyword arguments already. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 115 | """ |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 116 | data = Dummy._update_copy( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 117 | Dummy.DEFAULT_DUMMY_CRASHREPORTS_VALUES, kwargs |
| 118 | ) |
| 119 | if report_type and "boot_reason" not in kwargs: |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 120 | if report_type not in Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP: |
| 121 | raise InvalidCrashTypeError(report_type) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 122 | data["boot_reason"] = Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP.get( |
| 123 | report_type |
| 124 | ) |
Borjan Tchakaloff | fe5f25c | 2018-03-19 18:33:24 +0400 | [diff] [blame] | 125 | return data |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 126 | |
| 127 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 128 | class DeviceRegisterAPITestCase(APITestCase): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 129 | """Base class that offers a device registration method.""" |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 130 | |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 131 | REGISTER_DEVICE_URL = "api_v1_register_device" |
| 132 | |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 133 | def setUp(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 134 | """Create an admin user for accessing the API. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 135 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 136 | The APIClient that can be used to make authenticated requests to the |
| 137 | server is stored in self.admin. |
| 138 | """ |
| 139 | admin_user = User.objects.create_superuser( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 140 | "somebody", "somebody@example.com", "thepassword" |
| 141 | ) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 142 | self.admin = APIClient() |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 143 | self.admin.force_authenticate(admin_user) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 144 | |
| 145 | def _register_device(self, **kwargs): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 146 | """Register a new device. |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 147 | |
| 148 | Arguments: |
| 149 | **kwargs: The data to pass the dummy data creation |
| 150 | method `Dummy.device_register_data`. |
| 151 | Returns: |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 152 | (UUID, APIClient, str): The uuid of the new device as well as an |
| 153 | authentication token and the associated user with credentials. |
| 154 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 155 | """ |
| 156 | data = Dummy.device_register_data(**kwargs) |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 157 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 158 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 159 | |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 160 | uuid = response.data["uuid"] |
| 161 | token = response.data["token"] |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 162 | user = APIClient() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 163 | user.credentials(HTTP_AUTHORIZATION="Token " + token) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 164 | |
| 165 | return uuid, user, token |
| 166 | |
| 167 | |
| 168 | class DeviceTestCase(DeviceRegisterAPITestCase): |
| 169 | """Test cases for registering devices.""" |
| 170 | |
| 171 | def test_register(self): |
| 172 | """Test registration of devices.""" |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 173 | response = self.client.post( |
| 174 | reverse(self.REGISTER_DEVICE_URL), Dummy.device_register_data() |
| 175 | ) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 176 | self.assertTrue("token" in response.data) |
| 177 | self.assertTrue("uuid" in response.data) |
| 178 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 179 | |
| 180 | def test_create_missing_fields(self): |
| 181 | """Test registration with missing fields.""" |
| 182 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL)) |
| 183 | self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) |
| 184 | |
| 185 | def test_create_missing_board_date(self): |
| 186 | """Test registration with missing board date.""" |
| 187 | data = Dummy.device_register_data() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 188 | data.pop("board_date") |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 189 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data) |
| 190 | self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) |
| 191 | |
| 192 | def test_create_missing_chipset(self): |
| 193 | """Test registration with missing chipset.""" |
| 194 | data = Dummy.device_register_data() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 195 | data.pop("chipset") |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 196 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data) |
| 197 | self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) |
| 198 | |
| 199 | def test_create_invalid_board_date(self): |
| 200 | """Test registration with invalid board date.""" |
| 201 | data = Dummy.device_register_data() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 202 | data["board_date"] = "not_a_valid_date" |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 203 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data) |
| 204 | self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) |
| 205 | |
| 206 | def test_create_non_existent_time_board_date(self): |
| 207 | """Test registration with non existing time. |
| 208 | |
| 209 | Test the resolution of a naive date-time in which the |
| 210 | Europe/Amsterdam daylight saving time transition moved the time |
| 211 | "forward". The server should not crash when receiving a naive |
| 212 | date-time which does not exist in the server timezone or locale. |
| 213 | """ |
| 214 | data = Dummy.device_register_data() |
| 215 | # In 2017, the Netherlands changed from CET to CEST on March, |
| 216 | # 26 at 02:00 |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 217 | data["board_date"] = "2017-03-26 02:34:56" |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 218 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data) |
| 219 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
| 220 | |
| 221 | def test_create_ambiguous_time_board_date(self): |
| 222 | """Test registration with ambiguous time. |
| 223 | |
| 224 | Test the resolution of a naive date-time in which the |
| 225 | Europe/Amsterdam daylight saving time transition moved the time |
| 226 | "backward". The server should not crash when receiving a naive |
| 227 | date-time that can belong to multiple timezones. |
| 228 | """ |
| 229 | data = Dummy.device_register_data() |
| 230 | # In 2017, the Netherlands changed from CEST to CET on October, |
| 231 | # 29 at 03:00 |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 232 | data["board_date"] = "2017-10-29 02:34:56" |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 233 | response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data) |
| 234 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 235 | |
| 236 | |
| 237 | class ListDevicesTestCase(DeviceRegisterAPITestCase): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 238 | """Test cases for listing and deleting devices.""" |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 239 | |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 240 | LIST_CREATE_URL = "api_v1_list_devices" |
| 241 | RETRIEVE_URL = "api_v1_retrieve_device" |
| 242 | |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 243 | def test_device_list(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 244 | """Test registration of 2 devices.""" |
| 245 | number_of_devices = 2 |
| 246 | uuids = [ |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 247 | str(self._register_device()[0]) for _ in range(number_of_devices) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 248 | ] |
| 249 | |
| 250 | response = self.admin.get(reverse(self.LIST_CREATE_URL), {}) |
| 251 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 252 | self.assertEqual(len(response.data["results"]), number_of_devices) |
| 253 | for result in response.data["results"]: |
| 254 | self.assertIn(result["uuid"], uuids) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 255 | |
| 256 | def test_device_list_unauth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 257 | """Test listing devices without authentication.""" |
| 258 | response = self.client.get(reverse(self.LIST_CREATE_URL), {}) |
| 259 | self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 260 | |
| 261 | def test_retrieve_device_auth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 262 | """Test retrieval of devices as admin user.""" |
| 263 | uuid, _, token = self._register_device() |
| 264 | response = self.admin.get(reverse(self.RETRIEVE_URL, args=[uuid]), {}) |
| 265 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 266 | self.assertEqual(response.data["uuid"], str(uuid)) |
| 267 | self.assertEqual(response.data["token"], token) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 268 | |
| 269 | def test_retrieve_device_unauth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 270 | """Test retrieval of devices without authentication.""" |
| 271 | uuid, _, _ = self._register_device() |
| 272 | response = self.client.get(reverse(self.RETRIEVE_URL, args=[uuid]), {}) |
| 273 | self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 274 | |
| 275 | def test_delete_device_auth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 276 | """Test deletion of devices as admin user.""" |
| 277 | uuid, _, _ = self._register_device() |
| 278 | url = reverse(self.RETRIEVE_URL, args=[uuid]) |
| 279 | response = self.admin.delete(url, {}) |
| 280 | self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) |
| 281 | response = self.admin.delete(url, {}) |
| 282 | self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 283 | |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 284 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 285 | class HeartbeatListTestCase(DeviceRegisterAPITestCase): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 286 | """Test cases for heartbeats.""" |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 287 | |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 288 | LIST_CREATE_URL = "api_v1_heartbeats" |
| 289 | RETRIEVE_URL = "api_v1_heartbeat" |
| 290 | LIST_CREATE_BY_UUID_URL = "api_v1_heartbeats_by_uuid" |
| 291 | RETRIEVE_BY_UUID_URL = "api_v1_heartbeat_by_uuid" |
| 292 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 293 | @staticmethod |
| 294 | def _create_dummy_data(**kwargs): |
| 295 | return Dummy.heartbeat_data(**kwargs) |
| 296 | |
| 297 | def _post_multiple(self, client, data, count): |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 298 | return [ |
| 299 | client.post(reverse(self.LIST_CREATE_URL), data) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 300 | for _ in range(count) |
| 301 | ] |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 302 | |
| 303 | def _retrieve_single(self, user): |
| 304 | count = 5 |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 305 | response = self._post_multiple(self.admin, self.data, count) |
| 306 | self.assertEqual(len(response), count) |
| 307 | self.assertEqual(response[0].status_code, status.HTTP_201_CREATED) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 308 | url = reverse(self.RETRIEVE_URL, args=[response[0].data["id"]]) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 309 | request = user.get(url) |
| 310 | return request.status_code |
| 311 | |
| 312 | def _retrieve_single_by_device(self, user): |
| 313 | count = 5 |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 314 | response = self._post_multiple(self.user, self.data, count) |
| 315 | self.assertEqual(len(response), count) |
| 316 | self.assertEqual(response[0].status_code, status.HTTP_201_CREATED) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 317 | url = reverse( |
| 318 | self.RETRIEVE_BY_UUID_URL, |
| 319 | args=[self.uuid, response[0].data["device_local_id"]], |
| 320 | ) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 321 | request = user.get(url) |
| 322 | return request.status_code |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 323 | |
| 324 | def setUp(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 325 | """Set up a device and some data.""" |
| 326 | super().setUp() |
| 327 | self.uuid, self.user, self.token = self._register_device() |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 328 | self.data = self._create_dummy_data(uuid=self.uuid) |
Dirk Vogt | 67eb148 | 2016-10-13 12:42:56 +0200 | [diff] [blame] | 329 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 330 | def test_create_no_auth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 331 | """Test creation without authentication.""" |
| 332 | noauth_client = APIClient() |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 333 | response = noauth_client.post(reverse(self.LIST_CREATE_URL), self.data) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 334 | self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 335 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 336 | def test_create_as_admin(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 337 | """Test creation as admin.""" |
| 338 | response = self.admin.post(reverse(self.LIST_CREATE_URL), self.data) |
| 339 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 340 | self.assertTrue(response.data["id"] > 0) |
Dirk Vogt | f2a3342 | 2016-10-11 17:17:26 +0200 | [diff] [blame] | 341 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 342 | def test_create_as_admin_not_existing_device(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 343 | """Test creation of heartbeat on non-existing device.""" |
| 344 | response = self.admin.post( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 345 | reverse(self.LIST_CREATE_URL), self._create_dummy_data() |
| 346 | ) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 347 | self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 348 | |
| 349 | def test_create_as_uuid_owner(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 350 | """Test creation as owner.""" |
| 351 | response = self.user.post( |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 352 | reverse(self.LIST_CREATE_URL), |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 353 | self._create_dummy_data(uuid=self.uuid), |
| 354 | ) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 355 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 356 | self.assertEqual(response.data["id"], -1) |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 357 | |
| 358 | def test_create_as_uuid_not_owner(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 359 | """Test creation as non-owner.""" |
| 360 | uuid, _, _ = self._register_device() |
| 361 | response = self.user.post( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 362 | reverse(self.LIST_CREATE_URL), self._create_dummy_data(uuid=uuid) |
| 363 | ) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 364 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 365 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 366 | def test_list(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 367 | """Test listing of heartbeats.""" |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 368 | count = 5 |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 369 | self._post_multiple(self.user, self.data, count) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 370 | response = self.admin.get(reverse(self.LIST_CREATE_URL)) |
| 371 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 372 | self.assertEqual(len(response.data["results"]), count) |
Franz-Xaver Geiger | d612fd2 | 2018-02-28 10:33:08 +0100 | [diff] [blame] | 373 | |
| 374 | def test_retrieve_single_admin(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 375 | """Test retrieval as admin.""" |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 376 | self.assertEqual(self._retrieve_single(self.admin), status.HTTP_200_OK) |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 377 | |
| 378 | def test_retrieve_single_device_owner(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 379 | """Test retrieval as device owner.""" |
Franz-Xaver Geiger | d612fd2 | 2018-02-28 10:33:08 +0100 | [diff] [blame] | 380 | self.assertEqual( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 381 | self._retrieve_single(self.user), status.HTTP_403_FORBIDDEN |
| 382 | ) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 383 | |
| 384 | def test_retrieve_single_noauth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 385 | """Test retrieval without authentication.""" |
| 386 | noauth_client = APIClient() |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 387 | self.assertEqual( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 388 | self._retrieve_single(noauth_client), status.HTTP_401_UNAUTHORIZED |
| 389 | ) |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 390 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 391 | def test_retrieve_single_by_device_admin(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 392 | """Test retrieval by device as admin.""" |
Franz-Xaver Geiger | d612fd2 | 2018-02-28 10:33:08 +0100 | [diff] [blame] | 393 | self.assertEqual( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 394 | self._retrieve_single_by_device(self.admin), status.HTTP_200_OK |
| 395 | ) |
Dirk Vogt | 0d9d5d2 | 2016-10-13 16:17:57 +0200 | [diff] [blame] | 396 | |
| 397 | def test_retrieve_single_by_device_device_owner(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 398 | """Test retrieval by device as owner.""" |
Franz-Xaver Geiger | d612fd2 | 2018-02-28 10:33:08 +0100 | [diff] [blame] | 399 | self.assertEqual( |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 400 | self._retrieve_single_by_device(self.user), |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 401 | status.HTTP_403_FORBIDDEN, |
| 402 | ) |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 403 | |
| 404 | def test_retrieve_single_by_device_noauth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 405 | """Test retrieval by device without authentication.""" |
| 406 | noauth_client = APIClient() |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 407 | self.assertEqual( |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 408 | self._retrieve_single_by_device(noauth_client), |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 409 | status.HTTP_401_UNAUTHORIZED, |
| 410 | ) |
Dirk Vogt | 0d9d5d2 | 2016-10-13 16:17:57 +0200 | [diff] [blame] | 411 | |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 412 | def test_list_by_uuid(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 413 | """Test listing of devices by UUID.""" |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 414 | count = 5 |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 415 | uuid, _, _ = self._register_device() |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 416 | self._post_multiple(self.user, self.data, count) |
| 417 | self._post_multiple( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 418 | self.admin, self._create_dummy_data(uuid=uuid), count |
| 419 | ) |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 420 | url = reverse(self.LIST_CREATE_BY_UUID_URL, args=[self.uuid]) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 421 | response = self.admin.get(url) |
| 422 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 423 | self.assertEqual(len(response.data["results"]), count) |
Dirk Vogt | e178488 | 2016-10-13 16:09:38 +0200 | [diff] [blame] | 424 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 425 | def test_list_noauth(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 426 | """Test listing of devices without authentication.""" |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 427 | count = 5 |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 428 | noauth_client = APIClient() |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 429 | self._post_multiple(self.user, self.data, count) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 430 | response = noauth_client.get(reverse(self.LIST_CREATE_URL)) |
| 431 | self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 432 | |
| 433 | def test_list_device_owner(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 434 | """Test listing as device owner.""" |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 435 | count = 5 |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 436 | self._post_multiple(self.user, self.data, count) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 437 | response = self.user.get(reverse(self.LIST_CREATE_URL)) |
| 438 | self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 439 | |
Borjan Tchakaloff | 869cf92 | 2018-02-19 11:01:16 +0100 | [diff] [blame] | 440 | def test_no_radio_version(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 441 | """Test creation and retrieval without radio version.""" |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 442 | data = self._create_dummy_data(uuid=self.uuid) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 443 | data.pop("radio_version") |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 444 | response = self.user.post(reverse(self.LIST_CREATE_URL), data) |
| 445 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 446 | url = reverse(self.LIST_CREATE_BY_UUID_URL, args=[self.uuid]) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 447 | response = self.admin.get(url) |
| 448 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 449 | self.assertEqual(len(response.data["results"]), 1) |
| 450 | self.assertIsNone(response.data["results"][0]["radio_version"]) |
Borjan Tchakaloff | 869cf92 | 2018-02-19 11:01:16 +0100 | [diff] [blame] | 451 | |
| 452 | def test_radio_version_field(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 453 | """Test retrieval of radio version field.""" |
| 454 | response = self.user.post(reverse(self.LIST_CREATE_URL), self.data) |
| 455 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 456 | url = reverse(self.LIST_CREATE_BY_UUID_URL, args=[self.uuid]) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 457 | response = self.admin.get(url) |
| 458 | self.assertEqual(response.status_code, status.HTTP_200_OK) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 459 | self.assertEqual(len(response.data["results"]), 1) |
| 460 | self.assertEqual( |
| 461 | response.data["results"][0]["radio_version"], |
| 462 | self.data["radio_version"], |
| 463 | ) |
Borjan Tchakaloff | 869cf92 | 2018-02-19 11:01:16 +0100 | [diff] [blame] | 464 | |
Borjan Tchakaloff | 866f75e | 2018-03-01 12:04:00 +0400 | [diff] [blame] | 465 | def test_send_non_existent_time(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 466 | """Test sending of heartbeat with non existent time. |
| 467 | |
| 468 | Test the resolution of a naive date-time in which the |
| 469 | Europe/Amsterdam daylight saving time transition moved the time |
| 470 | "forward". |
Borjan Tchakaloff | 866f75e | 2018-03-01 12:04:00 +0400 | [diff] [blame] | 471 | """ |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 472 | data = self._create_dummy_data(uuid=self.uuid) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 473 | # In 2017, the Netherlands changed from CET to CEST on March, |
| 474 | # 26 at 02:00 |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 475 | data["date"] = "2017-03-26 02:34:56" |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 476 | response = self.user.post(reverse(self.LIST_CREATE_URL), data) |
| 477 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) |
Borjan Tchakaloff | 866f75e | 2018-03-01 12:04:00 +0400 | [diff] [blame] | 478 | |
| 479 | def test_send_ambiguous_time(self): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 480 | """Test sending of heartbeat with ambiguous time. |
| 481 | |
| 482 | Test the resolution of a naive date-time in which the |
| 483 | Europe/Amsterdam daylight saving time transition moved the time |
| 484 | "backward". |
Borjan Tchakaloff | 866f75e | 2018-03-01 12:04:00 +0400 | [diff] [blame] | 485 | """ |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 486 | data = self._create_dummy_data(uuid=self.uuid) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 487 | # In 2017, the Netherlands changed from CEST to CET on October, |
| 488 | # 29 at 03:00 |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 489 | data["date"] = "2017-10-29 02:34:56" |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 490 | response = self.user.post(reverse(self.LIST_CREATE_URL), data) |
| 491 | self.assertEqual(response.status_code, status.HTTP_201_CREATED) |
Borjan Tchakaloff | 866f75e | 2018-03-01 12:04:00 +0400 | [diff] [blame] | 492 | |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 493 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 494 | # pylint: disable=too-many-ancestors |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 495 | class CrashreportListTestCase(HeartbeatListTestCase): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 496 | """Test cases for crash reports.""" |
Dirk Vogt | c9e10ab | 2016-10-12 13:58:15 +0200 | [diff] [blame] | 497 | |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 498 | LIST_CREATE_URL = "api_v1_crashreports" |
| 499 | RETRIEVE_URL = "api_v1_crashreport" |
| 500 | LIST_CREATE_BY_UUID_URL = "api_v1_crashreports_by_uuid" |
| 501 | RETRIEVE_BY_UUID_URL = "api_v1_crashreport_by_uuid" |
Dirk Vogt | 67eb148 | 2016-10-13 12:42:56 +0200 | [diff] [blame] | 502 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 503 | @staticmethod |
| 504 | def _create_dummy_data(**kwargs): |
| 505 | return Dummy.crashreport_data(**kwargs) |
Dirk Vogt | 67eb148 | 2016-10-13 12:42:56 +0200 | [diff] [blame] | 506 | |
| 507 | |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 508 | class LogfileUploadTest(DeviceRegisterAPITestCase): |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 509 | """Test cases for upload of log files.""" |
Borjan Tchakaloff | ec814a7 | 2018-02-28 11:16:53 +0400 | [diff] [blame] | 510 | |
Franz-Xaver Geiger | 67504d0 | 2018-03-19 15:04:48 +0100 | [diff] [blame] | 511 | LIST_CREATE_URL = "api_v1_crashreports" |
| 512 | PUT_LOGFILE_URL = "api_v1_putlogfile_for_device_id" |
| 513 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 514 | def _upload_crashreport(self, user, uuid): |
| 515 | """ |
| 516 | Upload dummy crashreport data. |
Dirk Vogt | 67eb148 | 2016-10-13 12:42:56 +0200 | [diff] [blame] | 517 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 518 | Args: |
| 519 | user: The user which should be used for uploading the report |
| 520 | uuid: The uuid of the device to which the report should be uploaded |
Dirk Vogt | 3663569 | 2016-10-17 12:19:10 +0200 | [diff] [blame] | 521 | |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 522 | Returns: The local id of the device for which the report was uploaded. |
| 523 | |
| 524 | """ |
| 525 | data = Dummy.crashreport_data(uuid=uuid) |
| 526 | response = user.post(reverse(self.LIST_CREATE_URL), data) |
| 527 | self.assertEqual(status.HTTP_201_CREATED, response.status_code) |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 528 | self.assertTrue("device_local_id" in response.data) |
| 529 | device_local_id = response.data["device_local_id"] |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 530 | |
| 531 | return device_local_id |
| 532 | |
| 533 | def _test_logfile_upload(self, user, uuid): |
| 534 | # Upload crashreport |
| 535 | device_local_id = self._upload_crashreport(user, uuid) |
| 536 | |
| 537 | # Upload a logfile for the crashreport |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 538 | logfile = tempfile.NamedTemporaryFile("w+", suffix=".log", delete=True) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 539 | logfile.write(u"blihblahblub") |
| 540 | response = user.post( |
Mitja Nikolaus | cb50f2c | 2018-08-24 13:54:48 +0200 | [diff] [blame^] | 541 | reverse( |
| 542 | self.PUT_LOGFILE_URL, |
| 543 | args=[uuid, device_local_id, os.path.basename(logfile.name)], |
| 544 | ), |
| 545 | {"file": logfile}, |
| 546 | format="multipart", |
| 547 | ) |
Mitja Nikolaus | 3518160 | 2018-08-03 13:55:30 +0200 | [diff] [blame] | 548 | self.assertEqual(status.HTTP_201_CREATED, response.status_code) |
| 549 | |
| 550 | def test_logfile_upload_as_user(self): |
| 551 | """Test upload of logfiles as device owner.""" |
| 552 | uuid, user, _ = self._register_device() |
| 553 | self._test_logfile_upload(user, uuid) |
| 554 | |
| 555 | def test_logfile_upload_as_admin(self): |
| 556 | """Test upload of logfiles as admin user.""" |
| 557 | uuid, _, _ = self._register_device() |
| 558 | self._test_logfile_upload(self.admin, uuid) |