From 423e4e429b380384a6e6433ec2bb40f7d5abf5ed Mon Sep 17 00:00:00 2001 From: Safihre Date: Sat, 24 Oct 2020 12:03:16 +0200 Subject: [PATCH] Add functional test for Queue Repair Relates to #1649 --- sabnzbd/__init__.py | 8 +++--- sabnzbd/api.py | 3 ++- sabnzbd/nzbqueue.py | 1 + tests/test_functional_config.py | 7 +++-- tests/test_functional_downloads.py | 4 +-- tests/test_functional_misc.py | 52 ++++++++++++++++++++++++++++++++++++++ tests/testhelper.py | 1 + 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/sabnzbd/__init__.py b/sabnzbd/__init__.py index 16ab275..1f19fdb 100644 --- a/sabnzbd/__init__.py +++ b/sabnzbd/__init__.py @@ -27,7 +27,7 @@ import cherrypy import sys import ssl from threading import Lock, Thread -from typing import Any +from typing import Any, AnyStr ############################################################################## # Determine platform flags @@ -586,20 +586,20 @@ def unpause_all(): ############################################################################## -def backup_exists(filename): +def backup_exists(filename: str) -> bool: """ Return True if backup exists and no_dupes is set """ path = cfg.nzb_backup_dir.get_path() return path and os.path.exists(os.path.join(path, filename + ".gz")) -def backup_nzb(filename, data): +def backup_nzb(filename: str, data: AnyStr): """ Backup NZB file """ path = cfg.nzb_backup_dir.get_path() if path: save_compressed(path, filename, data) -def save_compressed(folder, filename, data): +def save_compressed(folder: str, filename: str, data: AnyStr): """ Save compressed NZB file in folder """ if filename.endswith(".nzb"): filename += ".gz" diff --git a/sabnzbd/api.py b/sabnzbd/api.py index 3df7abb..d7729dd 100644 --- a/sabnzbd/api.py +++ b/sabnzbd/api.py @@ -649,7 +649,8 @@ def _api_restart_repair(name, output, kwargs): """ API: accepts output """ logging.info("Queue repair requested by API") sabnzbd.request_repair() - sabnzbd.trigger_restart() + # Do the shutdown async to still send goodbye to browser + Thread(target=sabnzbd.trigger_restart, kwargs={"timeout": 1}).start() return report(output) diff --git a/sabnzbd/nzbqueue.py b/sabnzbd/nzbqueue.py index 5ebb9df..3776cb7 100644 --- a/sabnzbd/nzbqueue.py +++ b/sabnzbd/nzbqueue.py @@ -111,6 +111,7 @@ class NzbQueue: # Scan for any folders in "incomplete" that are not yet in the queue if repair: + logging.info("Starting queue repair") self.scan_jobs(not folders) # Handle any lost future jobs for item in globber_full(os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)): diff --git a/tests/test_functional_config.py b/tests/test_functional_config.py index 2002ccb..2c7a31d 100644 --- a/tests/test_functional_config.py +++ b/tests/test_functional_config.py @@ -234,7 +234,7 @@ class TestConfigRSS(SABnzbdBaseTest): time.sleep(2) # Let's check the queue - for _ in range(20): + for _ in range(10): queue_result_slots = get_api_result("queue")["queue"]["slots"] # Check if the fetch-request was added to the queue if queue_result_slots: @@ -246,9 +246,8 @@ class TestConfigRSS(SABnzbdBaseTest): return # Let's remove this thing - get_api_result("queue", extra_arguments={"name": "delete", "value": queue_result_slots[0]["nzo_id"]}) - queue_result_slots = get_api_result("queue")["queue"]["slots"] - assert len(queue_result_slots) == 0 + get_api_result("queue", extra_arguments={"name": "delete", "value": "all"}) + assert len(get_api_result("queue")["queue"]["slots"]) == 0 # Unpause assert get_api_result("resume") == {"status": True} diff --git a/tests/test_functional_downloads.py b/tests/test_functional_downloads.py index 88501b6..6108f14 100644 --- a/tests/test_functional_downloads.py +++ b/tests/test_functional_downloads.py @@ -85,8 +85,8 @@ class TestDownloadFlow(SABnzbdBaseTest): # See how it's doing self.open_page("http://%s:%s/sabnzbd/" % (SAB_HOST, SAB_PORT)) - # We wait for 60 seconds to let it complete - for _ in range(60): + # We wait for 20 seconds to let it complete + for _ in range(20): try: # Locate status of our job status_text = self.driver.find_element_by_xpath( diff --git a/tests/test_functional_misc.py b/tests/test_functional_misc.py index f2404a2..cb4f578 100644 --- a/tests/test_functional_misc.py +++ b/tests/test_functional_misc.py @@ -23,6 +23,8 @@ import subprocess import sys import sabnzbd.encoding +from sabnzbd import save_compressed +from sabnzbd.constants import JOB_ADMIN from tests.testhelper import * @@ -41,6 +43,56 @@ class TestShowLogging(SABnzbdBaseTest): assert "[misc]" in log_result +class TestQueueRepair(SABnzbdBaseTest): + def test_queue_repair(self): + """Test full queue repair by manually adding an orphaned job""" + nzb_data = create_and_read_nzb("basic_rar5") + test_job_name = "testfile_%s" % time.time() + + # Create folder and save compressed NZB like SABnzbd would do + admin_path = os.path.join(SAB_INCOMPLETE_DIR, test_job_name, JOB_ADMIN) + os.makedirs(admin_path) + save_compressed(admin_path, test_job_name, nzb_data) + assert os.path.exists(os.path.join(admin_path, test_job_name + ".nzb.gz")) + + # Pause the queue do we don't download stuff + assert get_api_result("pause") == {"status": True} + + # Request queue repair + assert get_api_result("restart_repair") == {"status": True} + + # Wait for the restart + time.sleep(2) + + # Let's check the queue + for _ in range(10): + queue_result_slots = {} + try: + # Can give timeout if still restarting + queue_result_slots = get_api_result("queue")["queue"]["slots"] + except requests.exceptions.RequestException: + pass + + # Check if the repaired job was added to the queue + if queue_result_slots: + break + time.sleep(1) + else: + # The loop never stopped, so we fail + pytest.fail("Did not find the repaired job in the queue") + return + + # Verify filename + assert queue_result_slots[0]["filename"] == test_job_name + + # Let's remove this thing + get_api_result("queue", extra_arguments={"name": "delete", "value": "all"}) + assert len(get_api_result("queue")["queue"]["slots"]) == 0 + + # Unpause + assert get_api_result("resume") == {"status": True} + + class TestSamplePostProc: def test_sample_post_proc(self): """ Make sure we don't break things """ diff --git a/tests/testhelper.py b/tests/testhelper.py index c9afbf4..c50ae8e 100644 --- a/tests/testhelper.py +++ b/tests/testhelper.py @@ -39,6 +39,7 @@ SAB_PORT = 8081 SAB_BASE_DIR = os.path.dirname(os.path.abspath(__file__)) SAB_CACHE_DIR = os.path.join(SAB_BASE_DIR, "cache") SAB_DATA_DIR = os.path.join(SAB_BASE_DIR, "data") +SAB_INCOMPLETE_DIR = os.path.join(SAB_CACHE_DIR, "Downloads", "incomplete") SAB_COMPLETE_DIR = os.path.join(SAB_CACHE_DIR, "Downloads", "complete") SAB_NEWSSERVER_HOST = "127.0.0.1" SAB_NEWSSERVER_PORT = 8888