TestMachineManager.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. import functools
  2. from unittest.mock import MagicMock, patch, PropertyMock
  3. import pytest
  4. from cura.Settings.MachineManager import MachineManager
  5. def createMockedStack(stack_id: str, name: str):
  6. stack = MagicMock(name=name)
  7. stack.getId = MagicMock(return_value=stack_id)
  8. return stack
  9. def getPropertyMocked(setting_key, setting_property, settings_dict):
  10. """
  11. Mocks the getProperty function of containers so that it returns the setting values needed for a test.
  12. Use this function as follows:
  13. container.getProperty = functools.partial(getPropertyMocked, settings_dict = {"print_sequence": "one_at_a_time"})
  14. :param setting_key: The key of the setting to be returned (e.g. "print_sequence", "infill_sparse_density" etc)
  15. :param setting_property: The setting property (usually "value")
  16. :param settings_dict: All the settings and their values expected to be returned by this mocked function
  17. :return: The mocked setting value specified by the settings_dict
  18. """
  19. if setting_property == "value":
  20. return settings_dict.get(setting_key)
  21. return None
  22. @pytest.fixture()
  23. def global_stack():
  24. return createMockedStack("GlobalStack", "Global Stack")
  25. @pytest.fixture()
  26. def machine_manager(application, extruder_manager, container_registry, global_stack) -> MachineManager:
  27. application.getExtruderManager = MagicMock(return_value = extruder_manager)
  28. application.getGlobalContainerStack = MagicMock(return_value = global_stack)
  29. with patch("cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance", MagicMock(return_value=container_registry)):
  30. manager = MachineManager(application)
  31. with patch.object(MachineManager, "updateNumberExtrudersEnabled", return_value = None):
  32. manager._onGlobalContainerChanged()
  33. return manager
  34. def test_getMachine():
  35. registry = MagicMock()
  36. mocked_global_stack = MagicMock()
  37. mocked_global_stack.getId = MagicMock(return_value="test_machine")
  38. mocked_global_stack.definition.getId = MagicMock(return_value = "test")
  39. registry.findContainerStacks = MagicMock(return_value=[mocked_global_stack])
  40. with patch("cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance", MagicMock(return_value=registry)):
  41. assert MachineManager.getMachine("test") == mocked_global_stack
  42. # Since only test is in the registry, this should be None
  43. assert MachineManager.getMachine("UnknownMachine") is None
  44. def test_addMachine(machine_manager):
  45. registry = MagicMock()
  46. mocked_stack = MagicMock()
  47. mocked_stack.getId = MagicMock(return_value="newlyCreatedStack")
  48. mocked_create_machine = MagicMock(name="createMachine", return_value = mocked_stack)
  49. machine_manager.setActiveMachine = MagicMock()
  50. with patch("cura.Settings.CuraStackBuilder.CuraStackBuilder.createMachine", mocked_create_machine):
  51. with patch("cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance", MagicMock(return_value=registry)):
  52. machine_manager.addMachine("derp")
  53. machine_manager.setActiveMachine.assert_called_with("newlyCreatedStack")
  54. def test_hasUserSettings(machine_manager, application):
  55. mocked_stack = application.getGlobalContainerStack()
  56. mocked_instance_container = MagicMock(name="UserSettingContainer")
  57. mocked_instance_container.getNumInstances = MagicMock(return_value = 12)
  58. mocked_stack.getTop = MagicMock(return_value = mocked_instance_container)
  59. machine_manager._reCalculateNumUserSettings()
  60. assert machine_manager.numUserSettings == 12
  61. assert machine_manager.hasUserSettings
  62. def test_hasUserSettingsExtruder(machine_manager, application):
  63. mocked_stack = application.getGlobalContainerStack()
  64. extruder = createMockedExtruder("extruder")
  65. mocked_instance_container_global = MagicMock(name="UserSettingContainerGlobal")
  66. mocked_instance_container_global.getNumInstances = MagicMock(return_value=0)
  67. mocked_stack.getTop = MagicMock(return_value=mocked_instance_container_global)
  68. mocked_stack.extruderList = [extruder]
  69. mocked_instance_container = MagicMock(name="UserSettingContainer")
  70. mocked_instance_container.getNumInstances = MagicMock(return_value=200)
  71. extruder.getTop = MagicMock(return_value = mocked_instance_container)
  72. machine_manager._reCalculateNumUserSettings()
  73. assert machine_manager.hasUserSettings
  74. assert machine_manager.numUserSettings == 200
  75. def test_hasUserSettingsEmptyUserChanges(machine_manager, application):
  76. mocked_stack = application.getGlobalContainerStack()
  77. extruder = createMockedExtruder("extruder")
  78. mocked_instance_container_global = MagicMock(name="UserSettingContainerGlobal")
  79. mocked_instance_container_global.getNumInstances = MagicMock(return_value=0)
  80. mocked_stack.getTop = MagicMock(return_value=mocked_instance_container_global)
  81. mocked_stack.extruderList = [extruder]
  82. mocked_instance_container = MagicMock(name="UserSettingContainer")
  83. mocked_instance_container.getNumInstances = MagicMock(return_value=0)
  84. extruder.getTop = MagicMock(return_value = mocked_instance_container)
  85. machine_manager._reCalculateNumUserSettings()
  86. assert not machine_manager.hasUserSettings
  87. def test_totalNumberOfSettings(machine_manager):
  88. registry = MagicMock()
  89. mocked_definition = MagicMock()
  90. mocked_definition.getAllKeys = MagicMock(return_value = ["omg", "zomg", "foo"])
  91. registry.findDefinitionContainers = MagicMock(return_value = [mocked_definition])
  92. with patch("cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance", MagicMock(return_value=registry)):
  93. assert machine_manager.totalNumberOfSettings == 3
  94. def createMockedExtruder(extruder_id):
  95. extruder = MagicMock()
  96. extruder.getId = MagicMock(return_value = extruder_id)
  97. return extruder
  98. def createMockedInstanceContainer(instance_id, name = ""):
  99. instance = MagicMock()
  100. instance.getName = MagicMock(return_value = name)
  101. instance.getId = MagicMock(return_value=instance_id)
  102. return instance
  103. def test_globalVariantName(machine_manager, application):
  104. global_stack = application.getGlobalContainerStack()
  105. global_stack.variant = createMockedInstanceContainer("beep", "zomg")
  106. assert machine_manager.globalVariantName == "zomg"
  107. def test_resetSettingForAllExtruders(machine_manager):
  108. global_stack = machine_manager.activeMachine
  109. extruder_1 = createMockedExtruder("extruder_1")
  110. extruder_2 = createMockedExtruder("extruder_2")
  111. extruder_1.userChanges = createMockedInstanceContainer("settings_1")
  112. extruder_2.userChanges = createMockedInstanceContainer("settings_2")
  113. global_stack.extruderList = [extruder_1, extruder_2]
  114. machine_manager.resetSettingForAllExtruders("whatever")
  115. extruder_1.userChanges.removeInstance.assert_called_once_with("whatever")
  116. extruder_2.userChanges.removeInstance.assert_called_once_with("whatever")
  117. def test_setUnknownActiveMachine(machine_manager):
  118. machine_action_manager = MagicMock()
  119. machine_manager.getMachineActionManager = MagicMock(return_value = machine_action_manager)
  120. machine_manager.setActiveMachine("UnknownMachine")
  121. # The machine isn't known to us, so this should not happen!
  122. machine_action_manager.addDefaultMachineActions.assert_not_called()
  123. def test_clearActiveMachine(machine_manager):
  124. machine_manager.setActiveMachine(None)
  125. machine_manager._application.setGlobalContainerStack.assert_called_once_with(None)
  126. def test_setActiveMachine(machine_manager):
  127. registry = MagicMock()
  128. machine_action_manager = MagicMock()
  129. machine_manager._validateVariantsAndMaterials = MagicMock() # Not testing that function, so whatever.
  130. machine_manager._application.getMachineActionManager = MagicMock(return_value=machine_action_manager)
  131. global_stack = createMockedStack("NewMachine", "Newly created Machine")
  132. # Ensure that the container stack will be found
  133. registry.findContainerStacks = MagicMock(return_value = [global_stack])
  134. with patch("cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance", MagicMock(return_value=registry)):
  135. with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=registry)):
  136. with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"): # Prevent the FixSingleExtruder from being called
  137. machine_manager.setActiveMachine("NewMachine")
  138. machine_action_manager.addDefaultMachineActions.assert_called_once_with(global_stack)
  139. # Yeah sure. It's technically an implementation detail. But if this function wasn't called, it exited early somehow
  140. machine_manager._validateVariantsAndMaterials.assert_called_once_with(global_stack)
  141. def test_setInvalidActiveMachine(machine_manager):
  142. registry = MagicMock()
  143. global_stack = createMockedStack("InvalidMachine", "Newly created Machine")
  144. # This machine is just plain wrong!
  145. global_stack.isValid = MagicMock(return_value = False)
  146. # Ensure that the container stack will be found
  147. registry.findContainerStacks = MagicMock(return_value=[global_stack])
  148. configuration_error_message = MagicMock()
  149. with patch("cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance", MagicMock(return_value=registry)):
  150. with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=registry)):
  151. with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"): # Prevent the FixSingleExtruder from being called
  152. with patch("UM.ConfigurationErrorMessage.ConfigurationErrorMessage.getInstance", MagicMock(return_value = configuration_error_message)):
  153. machine_manager.setActiveMachine("InvalidMachine")
  154. # Notification stuff should happen now!
  155. configuration_error_message.addFaultyContainers.assert_called_once_with("InvalidMachine")
  156. def test_clearUserSettingsAllCurrentStacks(machine_manager, application):
  157. global_stack = application.getGlobalContainerStack()
  158. extruder_1 = createMockedExtruder("extruder_1")
  159. instance_container = createMockedInstanceContainer("user", "UserContainer")
  160. extruder_1.getTop = MagicMock(return_value = instance_container)
  161. global_stack.extruderList = [extruder_1]
  162. machine_manager.clearUserSettingAllCurrentStacks("some_setting")
  163. instance_container.removeInstance.assert_called_once_with("some_setting", postpone_emit=True)
  164. def test_clearUserSettingsAllCurrentStacksLinkedSetting(machine_manager, application):
  165. global_stack = application.getGlobalContainerStack()
  166. extruder_1 = createMockedExtruder("extruder_1")
  167. instance_container = createMockedInstanceContainer("user", "UserContainer")
  168. instance_container_global = createMockedInstanceContainer("global_user", "GlobalUserContainer")
  169. global_stack.getTop = MagicMock(return_value = instance_container_global)
  170. extruder_1.getTop = MagicMock(return_value=instance_container)
  171. global_stack.extruderList = [extruder_1]
  172. global_stack.getProperty = MagicMock(side_effect = lambda key, prop: True if prop == "settable_per_extruder" else "-1" )
  173. machine_manager.clearUserSettingAllCurrentStacks("some_setting")
  174. instance_container.removeInstance.assert_not_called()
  175. instance_container_global.removeInstance.assert_called_once_with("some_setting", postpone_emit = True)
  176. def test_isActiveQualityExperimental(machine_manager):
  177. quality_group = MagicMock(is_experimental = True)
  178. machine_manager.activeQualityGroup = MagicMock(return_value = quality_group)
  179. assert machine_manager.isActiveQualityExperimental
  180. def test_isActiveQualityNotExperimental(machine_manager):
  181. quality_group = MagicMock(is_experimental = False)
  182. machine_manager.activeQualityGroup = MagicMock(return_value = quality_group)
  183. assert not machine_manager.isActiveQualityExperimental
  184. def test_isActiveQualityNotExperimental_noQualityGroup(machine_manager):
  185. machine_manager.activeQualityGroup = MagicMock(return_value=None)
  186. assert not machine_manager.isActiveQualityExperimental
  187. def test_isActiveQualitySupported(machine_manager):
  188. quality_group = MagicMock(is_available=True)
  189. machine_manager.activeQualityGroup = MagicMock(return_value=quality_group)
  190. assert machine_manager.isActiveQualitySupported
  191. def test_isActiveQualityNotSupported(machine_manager):
  192. quality_group = MagicMock(is_available=False)
  193. machine_manager.activeQualityGroup = MagicMock(return_value=quality_group)
  194. assert not machine_manager.isActiveQualitySupported
  195. def test_isActiveQualityNotSupported_noQualityGroup(machine_manager):
  196. machine_manager.activeQualityGroup = MagicMock(return_value=None)
  197. assert not machine_manager.isActiveQualitySupported
  198. def test_correctPrintSequence_globalStackHasAllAtOnce(machine_manager, application):
  199. # Global container stack already has all_at_once
  200. mocked_stack = application.getGlobalContainerStack()
  201. mocked_global_settings = {"print_sequence": "all_at_once"}
  202. mocked_stack.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_global_settings)
  203. mocked_user_changes_container = MagicMock(name="UserChangesContainer")
  204. mocked_stack.userChanges = mocked_user_changes_container
  205. machine_manager.correctPrintSequence()
  206. # After the function is called, the user changes container should not have tried to change any properties
  207. assert not mocked_user_changes_container.setProperty.called, "The Print Sequence should not be attempted to be changed when it is already 'all-at-once'"
  208. def test_correctPrintSequence_OneEnabledExtruder(machine_manager, application):
  209. # Global container stack reports print sequence as one_at_a_time
  210. mocked_stack = application.getGlobalContainerStack()
  211. mocked_global_settings = {"print_sequence": "one_at_a_time"}
  212. mocked_stack.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_global_settings)
  213. # The definition changes container reports 1 enabled extruders, so the correctPrintSequence should not attempt to
  214. # change the print sequence
  215. mocked_definition_changes_container = MagicMock(name = "DefinitionChangesContainer")
  216. mocked_definition_changes_settings = {"extruders_enabled_count": 1}
  217. mocked_definition_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_definition_changes_settings)
  218. mocked_stack.definitionChanges = mocked_definition_changes_container
  219. mocked_user_changes_container = MagicMock(name = "UserChangesContainer")
  220. mocked_stack.userChanges = mocked_user_changes_container
  221. machine_manager.correctPrintSequence()
  222. # After the function is called, the user changes container should not have tried to change any properties
  223. assert not mocked_user_changes_container.setProperty.called, "The Print Sequence should not be attempted to be changed when there is only one enabled extruder."
  224. def test_correctPrintSequence_TwoExtrudersEnabled_printSequenceIsOneAtATimeInUserSettings(machine_manager, application):
  225. # Global container stack reports print sequence as one_at_a_time
  226. mocked_stack = application.getGlobalContainerStack()
  227. mocked_global_settings = {"print_sequence": "one_at_a_time"}
  228. mocked_stack.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_global_settings)
  229. # The definition changes container reports 2 enabled extruders. Also the print sequence change is not saved in the
  230. # quality changes container.
  231. mocked_definition_changes_container = MagicMock(name = "DefinitionChangesContainer")
  232. mocked_definition_changes_settings = {"extruders_enabled_count": 2, "print_sequence": None}
  233. mocked_definition_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_definition_changes_settings)
  234. mocked_stack.definitionChanges = mocked_definition_changes_container
  235. # The user changes container reports print sequence as "one-at-a-time"
  236. mocked_user_changes_container = MagicMock(name = "UserChangesContainer")
  237. mocked_user_changes_settings = {"print_sequence": "one_at_a_time"}
  238. mocked_user_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_user_changes_settings)
  239. mocked_stack.userChanges = mocked_user_changes_container
  240. machine_manager.correctPrintSequence()
  241. # After the function is called, the user changes container should have tried to remove the print sequence from the
  242. # user changes container
  243. mocked_user_changes_container.removeInstance.assert_called_once_with("print_sequence")
  244. def test_correctPrintSequence_TwoExtrudersEnabled_printSequenceIsOneAtATimeInDefinitionChangesSettings(machine_manager, application):
  245. # Global container stack reports print sequence as one_at_a_time
  246. mocked_stack = application.getGlobalContainerStack()
  247. mocked_global_settings = {"print_sequence": "one_at_a_time"}
  248. mocked_stack.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_global_settings)
  249. # The definition changes container reports 2 enabled extruders and contains the print_sequence change to "one-at-a-time"
  250. mocked_definition_changes_container = MagicMock(name = "DefinitionChangesContainer")
  251. mocked_definition_changes_settings = {"extruders_enabled_count": 2, "print_sequence": "one_at_a_time"}
  252. mocked_definition_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_definition_changes_settings)
  253. mocked_stack.definitionChanges = mocked_definition_changes_container
  254. # The user changes container doesn't contain print_sequence
  255. mocked_user_changes_container = MagicMock(name = "UserChangesContainer")
  256. mocked_user_changes_settings = {"print_sequence": None}
  257. mocked_user_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_user_changes_settings)
  258. mocked_stack.userChanges = mocked_user_changes_container
  259. machine_manager.correctPrintSequence()
  260. # After the function is called, the print sequence should be set to "all-at-once" in the user changes container
  261. mocked_user_changes_container.setProperty.assert_called_once_with("print_sequence", "value", "all_at_once")
  262. def test_correctPrintSequence_TwoExtrudersEnabled_printSequenceInUserAndDefinitionChangesSettingsIsNone(machine_manager, application):
  263. # Global container stack reports print sequence as one_at_a_time
  264. mocked_stack = application.getGlobalContainerStack()
  265. mocked_global_settings = {"print_sequence": "one_at_a_time"}
  266. mocked_stack.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_global_settings)
  267. # The definition changes container reports 2 enabled extruders but doesn't contain the print_sequence changes
  268. mocked_definition_changes_container = MagicMock(name = "DefinitionChangesContainer")
  269. mocked_definition_changes_settings = {"extruders_enabled_count": 2, "print_sequence": None}
  270. mocked_definition_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_definition_changes_settings)
  271. mocked_stack.definitionChanges = mocked_definition_changes_container
  272. # The user changes container doesn't contain the print_sequence changes
  273. mocked_user_changes_container = MagicMock(name = "UserChangesContainer")
  274. mocked_user_changes_settings = {"print_sequence": None}
  275. mocked_user_changes_container.getProperty = functools.partial(getPropertyMocked, settings_dict=mocked_user_changes_settings)
  276. mocked_stack.userChanges = mocked_user_changes_container
  277. machine_manager.correctPrintSequence()
  278. # After the function is called, the print sequence should be set to "all-at-once" in the user changes container
  279. mocked_user_changes_container.setProperty.assert_called_once_with("print_sequence", "value", "all_at_once")