blob: 31a24b55ba78db18645385376602813c513fffdc [file] [log] [blame]
Franz-Xaver Geiger4d022d52018-03-20 13:12:49 +01001import os
2import tempfile
3
Dirk Vogtc9e10ab2016-10-12 13:58:15 +02004from django.contrib.auth.models import User
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +01005from django.urls import reverse
Dirk Vogtf2a33422016-10-11 17:17:26 +02006from rest_framework.test import APITestCase
7from rest_framework.test import APIClient
Dirk Vogt36635692016-10-17 12:19:10 +02008from rest_framework import status
Dirk Vogtf130c752016-08-23 14:45:01 +02009
Borjan Tchakalofffe5f25c2018-03-19 18:33:24 +040010from crashreports.models import Crashreport
11
12
13class InvalidCrashTypeError(BaseException):
14 """Invalid crash type encountered
15
16 The valid crash type values (strings) are:
17 - 'crash';
18 - 'smpl';
19 - 'other'.
20
21 Args:
22 - crash_type: The invalid crash type.
23 """
24
25 def __init__(self, crash_type):
26 super(InvalidCrashTypeError, self).__init__(
27 '{} is not a valid crash type'.format(crash_type))
28
Borjan Tchakaloffec814a72018-02-28 11:16:53 +040029
30class Dummy(object):
31 DEFAULT_DUMMY_DEVICE_REGISTER_VALUES = {
32 'board_date': '2015-12-15T01:23:45Z',
33 'chipset': 'Qualcomm MSM8974PRO-AA',
34 }
35
36 DEFAULT_DUMMY_HEARTBEAT_VALUES = {
37 'uuid': None,
38 'app_version': 10100,
39 'uptime': (
40 'up time: 16 days, 21:49:56, idle time: 5 days, 20:55:04, '
41 'sleep time: 10 days, 20:46:27'),
42 'build_fingerprint': (
43 'Fairphone/FP2/FP2:6.0.1/FP2-gms-18.03.1/FP2-gms-18.03.1:user/'
44 'release-keys'),
45 'radio_version': '4437.1-FP2-0-08',
46 'date': '2018-03-19T09:58:30.386Z',
47 }
48
49 DEFAULT_DUMMY_CRASHREPORTS_VALUES = DEFAULT_DUMMY_HEARTBEAT_VALUES.copy()
50 DEFAULT_DUMMY_CRASHREPORTS_VALUES.update({
51 'is_fake_report': 0,
52 'boot_reason': 'why?',
53 'power_on_reason': 'it was powered on',
54 'power_off_reason': 'something happened and it went off',
55 })
56
Borjan Tchakalofffe5f25c2018-03-19 18:33:24 +040057 CRASH_TYPE_TO_BOOT_REASON_MAP = {
58 'crash': Crashreport.BOOT_REASON_KEYBOARD_POWER_ON,
59 'smpl': Crashreport.BOOT_REASON_RTC_ALARM,
60 'other': 'whatever',
61 }
62
Borjan Tchakaloffec814a72018-02-28 11:16:53 +040063 @staticmethod
64 def _update_copy(original, update):
65 """Merge fields of update into a copy of original"""
66 data = original.copy()
67 data.update(update)
68 return data
69
70 @staticmethod
71 def device_register_data(**kwargs):
72 """
73 Return the data required to register a device.
74
75 Use the values passed as keyword arguments or default to
76 the ones from `Dummy.DEFAULT_DUMMY_DEVICE_REGISTER_VALUES`.
77 """
78 return Dummy._update_copy(
79 Dummy.DEFAULT_DUMMY_DEVICE_REGISTER_VALUES, kwargs)
80
81 @staticmethod
82 def heartbeat_data(**kwargs):
83 """
84 Return the data required to create a heartbeat.
85
86 Use the values passed as keyword arguments or default to
87 the ones from `Dummy.DEFAULT_DUMMY_HEARTBEAT_VALUES`.
88 """
89 return Dummy._update_copy(Dummy.DEFAULT_DUMMY_HEARTBEAT_VALUES, kwargs)
90
91 @staticmethod
Borjan Tchakalofffe5f25c2018-03-19 18:33:24 +040092 def crashreport_data(report_type=None, **kwargs):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +040093 """
94 Return the data required to create a crashreport.
95
96 Use the values passed as keyword arguments or default to
97 the ones from `Dummy.DEFAULT_DUMMY_CRASHREPORTS_VALUES`.
Borjan Tchakalofffe5f25c2018-03-19 18:33:24 +040098
99 Args:
100 report_type (str, optional): A valid value from
101 `Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP.keys()` that will
102 define the boot reason if not explicitly defined in the
103 keyword arguments already.
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400104 """
Borjan Tchakalofffe5f25c2018-03-19 18:33:24 +0400105 data = Dummy._update_copy(
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400106 Dummy.DEFAULT_DUMMY_CRASHREPORTS_VALUES, kwargs)
Borjan Tchakalofffe5f25c2018-03-19 18:33:24 +0400107 if report_type and 'boot_reason' not in kwargs:
108 if report_type not in Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP:
109 raise InvalidCrashTypeError(report_type)
110 data['boot_reason'] = Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP.get(
111 report_type)
112 return data
Dirk Vogtf2a33422016-10-11 17:17:26 +0200113
114
115class DeviceTestCase(APITestCase):
116
117 def setUp(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100118 self.url = reverse("api_v1_register_device")
Dirk Vogtf2a33422016-10-11 17:17:26 +0200119
120 def test(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400121 request = self.client.post(self.url, Dummy.device_register_data())
Dirk Vogtf2a33422016-10-11 17:17:26 +0200122 self.assertTrue("token" in request.data)
123 self.assertTrue("uuid" in request.data)
Dirk Vogt36635692016-10-17 12:19:10 +0200124 self.assertEqual(request.status_code, status.HTTP_200_OK)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200125
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +0100126 def test_create_missing_fields(self):
127 request = self.client.post(self.url)
128 self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST)
129
130 def test_create_missing_board_date(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400131 data = Dummy.device_register_data()
132 data.pop('board_date')
133 request = self.client.post(self.url, data)
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +0100134 self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST)
135
136 def test_create_missing_chipset(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400137 data = Dummy.device_register_data()
138 data.pop('chipset')
139 request = self.client.post(self.url, data)
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +0100140 self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST)
141
142 def test_create_invalid_board_date(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400143 data = Dummy.device_register_data()
144 data['board_date'] = 'not_a_valid_date'
145 request = self.client.post(self.url, data)
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +0100146 self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST)
147
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400148 def test_create_non_existent_time_board_date(self):
149 """
150 Test the resolution of a naive date-time in which the Europe/Amsterdam daylight saving
151 time transition moved the time "forward".
152 """
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400153 data = Dummy.device_register_data()
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400154 # In 2017, the Netherlands changed from CET to CEST on March, 26 at 02:00
155 data['board_date'] = '2017-03-26 02:34:56'
156 request = self.client.post(self.url, data)
157 self.assertEqual(request.status_code, status.HTTP_200_OK)
158
159 def test_create_ambiguous_time_board_date(self):
160 """
161 Test the resolution of a naive date-time in which the Europe/Amsterdam daylight saving
162 time transition moved the time "backward".
163 """
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400164 data = Dummy.device_register_data()
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400165 # In 2017, the Netherlands changed from CEST to CET on October, 29 at 03:00
166 data['board_date'] = '2017-10-29 02:34:56'
167 request = self.client.post(self.url, data)
168 self.assertEqual(request.status_code, status.HTTP_200_OK)
169
Franz-Xaver Geigerd9943352018-02-27 14:26:41 +0100170
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400171class DeviceRegisterAPITestCase(APITestCase):
172 """Base class that offers device registration as well as base users
Dirk Vogtf2a33422016-10-11 17:17:26 +0200173
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400174 Attributes:
175 number_of_devices_created (int): The number of devices created in the
176 database.
177 """
Dirk Vogtf2a33422016-10-11 17:17:26 +0200178
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100179 REGISTER_DEVICE_URL = "api_v1_register_device"
180
Dirk Vogtf2a33422016-10-11 17:17:26 +0200181 def setUp(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400182 self.number_of_devices_created = 0
183
184 _, response_data = self._register_device()
185 self.uuid = response_data['uuid']
186 self.token = response_data['token']
187 self.user = APIClient()
188 self.user.credentials(HTTP_AUTHORIZATION='Token ' + self.token)
189
190 _, response_data = self._register_device()
191 self.other_uuid = response_data['uuid']
192 self.other_token = response_data['token']
193 self.other_user = APIClient()
194 self.other_user.credentials(
195 HTTP_AUTHORIZATION='Token ' + self.other_token)
196
197 self.noauth_client = APIClient()
198
199 self.admin_user = User.objects.create_superuser(
200 'somebody', 'somebody@example.com', 'thepassword')
201 self.admin = APIClient()
202 self.admin.force_authenticate(self.admin_user)
203
204 def _register_device(self, **kwargs):
205 """Register a new device
206
207 Arguments:
208 **kwargs: The data to pass the dummy data creation
209 method `Dummy.device_register_data`.
210 Returns:
211 (dict(str, str), dict(str, str)): The tuple composed of the device
212 data that was used for the registration and the data returned by
213 the server in return.
214 """
215 data = Dummy.device_register_data(**kwargs)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100216 response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400217 self.assertEqual(response.status_code, status.HTTP_200_OK)
218 self.number_of_devices_created += 1
219
220 return (data, response.data)
221
222
223class ListDevicesTestCase(DeviceRegisterAPITestCase):
Dirk Vogtf2a33422016-10-11 17:17:26 +0200224
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100225 LIST_CREATE_URL = "api_v1_list_devices"
226 RETRIEVE_URL = "api_v1_retrieve_device"
227
Dirk Vogtf2a33422016-10-11 17:17:26 +0200228 def test_device_list(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100229 request = self.admin.get(reverse(self.LIST_CREATE_URL), {})
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400230 self.assertIsNot(request.data['results'][1]['uuid'], '')
231 self.assertEqual(
232 len(request.data['results']), self.number_of_devices_created)
Dirk Vogt36635692016-10-17 12:19:10 +0200233 self.assertEqual(request.status_code, status.HTTP_200_OK)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200234
235 def test_device_list_unauth(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100236 request = self.client.get(reverse(self.LIST_CREATE_URL), {})
Dirk Vogt36635692016-10-17 12:19:10 +0200237 self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200238
239 def test_retrieve_device_auth(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400240 request = self.admin.get(
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100241 reverse(self.RETRIEVE_URL, args=[self.uuid]), {})
Dirk Vogt36635692016-10-17 12:19:10 +0200242 self.assertEqual(request.status_code, status.HTTP_200_OK)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400243 self.assertEqual(request.data['uuid'], str(self.uuid))
244 self.assertEqual(request.data['token'], self.token)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200245
246 def test_retrieve_device_unauth(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400247 request = self.client.get(
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100248 reverse(self.RETRIEVE_URL, args=[self.uuid]), {})
Dirk Vogt36635692016-10-17 12:19:10 +0200249 self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200250
251 def test_delete_device_auth(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100252 url = reverse(self.RETRIEVE_URL, args=[self.other_uuid])
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400253 request = self.admin.delete(url, {})
Dirk Vogt36635692016-10-17 12:19:10 +0200254 self.assertEqual(request.status_code, status.HTTP_204_NO_CONTENT)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400255 request = self.admin.delete(url, {})
Dirk Vogt36635692016-10-17 12:19:10 +0200256 self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200257
Dirk Vogtf2a33422016-10-11 17:17:26 +0200258
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400259class HeartbeatListTestCase(DeviceRegisterAPITestCase):
260
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100261 LIST_CREATE_URL = "api_v1_heartbeats"
262 RETRIEVE_URL = "api_v1_heartbeat"
263 LIST_CREATE_BY_UUID_URL = "api_v1_heartbeats_by_uuid"
264 RETRIEVE_BY_UUID_URL = "api_v1_heartbeat_by_uuid"
265
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400266 @staticmethod
267 def _create_dummy_data(**kwargs):
268 return Dummy.heartbeat_data(**kwargs)
269
270 def _post_multiple(self, client, data, count):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100271 return [
272 client.post(reverse(self.LIST_CREATE_URL), data)
273 for _ in range(count)]
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400274
275 def _retrieve_single(self, user):
276 count = 5
Borjan Tchakaloff3340e482018-03-19 15:16:25 +0400277 requests = self._post_multiple(self.admin, self.data, count)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400278 self.assertEqual(len(requests), count)
279 self.assertEqual(requests[0].status_code, status.HTTP_201_CREATED)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100280 url = reverse(self.RETRIEVE_URL, args=[requests[0].data['id']])
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400281 request = user.get(url)
282 return request.status_code
283
284 def _retrieve_single_by_device(self, user):
285 count = 5
286 requests = self._post_multiple(self.user, self.data, count)
287 self.assertEqual(len(requests), count)
288 self.assertEqual(requests[0].status_code, status.HTTP_201_CREATED)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100289 url = reverse(self.RETRIEVE_BY_UUID_URL, args=[
290 self.uuid, requests[0].data['device_local_id']])
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400291 request = user.get(url)
292 return request.status_code
Dirk Vogtf2a33422016-10-11 17:17:26 +0200293
294 def setUp(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400295 super(HeartbeatListTestCase, self).setUp()
296 self.data = self._create_dummy_data(uuid=self.uuid)
Dirk Vogt67eb1482016-10-13 12:42:56 +0200297
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200298 def test_create_no_auth(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100299 request = self.noauth_client.post(
300 reverse(self.LIST_CREATE_URL), self.data)
Dirk Vogt36635692016-10-17 12:19:10 +0200301 self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200302
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200303 def test_create_as_admin(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100304 request = self.admin.post(reverse(self.LIST_CREATE_URL), self.data)
Dirk Vogt36635692016-10-17 12:19:10 +0200305 self.assertEqual(request.status_code, status.HTTP_201_CREATED)
Dirk Vogt67eb1482016-10-13 12:42:56 +0200306 self.assertTrue(request.data['id'] > 0)
Dirk Vogtf2a33422016-10-11 17:17:26 +0200307
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200308 def test_create_as_admin_not_existing_device(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100309 request = self.admin.post(
310 reverse(self.LIST_CREATE_URL), self._create_dummy_data())
Dirk Vogt36635692016-10-17 12:19:10 +0200311 self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND)
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200312
313 def test_create_as_uuid_owner(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400314 request = self.user.post(
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100315 reverse(self.LIST_CREATE_URL),
316 self._create_dummy_data(uuid=self.uuid))
Dirk Vogt36635692016-10-17 12:19:10 +0200317 self.assertEqual(request.status_code, status.HTTP_201_CREATED)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400318 self.assertEqual(request.data['id'], -1)
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200319
320 def test_create_as_uuid_not_owner(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400321 request = self.user.post(
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100322 reverse(self.LIST_CREATE_URL),
323 self._create_dummy_data(uuid=self.other_uuid))
Dirk Vogt36635692016-10-17 12:19:10 +0200324 self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN)
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200325
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200326 def test_list(self):
327 count = 5
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400328 self._post_multiple(self.user, self.data, count)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100329 request = self.admin.get(reverse(self.LIST_CREATE_URL))
Dirk Vogt36635692016-10-17 12:19:10 +0200330 self.assertEqual(request.status_code, status.HTTP_200_OK)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400331 self.assertEqual(len(request.data['results']), count)
Franz-Xaver Geigerd612fd22018-02-28 10:33:08 +0100332
333 def test_retrieve_single_admin(self):
334 self.assertEqual(
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400335 self._retrieve_single(self.admin), status.HTTP_200_OK)
Dirk Vogte1784882016-10-13 16:09:38 +0200336
337 def test_retrieve_single_device_owner(self):
Franz-Xaver Geigerd612fd22018-02-28 10:33:08 +0100338 self.assertEqual(
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400339 self._retrieve_single(self.user), status.HTTP_403_FORBIDDEN)
340
341 def test_retrieve_single_noauth(self):
342 self.assertEqual(
343 self._retrieve_single(self.noauth_client),
Franz-Xaver Geigerd612fd22018-02-28 10:33:08 +0100344 status.HTTP_401_UNAUTHORIZED)
Dirk Vogte1784882016-10-13 16:09:38 +0200345
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400346 def test_retrieve_single_by_device_admin(self):
Franz-Xaver Geigerd612fd22018-02-28 10:33:08 +0100347 self.assertEqual(
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400348 self._retrieve_single_by_device(self.admin), status.HTTP_200_OK)
Dirk Vogt0d9d5d22016-10-13 16:17:57 +0200349
350 def test_retrieve_single_by_device_device_owner(self):
Franz-Xaver Geigerd612fd22018-02-28 10:33:08 +0100351 self.assertEqual(
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400352 self._retrieve_single_by_device(self.user),
353 status.HTTP_403_FORBIDDEN)
354
355 def test_retrieve_single_by_device_noauth(self):
356 self.assertEqual(
357 self._retrieve_single_by_device(self.noauth_client),
Franz-Xaver Geigerd612fd22018-02-28 10:33:08 +0100358 status.HTTP_401_UNAUTHORIZED)
Dirk Vogt0d9d5d22016-10-13 16:17:57 +0200359
Dirk Vogte1784882016-10-13 16:09:38 +0200360 def test_list_by_uuid(self):
361 count = 5
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400362 self._post_multiple(self.user, self.data, count)
363 self._post_multiple(
364 self.admin, self._create_dummy_data(uuid=self.other_uuid), count)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100365 url = reverse(self.LIST_CREATE_BY_UUID_URL, args=[self.uuid])
Dirk Vogte1784882016-10-13 16:09:38 +0200366 request = self.admin.get(url)
Dirk Vogt36635692016-10-17 12:19:10 +0200367 self.assertEqual(request.status_code, status.HTTP_200_OK)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400368 self.assertEqual(len(request.data['results']), count)
Dirk Vogte1784882016-10-13 16:09:38 +0200369
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200370 def test_list_noauth(self):
371 count = 5
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400372 self._post_multiple(self.user, self.data, count)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100373 request = self.noauth_client.get(reverse(self.LIST_CREATE_URL))
Dirk Vogt36635692016-10-17 12:19:10 +0200374 self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED)
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200375
376 def test_list_device_owner(self):
377 count = 5
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400378 self._post_multiple(self.user, self.data, count)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100379 request = self.user.get(reverse(self.LIST_CREATE_URL))
Dirk Vogt36635692016-10-17 12:19:10 +0200380 self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN)
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200381
Borjan Tchakaloff869cf922018-02-19 11:01:16 +0100382 def test_no_radio_version(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400383 data = self._create_dummy_data(uuid=self.uuid)
Borjan Tchakaloff869cf922018-02-19 11:01:16 +0100384 data.pop('radio_version')
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100385 request = self.user.post(reverse(self.LIST_CREATE_URL), data)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400386 self.assertEqual(request.status_code, status.HTTP_201_CREATED)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100387 url = reverse(self.LIST_CREATE_BY_UUID_URL, args=[self.uuid])
Borjan Tchakaloff869cf922018-02-19 11:01:16 +0100388 request = self.admin.get(url)
389 self.assertEqual(request.status_code, status.HTTP_200_OK)
390 self.assertEqual(len(request.data['results']), 1)
391 self.assertIsNone(request.data['results'][0]['radio_version'])
392
393 def test_radio_version_field(self):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100394 request = self.user.post(reverse(self.LIST_CREATE_URL), self.data)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400395 self.assertEqual(request.status_code, status.HTTP_201_CREATED)
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100396 url = reverse(self.LIST_CREATE_BY_UUID_URL, args=[self.uuid])
Borjan Tchakaloff869cf922018-02-19 11:01:16 +0100397 request = self.admin.get(url)
398 self.assertEqual(request.status_code, status.HTTP_200_OK)
399 self.assertEqual(len(request.data['results']), 1)
400 self.assertEqual(request.data['results'][0]['radio_version'],
401 self.data['radio_version'])
402
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400403 def test_send_non_existent_time(self):
404 """
405 Test the resolution of a naive date-time in which the Europe/Amsterdam daylight saving
406 time transition moved the time "forward".
407 """
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400408 data = self._create_dummy_data(uuid=self.uuid)
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400409 # In 2017, the Netherlands changed from CET to CEST on March, 26 at 02:00
410 data['date'] = '2017-03-26 02:34:56'
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100411 request = self.user.post(reverse(self.LIST_CREATE_URL), data)
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400412 self.assertEqual(request.status_code, status.HTTP_201_CREATED)
413
414 def test_send_ambiguous_time(self):
415 """
416 Test the resolution of a naive date-time in which the Europe/Amsterdam daylight saving
417 time transition moved the time "backward".
418 """
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400419 data = self._create_dummy_data(uuid=self.uuid)
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400420 # In 2017, the Netherlands changed from CEST to CET on October, 29 at 03:00
421 data['date'] = '2017-10-29 02:34:56'
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100422 request = self.user.post(reverse(self.LIST_CREATE_URL), data)
Borjan Tchakaloff866f75e2018-03-01 12:04:00 +0400423 self.assertEqual(request.status_code, status.HTTP_201_CREATED)
424
Dirk Vogtc9e10ab2016-10-12 13:58:15 +0200425
426class CrashreportListTestCase(HeartbeatListTestCase):
427
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100428 LIST_CREATE_URL = "api_v1_crashreports"
429 RETRIEVE_URL = "api_v1_crashreport"
430 LIST_CREATE_BY_UUID_URL = "api_v1_crashreports_by_uuid"
431 RETRIEVE_BY_UUID_URL = "api_v1_crashreport_by_uuid"
Dirk Vogt67eb1482016-10-13 12:42:56 +0200432
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400433 @staticmethod
434 def _create_dummy_data(**kwargs):
435 return Dummy.crashreport_data(**kwargs)
Dirk Vogt67eb1482016-10-13 12:42:56 +0200436
437
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400438class LogfileUploadTest(DeviceRegisterAPITestCase):
439
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100440 LIST_CREATE_URL = "api_v1_crashreports"
441 PUT_LOGFILE_URL = "api_v1_putlogfile_for_device_id"
442
Dirk Vogt67eb1482016-10-13 12:42:56 +0200443 def setUp(self):
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400444 super(LogfileUploadTest, self).setUp()
Dirk Vogt67eb1482016-10-13 12:42:56 +0200445
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100446 url = reverse(self.LIST_CREATE_URL)
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400447 for uuid in [self.uuid, self.other_uuid]:
448 data = Dummy.crashreport_data(uuid=uuid)
449 for _ in range(2):
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100450 self.user.post(url, data)
Dirk Vogt36635692016-10-17 12:19:10 +0200451
Dirk Vogt67eb1482016-10-13 12:42:56 +0200452 def test_Logfile_upload_as_admin(self):
Dirk Vogt36635692016-10-17 12:19:10 +0200453 f = tempfile.NamedTemporaryFile('w+', suffix=".log", delete=True)
454 f.write(u"blihblahblub")
Borjan Tchakaloffec814a72018-02-28 11:16:53 +0400455 request = self.admin.post(
Franz-Xaver Geiger67504d02018-03-19 15:04:48 +0100456 reverse(self.PUT_LOGFILE_URL, args=[
457 self.uuid, 1, os.path.basename(f.name)
458 ]),
Dirk Vogt36635692016-10-17 12:19:10 +0200459 {'file': f}, format="multipart")
460 self.assertEqual(status.HTTP_201_CREATED, request.status_code)