Test fixes

This commit is contained in:
dgtlmoon
2026-02-02 11:06:11 +01:00
parent ef310e4a67
commit b7eaeb4ae4
7 changed files with 46 additions and 36 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ echo "-------------------- Running rest of tests in parallel -------------------
# REMOVE_REQUESTS_OLD_SCREENSHOTS disabled so that we can write a screenshot and send it in test_notifications.py without a real browser
REMOVE_REQUESTS_OLD_SCREENSHOTS=false \
pytest tests/test_*.py \
-n 30 \
-n 16 \
--dist=load \
-vvv \
-s \
+3
View File
@@ -166,6 +166,9 @@ class ChangeDetectionStore(DatastoreUpdatesMixin, FileSavingDataStore):
"""
logger.info(f"Datastore path is '{datastore_path}'")
# CRITICAL: Update datastore_path (was using old path from __init__)
self.datastore_path = datastore_path
# Initialize data structure
self.__data = App.model()
self.json_store_path = os.path.join(self.datastore_path, "changedetection.json")
+31 -7
View File
@@ -175,31 +175,55 @@ def prepare_test_function(live_server, datastore_path):
# CRITICAL: Get datastore and stop it from writing stale data
datastore = live_server.app.config.get('DATASTORE')
# Clear the queue before starting the test to prevent state leakage
from changedetectionio.flask_app import update_q
# CRITICAL: Clear ALL global state that persists between tests
from changedetectionio.flask_app import update_q, notification_q, notification_debug_log
# Clear update queue
while not update_q.empty():
try:
update_q.get_nowait()
except:
break
# Clear notification queue (was missing!)
while not notification_q.empty():
try:
notification_q.get_nowait()
except:
break
# Clear notification debug log (accumulates across tests!)
notification_debug_log.clear()
# Clear SALTED_PASS env var if set by previous test
if 'SALTED_PASS' in os.environ:
del os.environ['SALTED_PASS']
# Stop background thread with longer timeout
datastore.stop_thread = True
if hasattr(datastore, 'save_data_thread') and datastore.save_data_thread:
datastore.save_data_thread.join(timeout=2.0)
# Prevent background thread from writing during cleanup/reload
datastore.needs_write = False
datastore.needs_write_urgent = False
# Reset dirty tracking
datastore._dirty_watches = set()
datastore._dirty_settings = False
datastore._watch_hashes = {}
# CRITICAL: Clean up any files from previous tests
# This ensures a completely clean directory
cleanup(datastore_path)
# CRITICAL: Reload the EXISTING datastore instead of creating a new one
# This keeps blueprint references valid (they capture datastore at construction)
# reload_state() completely resets the datastore to a clean state
# Reset stop_thread so reload_state can start new thread
datastore.stop_thread = False
# Reload state with clean data (no default watches)
datastore.reload_state(
datastore_path=datastore_path,
include_default_watches=False,
version_tag=datastore.data.get('version_tag', '0.0.0')
version_tag='0.0.0'
)
live_server.app.secret_key = init_app_secret(datastore_path)
logger.debug(f"prepare_test_function: Reloaded datastore at {hex(id(datastore))}")
+1 -1
View File
@@ -142,7 +142,7 @@ def test_tag_import_singular(client, live_server, measure_memory_usage, datastor
)
# Should be only 1 tag because they both had the same
assert len(live_server.app.config['DATASTORE'].data['settings']['application'].get('tags')) ==1
wait_for_all_checks()
delete_all_watches(client)
def test_tag_add_in_ui(client, live_server, measure_memory_usage, datastore_path):
+1
View File
@@ -213,6 +213,7 @@ def test_method_in_request(client, live_server, measure_memory_usage, datastore_
follow_redirects=True
)
assert b"Updated watch." in res.data
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
# Give the thread time to pick up the first version
wait_for_all_checks(client)
@@ -236,22 +236,17 @@ def test_restock_itemprop_with_tag(client, live_server, measure_memory_usage, da
def test_itemprop_percent_threshold(client, live_server, measure_memory_usage, datastore_path):
delete_all_watches(client)
test_url = url_for('test_endpoint', _external=True)
set_original_response(props_markup=instock_props[0], price="950.95", datastore_path=datastore_path)
client.post(
url_for("ui.ui_views.form_quick_watch_add"),
data={"url": test_url, "tags": 'restock tests', 'processor': 'restock_diff'},
follow_redirects=True
)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url, tag="restock tests", extras={'processor':"restock_diff"})
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
# A change in price, should trigger a change by default
wait_for_all_checks(client)
res = client.post(
url_for("ui.ui_edit.edit_page", uuid="first"),
url_for("ui.ui_edit.edit_page", uuid=uuid),
data={"restock_settings-follow_price_changes": "y",
"restock_settings-price_change_threshold_percent": 5.0,
"url": test_url,
@@ -295,7 +290,6 @@ def test_itemprop_percent_threshold(client, live_server, measure_memory_usage, d
# Re #2600 - Switch the mode to normal type and back, and see if the values stick..
###################################################################################
uuid = next(iter(live_server.app.config['DATASTORE'].data['watching']))
res = client.post(
url_for("ui.ui_edit.edit_page", uuid=uuid),
@@ -314,9 +308,6 @@ def test_itemprop_percent_threshold(client, live_server, measure_memory_usage, d
res = client.get(url_for("ui.ui_edit.edit_page", uuid=uuid))
assert b'type="text" value="5.05"' in res.data
delete_all_watches(client)
def test_change_with_notification_values(client, live_server, measure_memory_usage, datastore_path):
@@ -390,16 +381,11 @@ def test_change_with_notification_values(client, live_server, measure_memory_usa
def test_data_sanity(client, live_server, measure_memory_usage, datastore_path):
delete_all_watches(client)
test_url = url_for('test_endpoint', _external=True)
test_url2 = url_for('test_endpoint2', _external=True)
set_original_response(props_markup=instock_props[0], price="950.95", datastore_path=datastore_path)
client.post(
url_for("ui.ui_views.form_quick_watch_add"),
data={"url": test_url, "tags": 'restock tests', 'processor': 'restock_diff'},
follow_redirects=True
)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url, tag="restock tests", extras={'processor':"restock_diff"})
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -418,16 +404,12 @@ def test_data_sanity(client, live_server, measure_memory_usage, datastore_path):
## different test, check the edit page works on an empty request result
delete_all_watches(client)
client.post(
url_for("ui.ui_views.form_quick_watch_add"),
data={"url": test_url2, "tags": 'restock tests', 'processor': 'restock_diff'},
follow_redirects=True
)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url2, tag="restock tests", extras={'processor':"restock_diff"})
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(
url_for("ui.ui_edit.edit_page", uuid="first"))
url_for("ui.ui_edit.edit_page", uuid=uuid))
assert test_url2.encode('utf-8') in res.data
delete_all_watches(client)
+1 -1
View File
@@ -144,7 +144,7 @@ def wait_for_all_checks(client=None):
"""
from changedetectionio.flask_app import update_q as global_update_q
from changedetectionio import worker_pool
time.sleep(0.05)
time.sleep(0.15)
# Use the shared wait logic from worker_handler
return worker_pool.wait_for_all_checks(global_update_q, timeout=150)