blob: b0aeb34b45aeaa70056485e63f2c8f5d65ad4f5e [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 Nikolausbc03e682018-11-13 16:48:20 +01006import unittest
Mitja Nikolausc2da2852018-10-04 15:09:11 +02007import zipfile
Mitja Nikolaus03e412b2018-09-18 17:50:15 +02008
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +02009from django.conf import settings
10from django.core.files.storage import default_storage
Mitja Nikolausbc03e682018-11-13 16:48:20 +010011from django.db import connection
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +020012from django.test import override_settings
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020013from django.urls import reverse
14
15from rest_framework import status
16
Mitja Nikolauscc90d572018-11-22 16:40:15 +010017from crashreports.models import (
18 crashreport_file_name,
19 Device,
20 Crashreport,
21 LogFile,
22)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010023from crashreports.tests.utils import (
24 Dummy,
25 RaceConditionsTestCase,
26 HiccupCrashreportsAPITestCase,
27)
28
29LIST_CREATE_URL = "api_v1_crashreports"
30PUT_LOGFILE_URL = "api_v1_putlogfile_for_device_id"
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020031
32
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +020033@override_settings(MEDIA_ROOT=tempfile.mkdtemp(".hiccup-tests"))
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020034class LogfileUploadTest(HiccupCrashreportsAPITestCase):
35 """Test cases for upload of log files."""
36
Mitja Nikolausbc03e682018-11-13 16:48:20 +010037 # pylint: disable=too-many-ancestors
38
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020039 LIST_CREATE_URL = "api_v1_crashreports"
40 PUT_LOGFILE_URL = "api_v1_putlogfile_for_device_id"
Mitja Nikolauscc90d572018-11-22 16:40:15 +010041 POST_LOGFILE_URL = "api_v1_logfiles_by_id"
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020042
Mitja Nikolaus188bca62018-10-04 15:17:48 +020043 def setUp(self):
44 """Call the super setup method and register a device."""
45 super().setUp()
46 self.device_uuid, self.user, _ = self._register_device()
47
Mitja Nikolausbc03e682018-11-13 16:48:20 +010048 def upload_crashreport(self, user, uuid):
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020049 """
50 Upload dummy crashreport data.
51
52 Args:
53 user: The user which should be used for uploading the report
54 uuid: The uuid of the device to which the report should be uploaded
55
56 Returns: The local id of the device for which the report was uploaded.
57
58 """
59 data = Dummy.crashreport_data(uuid=uuid)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010060 response = user.post(reverse(LIST_CREATE_URL), data)
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020061 self.assertEqual(status.HTTP_201_CREATED, response.status_code)
62 self.assertTrue("device_local_id" in response.data)
63 device_local_id = response.data["device_local_id"]
64
65 return device_local_id
66
Mitja Nikolausc2da2852018-10-04 15:09:11 +020067 def _assert_zip_file_contents_equal(self, file1, file2):
68 """Assert that the files within two zip files are equal."""
69 zip_file_1 = zipfile.ZipFile(file1)
70 zip_file_2 = zipfile.ZipFile(file2)
71 for file_name_1, file_name_2 in zip(
72 zip_file_1.filelist, zip_file_2.filelist
73 ):
74 file_1 = zip_file_1.open(file_name_1)
75 file_2 = zip_file_2.open(file_name_2)
76
77 self.assertEqual(file_1.read(), file_2.read())
78
Mitja Nikolausbc03e682018-11-13 16:48:20 +010079 def upload_logfile(self, client, uuid, device_local_id):
80 """Upload a log file and assert that it was created."""
Mitja Nikolausfd452f82018-11-07 11:53:59 +010081 logfile = open(Dummy.DEFAULT_DUMMY_LOG_FILE_PATHS[0], "rb")
Mitja Nikolausc2da2852018-10-04 15:09:11 +020082 logfile_name = os.path.basename(logfile.name)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010083 response = client.post(
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020084 reverse(
Mitja Nikolausbc03e682018-11-13 16:48:20 +010085 PUT_LOGFILE_URL, args=[uuid, device_local_id, logfile_name]
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020086 ),
87 {"file": logfile},
88 format="multipart",
89 )
Mitja Nikolaus6e118472018-10-04 11:15:29 +020090 logfile.close()
Mitja Nikolaus03e412b2018-09-18 17:50:15 +020091 self.assertEqual(status.HTTP_201_CREATED, response.status_code)
Mitja Nikolausbc03e682018-11-13 16:48:20 +010092 return response
93
94 def _test_logfile_upload(self, user, uuid):
95 # Upload crashreport
96 device_local_id = self.upload_crashreport(user, uuid)
97
98 # Upload a logfile for the crashreport
99 self.upload_logfile(user, uuid, device_local_id)
Mitja Nikolaus03e412b2018-09-18 17:50:15 +0200100
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200101 logfile_instance = (
102 Device.objects.get(uuid=uuid)
103 .crashreports.get(device_local_id=device_local_id)
104 .logfiles.last()
105 )
106 uploaded_logfile_path = crashreport_file_name(
Mitja Nikolausbc03e682018-11-13 16:48:20 +0100107 logfile_instance,
108 os.path.basename(Dummy.DEFAULT_DUMMY_LOG_FILE_PATHS[0]),
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200109 )
110
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +0200111 self.assertTrue(default_storage.exists(uploaded_logfile_path))
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200112 # The files are not 100% equal, because the server adds some extra
113 # bytes. However, we mainly care that the contents are equal:
114 self._assert_zip_file_contents_equal(
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +0200115 default_storage.path(uploaded_logfile_path),
Mitja Nikolausfd452f82018-11-07 11:53:59 +0100116 Dummy.DEFAULT_DUMMY_LOG_FILE_PATHS[0],
Mitja Nikolausc2da2852018-10-04 15:09:11 +0200117 )
118
Mitja Nikolaus03e412b2018-09-18 17:50:15 +0200119 def test_logfile_upload_as_user(self):
120 """Test upload of logfiles as device owner."""
Mitja Nikolaus188bca62018-10-04 15:17:48 +0200121 self._test_logfile_upload(self.user, self.device_uuid)
Mitja Nikolaus03e412b2018-09-18 17:50:15 +0200122
Mitja Nikolause0e83772018-11-05 10:00:53 +0100123 def test_logfile_upload_as_fp_staff(self):
124 """Test upload of logfiles as Fairphone staff user."""
125 self._test_logfile_upload(self.fp_staff_client, self.device_uuid)
Mitja Nikolaus188bca62018-10-04 15:17:48 +0200126
Mitja Nikolauscc90d572018-11-22 16:40:15 +0100127 def test_logfile_deletion(self):
128 """Test deletion of logfile instances."""
129 # Create a user, device and crashreport with logfile
130 device = Dummy.create_dummy_device(Dummy.create_dummy_user())
131 crashreport = Dummy.create_dummy_report(Crashreport, device)
132 logfile, logfile_path = Dummy.create_dummy_log_file_with_actual_file(
133 crashreport
134 )
135
136 # Assert that the crashreport and logfile have been created
137 self.assertEqual(Crashreport.objects.count(), 1)
138 self.assertEqual(LogFile.objects.count(), 1)
139 self.assertTrue(os.path.isfile(logfile_path))
140
141 # Delete the logfile
142 response = self.fp_staff_client.delete(
143 reverse(self.POST_LOGFILE_URL, args=[logfile.id])
144 )
145 self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
146
147 # Assert that the logfile has been deleted
148 self.assertEqual(LogFile.objects.count(), 0)
149 self.assertFalse(os.path.isfile(logfile_path))
150
Mitja Nikolaus188bca62018-10-04 15:17:48 +0200151 def tearDown(self):
152 """Remove the file and directories that were created for the test."""
Franz-Xaver Geiger38a66bc2018-10-09 14:52:26 +0200153 shutil.rmtree(settings.MEDIA_ROOT)
Mitja Nikolausbc03e682018-11-13 16:48:20 +0100154
155
156@unittest.skip("Fails because of race condition when assigning local IDs")
157class LogfileRaceConditionsTestCase(RaceConditionsTestCase):
158 """Test cases for logfile race conditions."""
159
160 def test_create_multiple_logfiles(self):
161 """Test that no race condition occurs when creating logfiles."""
162 uuid, user, _ = self._register_device()
163 device_local_id = LogfileUploadTest.upload_crashreport(self, user, uuid)
164
165 def upload_logfile(client, uuid, device_local_id):
166 LogfileUploadTest.upload_logfile(
167 self, client, uuid, device_local_id
168 )
169 connection.close()
170
171 argslist = [[user, uuid, device_local_id] for _ in range(10)]
172
173 self._test_create_multiple(
174 LogFile, upload_logfile, argslist, "crashreport_local_id"
175 )