tests.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import tempfile
  2. from django.core.files import File as DjangoFile
  3. from django.conf import settings
  4. from glitchtip.test_utils.test_case import GlitchTipTestCase
  5. from difs.tasks import (
  6. difs_create_file_from_chunks,
  7. difs_get_file_from_chunks,
  8. difs_concat_file_blobs_to_disk,
  9. ChecksumMismatched
  10. )
  11. from django.core.files.uploadedfile import SimpleUploadedFile
  12. from files.models import File
  13. from model_bakery import baker
  14. from hashlib import sha1
  15. import contextlib
  16. from unittest.mock import patch, MagicMock
  17. class DifsAssembleAPITestCase(GlitchTipTestCase):
  18. def setUp(self):
  19. self.create_user_and_project()
  20. self.url = f"/api/0/projects/{self.organization.slug}/{self.project.slug}/files/difs/assemble/" # noqa
  21. self.checksum = "0892b6a9469438d9e5ffbf2807759cd689996271"
  22. self.chunks = [
  23. "efa73a85c44d64e995ade0cc3286ea47cfc49c36",
  24. "966e44663054d6c1f38d04c6ff4af83467659bd7"
  25. ]
  26. self.data = {
  27. self.checksum: {
  28. "name": "test",
  29. "debug_id": "a959d2e6-e4e5-303e-b508-670eb84b392c",
  30. "chunks": self.chunks
  31. }
  32. }
  33. settings.GLITCHTIP_ENABLE_DIFS = True
  34. def tearDown(self):
  35. settings.GLITCHTIP_ENABLE_DIFS = False
  36. def test_difs_assemble_with_dif_existed(self):
  37. file = baker.make(
  38. "files.File",
  39. checksum=self.checksum
  40. )
  41. baker.make(
  42. "difs.DebugInformationFile",
  43. project=self.project,
  44. file=file,
  45. )
  46. expected_response = {
  47. self.checksum: {
  48. "state": "ok",
  49. "missingChunks": []
  50. }
  51. }
  52. response = self.client.post(self.url,
  53. self.data,
  54. format='json'
  55. )
  56. self.assertEqual(response.data, expected_response)
  57. def test_difs_assemble_with_missing_chunks(self):
  58. baker.make(
  59. "files.FileBlob",
  60. checksum=self.chunks[0]
  61. )
  62. data = {
  63. self.checksum: {
  64. "name": "test",
  65. "debug_id": "a959d2e6-e4e5-303e-b508-670eb84b392c",
  66. "chunks": self.chunks
  67. }
  68. }
  69. expected_response = {
  70. self.checksum: {
  71. "state": "not_found",
  72. "missingChunks": [self.chunks[1]]
  73. }
  74. }
  75. response = self.client.post(self.url,
  76. data,
  77. format='json'
  78. )
  79. self.assertEqual(response.data, expected_response)
  80. def test_difs_assemble_without_missing_chunks(self):
  81. for chunk in self.chunks:
  82. baker.make("files.FileBlob", checksum=chunk)
  83. expected_response = {
  84. self.checksum: {
  85. "state": "created",
  86. "missingChunks": []
  87. }
  88. }
  89. response = self.client.post(self.url,
  90. self.data,
  91. format='json'
  92. )
  93. self.assertEqual(response.data, expected_response)
  94. class DsymsAPIViewTestCase(GlitchTipTestCase):
  95. def setUp(self):
  96. self.create_user_and_project()
  97. self.url = f"/api/0/projects/{self.organization.slug}/{self.project.slug}/files/dsyms/" # noqa
  98. self.uuid = "afb116cf-efec-49af-a7fe-281ac680d8a0"
  99. self.checksum = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
  100. settings.GLITCHTIP_ENABLE_DIFS = True
  101. def tearDown(self):
  102. settings.GLITCHTIP_ENABLE_DIFS = False
  103. @contextlib.contextmanager
  104. def patch(self):
  105. proguard_file = MagicMock()
  106. proguard_file.read.return_value = b""
  107. uploaded_zip_file = MagicMock()
  108. uploaded_zip_file.namelist.return_value = iter(
  109. [f"proguard/{self.uuid}.txt"])
  110. uploaded_zip_file.open.return_value.__enter__.return_value = proguard_file # noqa
  111. with patch('zipfile.is_zipfile', return_value=True), \
  112. patch('zipfile.ZipFile') as ZipFile:
  113. ZipFile.return_value.__enter__.return_value = uploaded_zip_file
  114. yield
  115. def test_post(self):
  116. """
  117. It should return the expected response
  118. """
  119. upload_file = SimpleUploadedFile(
  120. "example.zip",
  121. b"random_content",
  122. content_type="multipart/form-data"
  123. )
  124. data = {
  125. "file": upload_file
  126. }
  127. with self.patch():
  128. response = self.client.post(self.url, data)
  129. expected_response = [{
  130. "id": response.data[0]["id"],
  131. "debugId": self.uuid,
  132. "cpuName": "any",
  133. 'objectName': 'proguard-mapping',
  134. 'symbolType': 'proguard',
  135. 'headers': {'Content-Type': 'text/x-proguard+plain'},
  136. 'size': 0,
  137. 'sha1': self.checksum,
  138. "dateCreated": response.data[0]["dateCreated"],
  139. "data": {
  140. "features": ["mapping"]
  141. }
  142. }]
  143. self.assertEqual(response.status_code, 200)
  144. self.assertEqual(len(response.data), 1)
  145. self.assertEqual(response.data, expected_response)
  146. def test_post_existing_file(self):
  147. """
  148. It should success and return the expected response
  149. """
  150. baker.make(
  151. "files.FileBlob",
  152. checksum=self.checksum
  153. )
  154. fileobj = baker.make(
  155. "files.File",
  156. checksum=self.checksum
  157. )
  158. dif = baker.make(
  159. "difs.DebugInformationFile",
  160. file=fileobj,
  161. project=self.project
  162. )
  163. upload_file = SimpleUploadedFile(
  164. "example.zip",
  165. b"random_content",
  166. content_type="multipart/form-data"
  167. )
  168. data = {
  169. "file": upload_file
  170. }
  171. with self.patch():
  172. response = self.client.post(self.url, data)
  173. expected_response = [{
  174. "id": dif.id,
  175. "debugId": self.uuid,
  176. "cpuName": "any",
  177. 'objectName': 'proguard-mapping',
  178. 'symbolType': 'proguard',
  179. 'headers': {'Content-Type': 'text/x-proguard+plain'},
  180. 'size': 0,
  181. 'sha1': 'da39a3ee5e6b4b0d3255bfef95601890afd80709',
  182. "dateCreated": response.data[0]["dateCreated"],
  183. "data": {
  184. "features": ["mapping"]
  185. }
  186. }]
  187. self.assertEqual(response.status_code, 200)
  188. self.assertEqual(len(response.data), 1)
  189. self.assertEqual(response.data, expected_response)
  190. def test_post_invalid_zip_file(self):
  191. upload_file = SimpleUploadedFile(
  192. "example.zip",
  193. b"random_content",
  194. content_type="multipart/form-data"
  195. )
  196. data = {
  197. "file": upload_file
  198. }
  199. response = self.client.post(self.url, data)
  200. expected_response = {"error": "Invalid file type uploaded"}
  201. self.assertEqual(response.data, expected_response)
  202. self.assertEqual(response.status_code, 400)
  203. class DifsTasksTestCase(GlitchTipTestCase):
  204. def setUp(self):
  205. self.create_user_and_project()
  206. def create_file_blob(self, name, content):
  207. bin = content.encode('utf-8')
  208. tmp = tempfile.NamedTemporaryFile()
  209. tmp.write(bin)
  210. tmp.flush()
  211. checksum = sha1(bin).hexdigest()
  212. fileblob = baker.make("files.FileBlob", checksum=checksum)
  213. fileblob.blob.save(name, DjangoFile(tmp))
  214. tmp.close()
  215. return fileblob
  216. def test_difs_create_file_from_chunks(self):
  217. fileblob1 = self.create_file_blob("1", "1")
  218. fileblob2 = self.create_file_blob("2", "2")
  219. checksum = sha1(b"12").hexdigest()
  220. chunks = [fileblob1.checksum, fileblob2.checksum]
  221. difs_create_file_from_chunks("12", checksum, chunks)
  222. file = File.objects.filter(checksum=checksum).first()
  223. self.assertEqual(file.checksum, checksum)
  224. def test_difs_create_file_from_chunks_with_mismatched_checksum(self):
  225. fileblob1 = self.create_file_blob("1", "1")
  226. fileblob2 = self.create_file_blob("2", "2")
  227. checksum = sha1(b"123").hexdigest()
  228. chunks = [fileblob1.checksum, fileblob2.checksum]
  229. with self.assertRaises(ChecksumMismatched):
  230. difs_create_file_from_chunks("123", checksum, chunks)
  231. def test_difs_get_file_from_chunks(self):
  232. fileblob1 = self.create_file_blob("1", "1")
  233. fileblob2 = self.create_file_blob("2", "2")
  234. checksum = sha1(b"12").hexdigest()
  235. chunks = [fileblob1.checksum, fileblob2.checksum]
  236. difs_create_file_from_chunks("12", checksum, chunks)
  237. file = difs_get_file_from_chunks(checksum, chunks)
  238. self.assertEqual(file.checksum, checksum)
  239. def test_difs_concat_file_blobs_to_disk(self):
  240. fileblob1 = self.create_file_blob("1", "1")
  241. fileblob2 = self.create_file_blob("2", "2")
  242. checksum = sha1(b"12").hexdigest()
  243. chunks = [fileblob1.checksum, fileblob2.checksum]
  244. file = difs_create_file_from_chunks("12", checksum, chunks)
  245. with difs_concat_file_blobs_to_disk(file.blobs.all()) as fd:
  246. content = fd.read()
  247. self.assertEqual(content, b"12")