1# Copyright (c) 2018 Ultimaker B.V.
2# Uranium is released under the terms of the LGPLv3 or higher.
3import os
4import pytest
5import unittest.mock
6from unittest.mock import MagicMock, patch
7
8from UM.PackageManager import PackageManager
9from UM.Version import Version
10
11test_package_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + "/UnitTestPackage.package")
12
13
14#@unittest.mock.patch.object(PackageManager, "__init__", lambda *args, **kwargs: None)
15def test_shouldInstallCandidate():
16
17    app_sdk = "2.2.3"
18    test_cases = [
19
20        # same sdk version, newer package
21        {"candidate_dict": {"sdk_version": app_sdk,
22                            "package_version": "1.1"},
23         "bundle_dict": {"sdk_version": app_sdk,
24                         "package_version": "1.0"},
25         "expected_result": True},
26
27        # compatible sdk version, newer package
28        {"candidate_dict": {"sdk_version": "2.1.1",
29                            "package_version": "1.1"},
30         "bundle_dict": {"sdk_version": app_sdk,
31                         "package_version": "1.0"},
32         "expected_result": True},
33
34        # incompatible sdk version (older)
35        {"candidate_dict": {"sdk_version": "1.0.0",
36                        "package_version": "1.1"},
37         "bundle_dict": {"sdk_version": app_sdk,
38                        "package_version": "1.0"},
39         "expected_result": False},
40
41        # incompatible sdk version (newer, same major)
42        {"candidate_dict": {"sdk_version": "2.4.0",
43                            "package_version": "1.1"},
44         "bundle_dict": {"sdk_version": app_sdk,
45                         "package_version": "1.0"},
46         "expected_result": False},
47
48        # same package versions, same sdk versions
49        {"candidate_dict": {"sdk_version": app_sdk,
50                            "package_version": "1.0"},
51         "bundle_dict": {"sdk_version": app_sdk,
52                         "package_version": "1.0"},
53         "expected_result": False},  # not an upgrade
54
55        # same package versions, compatible sdk versions
56        {"candidate_dict": {"sdk_version": "2.1.0",
57                        "package_version": "1.0"},
58         "bundle_dict": {"sdk_version": "2.2.3",
59                        "package_version": "1.0"},
60         "expected_result": False},  # not an upgrade
61
62        # older package versions, same sdk versions
63        {"candidate_dict": {"sdk_version": app_sdk,
64                        "package_version": "4.1"},
65         "bundle_dict": {"sdk_version": app_sdk,
66                        "package_version": "4.2"},
67         "expected_result": False},
68    ]
69
70    app = MagicMock()
71    app.getAPIVersion.return_value = Version(app_sdk)
72    package_manager = PackageManager(app)
73    for test_case_dict in test_cases:
74        candidate_dict = test_case_dict["candidate_dict"]
75        bundle_dict = test_case_dict["bundle_dict"]
76        expected_result = test_case_dict["expected_result"]
77
78        assert expected_result == package_manager._shouldInstallCandidate(candidate_dict, bundle_dict)
79
80
81def test_getLicense():
82    manager = PackageManager(MagicMock())
83    assert manager.getPackageLicense(test_package_path) == "Do whatever you want with this.\n"
84
85
86def test_installAndRemovePackage():
87    mock_application = MagicMock()
88    mock_registry = MagicMock()
89    mock_registry.isActivePlugin = MagicMock(return_value = False)
90    mock_application.getPluginRegistry = MagicMock(return_value = mock_registry)
91    manager = PackageManager(mock_application)
92    manager.installedPackagesChanged = MagicMock()
93    package_id = manager.installPackage(test_package_path)
94    assert manager.installedPackagesChanged.emit.call_count == 1
95    assert manager.isPackageInstalled("UnitTestPackage")
96    assert package_id == "UnitTestPackage"
97
98    info = manager.getInstalledPackageInfo("UnitTestPackage")
99    assert info["author"]["author_id"] == "nallath"
100    assert info["display_name"] == "UnitTestPackage"
101
102    # We don't want the package to be purged. We need that package for the other tests!
103    with patch("os.remove", MagicMock()):
104        manager._installPackage({"package_info": info, "filename": test_package_path})
105
106    assert "UnitTestPackage" in manager.getAllInstalledPackageIDs()
107    assert manager.isUserInstalledPackage("UnitTestPackage")
108    assert manager.getAllInstalledPackagesInfo()["plugin"][0]["display_name"] == "UnitTestPackage"
109    manager.initialize()
110    # Now to remove the package again!
111    manager.removePackage("UnitTestPackage")
112    assert manager.installedPackagesChanged.emit.call_count == 2
113
114
115def test_getPackageInfo():
116    manager = PackageManager(MagicMock())
117    info = manager.getPackageInfo(test_package_path)
118
119    assert info["author"]["author_id"] == "nallath"
120    assert info["display_name"] == "UnitTestPackage"
121
122
123def test_emptyInit():
124    manager = PackageManager(MagicMock())
125
126    assert not manager.getAllInstalledPackageIDs()
127    assert not manager.getAllInstalledPackagesInfo()
128
129    manager.installedPackagesChanged = MagicMock()
130    manager.removePackage("packageThatDoesNotExist")
131    assert manager.installedPackagesChanged.emit.call_count == 0
132
133    assert manager.getBundledPackageInfo("packageThatDoesNotExist") is None
134
135    with pytest.raises(FileNotFoundError):
136        assert manager.getPackageLicense("FileThatDoesntExist.package") == {}
137
138    assert manager.getPackageFiles("packageThatDoesNotExist") == []
139
140    assert manager.getPackageContainerIds("packageThatDoesNotExist") == []
141
142
143class TestAddAvailablePackageVersion:
144    def test_addNewVersionThatCanUpdate(self):
145        manager = PackageManager(MagicMock())
146        manager.checkIfPackageCanUpdate = MagicMock(return_value = True)
147        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
148
149        assert manager.packagesWithUpdate == {"beep"}
150
151    def test_addNewVersionThatCantUpdate(self):
152        manager = PackageManager(MagicMock())
153        manager.checkIfPackageCanUpdate = MagicMock(return_value=False)
154        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
155
156        assert manager.packagesWithUpdate == set()
157
158    def test_addMultipleVersions(self):
159        manager = PackageManager(MagicMock())
160        manager.checkIfPackageCanUpdate = MagicMock(return_value=True)
161        manager.addAvailablePackageVersion("beep", Version("1.2.0"))
162        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
163
164        assert manager.packagesWithUpdate == {"beep"}
165
166
167class TestCheckIfPackageCanUpdate:
168    def test_noAvailableVersions(self):
169        manager = PackageManager(MagicMock())
170        assert manager.checkIfPackageCanUpdate("beep") is False
171
172    def test_availableVersionNotInstalledOrBundled(self):
173        manager = PackageManager(MagicMock())
174        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
175
176        # Even though we have a known package version, it's not installed / bundled, so we cant update
177        assert manager.checkIfPackageCanUpdate("beep") is False
178
179    def test_olderVersionIsBundled(self):
180        manager = PackageManager(MagicMock())
181        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
182        manager._bundled_package_dict = {"beep": {"package_info": {"package_version": "0.9.0"}}}
183
184        assert manager.checkIfPackageCanUpdate("beep") is True
185
186    def test_newerVersionIsBundled(self):
187        manager = PackageManager(MagicMock())
188        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
189        manager._bundled_package_dict = {"beep": {"package_info": {"package_version": "1.9.0"}}}
190
191        assert manager.checkIfPackageCanUpdate("beep") is False
192
193    def test_olderVersionIsInstalled(self):
194        manager = PackageManager(MagicMock())
195        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
196        manager._installed_package_dict = {"beep": {"package_info": {"package_version": "0.9.0"}}}
197
198        assert manager.checkIfPackageCanUpdate("beep") is True
199
200    def test_newerVersionIsInstalled(self):
201        manager = PackageManager(MagicMock())
202        manager.addAvailablePackageVersion("beep", Version("1.0.0"))
203        manager._installed_package_dict = {"beep": {"package_info": {"package_version": "1.9.1"}}}
204
205        assert manager.checkIfPackageCanUpdate("beep") is False
206
207
208def test_removeAllScheduledPackages():
209    manager = PackageManager(MagicMock())
210    manager._purgePackage = MagicMock()
211
212    manager._to_remove_package_set = {"beep"}
213    manager._installed_package_dict = {"beep": {}}
214    manager._removeAllScheduledPackages()
215    assert manager._to_remove_package_set == set()
216
217
218def test_removeAllScheduledPackagesWithException():
219    manager = PackageManager(MagicMock())
220    manager._purgePackage = MagicMock(side_effect = Exception)
221    manager._installed_package_dict = {"beep": {}}
222    manager._to_remove_package_set = {"beep"}
223
224    manager._removeAllScheduledPackages()
225    assert manager._to_remove_package_set == {"beep"}