259 lines
10 KiB
Python
259 lines
10 KiB
Python
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
# ***************************************************************************
|
|
# * *
|
|
# * Copyright (c) 2022 FreeCAD Project Association *
|
|
# * *
|
|
# * This file is part of FreeCAD. *
|
|
# * *
|
|
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
|
# * under the terms of the GNU Lesser General Public License as *
|
|
# * published by the Free Software Foundation, either version 2.1 of the *
|
|
# * License, or (at your option) any later version. *
|
|
# * *
|
|
# * FreeCAD is distributed in the hope that it will be useful, but *
|
|
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
# * Lesser General Public License for more details. *
|
|
# * *
|
|
# * You should have received a copy of the GNU Lesser General Public *
|
|
# * License along with FreeCAD. If not, see *
|
|
# * <https://www.gnu.org/licenses/>. *
|
|
# * *
|
|
# ***************************************************************************
|
|
|
|
from time import sleep
|
|
import unittest
|
|
import FreeCAD
|
|
|
|
from Addon import Addon
|
|
|
|
from PySide import QtCore, QtWidgets
|
|
|
|
from addonmanager_update_all_gui import UpdateAllGUI, AddonStatus
|
|
|
|
|
|
class MockUpdater(QtCore.QObject):
|
|
success = QtCore.Signal(object)
|
|
failure = QtCore.Signal(object)
|
|
finished = QtCore.Signal()
|
|
|
|
def __init__(self, addon, addons=[]):
|
|
super().__init__()
|
|
self.addon_to_install = addon
|
|
self.addons = addons
|
|
self.has_run = False
|
|
self.emit_success = True
|
|
self.work_function = None # Set to some kind of callable to make this function take time
|
|
|
|
def run(self):
|
|
self.has_run = True
|
|
if self.work_function is not None and callable(self.work_function):
|
|
self.work_function()
|
|
if self.emit_success:
|
|
self.success.emit(self.addon_to_install)
|
|
else:
|
|
self.failure.emit(self.addon_to_install)
|
|
self.finished.emit()
|
|
|
|
|
|
class MockUpdaterFactory:
|
|
def __init__(self, addons):
|
|
self.addons = addons
|
|
self.work_function = None
|
|
self.updater = None
|
|
|
|
def get_updater(self, addon):
|
|
self.updater = MockUpdater(addon, self.addons)
|
|
self.updater.work_function = self.work_function
|
|
return self.updater
|
|
|
|
|
|
class MockAddon:
|
|
def __init__(self, name):
|
|
self.display_name = name
|
|
self.name = name
|
|
self.macro = None
|
|
|
|
def status(self):
|
|
return Addon.Status.UPDATE_AVAILABLE
|
|
|
|
|
|
class CallInterceptor:
|
|
def __init__(self):
|
|
self.called = False
|
|
self.args = None
|
|
|
|
def intercept(self, *args):
|
|
self.called = True
|
|
self.args = args
|
|
|
|
|
|
class TestUpdateAllGui(unittest.TestCase):
|
|
def setUp(self):
|
|
self.addons = []
|
|
for i in range(3):
|
|
self.addons.append(MockAddon(f"Mock Addon {i}"))
|
|
self.factory = MockUpdaterFactory(self.addons)
|
|
self.test_object = UpdateAllGUI(self.addons)
|
|
self.test_object.updater_factory = self.factory
|
|
|
|
def tearDown(self):
|
|
pass
|
|
|
|
def test_run(self):
|
|
self.factory.work_function = lambda: sleep(0.1)
|
|
self.test_object.run()
|
|
while self.test_object.is_running():
|
|
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
|
|
self.test_object.dialog.accept()
|
|
|
|
def test_setup_dialog(self):
|
|
self.test_object._setup_dialog()
|
|
self.assertIsNotNone(
|
|
self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel)
|
|
)
|
|
self.assertEqual(self.test_object.dialog.tableWidget.rowCount(), 3)
|
|
|
|
def test_cancelling_installation(self):
|
|
class Worker:
|
|
def __init__(self):
|
|
self.counter = 0
|
|
self.LIMIT = 100
|
|
self.limit_reached = False
|
|
|
|
def run(self):
|
|
while self.counter < self.LIMIT:
|
|
if QtCore.QThread.currentThread().isInterruptionRequested():
|
|
return
|
|
self.counter += 1
|
|
sleep(0.01)
|
|
self.limit_reached = True
|
|
|
|
worker = Worker()
|
|
self.factory.work_function = worker.run
|
|
self.test_object.run()
|
|
cancel_timer = QtCore.QTimer()
|
|
cancel_timer.timeout.connect(
|
|
self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel).click
|
|
)
|
|
cancel_timer.start(90)
|
|
while self.test_object.is_running():
|
|
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 10)
|
|
self.assertGreater(len(self.test_object.addons_with_update), 0)
|
|
|
|
def test_add_addon_to_table(self):
|
|
mock_addon = MockAddon("MockAddon")
|
|
self.test_object.dialog.tableWidget.clear()
|
|
self.test_object._add_addon_to_table(mock_addon)
|
|
self.assertEqual(self.test_object.dialog.tableWidget.rowCount(), 1)
|
|
|
|
def test_update_addon_status(self):
|
|
self.test_object._setup_dialog()
|
|
self.test_object._update_addon_status(0, AddonStatus.WAITING)
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.WAITING.ui_string(),
|
|
)
|
|
self.test_object._update_addon_status(0, AddonStatus.INSTALLING)
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.INSTALLING.ui_string(),
|
|
)
|
|
self.test_object._update_addon_status(0, AddonStatus.SUCCEEDED)
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.SUCCEEDED.ui_string(),
|
|
)
|
|
self.test_object._update_addon_status(0, AddonStatus.FAILED)
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.FAILED.ui_string(),
|
|
)
|
|
|
|
def test_process_next_update(self):
|
|
self.test_object._setup_dialog()
|
|
self.test_object._launch_active_installer = lambda: None
|
|
self.test_object._process_next_update()
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.INSTALLING.ui_string(),
|
|
)
|
|
|
|
self.test_object._process_next_update()
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(1, 1).text(),
|
|
AddonStatus.INSTALLING.ui_string(),
|
|
)
|
|
|
|
self.test_object._process_next_update()
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(2, 1).text(),
|
|
AddonStatus.INSTALLING.ui_string(),
|
|
)
|
|
|
|
self.test_object._process_next_update()
|
|
|
|
def test_launch_active_installer(self):
|
|
self.test_object.active_installer = self.factory.get_updater(self.addons[0])
|
|
self.test_object._update_succeeded = lambda _: None
|
|
self.test_object._update_failed = lambda _: None
|
|
self.test_object.process_next_update = lambda: None
|
|
self.test_object._launch_active_installer()
|
|
# The above call does not block, so spin until it has completed (basically instantly in testing)
|
|
while self.test_object.worker_thread.isRunning():
|
|
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
|
|
self.test_object.dialog.accept()
|
|
|
|
def test_update_succeeded(self):
|
|
self.test_object._setup_dialog()
|
|
self.test_object._update_succeeded(self.addons[0])
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.SUCCEEDED.ui_string(),
|
|
)
|
|
|
|
def test_update_failed(self):
|
|
self.test_object._setup_dialog()
|
|
self.test_object._update_failed(self.addons[0])
|
|
self.assertEqual(
|
|
self.test_object.dialog.tableWidget.item(0, 1).text(),
|
|
AddonStatus.FAILED.ui_string(),
|
|
)
|
|
|
|
def test_update_finished(self):
|
|
self.test_object._setup_dialog()
|
|
call_interceptor = CallInterceptor()
|
|
self.test_object.worker_thread = QtCore.QThread()
|
|
self.test_object.worker_thread.start()
|
|
self.test_object._process_next_update = call_interceptor.intercept
|
|
self.test_object.active_installer = self.factory.get_updater(self.addons[0])
|
|
self.test_object._update_finished()
|
|
self.assertFalse(self.test_object.worker_thread.isRunning())
|
|
self.test_object.worker_thread.quit()
|
|
self.assertTrue(call_interceptor.called)
|
|
self.test_object.worker_thread.wait()
|
|
|
|
def test_finalize(self):
|
|
self.test_object._setup_dialog()
|
|
self.test_object.worker_thread = QtCore.QThread()
|
|
self.test_object.worker_thread.start()
|
|
self.test_object._finalize()
|
|
self.assertFalse(self.test_object.worker_thread.isRunning())
|
|
self.test_object.worker_thread.quit()
|
|
self.test_object.worker_thread.wait()
|
|
self.assertFalse(self.test_object.running)
|
|
self.assertIsNotNone(
|
|
self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Close)
|
|
)
|
|
self.assertIsNone(
|
|
self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel)
|
|
)
|
|
|
|
def test_is_running(self):
|
|
self.assertFalse(self.test_object.is_running())
|
|
self.test_object.run()
|
|
self.assertTrue(self.test_object.is_running())
|
|
while self.test_object.is_running():
|
|
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
|
|
self.test_object.dialog.accept()
|