TestSendMaterialJob.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Copyright (c) 2018 Ultimaker B.V.
  3. # Cura is released under the terms of the LGPLv3 or higher.
  4. import io
  5. import json
  6. from unittest import TestCase, mock
  7. from unittest.mock import patch, call
  8. from PyQt5.QtCore import QByteArray
  9. from UM.MimeTypeDatabase import MimeType
  10. from UM.Application import Application
  11. from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob
  12. @patch("builtins.open", lambda _, __: io.StringIO("<xml></xml>"))
  13. @patch("UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile",
  14. lambda _: MimeType(name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile",
  15. suffixes = ["xml.fdm_material"]))
  16. @patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: ["/materials/generic_pla_white.xml.fdm_material"])
  17. @patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice")
  18. @patch("PyQt5.QtNetwork.QNetworkReply")
  19. class TestSendMaterialJob(TestCase):
  20. _LOCAL_MATERIAL_WHITE = {"type": "material", "status": "unknown", "id": "generic_pla_white",
  21. "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA",
  22. "brand": "Generic", "material": "PLA", "color_name": "White",
  23. "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "1", "color_code": "#ffffff",
  24. "description": "Test PLA White", "adhesion_info": "Use glue.", "approximate_diameter": "3",
  25. "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"},
  26. "definition": "fdmprinter", "compatible": True}
  27. _LOCAL_MATERIAL_BLACK = {"type": "material", "status": "unknown", "id": "generic_pla_black",
  28. "base_file": "generic_pla_black", "setting_version": "5", "name": "Yellow CPE",
  29. "brand": "Ultimaker", "material": "CPE", "color_name": "Black",
  30. "GUID": "5fbb362a-41f9-4818-bb43-15ea6df34aa4", "version": "1", "color_code": "#000000",
  31. "description": "Test PLA Black", "adhesion_info": "Use glue.", "approximate_diameter": "3",
  32. "properties": {"density": "1.01", "diameter": "2.85", "weight": "750"},
  33. "definition": "fdmprinter", "compatible": True}
  34. _REMOTE_MATERIAL_WHITE = {
  35. "guid": "badb0ee7-87c8-4f3f-9398-938587b67dce",
  36. "material": "PLA",
  37. "brand": "Generic",
  38. "version": 1,
  39. "color": "White",
  40. "density": 1.00
  41. }
  42. _REMOTE_MATERIAL_BLACK = {
  43. "guid": "5fbb362a-41f9-4818-bb43-15ea6df34aa4",
  44. "material": "PLA",
  45. "brand": "Generic",
  46. "version": 2,
  47. "color": "Black",
  48. "density": 1.00
  49. }
  50. def test_run(self, device_mock, reply_mock):
  51. job = SendMaterialJob(device_mock)
  52. job.run()
  53. # We expect the materials endpoint to be called when the job runs.
  54. device_mock.get.assert_called_with("materials/", on_finished = job._onGetRemoteMaterials)
  55. def test__onGetRemoteMaterials_withFailedRequest(self, reply_mock, device_mock):
  56. reply_mock.attribute.return_value = 404
  57. job = SendMaterialJob(device_mock)
  58. job._onGetRemoteMaterials(reply_mock)
  59. # We expect the device not to be called for any follow up.
  60. self.assertEqual(0, device_mock.createFormPart.call_count)
  61. def test__onGetRemoteMaterials_withWrongEncoding(self, reply_mock, device_mock):
  62. reply_mock.attribute.return_value = 200
  63. reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("cp500"))
  64. job = SendMaterialJob(device_mock)
  65. job._onGetRemoteMaterials(reply_mock)
  66. # Given that the parsing fails we do no expect the device to be called for any follow up.
  67. self.assertEqual(0, device_mock.createFormPart.call_count)
  68. def test__onGetRemoteMaterials_withBadJsonAnswer(self, reply_mock, device_mock):
  69. reply_mock.attribute.return_value = 200
  70. reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.")
  71. job = SendMaterialJob(device_mock)
  72. job._onGetRemoteMaterials(reply_mock)
  73. # Given that the parsing fails we do no expect the device to be called for any follow up.
  74. self.assertEqual(0, device_mock.createFormPart.call_count)
  75. def test__onGetRemoteMaterials_withMissingGuidInRemoteMaterial(self, reply_mock, device_mock):
  76. reply_mock.attribute.return_value = 200
  77. remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy()
  78. del remote_material_without_guid["guid"]
  79. reply_mock.readAll.return_value = QByteArray(json.dumps([remote_material_without_guid]).encode("ascii"))
  80. job = SendMaterialJob(device_mock)
  81. job._onGetRemoteMaterials(reply_mock)
  82. # Given that parsing fails we do not expect the device to be called for any follow up.
  83. self.assertEqual(0, device_mock.createFormPart.call_count)
  84. @patch("cura.Settings.CuraContainerRegistry")
  85. @patch("UM.Application")
  86. def test__onGetRemoteMaterials_withInvalidVersionInLocalMaterial(self, application_mock, container_registry_mock,
  87. reply_mock, device_mock):
  88. reply_mock.attribute.return_value = 200
  89. reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
  90. localMaterialWhiteWithInvalidVersion = self._LOCAL_MATERIAL_WHITE.copy()
  91. localMaterialWhiteWithInvalidVersion["version"] = "one"
  92. container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithInvalidVersion]
  93. application_mock.getContainerRegistry.return_value = container_registry_mock
  94. with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
  95. job = SendMaterialJob(device_mock)
  96. job._onGetRemoteMaterials(reply_mock)
  97. self.assertEqual(0, device_mock.createFormPart.call_count)
  98. @patch("cura.Settings.CuraContainerRegistry")
  99. @patch("UM.Application")
  100. def test__onGetRemoteMaterials_withNoUpdate(self, application_mock, container_registry_mock, reply_mock,
  101. device_mock):
  102. application_mock.getContainerRegistry.return_value = container_registry_mock
  103. device_mock.createFormPart.return_value = "_xXx_"
  104. container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE]
  105. reply_mock.attribute.return_value = 200
  106. reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
  107. with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
  108. job = SendMaterialJob(device_mock)
  109. job._onGetRemoteMaterials(reply_mock)
  110. self.assertEqual(0, device_mock.createFormPart.call_count)
  111. self.assertEqual(0, device_mock.postFormWithParts.call_count)
  112. @patch("cura.Settings.CuraContainerRegistry")
  113. @patch("UM.Application")
  114. def test__onGetRemoteMaterials_withUpdatedMaterial(self, application_mock, container_registry_mock, reply_mock,
  115. device_mock):
  116. application_mock.getContainerRegistry.return_value = container_registry_mock
  117. device_mock.createFormPart.return_value = "_xXx_"
  118. localMaterialWhiteWithHigherVersion = self._LOCAL_MATERIAL_WHITE.copy()
  119. localMaterialWhiteWithHigherVersion["version"] = "2"
  120. container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithHigherVersion]
  121. reply_mock.attribute.return_value = 200
  122. reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
  123. with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
  124. job = SendMaterialJob(device_mock)
  125. job._onGetRemoteMaterials(reply_mock)
  126. self.assertEqual(1, device_mock.createFormPart.call_count)
  127. self.assertEqual(1, device_mock.postFormWithParts.call_count)
  128. self.assertEquals(
  129. [call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", "<xml></xml>"),
  130. call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)],
  131. device_mock.method_calls)
  132. @patch("cura.Settings.CuraContainerRegistry")
  133. @patch("UM.Application")
  134. def test__onGetRemoteMaterials_withNewMaterial(self, application_mock, container_registry_mock, reply_mock,
  135. device_mock):
  136. application_mock.getContainerRegistry.return_value = container_registry_mock
  137. device_mock.createFormPart.return_value = "_xXx_"
  138. container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE,
  139. self._LOCAL_MATERIAL_BLACK]
  140. reply_mock.attribute.return_value = 200
  141. reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_BLACK]).encode("ascii"))
  142. with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
  143. job = SendMaterialJob(device_mock)
  144. job._onGetRemoteMaterials(reply_mock)
  145. self.assertEqual(1, device_mock.createFormPart.call_count)
  146. self.assertEqual(1, device_mock.postFormWithParts.call_count)
  147. self.assertEquals(
  148. [call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", "<xml></xml>"),
  149. call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)],
  150. device_mock.method_calls)