tests.py 7.8 KB

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