This commit is contained in:
dgtlmoon
2025-10-28 17:30:17 +01:00
parent 0ca2acd38c
commit 7d8c127e1f
11 changed files with 30 additions and 22 deletions

View File

@@ -1,4 +1,5 @@
from os import getenv
from copy import deepcopy
from changedetectionio.blueprint.rss import RSS_FORMAT_TYPES
@@ -74,7 +75,8 @@ class model(dict):
def __init__(self, *arg, **kw):
super(model, self).__init__(*arg, **kw)
self.update(self.base_config)
# CRITICAL: deepcopy to avoid sharing mutable objects between instances
self.update(deepcopy(self.base_config))
def parse_headers_from_text_file(filepath):

View File

@@ -32,7 +32,7 @@ def prepare_filter_prevew(datastore, watch_uuid, form_data):
'''Used by @app.route("/edit/<string:uuid>/preview-rendered", methods=['POST'])'''
from changedetectionio import forms, html_tools
from changedetectionio.model.Watch import model as watch_model
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import ThreadPoolExecutor
from copy import deepcopy
from flask import request
import brotli
@@ -76,13 +76,16 @@ def prepare_filter_prevew(datastore, watch_uuid, form_data):
update_handler.fetcher.headers['content-type'] = tmp_watch.get('content-type')
# Process our watch with filters and the HTML from disk, and also a blank watch with no filters but also with the same HTML from disk
# Do this as a parallel process because it could take some time
with ProcessPoolExecutor(max_workers=2) as executor:
future1 = executor.submit(_task, tmp_watch, update_handler)
future2 = executor.submit(_task, blank_watch_no_filters, update_handler)
# Do this as parallel threads (not processes) to avoid pickle issues with Lock objects
try:
with ThreadPoolExecutor(max_workers=2) as executor:
future1 = executor.submit(_task, tmp_watch, update_handler)
future2 = executor.submit(_task, blank_watch_no_filters, update_handler)
text_after_filter = future1.result()
text_before_filter = future2.result()
text_after_filter = future1.result()
text_before_filter = future2.result()
except Exception as e:
x=1
try:
trigger_line_numbers = html_tools.strip_ignore_text(content=text_after_filter,

View File

@@ -10,8 +10,9 @@
set -e
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# 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 time pytest -n 16 --dist load --tb=long tests/test_*.py
REMOVE_REQUESTS_OLD_SCREENSHOTS=false pytest -n 30 --dist load tests/test_*.py
#time pytest -n auto --dist loadfile -vv --tb=long tests/test_*.py
echo "RUNNING WITH BASE_URL SET"

View File

@@ -421,7 +421,6 @@ class ChangeDetectionStore:
self.sync_to_json()
return
else:
try:
# Re #286 - First write to a temp file, then confirm it looks OK and rename it
# This is a fairly basic strategy to deal with the case that the file is corrupted,

View File

@@ -11,6 +11,7 @@ import os
import sys
from loguru import logger
from changedetectionio.flask_app import init_app_secret
from changedetectionio.tests.util import live_server_setup, new_live_server_setup
# https://github.com/pallets/flask/blob/1.1.2/examples/tutorial/tests/test_auth.py
@@ -131,6 +132,13 @@ def prepare_test_function(live_server, datastore_path):
# CRITICAL: Point app to THIS test's unique datastore directory
live_server.app.config['TEST_DATASTORE_PATH'] = datastore_path
# CRITICAL: Get datastore and stop it from writing stale data
datastore = live_server.app.config.get('DATASTORE')
# Prevent background thread from writing during cleanup/reload
datastore.needs_write = False
datastore.needs_write_urgent = False
# CRITICAL: Clean up any files from previous tests
# This ensures a completely clean directory
cleanup(datastore_path)
@@ -138,7 +146,6 @@ def prepare_test_function(live_server, 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
datastore = live_server.app.config.get('DATASTORE')
# Reload state with clean data (no default watches)
datastore.reload_state(
@@ -146,7 +153,7 @@ def prepare_test_function(live_server, datastore_path):
include_default_watches=False,
version_tag=datastore.data.get('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))}")
logger.debug(f"prepare_test_function: Path {datastore.datastore_path}")

View File

@@ -65,6 +65,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
"time_between_check_use_default": "y"},
follow_redirects=True
)
assert b"Updated watch." in res.data
wait_for_all_checks(client)
set_original(excluding='Something irrelevant', datastore_path=datastore_path)

View File

@@ -14,9 +14,6 @@ def test_backup(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# Give the endpoint time to spin up
time.sleep(1)
# Add our URL to the import page
res = client.post(
url_for("imports.import_page"),
@@ -32,7 +29,7 @@ def test_backup(client, live_server, measure_memory_usage, datastore_path):
url_for("backups.request_backup"),
follow_redirects=True
)
time.sleep(2)
time.sleep(4)
res = client.get(
url_for("backups.index"),

View File

@@ -136,8 +136,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
with open('/tmp/fuck.html', 'wb') as f:
f.write(res.data)
assert b'has-unread-changes' in res.data

View File

@@ -44,8 +44,7 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
res = client.get(url_for("watchlist.index"))
with open('/tmp/fuck.html', 'wb') as f:
f.write(res.data)
assert b'No website watches configured' not in res.data

View File

@@ -21,7 +21,7 @@ something to trigger<br>
def test_content_filter_live_preview(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_response(datastore_path)
set_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)

View File

@@ -101,7 +101,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
# A totally zero byte (#2528) response should also not trigger an error
set_zero_byte_response()
set_zero_byte_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
# 2877