blob: f66a3574c3f76ee2262d1741feec07b929d1a668 [file] [log] [blame]
Mitja Nikolaus03e412b2018-09-18 17:50:15 +02001"""Tests for the logfiles REST API."""
2
3import os
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +02004import shutil
5import tempfile
Mitja Nikolausc2da2852018-10-04 15:09:11 +02006import zipfile
Mitja Nikolaus03e412b2018-09-18 17:50:15 +02007
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +02008from django.conf import settings
9from django.core.files.storage import default_storage
Mitja Nikolausbc03e682018-11-13 16:48:20 +010010from django.db import connection
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +020011from django.test import override_settings
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020012from django.urls import reverse
13
14from rest_framework import status
15
Mitja Nikolauscc90d572018-11-22 16:40:15 +010016from crashreports.models import (
17 crashreport_file_name,
18 Device,
19 Crashreport,
20 LogFile,
21)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010022from crashreports.tests.utils import (
23 Dummy,
24 RaceConditionsTestCase,
25 HiccupCrashreportsAPITestCase,
26)
27
28LIST_CREATE_URL = "api_v1_crashreports"
29PUT_LOGFILE_URL = "api_v1_putlogfile_for_device_id"
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020030
31
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +020032@override_settings(MEDIA_ROOT=tempfile.mkdtemp(".hiccup-tests"))
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020033class LogfileUploadTest(HiccupCrashreportsAPITestCase):
34 """Test cases for upload of log files."""
35
Mitja Nikolausbc03e682018-11-13 16:48:20 +010036 # pylint: disable=too-many-ancestors
37
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020038 LIST_CREATE_URL = "api_v1_crashreports"
39 PUT_LOGFILE_URL = "api_v1_putlogfile_for_device_id"
Mitja Nikolauscc90d572018-11-22 16:40:15 +010040 POST_LOGFILE_URL = "api_v1_logfiles_by_id"
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020041
Mitja Nikolaus188bca62018-10-04 15:17:48 +020042 def setUp(self):
43 """Call the super setup method and register a device."""
44 super().setUp()
45 self.device_uuid, self.user, _ = self._register_device()
46
Mitja Nikolausbc03e682018-11-13 16:48:20 +010047 def upload_crashreport(self, user, uuid):
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020048 """
49 Upload dummy crashreport data.
50
51 Args:
52 user: The user which should be used for uploading the report
53 uuid: The uuid of the device to which the report should be uploaded
54
55 Returns: The local id of the device for which the report was uploaded.
56
57 """
58 data = Dummy.crashreport_data(uuid=uuid)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010059 response = user.post(reverse(LIST_CREATE_URL), data)
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020060 self.assertEqual(status.HTTP_201_CREATED, response.status_code)
61 self.assertTrue("device_local_id" in response.data)
62 device_local_id = response.data["device_local_id"]
63
64 return device_local_id
65
Mitja Nikolausc2da2852018-10-04 15:09:11 +020066 def _assert_zip_file_contents_equal(self, file1, file2):
67 """Assert that the files within two zip files are equal."""
68 zip_file_1 = zipfile.ZipFile(file1)
69 zip_file_2 = zipfile.ZipFile(file2)
70 for file_name_1, file_name_2 in zip(
71 zip_file_1.filelist, zip_file_2.filelist
72 ):
73 file_1 = zip_file_1.open(file_name_1)
74 file_2 = zip_file_2.open(file_name_2)
75
76 self.assertEqual(file_1.read(), file_2.read())
77
Mitja Nikolausbc03e682018-11-13 16:48:20 +010078 def upload_logfile(self, client, uuid, device_local_id):
79 """Upload a log file and assert that it was created."""
Mitja Nikolaus77dd5652018-12-06 11:27:01 +010080 logfile = open(Dummy.DEFAULT_LOG_FILE_PATHS[0], "rb")
Mitja Nikolausc2da2852018-10-04 15:09:11 +020081 logfile_name = os.path.basename(logfile.name)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010082 response = client.post(
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020083 reverse(
Mitja Nikolausbc03e682018-11-13 16:48:20 +010084 PUT_LOGFILE_URL, args=[uuid, device_local_id, logfile_name]
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020085 ),
86 {"file": logfile},
87 format="multipart",
88 )
Mitja Nikolaus6e118472018-10-04 11:15:29 +020089 logfile.close()
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020090 self.assertEqual(status.HTTP_201_CREATED, response.status_code)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010091 return response
92
93 def _test_logfile_upload(self, user, uuid):
94 # Upload crashreport
95 device_local_id = self.upload_crashreport(user, uuid)
96
97 # Upload a logfile for the crashreport
98 self.upload_logfile(user, uuid, device_local_id)
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020099
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200100 logfile_instance = (
101 Device.objects.get(uuid=uuid)
102 .crashreports.get(device_local_id=device_local_id)
103 .logfiles.last()
104 )
105 uploaded_logfile_path = crashreport_file_name(
Mitja Nikolaus77dd5652018-12-06 11:27:01 +0100106 logfile_instance, os.path.basename(Dummy.DEFAULT_LOG_FILE_PATHS[0])
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200107 )
108
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +0200109 self.assertTrue(default_storage.exists(uploaded_logfile_path))
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200110 # The files are not 100% equal, because the server adds some extra
111 # bytes. However, we mainly care that the contents are equal:
112 self._assert_zip_file_contents_equal(
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +0200113 default_storage.path(uploaded_logfile_path),
Mitja Nikolaus77dd5652018-12-06 11:27:01 +0100114 Dummy.DEFAULT_LOG_FILE_PATHS[0],
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200115 )
116
Mitja Nikolaus03e412b2018-09-18 17:50:15 +0200117 def test_logfile_upload_as_user(self):
118 """Test upload of logfiles as device owner."""
Mitja Nikolaus188bca62018-10-04 15:17:48 +0200119 self._test_logfile_upload(self.user, self.device_uuid)
Mitja Nikolaus03e412b2018-09-18 17:50:15 +0200120
Mitja Nikolause0e83772018-11-05 10:00:53 +0100121 def test_logfile_upload_as_fp_staff(self):
122 """Test upload of logfiles as Fairphone staff user."""
123 self._test_logfile_upload(self.fp_staff_client, self.device_uuid)
Mitja Nikolaus188bca62018-10-04 15:17:48 +0200124
Mitja Nikolauscc90d572018-11-22 16:40:15 +0100125 def test_logfile_deletion(self):
126 """Test deletion of logfile instances."""
127 # Create a user, device and crashreport with logfile
Mitja Nikolaus77dd5652018-12-06 11:27:01 +0100128 device = Dummy.create_device(Dummy.create_user())
129 crashreport = Dummy.create_report(Crashreport, device)
130 logfile, logfile_path = Dummy.create_log_file_with_actual_file(
Mitja Nikolauscc90d572018-11-22 16:40:15 +0100131 crashreport
132 )
133
134 # Assert that the crashreport and logfile have been created
135 self.assertEqual(Crashreport.objects.count(), 1)
136 self.assertEqual(LogFile.objects.count(), 1)
137 self.assertTrue(os.path.isfile(logfile_path))
138
139 # Delete the logfile
140 response = self.fp_staff_client.delete(
141 reverse(self.POST_LOGFILE_URL, args=[logfile.id])
142 )
143 self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
144
145 # Assert that the logfile has been deleted
146 self.assertEqual(LogFile.objects.count(), 0)
147 self.assertFalse(os.path.isfile(logfile_path))
148
Mitja Nikolaus188bca62018-10-04 15:17:48 +0200149 def tearDown(self):
150 """Remove the file and directories that were created for the test."""
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +0200151 shutil.rmtree(settings.MEDIA_ROOT)
Mitja Nikolausbc03e682018-11-13 16:48:20 +0100152
153
Mitja Nikolausbc03e682018-11-13 16:48:20 +0100154class LogfileRaceConditionsTestCase(RaceConditionsTestCase):
155 """Test cases for logfile race conditions."""
156
157 def test_create_multiple_logfiles(self):
158 """Test that no race condition occurs when creating logfiles."""
159 uuid, user, _ = self._register_device()
160 device_local_id = LogfileUploadTest.upload_crashreport(self, user, uuid)
161
162 def upload_logfile(client, uuid, device_local_id):
163 LogfileUploadTest.upload_logfile(
164 self, client, uuid, device_local_id
165 )
166 connection.close()
167
168 argslist = [[user, uuid, device_local_id] for _ in range(10)]
169
170 self._test_create_multiple(
171 LogFile, upload_logfile, argslist, "crashreport_local_id"
172 )