tests.py 9.7 KB

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