Merge branch 'tests-for-um3networkplugin' of https://github.com/Ultimaker/Cura into tests-for-um3networkplugin

This commit is contained in:
ChrisTerBeke 2018-11-23 11:27:41 +01:00
commit e3894c291c
5 changed files with 204 additions and 299 deletions

43
Jenkinsfile vendored
View File

@ -38,20 +38,9 @@ parallel_nodes(['linux && cura', 'windows && cura'])
{ {
if (isUnix()) if (isUnix())
{ {
// For Linux to show everything // For Linux
def branch = env.BRANCH_NAME
if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}"))
{
branch = "master"
}
def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}")
try { try {
sh """ sh 'make CTEST_OUTPUT_ON_FAILURE=TRUE test'
cd ..
export PYTHONPATH=.:"${uranium_dir}"
${env.CURA_ENVIRONMENT_PATH}/${branch}/bin/pytest -x --verbose --full-trace --capture=no ./tests
"""
} catch(e) } catch(e)
{ {
currentBuild.result = "UNSTABLE" currentBuild.result = "UNSTABLE"
@ -70,34 +59,6 @@ parallel_nodes(['linux && cura', 'windows && cura'])
} }
} }
} }
stage('Code Style')
{
if (isUnix())
{
// For Linux to show everything.
// CMake also runs this test, but if it fails then the test just shows "failed" without details of what exactly failed.
def branch = env.BRANCH_NAME
if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}"))
{
branch = "master"
}
def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}")
try
{
sh """
cd ..
export PYTHONPATH=.:"${uranium_dir}"
${env.CURA_ENVIRONMENT_PATH}/${branch}/bin/python3 run_mypy.py
"""
}
catch(e)
{
currentBuild.result = "UNSTABLE"
}
}
}
} }
} }

View File

@ -2,31 +2,32 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from collections import namedtuple from collections import namedtuple
ClusterMaterial = namedtuple('ClusterMaterial', [ ClusterMaterial = namedtuple("ClusterMaterial", [
'guid', "guid", # Type: str
'material', "material", # Type: str
'brand', "brand", # Type: str
'version', "version", # Type: int
'color', "color", # Type: str
'density' "density" # Type: str
]) ])
LocalMaterial = namedtuple('LocalMaterial', [ LocalMaterial = namedtuple("LocalMaterial", [
'GUID', "GUID", # Type: str
'id', "id", # Type: str
'type', "type", # Type: str
'status', "status", # Type: str
'base_file', "base_file", # Type: str
'setting_version', "setting_version", # Type: int
'version', "version", # Type: int
'name', "name", # Type: str
'brand', "brand", # Type: str
'material', "material", # Type: str
'color_name', "color_name", # Type: str
'description', "color_code", # Type: str
'adhesion_info', "description", # Type: str
'approximate_diameter', "adhesion_info", # Type: str
'properties', "approximate_diameter", # Type: str
'definition', "properties", # Type: str
'compatible' "definition", # Type: str
"compatible" # Type: str
]) ])

View File

@ -7,12 +7,12 @@ from typing import Dict, TYPE_CHECKING, Set
from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
from UM.Application import Application
from UM.Job import Job from UM.Job import Job
from UM.Logger import Logger from UM.Logger import Logger
from UM.MimeTypeDatabase import MimeTypeDatabase from UM.MimeTypeDatabase import MimeTypeDatabase
from UM.Resources import Resources from UM.Resources import Resources
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
# Absolute imports don't work in plugins # Absolute imports don't work in plugins
from .Models import ClusterMaterial, LocalMaterial from .Models import ClusterMaterial, LocalMaterial
@ -28,7 +28,6 @@ class SendMaterialJob(Job):
def __init__(self, device: "ClusterUM3OutputDevice") -> None: def __init__(self, device: "ClusterUM3OutputDevice") -> None:
super().__init__() super().__init__()
self.device = device # type: ClusterUM3OutputDevice self.device = device # type: ClusterUM3OutputDevice
self._application = CuraApplication.getInstance() # type: CuraApplication
## Send the request to the printer and register a callback ## Send the request to the printer and register a callback
def run(self) -> None: def run(self) -> None:
@ -45,13 +44,9 @@ class SendMaterialJob(Job):
return return
# Collect materials from the printer's reply and send the missing ones if needed. # Collect materials from the printer's reply and send the missing ones if needed.
try:
remote_materials_by_guid = self._parseReply(reply) remote_materials_by_guid = self._parseReply(reply)
if remote_materials_by_guid:
self._sendMissingMaterials(remote_materials_by_guid) self._sendMissingMaterials(remote_materials_by_guid)
except json.JSONDecodeError:
Logger.logException("w", "Error parsing materials from printer")
except KeyError:
Logger.logException("w", "Error parsing materials from printer")
## Determine which materials should be updated and send them to the printer. ## Determine which materials should be updated and send them to the printer.
# #
@ -75,7 +70,8 @@ class SendMaterialJob(Job):
## From the local and remote materials, determine which ones should be synchronized. ## From the local and remote materials, determine which ones should be synchronized.
# #
# Makes a Set containing only the materials that are not on the printer yet or the ones that are newer in Cura. # Makes a Set of id's containing only the id's of the materials that are not on the printer yet or the ones that
# are newer in Cura.
# #
# \param local_materials The local materials by GUID. # \param local_materials The local materials by GUID.
# \param remote_materials The remote materials by GUID. # \param remote_materials The remote materials by GUID.
@ -83,7 +79,8 @@ class SendMaterialJob(Job):
def _determineMaterialsToSend(local_materials: Dict[str, LocalMaterial], def _determineMaterialsToSend(local_materials: Dict[str, LocalMaterial],
remote_materials: Dict[str, ClusterMaterial]) -> Set[str]: remote_materials: Dict[str, ClusterMaterial]) -> Set[str]:
return { return {
material.id for guid, material in local_materials.items() material.id
for guid, material in local_materials.items()
if guid not in remote_materials or material.version > remote_materials[guid].version if guid not in remote_materials or material.version > remote_materials[guid].version
} }
@ -152,12 +149,18 @@ class SendMaterialJob(Job):
# Parses the reply to a "/materials" request to the printer # Parses the reply to a "/materials" request to the printer
# #
# \return a dictionary of ClusterMaterial objects by GUID # \return a dictionary of ClusterMaterial objects by GUID
# \throw json.JSONDecodeError Raised when the reply does not contain a valid json string
# \throw KeyError Raised when on of the materials does not include a valid guid # \throw KeyError Raised when on of the materials does not include a valid guid
@classmethod @classmethod
def _parseReply(cls, reply: QNetworkReply) -> Dict[str, ClusterMaterial]: def _parseReply(cls, reply: QNetworkReply) -> Dict[str, ClusterMaterial]:
try:
remote_materials = json.loads(reply.readAll().data().decode("utf-8")) remote_materials = json.loads(reply.readAll().data().decode("utf-8"))
return {material["id"]: ClusterMaterial(**material) for material in remote_materials} return {material["guid"]: ClusterMaterial(**material) for material in remote_materials}
except UnicodeDecodeError:
Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.")
except json.JSONDecodeError:
Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.")
except TypeError:
Logger.log("e", "Request material storage on printer: Printer's answer was missing GUIDs.")
## Retrieves a list of local materials ## Retrieves a list of local materials
# #
@ -166,16 +169,25 @@ class SendMaterialJob(Job):
# \return a dictionary of LocalMaterial objects by GUID # \return a dictionary of LocalMaterial objects by GUID
def _getLocalMaterials(self) -> Dict[str, LocalMaterial]: def _getLocalMaterials(self) -> Dict[str, LocalMaterial]:
result = {} # type: Dict[str, LocalMaterial] result = {} # type: Dict[str, LocalMaterial]
container_registry = self._application.getContainerRegistry() container_registry = Application.getInstance().getContainerRegistry()
material_containers = container_registry.findContainersMetadata(type = "material") material_containers = container_registry.findContainersMetadata(type = "material")
# Find the latest version of all material containers in the registry. # Find the latest version of all material containers in the registry.
local_materials = {} # type: Dict[str, LocalMaterial]
for material in material_containers: for material in material_containers:
try: try:
material = LocalMaterial(**material) # material version must be an int
if material.GUID not in result or material.version > result.get(material.GUID).version: material["version"] = int(material["version"])
local_materials[material.GUID] = material
# Create a new local material
local_material = LocalMaterial(**material)
if local_material.GUID not in result or \
local_material.version > result.get(local_material.GUID).version:
result[local_material.GUID] = local_material
except KeyError:
Logger.logException("w", "Local material {} has missing values.".format(material["id"]))
except ValueError: except ValueError:
Logger.logException("w", "Local material {} has invalid values.".format(material["id"])) Logger.logException("w", "Local material {} has invalid values.".format(material["id"]))
return result return result

View File

@ -1,55 +1,27 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import io
import json import json
from unittest import TestCase, mock
from typing import Any, List
from unittest import TestCase
from unittest.mock import patch, call from unittest.mock import patch, call
from PyQt5.QtCore import QByteArray from PyQt5.QtCore import QByteArray
from UM.Settings.ContainerRegistry import ContainerInterface, ContainerRegistryInterface, DefinitionContainerInterface from UM.MimeTypeDatabase import MimeType
from plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice import ClusterUM3OutputDevice from UM.Application import Application
from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob
class ContainerRegistryMock(ContainerRegistryInterface): @patch("builtins.open", lambda _, __: io.StringIO("<xml></xml>"))
@patch("UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile",
def __init__(self): lambda _: MimeType(name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile",
self.containersMetaData = None suffixes = ["xml.fdm_material"]))
@patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: ["/materials/generic_pla_white.xml.fdm_material"])
def findContainers(self, *, ignore_case: bool = False, **kwargs: Any) -> List[ContainerInterface]: @patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice")
raise NotImplementedError() @patch("PyQt5.QtNetwork.QNetworkReply")
def findDefinitionContainers(self, **kwargs: Any) -> List[DefinitionContainerInterface]:
raise NotImplementedError()
@classmethod
def getApplication(cls) -> "Application":
raise NotImplementedError()
def getEmptyInstanceContainer(self) -> "InstanceContainer":
raise NotImplementedError()
def isReadOnly(self, container_id: str) -> bool:
raise NotImplementedError()
def setContainersMetadata(self, value):
self.containersMetaData = value
def findContainersMetadata(self, type):
return self.containersMetaData
class MockOutputDevice(ClusterUM3OutputDevice):
def _createFormPart(self, content_header, data, content_type=None):
return "xxx"
class TestSendMaterialJob(TestCase): class TestSendMaterialJob(TestCase):
_LOCAL_MATERIAL_WHITE = {"type": "material", "status": "unknown", "id": "generic_pla_white", _LOCAL_MATERIAL_WHITE = {"type": "material", "status": "unknown", "id": "generic_pla_white",
"base_file": "generic_pla_white", "setting_version": 5, "name": "White PLA", "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA",
"brand": "Generic", "material": "PLA", "color_name": "White", "brand": "Generic", "material": "PLA", "color_name": "White",
"GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "1", "color_code": "#ffffff", "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "1", "color_code": "#ffffff",
"description": "Test PLA White", "adhesion_info": "Use glue.", "approximate_diameter": "3", "description": "Test PLA White", "adhesion_info": "Use glue.", "approximate_diameter": "3",
@ -57,7 +29,7 @@ class TestSendMaterialJob(TestCase):
"definition": "fdmprinter", "compatible": True} "definition": "fdmprinter", "compatible": True}
_LOCAL_MATERIAL_BLACK = {"type": "material", "status": "unknown", "id": "generic_pla_black", _LOCAL_MATERIAL_BLACK = {"type": "material", "status": "unknown", "id": "generic_pla_black",
"base_file": "generic_pla_black", "setting_version": 5, "name": "Yellow CPE", "base_file": "generic_pla_black", "setting_version": "5", "name": "Yellow CPE",
"brand": "Ultimaker", "material": "CPE", "color_name": "Black", "brand": "Ultimaker", "material": "CPE", "color_name": "Black",
"GUID": "5fbb362a-41f9-4818-bb43-15ea6df34aa4", "version": "1", "color_code": "#000000", "GUID": "5fbb362a-41f9-4818-bb43-15ea6df34aa4", "version": "1", "color_code": "#000000",
"description": "Test PLA Black", "adhesion_info": "Use glue.", "approximate_diameter": "3", "description": "Test PLA Black", "adhesion_info": "Use glue.", "approximate_diameter": "3",
@ -82,17 +54,14 @@ class TestSendMaterialJob(TestCase):
"density": 1.00 "density": 1.00
} }
@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") def test_run(self, device_mock, reply_mock):
def test_run(self, device_mock):
job = SendMaterialJob(device_mock) job = SendMaterialJob(device_mock)
job.run() job.run()
# We expect the materials endpoint to be called when the job runs. # We expect the materials endpoint to be called when the job runs.
device_mock.get.assert_called_with("materials/", on_finished=job._onGetRemoteMaterials) device_mock.get.assert_called_with("materials/", on_finished = job._onGetRemoteMaterials)
@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") def test__onGetRemoteMaterials_withFailedRequest(self, reply_mock, device_mock):
@patch("PyQt5.QtNetwork.QNetworkReply")
def test_sendMissingMaterials_withFailedRequest(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 404 reply_mock.attribute.return_value = 404
job = SendMaterialJob(device_mock) job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock) job._onGetRemoteMaterials(reply_mock)
@ -101,9 +70,18 @@ class TestSendMaterialJob(TestCase):
self.assertEqual([call.attribute(0), call.errorString()], reply_mock.method_calls) self.assertEqual([call.attribute(0), call.errorString()], reply_mock.method_calls)
self.assertEqual(0, device_mock.createFormPart.call_count) self.assertEqual(0, device_mock.createFormPart.call_count)
@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") def test__onGetRemoteMaterials_withWrongEncoding(self, reply_mock, device_mock):
@patch("PyQt5.QtNetwork.QNetworkReply") reply_mock.attribute.return_value = 200
def test_sendMissingMaterials_withBadJsonAnswer(self, reply_mock, device_mock): reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("cp500"))
job = SendMaterialJob(device_mock)
job._onGetRemoteMaterials(reply_mock)
# We expect the reply to be called once to try to get the printers from the list (readAll()).
# Given that the parsing fails we do no expect the device to be called for any follow up.
self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
self.assertEqual(0, device_mock.createFormPart.call_count)
def test__onGetRemoteMaterials_withBadJsonAnswer(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 200 reply_mock.attribute.return_value = 200
reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.") reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.")
job = SendMaterialJob(device_mock) job = SendMaterialJob(device_mock)
@ -114,9 +92,7 @@ class TestSendMaterialJob(TestCase):
self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls) self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
self.assertEqual(0, device_mock.createFormPart.call_count) self.assertEqual(0, device_mock.createFormPart.call_count)
@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") def test__onGetRemoteMaterials_withMissingGuidInRemoteMaterial(self, reply_mock, device_mock):
@patch("PyQt5.QtNetwork.QNetworkReply")
def test_sendMissingMaterials_withMissingGuid(self, reply_mock, device_mock):
reply_mock.attribute.return_value = 200 reply_mock.attribute.return_value = 200
remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy() remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy()
del remote_material_without_guid["guid"] del remote_material_without_guid["guid"]
@ -127,151 +103,106 @@ class TestSendMaterialJob(TestCase):
# We expect the reply to be called once to try to get the printers from the list (readAll()). # We expect the reply to be called once to try to get the printers from the list (readAll()).
# Given that parsing fails we do not expect the device to be called for any follow up. # Given that parsing fails we do not expect the device to be called for any follow up.
self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls) self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
self.assertEqual(1, device_mock.createFormPart.call_count) self.assertEqual(0, device_mock.createFormPart.call_count)
# @patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: []) @patch("cura.Settings.CuraContainerRegistry")
# @patch("PyQt5.QtNetwork.QNetworkReply") @patch("UM.Application")
# def test_sendMissingMaterials_WithInvalidVersionInLocalMaterial(self, reply_mock): def test__onGetRemoteMaterials_withInvalidVersionInLocalMaterial(self, application_mock, container_registry_mock,
# reply_mock.attribute.return_value = 200 reply_mock, device_mock):
# reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTEMATERIAL_WHITE]).encode("ascii")) reply_mock.attribute.return_value = 200
# reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
# containerRegistry = ContainerRegistryMock()
# localMaterialWhiteWithInvalidVersion = self._LOCALMATERIAL_WHITE.copy() localMaterialWhiteWithInvalidVersion = self._LOCAL_MATERIAL_WHITE.copy()
# localMaterialWhiteWithInvalidVersion["version"] = "one" localMaterialWhiteWithInvalidVersion["version"] = "one"
# containerRegistry.setContainersMetadata([localMaterialWhiteWithInvalidVersion]) container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithInvalidVersion]
#
# with mock.patch.object(Logger, "log", new=new_log): application_mock.getContainerRegistry.return_value = container_registry_mock
# with mock.patch.object(ContainerRegistry, "getInstance", lambda: containerRegistry):
# SendMaterialJob(None).sendMissingMaterials(reply_mock) with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
# job = SendMaterialJob(device_mock)
# reply_mock.attribute.assert_called_with(0) job._onGetRemoteMaterials(reply_mock)
# self.assertEqual(reply_mock.method_calls, [call.attribute(0), call.readAll()])
# self._assertLogEntries([("e", "Material generic_pla_white has invalid version number one.")], _logentries) self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
# self.assertEqual([call.getContainerRegistry()], application_mock.method_calls)
# @patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: []) self.assertEqual([call.findContainersMetadata(type = "material")], container_registry_mock.method_calls)
# @patch("PyQt5.QtNetwork.QNetworkReply") self.assertEqual(0, device_mock.createFormPart.call_count)
# def test_sendMissingMaterials_WithMultipleLocalVersionsLowFirst(self, reply_mock):
# reply_mock.attribute.return_value = 200 @patch("cura.Settings.CuraContainerRegistry")
# reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTEMATERIAL_WHITE]).encode("ascii")) @patch("UM.Application")
# def test__onGetRemoteMaterials_withNoUpdate(self, application_mock, container_registry_mock, reply_mock,
# containerRegistry = ContainerRegistryMock() device_mock):
# localMaterialWhiteWithHigherVersion = self._LOCALMATERIAL_WHITE.copy() application_mock.getContainerRegistry.return_value = container_registry_mock
# localMaterialWhiteWithHigherVersion["version"] = "2"
# containerRegistry.setContainersMetadata([self._LOCALMATERIAL_WHITE, localMaterialWhiteWithHigherVersion]) device_mock.createFormPart.return_value = "_xXx_"
#
# with mock.patch.object(Logger, "log", new=new_log): container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE]
# with mock.patch.object(ContainerRegistry, "getInstance", lambda: containerRegistry):
# SendMaterialJob(None).sendMissingMaterials(reply_mock) reply_mock.attribute.return_value = 200
# reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
# reply_mock.attribute.assert_called_with(0)
# self.assertEqual(reply_mock.method_calls, [call.attribute(0), call.readAll()]) with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
# self._assertLogEntries([], _logentries) job = SendMaterialJob(device_mock)
# job._onGetRemoteMaterials(reply_mock)
# @patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: [])
# @patch("PyQt5.QtNetwork.QNetworkReply") self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
# def test_sendMissingMaterials_MaterialMissingOnPrinter(self, reply_mock): self.assertEqual([call.getContainerRegistry()], application_mock.method_calls)
# reply_mock.attribute.return_value = 200 self.assertEqual([call.findContainersMetadata(type = "material")], container_registry_mock.method_calls)
# reply_mock.readAll.return_value = QByteArray( self.assertEqual(0, device_mock.createFormPart.call_count)
# json.dumps([self._REMOTEMATERIAL_WHITE]).encode("ascii")) self.assertEqual(0, device_mock.postFormWithParts.call_count)
#
# containerRegistry = ContainerRegistryMock() @patch("cura.Settings.CuraContainerRegistry")
# containerRegistry.setContainersMetadata([self._LOCALMATERIAL_WHITE, self._LOCALMATERIAL_BLACK]) @patch("UM.Application")
# def test__onGetRemoteMaterials_withUpdatedMaterial(self, application_mock, container_registry_mock, reply_mock,
# with mock.patch.object(Logger, "log", new=new_log): device_mock):
# with mock.patch.object(ContainerRegistry, "getInstance", lambda: containerRegistry): application_mock.getContainerRegistry.return_value = container_registry_mock
# SendMaterialJob(None).sendMissingMaterials(reply_mock)
# device_mock.createFormPart.return_value = "_xXx_"
# reply_mock.attribute.assert_called_with(0)
# self.assertEqual(reply_mock.method_calls, [call.attribute(0), call.readAll()]) localMaterialWhiteWithHigherVersion = self._LOCAL_MATERIAL_WHITE.copy()
# self._assertLogEntries([], _logentries) localMaterialWhiteWithHigherVersion["version"] = "2"
# container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithHigherVersion]
# @patch("builtins.open", lambda a, b: io.StringIO("<xml></xml>"))
# @patch("UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile", reply_mock.attribute.return_value = 200
# lambda _: MimeType(name="application/x-ultimaker-material-profile", comment="Ultimaker Material Profile", reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
# suffixes=["xml.fdm_material"]))
# @patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: ["/materials/generic_pla_white.xml.fdm_material"]) with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
# @patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") job = SendMaterialJob(device_mock)
# def test_sendMaterialsToPrinter(self, device_mock): job._onGetRemoteMaterials(reply_mock)
# device_mock._createFormPart.return_value = "_xXx_"
# with mock.patch.object(Logger, "log", new=new_log): self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
# job = SendMaterialJob(device_mock) self.assertEqual([call.getContainerRegistry()], application_mock.method_calls)
# job.sendMaterialsToPrinter({"generic_pla_white"}) self.assertEqual([call.findContainersMetadata(type = "material")], container_registry_mock.method_calls)
# self.assertEqual(1, device_mock.createFormPart.call_count)
# self._assertLogEntries([("d", "Syncing material generic_pla_white with cluster.")], _logentries) self.assertEqual(1, device_mock.postFormWithParts.call_count)
# self.assertEqual([call._createFormPart("name="file"; filename="generic_pla_white.xml.fdm_material"", "<xml></xml>"), self.assertEquals(
# call.postFormWithParts(on_finished=job.sendingFinished, parts = ["_xXx_"], target = "materials/")], device_mock.method_calls) [call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", "<xml></xml>"),
# call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)],
# @patch("PyQt5.QtNetwork.QNetworkReply") device_mock.method_calls)
# def test_sendingFinished_success(self, reply_mock) -> None:
# reply_mock.attribute.return_value = 200 @patch("cura.Settings.CuraContainerRegistry")
# with mock.patch.object(Logger, "log", new=new_log): @patch("UM.Application")
# SendMaterialJob(None).sendingFinished(reply_mock) def test__onGetRemoteMaterials_withNewMaterial(self, application_mock, container_registry_mock, reply_mock,
# device_mock):
# reply_mock.attribute.assert_called_once_with(0) application_mock.getContainerRegistry.return_value = container_registry_mock
# self.assertEqual(0, len(_logentries))
# device_mock.createFormPart.return_value = "_xXx_"
# @patch("PyQt5.QtNetwork.QNetworkReply")
# def test_sendingFinished_failed(self, reply_mock) -> None: container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE,
# reply_mock.attribute.return_value = 404 self._LOCAL_MATERIAL_BLACK]
# reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.")
# reply_mock.attribute.return_value = 200
# with mock.patch.object(Logger, "log", new=new_log): reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_BLACK]).encode("ascii"))
# SendMaterialJob(None).sendingFinished(reply_mock)
# with mock.patch.object(Application, "getInstance", new = lambda: application_mock):
# reply_mock.attribute.assert_called_with(0) job = SendMaterialJob(device_mock)
# self.assertEqual(reply_mock.method_calls, [call.attribute(0), call.attribute(0), call.readAll()]) job._onGetRemoteMaterials(reply_mock)
#
# self._assertLogEntries([ self.assertEqual([call.attribute(0), call.readAll()], reply_mock.method_calls)
# ("e", "Received error code from printer when syncing material: 404"), self.assertEqual([call.getContainerRegistry()], application_mock.method_calls)
# ("e", "Six sick hicks nick six slick bricks with picks and sticks.") self.assertEqual([call.findContainersMetadata(type = "material")], container_registry_mock.method_calls)
# ], _logentries) self.assertEqual(1, device_mock.createFormPart.call_count)
# self.assertEqual(1, device_mock.postFormWithParts.call_count)
# @patch("PyQt5.QtNetwork.QNetworkReply") self.assertEquals(
# def test_parseReply(self, reply_mock): [call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", "<xml></xml>"),
# reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTEMATERIAL_WHITE]).encode("ascii")) call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)],
# device_mock.method_calls)
# response = SendMaterialJob._parseReply(reply_mock)
#
# self.assertTrue(len(response) == 1)
# self.assertEqual(next(iter(response.values())), ClusterMaterial(**self._REMOTEMATERIAL_WHITE))
#
# @patch("PyQt5.QtNetwork.QNetworkReply")
# def test_parseReplyWithInvalidMaterial(self, reply_mock):
# remoteMaterialWithInvalidVersion = self._REMOTEMATERIAL_WHITE.copy()
# remoteMaterialWithInvalidVersion["version"] = "one"
# reply_mock.readAll.return_value = QByteArray(json.dumps([remoteMaterialWithInvalidVersion]).encode("ascii"))
#
# with self.assertRaises(ValueError):
# SendMaterialJob._parseReply(reply_mock)
#
# def test__getLocalMaterials(self):
# containerRegistry = ContainerRegistryMock()
# containerRegistry.setContainersMetadata([self._LOCALMATERIAL_WHITE, self._LOCALMATERIAL_BLACK])
#
# with mock.patch.object(Logger, "log", new=new_log):
# with mock.patch.object(ContainerRegistry, "getInstance", lambda: containerRegistry):
# local_materials = SendMaterialJob(None)._getLocalMaterials()
#
# self.assertTrue(len(local_materials) == 2)
#
# def test__getLocalMaterialsWithMultipleVersions(self):
# containerRegistry = ContainerRegistryMock()
# localMaterialWithNewerVersion = self._LOCALMATERIAL_WHITE.copy()
# localMaterialWithNewerVersion["version"] = 2
# containerRegistry.setContainersMetadata([self._LOCALMATERIAL_WHITE, localMaterialWithNewerVersion])
#
# with mock.patch.object(Logger, "log", new=new_log):
# with mock.patch.object(ContainerRegistry, "getInstance", lambda: containerRegistry):
# local_materials = SendMaterialJob(None)._getLocalMaterials()
#
# self.assertTrue(len(local_materials) == 1)
# self.assertTrue(list(local_materials.values())[0].version == 2)
#
# containerRegistry.setContainersMetadata([localMaterialWithNewerVersion, self._LOCALMATERIAL_WHITE])
#
# with mock.patch.object(Logger, "log", new=new_log):
# with mock.patch.object(ContainerRegistry, "getInstance", lambda: containerRegistry):
# local_materials = SendMaterialJob(None)._getLocalMaterials()
#
# self.assertTrue(len(local_materials) == 1)
# self.assertTrue(list(local_materials.values())[0].version == 2)

View File

@ -73,7 +73,7 @@ UM.Dialog
{ {
top: parent.top top: parent.top
left: parent.left left: parent.left
topMargin: UM.Theme.getSize("default_margin") topMargin: UM.Theme.getSize("default_margin").height
} }
text: catalog.i18nc("@title:tab", "Add a printer to Cura") text: catalog.i18nc("@title:tab", "Add a printer to Cura")