diff --git a/inbc-program/inbc/parser/parser.py b/inbc-program/inbc/parser/parser.py
index f20b4a7de..5679d1b46 100644
--- a/inbc-program/inbc/parser/parser.py
+++ b/inbc-program/inbc/parser/parser.py
@@ -224,7 +224,7 @@ def parse_sota_args(self) -> None:
parser_sota.add_argument('--reboot', '-rb', default='yes', required=False, choices=['yes', 'no'],
help='Type of information [ yes | no ]')
parser_sota.add_argument('--mode', '-m', default='full',
- required=False, choices=['full', 'download-only', 'no-download'])
+ required=False, choices=['full', 'download-only', 'no-download', 'cancel'])
parser_sota.add_argument('--package-list', '-p', required=False,
type=lambda x: validate_package_list(x),
help='Comma-separated list of package names to install')
diff --git a/inbm/Changelog.md b/inbm/Changelog.md
index 07715157d..4232c4865 100644
--- a/inbm/Changelog.md
+++ b/inbm/Changelog.md
@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
## NEXT - MMMM-DD-YY
-
+ - (NEXMANAGE-737) Enable sota cancel mode
## 4.2.6 - 2024-10-04
### Added
diff --git a/inbm/dispatcher-agent/dispatcher/dispatcher_class.py b/inbm/dispatcher-agent/dispatcher/dispatcher_class.py
index 468f30779..e0953e596 100644
--- a/inbm/dispatcher-agent/dispatcher/dispatcher_class.py
+++ b/inbm/dispatcher-agent/dispatcher/dispatcher_class.py
@@ -12,7 +12,7 @@
import signal
import sys
from queue import Queue
-from threading import Thread, active_count, Lock
+from threading import Thread, active_count, Lock, Event
from time import sleep
from typing import Optional, Any, Mapping, Tuple, Sequence
@@ -55,6 +55,7 @@
from .sota.os_factory import SotaOsFactory
from .sota.sota import SOTA
from .sota.sota_error import SotaError
+from .sota.cancel import cancel_thread
from .workload_orchestration import WorkloadOrchestration
from inbm_lib.xmlhandler import *
from inbm_lib.version import get_friendly_inbm_version_commit
@@ -94,6 +95,8 @@ def __init__(self, args: list[str], broker: DispatcherBroker, install_check_serv
# Initialize update_queue with a capacity of 1 to ensure serialized handling of updates.
self.update_queue: Queue[Tuple[str, str, Optional[str]]] = Queue(1)
self._thread_count = 1
+ self._thread_list: list[Thread] = []
+ self._active_thread_manifest: Optional[str] = None
self._sota_repos = None
self.sota_mode = None
self._package_list: str = ""
@@ -115,6 +118,7 @@ def __init__(self, args: list[str], broker: DispatcherBroker, install_check_serv
self.sqlite_mgr = SqliteManager()
self.ap_scheduler = APScheduler(sqlite_mgr=self.sqlite_mgr)
+ self._cancel_event = Event()
def stop(self) -> None:
self.RUNNING = False
@@ -186,7 +190,13 @@ def _sig_handler(signo, frame) -> None:
if active_count() - active_start_count < self._thread_count:
worker = Thread(target=handle_updates, args=(self,))
worker.setDaemon(True)
+ self._thread_list.append(worker)
worker.start()
+
+ # Periodically check if processes have finished. If process finished, remove it from the list.
+ for thread in self._thread_list:
+ if not thread.is_alive():
+ self._thread_list.remove(thread)
sleep(1)
self._dispatcher_broker.mqtt_publish(f'{AGENT}/state', 'dead', retain=True)
@@ -310,6 +320,7 @@ def do_install(self, xml: str, schema_location: Optional[str] = None, job_id: st
result: Result = Result()
logger.debug("do_install")
parsed_head = None
+ self._active_thread_manifest = xml
try: # TODO: Split into multiple try/except blocks
type_of_manifest, parsed_head = \
_check_type_validate_manifest(xml, schema_location=schema_location)
@@ -411,7 +422,8 @@ def _do_ota_update(self, ota_type: str, repo_type: str, resource: dict,
self._sota_repos,
self._install_check_service,
self._update_logger,
- self.config_dbs)
+ self.config_dbs,
+ self._cancel_event)
p = factory.create_parser()
# NOTE: p.parse can raise one of the *otaError exceptions
@@ -440,7 +452,8 @@ def _validate_pota_manifest(self, repo_type: str,
self._sota_repos,
self._install_check_service,
self._update_logger,
- self.config_dbs)
+ self.config_dbs,
+ self._cancel_event)
p = factory.create_parser()
# NOTE: p.parse can raise one of the *otaError exceptions
parsed_manifest = p.parse(ota_list[ota], kwargs, parsed_head)
@@ -497,7 +510,32 @@ def _on_cloud_request(self, topic: str, payload: str, qos: int) -> None:
request_type = topic.split('/')[2]
request_id = topic.split('/')[3] if len(topic.split('/')) > 3 else None
manifest = payload
- self._add_request_to_queue(request_type, manifest, request_id)
+ if not self._handle_cancel_request(request_type, manifest):
+ self._add_request_to_queue(request_type, manifest, request_id)
+
+ def _handle_cancel_request(self, request_type, manifest) -> bool:
+ """
+ Check if it is a SOTA cancel request. If it is, send the terminate signal to current process.
+
+ @param request_type: type of the request
+ @param manifest: manifest to be processed
+ @return: True if the request has been processed; False if no request has been handled.
+ """
+ if request_type == "install":
+ type_of_manifest, parsed_head = \
+ _check_type_validate_manifest(manifest)
+ type_of_active_manifest = active_thread_parsed_head = None
+ if self._active_thread_manifest:
+ type_of_active_manifest, active_thread_parsed_head = \
+ _check_type_validate_manifest(self._active_thread_manifest)
+ result = cancel_thread(type_of_manifest, parsed_head, self._thread_list,
+ type_of_active_manifest, active_thread_parsed_head,
+ self._dispatcher_broker, self._cancel_event)
+ if result:
+ logger.debug(f"Request cancel complete.")
+ self._send_result(str(Result(CODE_OK, "Request complete.")))
+ return True
+ return False
def _on_message(self, topic: str, payload: Any, qos: int) -> None:
"""Called when a message is received from _telemetry-agent
@@ -619,6 +657,7 @@ def invoke_sota(self, snapshot: Optional[Any] = None, action: Optional[Any] = No
self._update_logger,
self._sota_repos,
self._install_check_service,
+ self._cancel_event,
snapshot, action)
sota_instance.execute(self.proceed_without_rollback)
diff --git a/inbm/dispatcher-agent/dispatcher/ota_factory.py b/inbm/dispatcher-agent/dispatcher/ota_factory.py
index 879ab2936..f55c90e3d 100644
--- a/inbm/dispatcher-agent/dispatcher/ota_factory.py
+++ b/inbm/dispatcher-agent/dispatcher/ota_factory.py
@@ -6,6 +6,7 @@
"""
import abc
import logging
+import threading
from typing import Any, Optional, Mapping
from .config_dbs import ConfigDbs
@@ -53,7 +54,8 @@ def get_factory(ota_type,
sota_repos: Optional[str],
install_check_service: InstallCheckService,
update_logger: UpdateLogger,
- dbs: ConfigDbs) -> "OtaFactory":
+ dbs: ConfigDbs,
+ cancel_event: threading.Event) -> "OtaFactory":
"""Create an OTA factory of a specified OTA type
@param ota_type: The OTA type
@@ -64,6 +66,7 @@ def get_factory(ota_type,
@param install_check_service: provides install_check
@param update_logger: UpdateLogger (expected to update after OTA)
@param dbs: ConfigDbs.ON or ConfigDbs.WARN or ConfigDbs.OFF
+ @param cancel_event: Event used to stop the downloading process
@raise ValueError: Unsupported OTA type
"""
@@ -72,7 +75,7 @@ def get_factory(ota_type,
return FotaFactory(repo_type, dispatcher_broker, install_check_service, update_logger)
if ota_type == OtaType.SOTA.name:
return SotaFactory(repo_type, dispatcher_broker, proceed_without_rollback,
- sota_repos, install_check_service, update_logger)
+ sota_repos, install_check_service, update_logger, cancel_event)
if ota_type == OtaType.AOTA.name:
return AotaFactory(repo_type, dispatcher_broker, install_check_service, update_logger, dbs=dbs)
if ota_type == OtaType.POTA.name:
@@ -116,7 +119,8 @@ class SotaFactory(OtaFactory):
@param proceed_without_rollback: Is it OK to run SOTA without rollback ability?
@param install_check_service: provides InstallCheckService
@param sota_repos: new Ubuntu/Debian mirror (or None)
- @param update_logger: UpdateLogger (expected to update after OTA)
+ @param update_logger: UpdateLogger (expected to update after OTA)
+ @param cancel_event: Event used to stop the downloading process
"""
def __init__(self,
@@ -125,13 +129,15 @@ def __init__(self,
proceed_without_rollback: bool,
sota_repos: Optional[str],
install_check_service: InstallCheckService,
- update_logger: UpdateLogger) -> None:
+ update_logger: UpdateLogger,
+ cancel_event: threading.Event) -> None:
super().__init__(repo_type, install_check_service)
self._sota_repos = sota_repos
self._proceed_without_rollback = proceed_without_rollback
self._update_logger = update_logger
self._dispatcher_broker = dispatcher_broker
+ self._cancel_event = cancel_event
def create_parser(self) -> OtaParser:
logger.debug(" ")
@@ -145,7 +151,8 @@ def create_thread(self, parsed_manifest: Mapping[str, Optional[Any]]) -> OtaThre
self._sota_repos,
self._install_check_service,
parsed_manifest,
- self._update_logger)
+ self._update_logger,
+ self._cancel_event)
class AotaFactory(OtaFactory):
diff --git a/inbm/dispatcher-agent/dispatcher/ota_thread.py b/inbm/dispatcher-agent/dispatcher/ota_thread.py
index ecd58b5aa..5083e295f 100644
--- a/inbm/dispatcher-agent/dispatcher/ota_thread.py
+++ b/inbm/dispatcher-agent/dispatcher/ota_thread.py
@@ -7,6 +7,7 @@
import abc
import logging
import os
+import threading
from threading import Lock
from typing import Optional, Any, Mapping
@@ -142,6 +143,7 @@ class SotaThread(OtaThread):
@param install_check_service: provides install_check
@param parsed_manifest: parameters from OTA manifest
@param update_logger: UpdateLogger instance; expected to update when done with OTA
+ @param cancel_event: Event used to stop the downloading process
@return (dict): dict representation of COMMAND_SUCCESS or OTA_FAILURE/OTA_FAILURE_IN_PROGRESS
"""
@@ -152,13 +154,15 @@ def __init__(self,
sota_repos: Optional[str],
install_check_service: InstallCheckService,
parsed_manifest: Mapping[str, Optional[Any]],
- update_logger: UpdateLogger) -> None:
+ update_logger: UpdateLogger,
+ cancel_event: threading.Event) -> None:
super().__init__(repo_type, parsed_manifest,
install_check_service=install_check_service)
self._sota_repos = sota_repos
self._proceed_without_rollback = proceed_without_rollback
self._update_logger = update_logger
self._dispatcher_broker = dispatcher_broker
+ self._cancel_event = cancel_event
def start(self) -> Result: # pragma: no cover
"""Starts the SOTA thread and which checks for existing locks before delegating to
@@ -177,6 +181,7 @@ def start(self) -> Result: # pragma: no cover
dispatcher_broker=self._dispatcher_broker,
update_logger=self._update_logger,
sota_repos=self._sota_repos,
+ cancel_event=self._cancel_event,
install_check_service=self._install_check_service)
try:
sota_instance.execute(self._proceed_without_rollback)
@@ -200,6 +205,7 @@ def check(self) -> None:
dispatcher_broker=self._dispatcher_broker,
update_logger=self._update_logger,
sota_repos=self._sota_repos,
+ cancel_event=self._cancel_event,
install_check_service=self._install_check_service)
sota_instance.check()
except SotaError as e:
diff --git a/inbm/dispatcher-agent/dispatcher/sota/cancel.py b/inbm/dispatcher-agent/dispatcher/sota/cancel.py
new file mode 100644
index 000000000..da7fa611d
--- /dev/null
+++ b/inbm/dispatcher-agent/dispatcher/sota/cancel.py
@@ -0,0 +1,86 @@
+"""
+ Method to handle cancel request
+
+ Copyright (C) 2017-2024 Intel Corporation
+ SPDX-License-Identifier: Apache-2.0
+"""
+
+import logging
+from typing import Optional
+from threading import Event
+from inbm_lib.xmlhandler import XmlHandler
+from threading import Thread
+from .constants import SOTA_CACHE
+from ..constants import OtaType
+from dispatcher.dispatcher_exception import DispatcherException
+from dispatcher.packagemanager.local_repo import DirectoryRepo
+from dispatcher.dispatcher_broker import DispatcherBroker
+from dispatcher.common.result_constants import Result, CODE_OK, CODE_BAD_REQUEST
+
+logger = logging.getLogger(__name__)
+
+
+def cancel_thread(type_of_manifest: str, parsed_head: XmlHandler, thread_list: list[Thread],
+ type_of_active_manifest: Optional[str], active_thread_parsed_head: Optional[XmlHandler],
+ dispatcher_broker: DispatcherBroker, cancel_event: Event) -> bool:
+ """
+ Cancel the current active thread by sending the terminate signal.
+
+ @param type_of_manifest: type of the request
+ @param parsed_head: The root parsed xml
+ @param thread_list: List of the active thread
+ @param type_of_active_manifest: type of the request on running thread
+ @param active_thread_parsed_head: The root parsed xml of running thread
+ @param dispatcher_broker: DispatcherBroker object used to communicate with other INBM services
+ @param cancel_event: Event used to stop the downloading process
+ @return: True if the request has been processed; False if no request has been handled.
+ """
+ if type_of_manifest == 'ota':
+ header = parsed_head.get_children('ota/header')
+ ota_type = header['type']
+ resource = parsed_head.get_children(f'ota/type/{ota_type}')
+ if ota_type == OtaType.SOTA.name.lower():
+ sota_mode = resource.get('mode', None)
+ if sota_mode == 'cancel':
+ logger.debug(f"Receive sota cancel request.")
+ # If the active thread is not SOTA download-only, forbid the cancel request.
+ if type_of_active_manifest and active_thread_parsed_head:
+ if not is_active_ota_sota_download_only(type_of_active_manifest, active_thread_parsed_head):
+ dispatcher_broker.send_result(
+ str(Result(CODE_BAD_REQUEST, "Current thread is not SOTA download-only. "
+ "Cannot proceed with the cancel request.")))
+ return True
+ else:
+ dispatcher_broker.send_result(str(Result(CODE_BAD_REQUEST, "Running thread manifest not found.")))
+ return True
+
+ # The list should only contain one OTA process.
+ for thread in thread_list:
+ if thread.is_alive():
+ cancel_event.set()
+ # Wait thread to gracefully exit
+ logger.debug(f"Waiting thread to exit...")
+ thread.join()
+ logger.debug(f"Request cancel complete.")
+ return True
+ return False
+
+
+def is_active_ota_sota_download_only(type_of_active_manifest: str, active_parsed_head: XmlHandler) -> bool:
+ """
+ Check whether the current active thread is SOTA download-only mode.
+
+ @param type_of_active_manifest: type of the request
+ @param active_parsed_head: The root parsed xml
+ @return: True if it is SOTA download-only; False if not.
+ """
+ logger.debug("")
+ if type_of_active_manifest == 'ota':
+ header = active_parsed_head.get_children('ota/header')
+ ota_type = header['type']
+ resource = active_parsed_head.get_children(f'ota/type/{ota_type}')
+ if ota_type == OtaType.SOTA.name.lower():
+ sota_mode = resource.get('mode', None)
+ if sota_mode == 'download-only':
+ return True
+ return False
diff --git a/inbm/dispatcher-agent/dispatcher/sota/sota.py b/inbm/dispatcher-agent/dispatcher/sota/sota.py
index ce650c99c..60c0363fb 100644
--- a/inbm/dispatcher-agent/dispatcher/sota/sota.py
+++ b/inbm/dispatcher-agent/dispatcher/sota/sota.py
@@ -7,6 +7,7 @@
import logging
import os
+import threading
import time
import threading
from typing import Any, List, Optional, Union, Mapping
@@ -84,6 +85,7 @@ def __init__(self,
update_logger: UpdateLogger,
sota_repos: Optional[str],
install_check_service: InstallCheckService,
+ cancel_event: threading.Event,
snapshot: Optional[Any] = None,
action: Optional[Any] = None) -> None:
"""SOTA thread instance
@@ -94,6 +96,7 @@ def __init__(self,
@param sota_repos: new Ubuntu/Debian mirror (or None)
@param update_logger: UpdateLogger instance--expected to notify it with update status
@param kwargs:
+ @param cancel_event: Event used to stop the downloading process
"""
self._parsed_manifest = parsed_manifest
@@ -115,6 +118,7 @@ def __init__(self,
self._update_logger = update_logger
self._dispatcher_broker = dispatcher_broker
self._granular_log_handler = GranularLogHandler()
+ self._cancel_event = cancel_event
try:
manifest_package_list = parsed_manifest['package_list']
@@ -341,9 +345,15 @@ def execute_from_manifest(self,
if setup_helper.pre_processing():
if self.sota_mode != 'no-download':
self._download_sota_files(sota_cache_repo, release_date)
+ if self._cancel_event.is_set():
+ sota_cache_repo.delete_all() # clean cache directory
+ raise SotaError("Request cancel.")
download_success = True
snapshotter.take_snapshot()
cmd_list = self.calculate_and_execute_sota_upgrade(sota_cache_repo)
+ if self._cancel_event.is_set():
+ sota_cache_repo.delete_all() # clean cache directory
+ raise SotaError("Request cancel.")
sota_cache_repo.delete_all() # clean cache directory
if get_command_status(cmd_list) == SUCCESS:
self._dispatcher_broker.send_result(
diff --git a/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd b/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd
index d787263a8..3f6f579e3 100644
--- a/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd
+++ b/inbm/dispatcher-agent/fpm-template/usr/share/dispatcher-agent/manifest_schema.xsd
@@ -465,6 +465,7 @@
+
diff --git a/inbm/dispatcher-agent/tests/unit/sota/test_cancel.py b/inbm/dispatcher-agent/tests/unit/sota/test_cancel.py
new file mode 100644
index 000000000..d1fe9a72f
--- /dev/null
+++ b/inbm/dispatcher-agent/tests/unit/sota/test_cancel.py
@@ -0,0 +1,74 @@
+import unittest
+from unittest.mock import Mock
+import os
+import threading
+from time import sleep
+from inbm_lib.xmlhandler import XmlHandler
+
+from dispatcher.sota.cancel import cancel_thread, is_active_ota_sota_download_only
+
+TEST_SCHEMA_LOCATION = os.path.join(os.path.dirname(__file__),
+ '../../../fpm-template/usr/share/dispatcher-agent/'
+ 'manifest_schema.xsd')
+
+
+class TestCancelThread(unittest.TestCase):
+
+ def test_cancel_thread_success(self) -> None:
+ def mock_thread(cancel_event: threading.Event):
+ while not cancel_event.is_set():
+ sleep(3)
+
+ sota_cancel_manifest = """otaupdate
+ cancelyes
+ """
+
+ cancel_event = threading.Event()
+
+ type_of_manifest = "ota"
+ thread_list = []
+ worker = threading.Thread(target=mock_thread, args=(cancel_event,))
+ worker.setDaemon(True)
+ thread_list.append(worker)
+ worker.start()
+ sleep(1)
+ parsed_head = XmlHandler(sota_cancel_manifest, is_file=False, schema_location=TEST_SCHEMA_LOCATION)
+
+ sota_download_only_manifest = """otaupdate
+ download-onlyyes
+ """
+ active_parsed_head = XmlHandler(sota_download_only_manifest, is_file=False, schema_location=TEST_SCHEMA_LOCATION)
+
+ self.assertTrue(cancel_thread(type_of_manifest=type_of_manifest,
+ parsed_head=parsed_head,
+ thread_list=thread_list,
+ type_of_active_manifest=type_of_manifest,
+ active_thread_parsed_head=active_parsed_head,
+ dispatcher_broker=Mock(),
+ cancel_event=cancel_event))
+
+ def test_is_active_ota_sota_download_only_return_true(self) -> None:
+
+ sota_download_only_manifest = """otaupdate
+ download-onlyyes
+ """
+
+ type_of_manifest = "ota"
+ parsed_head = XmlHandler(sota_download_only_manifest, is_file=False, schema_location=TEST_SCHEMA_LOCATION)
+
+ self.assertTrue(is_active_ota_sota_download_only(type_of_manifest, parsed_head))
+
+ def test_is_active_ota_sota_download_only_return_false(self) -> None:
+
+ sota_download_only_manifest = """otaupdate
+ no-downloadyes
+ """
+
+ type_of_manifest = "ota"
+ parsed_head = XmlHandler(sota_download_only_manifest, is_file=False, schema_location=TEST_SCHEMA_LOCATION)
+
+ self.assertFalse(is_active_ota_sota_download_only(type_of_manifest, parsed_head))
diff --git a/inbm/dispatcher-agent/tests/unit/sota/test_downloader.py b/inbm/dispatcher-agent/tests/unit/sota/test_downloader.py
index 7c709cf3f..2338a363c 100644
--- a/inbm/dispatcher-agent/tests/unit/sota/test_downloader.py
+++ b/inbm/dispatcher-agent/tests/unit/sota/test_downloader.py
@@ -3,6 +3,7 @@
import shutil
from typing import Optional
import os
+import threading
from ..common.mock_resources import *
@@ -45,6 +46,7 @@ def setUp(cls) -> None:
MockDispatcherBroker.build_mock_dispatcher_broker(),
UpdateLogger("SOTA", "metadata"),
None,
+ cancel_event=threading.Event(),
install_check_service=MockInstallCheckService())
cls.sota_instance.factory = SotaOsFactory(
MockDispatcherBroker.build_mock_dispatcher_broker(), None, []).get_os('YoctoX86_64')
diff --git a/inbm/dispatcher-agent/tests/unit/sota/test_os_updater_nose_style.py b/inbm/dispatcher-agent/tests/unit/sota/test_os_updater_nose_style.py
index a2f963277..852117589 100644
--- a/inbm/dispatcher-agent/tests/unit/sota/test_os_updater_nose_style.py
+++ b/inbm/dispatcher-agent/tests/unit/sota/test_os_updater_nose_style.py
@@ -1,6 +1,7 @@
import unittest
from typing import Optional
import os
+import threading
from ..common.mock_resources import *
from dispatcher.sota.os_factory import SotaOsFactory
@@ -45,6 +46,7 @@ def setUpClass(cls) -> None:
cls.mock_disp_obj._update_logger,
None,
MockInstallCheckService(),
+ cancel_event=threading.Event(),
snapshot=1)
parsed_manifest_packages = {'resource': cls.resource,
@@ -57,6 +59,7 @@ def setUpClass(cls) -> None:
cls.mock_disp_obj._update_logger,
None,
MockInstallCheckService(),
+ cancel_event=threading.Event(),
snapshot=1)
def test_create_no_download_cmd_with_no_package_list(self) -> None:
diff --git a/inbm/dispatcher-agent/tests/unit/sota/test_sota.py b/inbm/dispatcher-agent/tests/unit/sota/test_sota.py
index d971a0f8a..fe7743805 100644
--- a/inbm/dispatcher-agent/tests/unit/sota/test_sota.py
+++ b/inbm/dispatcher-agent/tests/unit/sota/test_sota.py
@@ -1,3 +1,5 @@
+import threading
+
import testtools
import os
import tempfile
@@ -46,12 +48,14 @@ def setUpClass(cls) -> None:
UpdateLogger("SOTA", "metadata"),
None,
install_check_service=MockInstallCheckService(),
+ cancel_event=threading.Event(),
snapshot=1)
cls.sota_local_instance = SOTA(parsed_manifest, 'local',
cls.mock_disp_broker,
UpdateLogger("SOTA", "metadata"),
None,
install_check_service=MockInstallCheckService(),
+ cancel_event=threading.Event(),
snapshot=1)
cls.sota_util_instance = SOTAUtil()
@@ -126,7 +130,8 @@ def test_run_raises(self, mock_reboot, mock_rollback_and_delete_snap, mock_print
sota_instance = SOTA(parsed_manifest, 'remote',
mock_disp_broker,
UpdateLogger("SOTA", "metadata"), None,
- MockInstallCheckService(), snapshot=1)
+ MockInstallCheckService(), cancel_event=threading.Event(),
+ snapshot=1)
sota_instance.execute(proceed_without_rollback=False, skip_sleeps=True)
mock_print.assert_called_once()
if TestSota.sota_instance.proceed_without_rollback:
@@ -151,7 +156,8 @@ def test_run_pass(self, mock_run, mock_rollback_and_delete_snap, mock_print,
mock_disp_broker = MockDispatcherBroker.build_mock_dispatcher_broker()
try:
sota_instance = SOTA(parsed_manifest, 'remote', mock_disp_broker,
- UpdateLogger("SOTA", "metadata"), None, MockInstallCheckService(), snapshot=1)
+ UpdateLogger("SOTA", "metadata"), None, MockInstallCheckService(),
+ cancel_event=threading.Event(),snapshot=1)
sota_instance.execute(proceed_without_rollback=False, skip_sleeps=True)
mock_print.assert_called_once()
if TestSota.sota_instance.proceed_without_rollback:
diff --git a/inbm/dispatcher-agent/tests/unit/test_ota_factory.py b/inbm/dispatcher-agent/tests/unit/test_ota_factory.py
index a25b4e3bc..22af86a69 100644
--- a/inbm/dispatcher-agent/tests/unit/test_ota_factory.py
+++ b/inbm/dispatcher-agent/tests/unit/test_ota_factory.py
@@ -1,3 +1,5 @@
+import threading
+
import pytest
from unit.common.mock_resources import *
@@ -28,7 +30,8 @@ def test_get_factory(ota_type, expected_factory, mock_disp_obj, mock_disp_broker
None,
MockInstallCheckService(),
UpdateLogger(ota_type=ota_type, data="metadata"),
- ConfigDbs.ON
+ ConfigDbs.ON,
+ cancel_event=threading.Event()
)
assert isinstance(factory, expected_factory)
@@ -43,7 +46,8 @@ def test_raise_error_unsupported_ota(mock_disp_obj, mock_disp_broker) -> None:
None,
MockInstallCheckService(),
UpdateLogger(ota_type="IOTA", data="metadata"),
- ConfigDbs.OFF
+ ConfigDbs.OFF,
+ cancel_event=threading.Event()
)
@@ -61,7 +65,8 @@ def test_create_parser(ota_type, expected_parser, mock_disp_obj, mock_disp_broke
None,
MockInstallCheckService(),
UpdateLogger(ota_type=ota_type, data="metadata"),
- ConfigDbs.ON
+ ConfigDbs.ON,
+ cancel_event=threading.Event()
).create_parser()
assert isinstance(parser, expected_parser)
@@ -80,6 +85,7 @@ def test_create_thread(ota_type, expected_thread, mock_disp_obj, mock_disp_broke
None,
MockInstallCheckService(),
UpdateLogger(ota_type=ota_type, data="metadata"),
- ConfigDbs.ON
+ ConfigDbs.ON,
+ cancel_event=threading.Event()
).create_thread({'abc': 'def'})
assert isinstance(thread, expected_thread)