Compare commits

...

21 Commits

Author SHA1 Message Date
dgtlmoon
ca63dad896 Add extra test 2025-10-28 21:31:25 +01:00
dgtlmoon
bd9b72dbfa fix socks proxy test 2025-10-28 21:24:56 +01:00
dgtlmoon
8473da4bdb these are prolly needed 2025-10-28 21:16:50 +01:00
dgtlmoon
762e2dacb2 tweaks 2025-10-28 21:07:39 +01:00
dgtlmoon
62ea1f9b24 Fix paths 2025-10-28 21:02:41 +01:00
dgtlmoon
14a6ced8f4 adding proxy id info 2025-10-28 20:19:22 +01:00
dgtlmoon
465e5e2ecc more out 2025-10-28 19:05:06 +01:00
dgtlmoon
ada63a3200 more debug 2025-10-28 18:56:38 +01:00
dgtlmoon
eef5425908 more debug 2025-10-28 18:52:11 +01:00
dgtlmoon
096bd21663 m,ore debug 2025-10-28 18:47:11 +01:00
dgtlmoon
0f53233272 more debug 2025-10-28 18:24:28 +01:00
dgtlmoon
faaa9937d6 More caching more debug 2025-10-28 18:17:28 +01:00
dgtlmoon
950d59ccfa Give a startup delay 2025-10-28 18:08:20 +01:00
dgtlmoon
bd3f0360e4 maybe not needed? 2025-10-28 18:07:38 +01:00
dgtlmoon
57347fd55c Show output 2025-10-28 18:01:07 +01:00
dgtlmoon
8ef782760a remove debug 2025-10-28 17:53:20 +01:00
dgtlmoon
4e20fce82c tweaks 2025-10-28 17:47:32 +01:00
dgtlmoon
7d8c127e1f WIP 2025-10-28 17:30:17 +01:00
dgtlmoon
0ca2acd38c pytest-xdist 2025-10-28 16:35:07 +01:00
dgtlmoon
2a0131d0f4 WIP 2025-10-28 16:33:26 +01:00
dgtlmoon
9ed236434e WIP 2025-10-28 16:14:57 +01:00
87 changed files with 986 additions and 773 deletions

View File

@@ -23,26 +23,29 @@ runs:
- name: Dump container log
shell: bash
run: |
docker logs ${{ inputs.container-name }} > ${{ inputs.output-dir }}/${{ inputs.container-name }}-stdout-${{ inputs.python-version }}.txt 2>&1 || echo "Could not get stdout"
docker logs ${{ inputs.container-name }} 2> ${{ inputs.output-dir }}/${{ inputs.container-name }}-stderr-${{ inputs.python-version }}.txt || echo "Could not get stderr"
echo "Disabled for now"
# return
# docker logs ${{ inputs.container-name }} > ${{ inputs.output-dir }}/${{ inputs.container-name }}-stdout-${{ inputs.python-version }}.txt 2>&1 || echo "Could not get stdout"
# docker logs ${{ inputs.container-name }} 2> ${{ inputs.output-dir }}/${{ inputs.container-name }}-stderr-${{ inputs.python-version }}.txt || echo "Could not get stderr"
- name: Extract and display memory test report
shell: bash
run: |
echo "Extracting test-memory.log from container..."
docker cp ${{ inputs.container-name }}:/app/changedetectionio/test-memory.log ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log || echo "test-memory.log not found in container"
echo "=== Top 10 Highest Peak Memory Tests ==="
if [ -f ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log ]; then
grep "Peak memory:" ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log | \
sed 's/.*Peak memory: //' | \
paste -d'|' - <(grep "Peak memory:" ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log) | \
sort -t'|' -k1 -nr | \
cut -d'|' -f2 | \
head -10
echo ""
echo "=== Full Memory Test Report ==="
cat ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log
else
echo "No memory log available"
fi
echo "Disabled for now"
# echo "Extracting test-memory.log from container..."
# docker cp ${{ inputs.container-name }}:/app/changedetectionio/test-memory.log ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log || echo "test-memory.log not found in container"
#
# echo "=== Top 10 Highest Peak Memory Tests ==="
# if [ -f ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log ]; then
# grep "Peak memory:" ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log | \
# sed 's/.*Peak memory: //' | \
# paste -d'|' - <(grep "Peak memory:" ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log) | \
# sort -t'|' -k1 -nr | \
# cut -d'|' -f2 | \
# head -10
# echo ""
# echo "=== Full Memory Test Report ==="
# cat ${{ inputs.output-dir }}/test-memory-${{ inputs.python-version }}.log
# else
# echo "No memory log available"
# fi

View File

@@ -45,6 +45,14 @@ jobs:
with:
python-version: 3.11
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip

View File

@@ -50,6 +50,14 @@ jobs:
with:
python-version: 3.11
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
# Just test that the build works, some libraries won't compile on ARM/rPi etc
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

View File

@@ -28,6 +28,15 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-py${{ env.PYTHON_VERSION }}-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-py${{ env.PYTHON_VERSION }}-
${{ runner.os }}-pip-
- name: Build changedetection.io container for testing under Python ${{ env.PYTHON_VERSION }}
run: |
echo "---- Building for Python ${{ env.PYTHON_VERSION }} -----"
@@ -289,15 +298,18 @@ jobs:
docker run --network changedet-network -d -e "LOG_LEVEL=TRACE" --cap-add=SYS_ADMIN --name sockpuppetbrowser --hostname sockpuppetbrowser --rm -p 3000:3000 dgtlmoon/sockpuppetbrowser:latest
docker run --network changedet-network -d -e "LOG_LEVEL=TRACE" --cap-add=SYS_ADMIN --name sockpuppetbrowser-custom-url --hostname sockpuppetbrowser-custom-url -p 3001:3000 --rm dgtlmoon/sockpuppetbrowser:latest
- name: Test proxy squid style interaction
- name: Test proxy Squid style interaction
run: |
cd changedetectionio
./run_proxy_tests.sh
docker ps
cd ..
- name: Test proxy SOCKS5 style interaction
run: |
cd changedetectionio
./run_socks_proxy_tests.sh
cd ..
# Custom browser URL tests
custom-browser-tests:

View File

@@ -36,6 +36,7 @@ ENV OPENSSL_INCLUDE_DIR="/usr/include/openssl"
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
RUN --mount=type=cache,target=/tmp/pip-cache \
pip install \
--prefer-binary \
--extra-index-url https://www.piwheels.org/simple \
--extra-index-url https://pypi.anaconda.org/ARM-software/simple \
--cache-dir=/tmp/pip-cache \
@@ -47,6 +48,7 @@ RUN --mount=type=cache,target=/tmp/pip-cache \
# https://github.com/dgtlmoon/changedetection.io/pull/1067 also musl/alpine (not supported)
RUN --mount=type=cache,target=/tmp/pip-cache \
pip install \
--prefer-binary \
--cache-dir=/tmp/pip-cache \
--target=/dependencies \
playwright~=1.48.0 \

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

@@ -91,6 +91,8 @@ class difference_detection_processor():
else:
logger.debug("Skipping adding proxy data when custom Browser endpoint is specified. ")
logger.debug(f"Using proxy '{proxy_url}' for {self.watch['uuid']}")
# Now call the fetcher (playwright/requests/etc) with arguments that only a fetcher would need.
# When browser_connection_url is None, it method should default to working out whats the best defaults (os env vars etc)
self.fetcher = fetcher_obj(proxy_override=proxy_url,

View File

@@ -88,7 +88,7 @@ class guess_stream_type():
magic_content_header = mime
except Exception as e:
logger.error(f"Error getting a more precise mime type from 'puremagic' library ({str(e)}), using content-based detection")
logger.warning(f"Error getting a more precise mime type from 'puremagic' library ({str(e)}), using content-based detection")
# Content-based detection (most reliable for text formats)
# Check for HTML patterns first - if found, override magic's text/plain

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

@@ -1,5 +1,5 @@
[pytest]
addopts = --no-start-live-server --live-server-port=5005
addopts = --no-start-live-server --live-server-port=0
#testpaths = tests pytest_invenio
#live_server_scope = function

View File

@@ -11,19 +11,16 @@ set -e
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
find tests/test_*py -type f|while read test_name
do
echo "TEST RUNNING $test_name"
# 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 -vv -s --maxfail=1 --tb=long $test_name
done
# 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 -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"
# Now re-run some tests with BASE_URL enabled
# Re #65 - Ability to include a link back to the installation, in the notification.
export BASE_URL="https://really-unique-domain.io"
REMOVE_REQUESTS_OLD_SCREENSHOTS=false pytest -vv -s --maxfail=1 tests/test_notification.py
REMOVE_REQUESTS_OLD_SCREENSHOTS=false pytest -vv --maxfail=1 tests/test_notification.py
# Re-run with HIDE_REFERER set - could affect login

View File

@@ -5,8 +5,6 @@ set -e
# enable debug
set -x
docker network inspect changedet-network >/dev/null 2>&1 || docker network create changedet-network
# Test proxy list handling, starting two squids on different ports
# Each squid adds a different header to the response, which is the main thing we test for.
docker run --network changedet-network -d --name squid-one --hostname squid-one --rm -v `pwd`/tests/proxy_list/squid.conf:/etc/squid/conf.d/debian.conf ubuntu/squid:4.13-21.10_edge
@@ -21,12 +19,13 @@ docker run --network changedet-network -d \
-v `pwd`/tests/proxy_list/squid-passwords.txt:/etc/squid3/passwords \
ubuntu/squid:4.13-21.10_edge
sleep 5
## 2nd test actually choose the preferred proxy from proxies.json
# This will force a request via "proxy-two"
docker run --network changedet-network \
-v `pwd`/tests/proxy_list/proxies.json-example:/app/changedetectionio/test-datastore/proxies.json \
-v `pwd`/tests/proxy_list/proxies.json-example:/tmp/proxies.json \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_multiple_proxy.py'
bash -c 'cd changedetectionio && pytest -s tests/proxy_list/test_multiple_proxy.py --datastore-path /tmp'
set +e
echo "- Looking for chosen.changedetection.io request in squid-one - it should NOT be here"
@@ -50,8 +49,10 @@ fi
# Test the UI configurable proxies
docker run --network changedet-network \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_select_custom_proxy.py'
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_select_custom_proxy.py --datastore-path /tmp'
# Give squid proxies a moment to flush their logs
sleep 2
# Should see a request for one.changedetection.io in there
echo "- Looking for .changedetection.io request in squid-custom"
@@ -65,7 +66,10 @@ fi
# Test "no-proxy" option
docker run --network changedet-network \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_noproxy.py'
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_noproxy.py --datastore-path /tmp'
# Give squid proxies a moment to flush their logs
sleep 2
# We need to handle grep returning 1
set +e
@@ -82,6 +86,8 @@ for c in $(echo "squid-one squid-two squid-custom"); do
fi
done
echo "docker ps output"
docker ps
docker kill squid-one squid-two squid-custom
@@ -90,19 +96,19 @@ docker kill squid-one squid-two squid-custom
# Requests
docker run --network changedet-network \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_proxy_noconnect.py'
bash -c 'cd changedetectionio && pytest tests/proxy_list/test_proxy_noconnect.py --datastore-path /tmp'
# Playwright
docker run --network changedet-network \
test-changedetectionio \
bash -c 'cd changedetectionio && PLAYWRIGHT_DRIVER_URL=ws://sockpuppetbrowser:3000 pytest tests/proxy_list/test_proxy_noconnect.py'
bash -c 'cd changedetectionio && PLAYWRIGHT_DRIVER_URL=ws://sockpuppetbrowser:3000 pytest tests/proxy_list/test_proxy_noconnect.py --datastore-path /tmp'
# Puppeteer fast
docker run --network changedet-network \
test-changedetectionio \
bash -c 'cd changedetectionio && FAST_PUPPETEER_CHROME_FETCHER=1 PLAYWRIGHT_DRIVER_URL=ws://sockpuppetbrowser:3000 pytest tests/proxy_list/test_proxy_noconnect.py'
bash -c 'cd changedetectionio && FAST_PUPPETEER_CHROME_FETCHER=1 PLAYWRIGHT_DRIVER_URL=ws://sockpuppetbrowser:3000 pytest tests/proxy_list/test_proxy_noconnect.py --datastore-path /tmp'
# Selenium
docker run --network changedet-network \
test-changedetectionio \
bash -c 'cd changedetectionio && WEBDRIVER_URL=http://selenium:4444/wd/hub pytest tests/proxy_list/test_proxy_noconnect.py'
bash -c 'cd changedetectionio && WEBDRIVER_URL=http://selenium:4444/wd/hub pytest tests/proxy_list/test_proxy_noconnect.py --datastore-path /tmp'

View File

@@ -15,13 +15,13 @@ docker run --network changedet-network -d --hostname socks5proxy-noauth --rm -p
echo "---------------------------------- SOCKS5 -------------------"
# SOCKS5 related - test from proxies.json
docker run --network changedet-network \
-v `pwd`/tests/proxy_socks5/proxies.json-example:/app/changedetectionio/test-datastore/proxies.json \
-v `pwd`/tests/proxy_socks5/proxies.json-example:/tmp/proxies.json \
--rm \
-e "FLASK_SERVER_NAME=cdio" \
--hostname cdio \
-e "SOCKSTEST=proxiesjson" \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest --live-server-host=0.0.0.0 --live-server-port=5004 -s tests/proxy_socks5/test_socks5_proxy_sources.py'
bash -c 'cd changedetectionio && pytest --live-server-host=0.0.0.0 --live-server-port=5004 -s tests/proxy_socks5/test_socks5_proxy_sources.py --datastore-path /tmp'
# SOCKS5 related - by manually entering in UI
docker run --network changedet-network \
@@ -30,18 +30,18 @@ docker run --network changedet-network \
--hostname cdio \
-e "SOCKSTEST=manual" \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest --live-server-host=0.0.0.0 --live-server-port=5004 -s tests/proxy_socks5/test_socks5_proxy.py'
bash -c 'cd changedetectionio && pytest --live-server-host=0.0.0.0 --live-server-port=5004 -s tests/proxy_socks5/test_socks5_proxy.py --datastore-path /tmp'
# SOCKS5 related - test from proxies.json via playwright - NOTE- PLAYWRIGHT DOESNT SUPPORT AUTHENTICATING PROXY
docker run --network changedet-network \
-e "SOCKSTEST=manual-playwright" \
--hostname cdio \
-e "FLASK_SERVER_NAME=cdio" \
-v `pwd`/tests/proxy_socks5/proxies.json-example-noauth:/app/changedetectionio/test-datastore/proxies.json \
-v `pwd`/tests/proxy_socks5/proxies.json-example-noauth:/tmp/proxies.json \
-e "PLAYWRIGHT_DRIVER_URL=ws://sockpuppetbrowser:3000" \
--rm \
test-changedetectionio \
bash -c 'cd changedetectionio && pytest --live-server-host=0.0.0.0 --live-server-port=5004 -s tests/proxy_socks5/test_socks5_proxy_sources.py'
bash -c 'cd changedetectionio && pytest --live-server-host=0.0.0.0 --live-server-port=5004 -s tests/proxy_socks5/test_socks5_proxy_sources.py --datastore-path /tmp'
echo "socks5 server logs"
docker logs socks5proxy

View File

@@ -42,17 +42,24 @@ class ChangeDetectionStore:
needs_write_urgent = False
__version_check = True
save_data_thread = None
def __init__(self, datastore_path="/datastore", include_default_watches=True, version_tag="0.0.0"):
# Should only be active for docker
# logging.basicConfig(filename='/dev/stdout', level=logging.INFO)
self.__data = App.model()
self.datastore_path = datastore_path
self.json_store_path = os.path.join(self.datastore_path, "url-watches.json")
logger.info(f"Datastore path is '{self.json_store_path}'")
self.needs_write = False
self.start_time = time.time()
self.stop_thread = False
self.reload_state(datastore_path=datastore_path, include_default_watches=include_default_watches, version_tag=version_tag)
def reload_state(self, datastore_path, include_default_watches, version_tag):
logger.info(f"Datastore path is '{datastore_path}'")
self.__data = App.model()
self.datastore_path = datastore_path
self.json_store_path = os.path.join(self.datastore_path, "url-watches.json")
# Base definition for all watchers
# deepcopy part of #569 - not sure why its needed exactly
self.generic_definition = deepcopy(Watch.model(datastore_path = datastore_path, default={}))
@@ -145,7 +152,10 @@ class ChangeDetectionStore:
self.needs_write = True
# Finally start the thread that will manage periodic data saves to JSON
save_data_thread = threading.Thread(target=self.save_datastore).start()
# Only start if thread is not already running (reload_state might be called multiple times)
if not self.save_data_thread or not self.save_data_thread.is_alive():
self.save_data_thread = threading.Thread(target=self.save_datastore)
self.save_data_thread.start()
def rehydrate_entity(self, uuid, entity, processor_override=None):
"""Set the dict back to the dict Watch object"""
@@ -411,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,
@@ -441,7 +450,7 @@ class ChangeDetectionStore:
logger.remove()
logger.add(sys.stderr)
logger.critical("Shutting down datastore thread")
logger.info(f"Shutting down datastore '{self.datastore_path}' thread")
return
if self.needs_write or self.needs_write_urgent:

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
@@ -87,7 +88,6 @@ def measure_memory_usage(request):
def cleanup(datastore_path):
import glob
# Unlink test output files
for g in ["*.txt", "*.json", "*.pdf"]:
files = glob.glob(os.path.join(datastore_path, g))
for f in files:
@@ -97,34 +97,121 @@ def cleanup(datastore_path):
if os.path.isfile(f):
os.unlink(f)
@pytest.fixture(scope='function', autouse=True)
def prepare_test_function(live_server):
def pytest_addoption(parser):
"""Add custom command-line options for pytest.
Provides --datastore-path option for specifying custom datastore location.
Note: Cannot use -d short option as it's reserved by pytest for debug mode.
"""
parser.addoption(
"--datastore-path",
action="store",
default=None,
help="Custom datastore path for tests"
)
@pytest.fixture(scope='session')
def datastore_path(tmp_path_factory, request):
"""Provide datastore path unique to this worker.
Supports custom path via --datastore-path/-d flag (mirrors main app).
CRITICAL for xdist isolation:
- Each WORKER gets its own directory
- Tests on same worker run SEQUENTIALLY and cleanup between tests
- No subdirectories needed since tests don't overlap on same worker
- Example: /tmp/test-datastore-gw0/ for worker gw0
"""
# Check for custom path first (mirrors main app's -d flag)
custom_path = request.config.getoption("--datastore-path")
if custom_path:
# Ensure the directory exists
os.makedirs(custom_path, exist_ok=True)
logger.info(f"Using custom datastore path: {custom_path}")
return custom_path
# Otherwise use default tmp_path_factory logic
worker_id = getattr(request.config, 'workerinput', {}).get('workerid', 'master')
if worker_id == 'master':
path = tmp_path_factory.mktemp("test-datastore")
else:
path = tmp_path_factory.mktemp(f"test-datastore-{worker_id}")
return str(path)
@pytest.fixture(scope='function', autouse=True)
def prepare_test_function(live_server, datastore_path):
"""Prepare each test with complete isolation.
CRITICAL for xdist per-test isolation:
- Reuses the SAME datastore instance (so blueprint references stay valid)
- Clears all watches and state for a clean slate
- First watch will get uuid="first"
"""
routes = [rule.rule for rule in live_server.app.url_map.iter_rules()]
if '/test-random-content-endpoint' not in routes:
logger.debug("Setting up test URL routes")
new_live_server_setup(live_server)
# 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)
# 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
# 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')
)
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}")
yield
# Then cleanup/shutdown
live_server.app.config['DATASTORE'].data['watching']={}
time.sleep(0.3)
live_server.app.config['DATASTORE'].data['watching']={}
# Cleanup: Clear watches again after test
try:
datastore.data['watching'] = {}
datastore.needs_write = True
except Exception as e:
logger.warning(f"Error during datastore cleanup: {e}")
# So the app can also know which test name it was
@pytest.fixture(autouse=True)
def set_test_name(request):
"""Automatically set TEST_NAME env var for every test"""
test_name = request.node.name
os.environ['PYTEST_CURRENT_TEST'] = test_name
yield
# Cleanup if needed
@pytest.fixture(scope='session')
def app(request):
"""Create application for the tests."""
datastore_path = "./test-datastore"
def app(request, datastore_path):
"""Create application once per worker (session).
Note: Actual per-test isolation is handled by:
- prepare_test_function() recreates datastore and cleans directory
- All tests on same worker use same directory (cleaned between tests)
"""
# So they don't delay in fetching
os.environ["MINIMUM_SECONDS_RECHECK_TIME"] = "0"
try:
os.mkdir(datastore_path)
except FileExistsError:
pass
logger.debug(f"Testing with datastore_path={datastore_path}")
cleanup(datastore_path)
app_config = {'datastore_path': datastore_path, 'disable_checkver' : True}
@@ -147,6 +234,8 @@ def app(request):
# Disable CSRF while running tests
app.config['WTF_CSRF_ENABLED'] = False
app.config['STOP_THREADS'] = True
# Store datastore_path so Flask routes can access it
app.config['TEST_DATASTORE_PATH'] = datastore_path
def teardown():
# Stop all threads and services

View File

@@ -73,13 +73,13 @@ def do_test(client, live_server, make_test_use_extra_browser=False):
# Requires playwright to be installed
def test_request_via_custom_browser_url(client, live_server, measure_memory_usage):
def test_request_via_custom_browser_url(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# We do this so we can grep the logs of the custom container and see if the request actually went through that container
do_test(client, live_server, make_test_use_extra_browser=True)
def test_request_not_via_custom_browser_url(client, live_server, measure_memory_usage):
def test_request_not_via_custom_browser_url(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# We do this so we can grep the logs of the custom container and see if the request actually went through that container
do_test(client, live_server, make_test_use_extra_browser=False)

View File

@@ -8,7 +8,7 @@ import logging
# Requires playwright to be installed
def test_fetch_webdriver_content(client, live_server, measure_memory_usage):
def test_fetch_webdriver_content(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
#####################

View File

@@ -3,7 +3,7 @@ from flask import url_for
from ..util import live_server_setup, wait_for_all_checks, extract_UUID_from_client
def test_execute_custom_js(client, live_server, measure_memory_usage):
def test_execute_custom_js(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
assert os.getenv('PLAYWRIGHT_DRIVER_URL'), "Needs PLAYWRIGHT_DRIVER_URL set for this test"

View File

@@ -5,7 +5,7 @@ from flask import url_for
from ..util import live_server_setup, wait_for_all_checks
def test_preferred_proxy(client, live_server, measure_memory_usage):
def test_preferred_proxy(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
url = "http://chosen.changedetection.io"

View File

@@ -5,7 +5,7 @@ from flask import url_for
from ..util import live_server_setup, wait_for_all_checks, extract_UUID_from_client
def test_noproxy_option(client, live_server, measure_memory_usage):
def test_noproxy_option(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# Run by run_proxy_tests.sh
# Call this URL then scan the containers that it never went through them

View File

@@ -5,7 +5,7 @@ from flask import url_for
from ..util import live_server_setup, wait_for_all_checks, extract_UUID_from_client
# just make a request, we will grep in the docker logs to see it actually got called
def test_check_basic_change_detection_functionality(client, live_server, measure_memory_usage):
def test_check_basic_change_detection_functionality(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
res = client.post(
url_for("imports.import_page"),

View File

@@ -12,7 +12,7 @@ from ... import strtobool
# FAST_PUPPETEER_CHROME_FETCHER=True PLAYWRIGHT_DRIVER_URL=ws://127.0.0.1:3000 pytest tests/proxy_list/test_proxy_noconnect.py
# WEBDRIVER_URL=http://127.0.0.1:4444/wd/hub pytest tests/proxy_list/test_proxy_noconnect.py
def test_proxy_noconnect_custom(client, live_server, measure_memory_usage):
def test_proxy_noconnect_custom(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# Goto settings, add our custom one

View File

@@ -6,7 +6,7 @@ from ..util import live_server_setup, wait_for_all_checks
import os
# just make a request, we will grep in the docker logs to see it actually got called
def test_select_custom(client, live_server, measure_memory_usage):
def test_select_custom(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# Goto settings, add our custom one
@@ -50,7 +50,7 @@ def test_select_custom(client, live_server, measure_memory_usage):
# Now we should see the request in the container logs for "squid-squid-custom" because it will be the only default
def test_custom_proxy_validation(client, live_server, measure_memory_usage):
def test_custom_proxy_validation(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# Goto settings, add our custom one

View File

@@ -5,7 +5,7 @@ from flask import url_for
from changedetectionio.tests.util import live_server_setup, wait_for_all_checks, extract_UUID_from_client, delete_all_watches
def set_response():
def set_response(datastore_path):
import time
data = """<html>
<body>
@@ -15,13 +15,13 @@ def set_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(data)
time.sleep(1)
def test_socks5(client, live_server, measure_memory_usage):
def test_socks5(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_response()
set_response(datastore_path)
# Setup a proxy
res = client.post(

View File

@@ -4,7 +4,7 @@ from flask import url_for
from changedetectionio.tests.util import live_server_setup, wait_for_all_checks
def set_response():
def set_response(datastore_path):
import time
data = """<html>
<body>
@@ -14,15 +14,15 @@ def set_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(data)
time.sleep(1)
# should be proxies.json mounted from run_proxy_tests.sh already
# -v `pwd`/tests/proxy_socks5/proxies.json-example:/app/changedetectionio/test-datastore/proxies.json
def test_socks5_from_proxiesjson_file(client, live_server, measure_memory_usage):
def test_socks5_from_proxiesjson_file(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_response()
set_response(datastore_path)
# Because the socks server should connect back to us
test_url = url_for('test_endpoint', _external=True) + f"?socks-test-tag={os.getenv('SOCKSTEST', '')}"
test_url = test_url.replace('localhost.localdomain', 'cdio')

View File

@@ -11,7 +11,7 @@ from changedetectionio.notification import (
)
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
<section id=header style="padding: 50px; height: 350px">This is the header which should be ignored always - <span>add to cart</span></section>
@@ -26,13 +26,13 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_back_in_stock_response():
def set_back_in_stock_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -45,14 +45,14 @@ def set_back_in_stock_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
# Add a site in paused mode, add an invalid filter, we should still have visual selector data ready
def test_restock_detection(client, live_server, measure_memory_usage):
def test_restock_detection(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
#assert os.getenv('PLAYWRIGHT_DRIVER_URL'), "Needs PLAYWRIGHT_DRIVER_URL set for this test"
# live_server_setup(live_server) # Setup on conftest per function
#####################
@@ -88,24 +88,25 @@ def test_restock_detection(client, live_server, measure_memory_usage):
assert b'not-in-stock' in res.data # should be out of stock
# Is it correctly shown as in stock
set_back_in_stock_response()
set_back_in_stock_response(datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
assert b'not-in-stock' not in res.data
# We should have a notification
wait_for_notification_endpoint_output()
assert os.path.isfile("test-datastore/notification.txt"), "Notification received"
os.unlink("test-datastore/notification.txt")
notification_file = os.path.join(datastore_path, "notification.txt")
wait_for_notification_endpoint_output(datastore_path=datastore_path)
assert os.path.isfile(notification_file), "Notification received"
os.unlink(notification_file)
# Default behaviour is to only fire notification when it goes OUT OF STOCK -> IN STOCK
# So here there should be no file, because we go IN STOCK -> OUT OF STOCK
set_original_response()
set_original_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
time.sleep(5)
assert not os.path.isfile("test-datastore/notification.txt"), "No notification should have fired when it went OUT OF STOCK by default"
assert not os.path.isfile(notification_file), "No notification should have fired when it went OUT OF STOCK by default"
# BUT we should see that it correctly shows "not in stock"
res = client.get(url_for("watchlist.index"))

View File

@@ -40,9 +40,10 @@ def get_last_message_from_smtp_server():
# Requires running the test SMTP server
def test_check_notification_email_formats_default_HTML(client, live_server, measure_memory_usage):
def test_check_notification_email_formats_default_HTML(client, live_server, measure_memory_usage, datastore_path):
## live_server_setup(live_server) # Setup on conftest per function
set_original_response()
set_original_response(datastore_path=datastore_path)
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -71,7 +72,7 @@ def test_check_notification_email_formats_default_HTML(client, live_server, meas
assert b"Watch added" in res.data
wait_for_all_checks(client)
set_longer_modified_response()
set_longer_modified_response(datastore_path=datastore_path)
time.sleep(2)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -112,8 +113,9 @@ def test_check_notification_email_formats_default_HTML(client, live_server, meas
delete_all_watches(client)
def test_check_notification_plaintext_format(client, live_server, measure_memory_usage):
set_original_response()
def test_check_notification_plaintext_format(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -138,7 +140,7 @@ def test_check_notification_plaintext_format(client, live_server, measure_memory
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
time.sleep(2)
set_longer_modified_response()
set_longer_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -164,8 +166,9 @@ def test_check_notification_plaintext_format(client, live_server, measure_memory
def test_check_notification_html_color_format(client, live_server, measure_memory_usage):
set_original_response()
def test_check_notification_html_color_format(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -195,7 +198,7 @@ def test_check_notification_html_color_format(client, live_server, measure_memor
assert b"Watch added" in res.data
wait_for_all_checks(client)
set_longer_modified_response()
set_longer_modified_response(datastore_path=datastore_path)
time.sleep(2)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -235,8 +238,9 @@ def test_check_notification_html_color_format(client, live_server, measure_memor
assert 'some text<br>' in html_content
delete_all_watches(client)
def test_check_notification_markdown_format(client, live_server, measure_memory_usage):
set_original_response()
def test_check_notification_markdown_format(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -266,7 +270,7 @@ def test_check_notification_markdown_format(client, live_server, measure_memory_
assert b"Watch added" in res.data
wait_for_all_checks(client)
set_longer_modified_response()
set_longer_modified_response(datastore_path=datastore_path)
time.sleep(2)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -305,12 +309,13 @@ def test_check_notification_markdown_format(client, live_server, measure_memory_
delete_all_watches(client)
# Custom notification body with HTML, that is either sent as HTML or rendered to plaintext and sent
def test_check_notification_email_formats_default_Text_override_HTML(client, live_server, measure_memory_usage):
def test_check_notification_email_formats_default_Text_override_HTML(client, live_server, measure_memory_usage, datastore_path):
# HTML problems? see this
# https://github.com/caronc/apprise/issues/633
set_original_response()
set_original_response(datastore_path=datastore_path)
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
notification_body = f"""<!DOCTYPE html>
<html lang="en">
@@ -350,7 +355,7 @@ def test_check_notification_email_formats_default_Text_override_HTML(client, liv
#################################### FIRST SITUATION, PLAIN TEXT NOTIFICATION IS WANTED BUT WE HAVE HTML IN OUR TEMPLATE AND CONTENT ##########
wait_for_all_checks(client)
set_longer_modified_response()
set_longer_modified_response(datastore_path=datastore_path)
time.sleep(2)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -375,7 +380,8 @@ def test_check_notification_email_formats_default_Text_override_HTML(client, liv
#################################### SECOND SITUATION, HTML IS CORRECTLY PASSED THROUGH TO THE EMAIL ####################
set_original_response()
set_original_response(datastore_path=datastore_path)
# Now override as HTML format
res = client.post(
url_for("ui.ui_edit.edit_page", uuid="first"),
@@ -424,10 +430,11 @@ def test_check_notification_email_formats_default_Text_override_HTML(client, liv
delete_all_watches(client)
def test_check_plaintext_document_plaintext_notification_smtp(client, live_server, measure_memory_usage):
def test_check_plaintext_document_plaintext_notification_smtp(client, live_server, measure_memory_usage, datastore_path):
"""When following a plaintext document, notification in Plain Text format is sent correctly"""
import os
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Some nice plain text\nwhich we add some extra data\nover here\n")
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -454,7 +461,7 @@ def test_check_plaintext_document_plaintext_notification_smtp(client, live_serve
wait_for_all_checks(client)
# Change the content
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Some nice plain text\nwhich we add some extra data\nAnd let's talk about <title> tags\nover here\n")
@@ -476,10 +483,11 @@ def test_check_plaintext_document_plaintext_notification_smtp(client, live_serve
assert '<pre' not in body
delete_all_watches(client)
def test_check_plaintext_document_html_notifications(client, live_server, measure_memory_usage):
def test_check_plaintext_document_html_notifications(client, live_server, measure_memory_usage, datastore_path):
"""When following a plaintext document, notification in Plain Text format is sent correctly"""
import os
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(" Some nice plain text\nwhich we add some extra data\nover here\n")
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -506,7 +514,7 @@ def test_check_plaintext_document_html_notifications(client, live_server, measur
wait_for_all_checks(client)
# Change the content
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(" Some nice plain text\nwhich we add some extra data\nAnd let's talk about <title> tags\nover here\n")
@@ -554,10 +562,11 @@ def test_check_plaintext_document_html_notifications(client, live_server, measur
delete_all_watches(client)
def test_check_plaintext_document_html_color_notifications(client, live_server, measure_memory_usage):
def test_check_plaintext_document_html_color_notifications(client, live_server, measure_memory_usage, datastore_path):
"""When following a plaintext document, notification in Plain Text format is sent correctly"""
import os
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Some nice plain text\nwhich we add some extra data\nover here\n")
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -585,7 +594,7 @@ def test_check_plaintext_document_html_color_notifications(client, live_server,
wait_for_all_checks(client)
# Change the content
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Some nice plain text\nwhich we add some extra data\nAnd let's talk about <title> tags\nover here\n")
time.sleep(1)
@@ -626,10 +635,11 @@ def test_check_plaintext_document_html_color_notifications(client, live_server,
assert '<pre role="article"' in html_content # Should have got wrapped nicely in email_helpers.py
delete_all_watches(client)
def test_check_html_document_plaintext_notification(client, live_server, measure_memory_usage):
def test_check_html_document_plaintext_notification(client, live_server, measure_memory_usage, datastore_path):
"""When following a HTML document, notification in Plain Text format is sent correctly"""
import os
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html><body>some stuff<br>and more stuff<br>and even more stuff<br></body></html>")
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com'
@@ -656,7 +666,7 @@ def test_check_html_document_plaintext_notification(client, live_server, measure
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html><body>sxome stuff<br>and more stuff<br>lets slip this in<br>and this in<br>and even more stuff<br>&lt;tag&gt;</body></html>")
time.sleep(0.1)
@@ -682,9 +692,10 @@ def test_check_html_document_plaintext_notification(client, live_server, measure
delete_all_watches(client)
def test_check_html_notification_with_apprise_format_is_html(client, live_server, measure_memory_usage):
def test_check_html_notification_with_apprise_format_is_html(client, live_server, measure_memory_usage, datastore_path):
## live_server_setup(live_server) # Setup on conftest per function
set_original_response()
set_original_response(datastore_path=datastore_path)
notification_url = f'mailto://changedetection@{smtp_test_server}:11025/?to=fff@home.com&format=html'
@@ -713,7 +724,7 @@ def test_check_html_notification_with_apprise_format_is_html(client, live_server
assert b"Watch added" in res.data
wait_for_all_checks(client)
set_longer_modified_response()
set_longer_modified_response(datastore_path=datastore_path)
time.sleep(2)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -2,7 +2,7 @@ from .util import live_server_setup, wait_for_all_checks
from flask import url_for
import time
def test_check_access_control(app, client, live_server, measure_memory_usage):
def test_check_access_control(app, client, live_server, measure_memory_usage, datastore_path):
# Still doesnt work, but this is closer.
# live_server_setup(live_server) # Setup on conftest per function

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import os.path
import os
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, wait_for_notification_endpoint_output, delete_all_watches
@@ -9,7 +10,7 @@ import time
from ..diff import ADDED_PLACEMARKER_OPEN
def set_original(excluding=None, add_line=None):
def set_original(datastore_path, excluding=None, add_line=None):
test_return_data = """<html>
<body>
<p>Some initial text</p>
@@ -35,16 +36,16 @@ def set_original(excluding=None, add_line=None):
test_return_data = output
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_check_removed_line_contains_trigger(client, live_server, measure_memory_usage):
def test_check_removed_line_contains_trigger(client, live_server, measure_memory_usage, datastore_path):
# Give the endpoint time to spin up
set_original()
set_original(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -64,9 +65,10 @@ 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')
set_original(excluding='Something irrelevant', datastore_path=datastore_path)
# A line thats not the trigger should not trigger anything
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -77,7 +79,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
assert b'has-unread-changes' not in res.data
# The trigger line is REMOVED, this should trigger
set_original(excluding='The golden line')
set_original(excluding='The golden line', datastore_path=datastore_path)
# Check in the processor here what's going on, its triggering empty-reply and no change.
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -92,7 +94,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
time.sleep(0.2)
time.sleep(1)
set_original(excluding=None)
set_original(excluding=None, datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
time.sleep(1)
@@ -100,7 +102,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
assert b'has-unread-changes' not in res.data
# Remove it again, and we should get a trigger
set_original(excluding='The golden line')
set_original(excluding='The golden line', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -109,7 +111,7 @@ def test_check_removed_line_contains_trigger(client, live_server, measure_memory
delete_all_watches(client)
def test_check_add_line_contains_trigger(client, live_server, measure_memory_usage):
def test_check_add_line_contains_trigger(client, live_server, measure_memory_usage, datastore_path):
delete_all_watches(client)
time.sleep(1)
@@ -132,7 +134,7 @@ def test_check_add_line_contains_trigger(client, live_server, measure_memory_usa
)
assert b'Settings updated' in res.data
set_original()
set_original(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -155,7 +157,7 @@ def test_check_add_line_contains_trigger(client, live_server, measure_memory_usa
)
assert b"Updated watch." in res.data
wait_for_all_checks(client)
set_original(excluding='Something irrelevant')
set_original(excluding='Something irrelevant', datastore_path=datastore_path)
# A line thats not the trigger should not trigger anything
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -166,7 +168,7 @@ def test_check_add_line_contains_trigger(client, live_server, measure_memory_usa
assert b'has-unread-changes' not in res.data
# The trigger line is ADDED, this should trigger
set_original(add_line='<p>Oh yes please</p>')
set_original(add_line='<p>Oh yes please</p>', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -174,9 +176,9 @@ def test_check_add_line_contains_trigger(client, live_server, measure_memory_usa
assert b'has-unread-changes' in res.data
# Takes a moment for apprise to fire
wait_for_notification_endpoint_output()
assert os.path.isfile("test-datastore/notification.txt"), "Notification fired because I can see the output file"
with open("test-datastore/notification.txt", 'rb') as f:
wait_for_notification_endpoint_output(datastore_path=datastore_path)
assert os.path.isfile(os.path.join(datastore_path, "notification.txt")), "Notification fired because I can see the output file"
with open(os.path.join(datastore_path, "notification.txt"), 'rb') as f:
response = f.read()
assert ADDED_PLACEMARKER_OPEN.encode('utf-8') not in response # _apply_diff_filtering shouldnt add something here
assert b'-Oh yes please' in response

View File

@@ -3,12 +3,13 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
import os
import json
import uuid
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -21,12 +22,12 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -39,7 +40,7 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
@@ -52,17 +53,17 @@ def is_valid_uuid(val):
return False
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_api_simple(client, live_server, measure_memory_usage):
def test_api_simple(client, live_server, measure_memory_usage, datastore_path):
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
# Create a watch
set_original_response()
set_original_response(datastore_path=datastore_path)
# Validate bad URL
test_url = url_for('test_endpoint', _external=True )
@@ -111,7 +112,7 @@ def test_api_simple(client, live_server, measure_memory_usage):
time.sleep(1)
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger recheck of all ?recheck_all=1
client.get(
url_for("createwatch", recheck_all='1'),
@@ -244,7 +245,7 @@ def test_api_simple(client, live_server, measure_memory_usage):
)
assert len(res.json) == 0, "Watch list should be empty"
def test_access_denied(client, live_server, measure_memory_usage):
def test_access_denied(client, live_server, measure_memory_usage, datastore_path):
# `config_api_token_enabled` Should be On by default
res = client.get(
url_for("createwatch")
@@ -289,11 +290,11 @@ def test_access_denied(client, live_server, measure_memory_usage):
)
assert b"Settings updated." in res.data
def test_api_watch_PUT_update(client, live_server, measure_memory_usage):
def test_api_watch_PUT_update(client, live_server, measure_memory_usage, datastore_path):
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
# Create a watch
set_original_response()
set_original_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)
# Create new
@@ -398,7 +399,7 @@ def test_api_watch_PUT_update(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_api_import(client, live_server, measure_memory_usage):
def test_api_import(client, live_server, measure_memory_usage, datastore_path):
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -420,7 +421,7 @@ def test_api_import(client, live_server, measure_memory_usage):
res = client.get(url_for('tags.tags_overview_page'))
assert b'import-test' in res.data
def test_api_conflict_UI_password(client, live_server, measure_memory_usage):
def test_api_conflict_UI_password(client, live_server, measure_memory_usage, datastore_path):
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -438,7 +439,7 @@ def test_api_conflict_UI_password(client, live_server, measure_memory_usage):
assert b"Password protection enabled." in res.data
# Create a watch
set_original_response()
set_original_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)
# Create new

View File

@@ -4,7 +4,7 @@ from flask import url_for
from .util import live_server_setup
import json
def test_api_notifications_crud(client, live_server, measure_memory_usage):
def test_api_notifications_crud(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')

View File

@@ -12,7 +12,7 @@ from flask import url_for
from .util import live_server_setup, wait_for_all_checks
def test_openapi_validation_invalid_content_type_on_create_watch(client, live_server, measure_memory_usage):
def test_openapi_validation_invalid_content_type_on_create_watch(client, live_server, measure_memory_usage, datastore_path):
"""Test that creating a watch with invalid content-type triggers OpenAPI validation error."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -29,7 +29,7 @@ def test_openapi_validation_invalid_content_type_on_create_watch(client, live_se
assert b"OpenAPI validation failed" in res.data, "Should contain OpenAPI validation error message"
def test_openapi_validation_missing_required_field_create_watch(client, live_server, measure_memory_usage):
def test_openapi_validation_missing_required_field_create_watch(client, live_server, measure_memory_usage, datastore_path):
"""Test that creating a watch without required URL field triggers OpenAPI validation error."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -46,7 +46,7 @@ def test_openapi_validation_missing_required_field_create_watch(client, live_ser
assert b"OpenAPI validation failed" in res.data, "Should contain OpenAPI validation error message"
def test_openapi_validation_invalid_field_in_request_body(client, live_server, measure_memory_usage):
def test_openapi_validation_invalid_field_in_request_body(client, live_server, measure_memory_usage, datastore_path):
"""Test that including invalid fields triggers OpenAPI validation error."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -83,7 +83,7 @@ def test_openapi_validation_invalid_field_in_request_body(client, live_server, m
assert b"Additional properties are not allowed" in res.data, "Should contain validation error about additional properties"
def test_openapi_validation_import_wrong_content_type(client, live_server, measure_memory_usage):
def test_openapi_validation_import_wrong_content_type(client, live_server, measure_memory_usage, datastore_path):
"""Test that import endpoint with wrong content-type triggers OpenAPI validation error."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -100,7 +100,7 @@ def test_openapi_validation_import_wrong_content_type(client, live_server, measu
assert b"OpenAPI validation failed" in res.data, "Should contain OpenAPI validation error message"
def test_openapi_validation_import_correct_content_type_succeeds(client, live_server, measure_memory_usage):
def test_openapi_validation_import_correct_content_type_succeeds(client, live_server, measure_memory_usage, datastore_path):
"""Test that import endpoint with correct content-type succeeds (positive test)."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -117,7 +117,7 @@ def test_openapi_validation_import_correct_content_type_succeeds(client, live_se
assert len(res.json) == 2, "Should import 2 URLs"
def test_openapi_validation_get_requests_bypass_validation(client, live_server, measure_memory_usage):
def test_openapi_validation_get_requests_bypass_validation(client, live_server, measure_memory_usage, datastore_path):
"""Test that GET requests bypass OpenAPI validation entirely."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -141,7 +141,7 @@ def test_openapi_validation_get_requests_bypass_validation(client, live_server,
assert isinstance(res.json, dict), "Should return JSON dictionary for watch list"
def test_openapi_validation_create_tag_missing_required_title(client, live_server, measure_memory_usage):
def test_openapi_validation_create_tag_missing_required_title(client, live_server, measure_memory_usage, datastore_path):
"""Test that creating a tag without required title triggers OpenAPI validation error."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
@@ -158,7 +158,7 @@ def test_openapi_validation_create_tag_missing_required_title(client, live_serve
assert b"OpenAPI validation failed" in res.data, "Should contain OpenAPI validation error message"
def test_openapi_validation_watch_update_allows_partial_updates(client, live_server, measure_memory_usage):
def test_openapi_validation_watch_update_allows_partial_updates(client, live_server, measure_memory_usage, datastore_path):
"""Test that watch updates allow partial updates without requiring all fields (positive test)."""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')

View File

@@ -6,7 +6,7 @@ import time
from .util import live_server_setup, wait_for_all_checks
def test_api_search(client, live_server, measure_memory_usage):
def test_api_search(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')

View File

@@ -5,13 +5,14 @@ from .util import live_server_setup, wait_for_all_checks, set_original_response
import json
import time
def test_api_tags_listing(client, live_server, measure_memory_usage):
def test_api_tags_listing(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
tag_title = 'Test Tag'
set_original_response()
set_original_response(datastore_path=datastore_path)
res = client.get(
url_for("tags"),

View File

@@ -5,7 +5,7 @@ from flask import url_for
from .util import live_server_setup, wait_for_all_checks
# test pages with http://username@password:foobar.com/ work
def test_basic_auth(client, live_server, measure_memory_usage):
def test_basic_auth(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function

View File

@@ -3,9 +3,10 @@
import time
from flask import url_for
from .util import live_server_setup, extract_UUID_from_client, wait_for_all_checks
import os
def set_response_with_ldjson():
def set_response_with_ldjson(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -55,11 +56,11 @@ def set_response_with_ldjson():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_response_without_ldjson():
def set_response_without_ldjson(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -72,17 +73,17 @@ def set_response_without_ldjson():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# actually only really used by the distll.io importer, but could be handy too
def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage):
def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage, datastore_path):
set_response_with_ldjson()
set_response_with_ldjson(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -121,7 +122,7 @@ def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage
##########################################################################################
# And we shouldnt see the offer
set_response_without_ldjson()
set_response_without_ldjson(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -151,7 +152,7 @@ def _test_runner_check_bad_format_ignored(live_server, client, has_ldjson_price_
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_bad_ldjson_is_correctly_ignored(client, live_server, measure_memory_usage):
def test_bad_ldjson_is_correctly_ignored(client, live_server, measure_memory_usage, datastore_path):
test_return_data = """
<html>
@@ -181,7 +182,7 @@ def test_bad_ldjson_is_correctly_ignored(client, live_server, measure_memory_usa
<div class="yes">Some extra stuff</div>
</body></html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
_test_runner_check_bad_format_ignored(live_server=live_server, client=client, has_ldjson_price_data=True)
@@ -215,7 +216,7 @@ def test_bad_ldjson_is_correctly_ignored(client, live_server, measure_memory_usa
# <div class="yes">Some extra stuff</div>
# </body></html>
# """
# with open("test-datastore/endpoint-content.txt", "w") as f:
# with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
# f.write(test_return_data)
#
# _test_runner_check_bad_format_ignored(live_server=live_server, client=client, has_ldjson_price_data=False)

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python3
import os
import time
from flask import url_for
@@ -16,8 +17,8 @@ def test_inscriptus():
assert stripped_text_from_html == 'test!\nok man'
def test_check_basic_change_detection_functionality(client, live_server, measure_memory_usage):
set_original_response()
def test_check_basic_change_detection_functionality(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# live_server_setup(live_server) # Setup on conftest per function
# Add our URL to the import page
@@ -60,7 +61,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
assert b'foobar-detection' not in res.data
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Force recheck
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -121,7 +122,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
assert b'test-endpoint' in res.data
# Recheck it but only with a title change, content wasnt changed
set_original_response(extra_title=" and more")
set_original_response(datastore_path=datastore_path, extra_title=" and more")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -167,7 +168,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
# Server says its plaintext, we should always treat it as plaintext, and then if they have a filter, try to apply that
def test_requests_timeout(client, live_server, measure_memory_usage):
def test_requests_timeout(client, live_server, measure_memory_usage, datastore_path):
delay = 2
test_url = url_for('test_endpoint', delay=delay, _external=True)
@@ -205,7 +206,7 @@ def test_requests_timeout(client, live_server, measure_memory_usage):
res = client.get(url_for("watchlist.index"))
assert b'Read timed out' not in res.data
def test_non_text_mime_or_downloads(client, live_server, measure_memory_usage):
def test_non_text_mime_or_downloads(client, live_server, measure_memory_usage, datastore_path):
"""
https://github.com/dgtlmoon/changedetection.io/issues/3434
@@ -220,7 +221,7 @@ def test_non_text_mime_or_downloads(client, live_server, measure_memory_usage):
:param measure_memory_usage:
:return:
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""some random text that should be split by line
and not parsed with html_to_text
this way we know that it correctly parsed as plain text
@@ -264,7 +265,7 @@ got it\r\n
delete_all_watches(client)
def test_standard_text_plain(client, live_server, measure_memory_usage):
def test_standard_text_plain(client, live_server, measure_memory_usage, datastore_path):
"""
https://github.com/dgtlmoon/changedetection.io/issues/3434
@@ -279,7 +280,7 @@ def test_standard_text_plain(client, live_server, measure_memory_usage):
:param measure_memory_usage:
:return:
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""some random text that should be split by line
and not parsed with html_to_text
<title>Even this title should stay because we are just plain text</title>
@@ -325,9 +326,9 @@ got it\r\n
delete_all_watches(client)
# Server says its plaintext, we should always treat it as plaintext
def test_plaintext_even_if_xml_content(client, live_server, measure_memory_usage):
def test_plaintext_even_if_xml_content(client, live_server, measure_memory_usage, datastore_path):
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Activity and fragment titles-->
@@ -353,10 +354,10 @@ def test_plaintext_even_if_xml_content(client, live_server, measure_memory_usage
delete_all_watches(client)
# Server says its plaintext, we should always treat it as plaintext, and then if they have a filter, try to apply that
def test_plaintext_even_if_xml_content_and_can_apply_filters(client, live_server, measure_memory_usage):
def test_plaintext_even_if_xml_content_and_can_apply_filters(client, live_server, measure_memory_usage, datastore_path):
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Activity and fragment titles-->

View File

@@ -8,13 +8,11 @@ import re
import time
def test_backup(client, live_server, measure_memory_usage):
def test_backup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_original_response()
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(
@@ -31,7 +29,7 @@ def test_backup(client, live_server, measure_memory_usage):
url_for("backups.request_backup"),
follow_redirects=True
)
time.sleep(2)
time.sleep(4)
res = client.get(
url_for("backups.index"),

View File

@@ -10,11 +10,12 @@ from .util import (
)
from loguru import logger
def run_socketio_watch_update_test(client, live_server, password_mode=""):
def run_socketio_watch_update_test(client, live_server, password_mode="", datastore_path=""):
"""Test that the socketio emits a watch update event when content changes"""
# Set up the test server
set_original_response()
set_original_response(datastore_path=datastore_path)
# Get the SocketIO instance from the app
from changedetectionio.flask_app import app
@@ -47,7 +48,7 @@ def run_socketio_watch_update_test(client, live_server, password_mode=""):
socketio_test_client.get_received()
# Make a change to trigger an update
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Force recheck
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -105,11 +106,11 @@ def run_socketio_watch_update_test(client, live_server, password_mode=""):
# Clean up
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_everything(live_server, client):
def test_everything(live_server, client, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
run_socketio_watch_update_test(password_mode="", live_server=live_server, client=client)
run_socketio_watch_update_test(password_mode="", live_server=live_server, client=client, datastore_path=datastore_path)
############################ Password required auth check ##############################
@@ -124,7 +125,7 @@ def test_everything(live_server, client):
assert b"Password protection enabled." in res.data
run_socketio_watch_update_test(password_mode="not logged in, should exit on connect", live_server=live_server, client=client)
run_socketio_watch_update_test(password_mode="not logged in, should exit on connect", live_server=live_server, client=client, datastore_path=datastore_path)
res = client.post(
url_for("login"),
data={"password": "foobar"},
@@ -133,4 +134,4 @@ def test_everything(live_server, client):
# Yes we are correctly logged in
assert b"LOG OUT" in res.data
run_socketio_watch_update_test(password_mode="should be like normal", live_server=live_server, client=client)
run_socketio_watch_update_test(password_mode="should be like normal", live_server=live_server, client=client, datastore_path=datastore_path)

View File

@@ -4,8 +4,9 @@ import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
from changedetectionio import html_tools
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -17,11 +18,11 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_original_ignore_response():
def set_modified_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some NEW nice initial text<br>
@@ -36,12 +37,12 @@ def set_modified_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# Is the same but includes ZZZZZ, 'ZZZZZ' is the last line in ignore_text
def set_modified_response_minus_block_text():
def set_modified_response_minus_block_text(datastore_path):
test_return_data = """<html>
<body>
Some NEW nice initial text<br>
@@ -56,16 +57,16 @@ def set_modified_response_minus_block_text():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_check_block_changedetection_text_NOT_present(client, live_server, measure_memory_usage):
def test_check_block_changedetection_text_NOT_present(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# Use a mix of case in ZzZ to prove it works case-insensitive.
ignore_text = "out of stoCk\r\nfoobar"
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Add our URL to the import page
@@ -109,7 +110,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
assert b'/test-endpoint' in res.data
# The page changed, BUT the text is still there, just the rest of it changes, we should not see a change
set_modified_original_ignore_response()
set_modified_original_ignore_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -123,7 +124,7 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
# 2548
# Going back to the ORIGINAL should NOT trigger a change
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -131,10 +132,11 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
# Now we set a change where the text is gone AND its different content, it should now trigger
set_modified_response_minus_block_text()
set_modified_response_minus_block_text(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
assert b'has-unread-changes' in res.data

View File

@@ -3,12 +3,13 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks
import os
def test_clone_functionality(client, live_server, measure_memory_usage):
def test_clone_functionality(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html><body>Some content</body></html>")
test_url = url_for('test_endpoint', _external=True)

View File

@@ -1,13 +1,14 @@
#!/usr/bin/env python3
import json
import time
import os
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
from ..model import CONDITIONS_MATCH_LOGIC_DEFAULT
def set_original_response(number="50"):
def set_original_response(datastore_path, number="50"):
test_return_data = f"""<html>
<body>
<h1>Test Page for Conditions</h1>
@@ -17,10 +18,10 @@ def set_original_response(number="50"):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_number_in_range_response(number="75"):
def set_number_in_range_response(datastore_path, number="75"):
test_return_data = f"""<html>
<body>
<h1>Test Page for Conditions</h1>
@@ -30,10 +31,10 @@ def set_number_in_range_response(number="75"):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_number_out_of_range_response(number="150"):
def set_number_out_of_range_response(datastore_path, number="150"):
test_return_data = f"""<html>
<body>
<h1>Test Page for Conditions</h1>
@@ -43,18 +44,18 @@ def set_number_out_of_range_response(number="150"):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
"""Test that both text and number conditions work together with AND logic."""
# live_server_setup(live_server) # Setup on conftest per function
def test_conditions_with_text_and_number(client, live_server, measure_memory_usage):
def test_conditions_with_text_and_number(client, live_server, measure_memory_usage, datastore_path):
"""Test that both text and number conditions work together with AND logic."""
set_original_response("50")
set_original_response(datastore_path=datastore_path, number="50")
test_url = url_for('test_endpoint', _external=True)
@@ -114,7 +115,7 @@ def test_conditions_with_text_and_number(client, live_server, measure_memory_usa
wait_for_all_checks(client)
# Case 1
set_number_in_range_response("70.5")
set_number_in_range_response(datastore_path=datastore_path, number="70.5")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -129,7 +130,7 @@ def test_conditions_with_text_and_number(client, live_server, measure_memory_usa
client.get(url_for("ui.mark_all_viewed"), follow_redirects=True)
time.sleep(0.2)
set_number_out_of_range_response("150.5")
set_number_out_of_range_response(datastore_path=datastore_path, number="150.5")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -142,9 +143,9 @@ def test_conditions_with_text_and_number(client, live_server, measure_memory_usa
delete_all_watches(client)
# The 'validate' button next to each rule row
def test_condition_validate_rule_row(client, live_server, measure_memory_usage):
def test_condition_validate_rule_row(client, live_server, measure_memory_usage, datastore_path):
set_original_response("50")
set_original_response(datastore_path=datastore_path, number="50")
test_url = url_for('test_endpoint', _external=True)
@@ -203,7 +204,7 @@ def test_condition_validate_rule_row(client, live_server, measure_memory_usage):
# If there was only a change in the whitespacing, then we shouldnt have a change detected
def test_wordcount_conditions_plugin(client, live_server, measure_memory_usage):
def test_wordcount_conditions_plugin(client, live_server, measure_memory_usage, datastore_path):
test_return_data = """<html>
@@ -216,7 +217,7 @@ def test_wordcount_conditions_plugin(client, live_server, measure_memory_usage):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# Add our URL to the import page
@@ -242,10 +243,10 @@ def test_wordcount_conditions_plugin(client, live_server, measure_memory_usage):
)
# If there was only a change in the whitespacing, then we shouldnt have a change detected
def test_lev_conditions_plugin(client, live_server, measure_memory_usage):
def test_lev_conditions_plugin(client, live_server, measure_memory_usage, datastore_path):
# This should break..
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<html>
<body>
Some initial text<br>
@@ -297,7 +298,7 @@ def test_lev_conditions_plugin(client, live_server, measure_memory_usage):
############### Now change it a LITTLE bit...
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<html>
<body>
Some initial text<br>
@@ -326,7 +327,7 @@ def test_lev_conditions_plugin(client, live_server, measure_memory_usage):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data

View File

@@ -3,12 +3,13 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks
import os
from ..html_tools import *
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -21,11 +22,11 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -38,7 +39,7 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
@@ -69,12 +70,12 @@ def test_include_filters_output():
# Tests the whole stack works with the CSS Filter
def test_check_markup_include_filters_restriction(client, live_server, measure_memory_usage):
def test_check_markup_include_filters_restriction(client, live_server, measure_memory_usage, datastore_path):
sleep_time_for_fetch_thread = 3
include_filters = "#sametext"
set_original_response()
set_original_response(datastore_path=datastore_path)
# Give the endpoint time to spin up
time.sleep(1)
@@ -105,7 +106,7 @@ def test_check_markup_include_filters_restriction(client, live_server, measure_m
# Give the thread time to pick it up
time.sleep(sleep_time_for_fetch_thread)
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -119,11 +120,11 @@ def test_check_markup_include_filters_restriction(client, live_server, measure_m
# Tests the whole stack works with the CSS Filter
def test_check_multiple_filters(client, live_server, measure_memory_usage):
def test_check_multiple_filters(client, live_server, measure_memory_usage, datastore_path):
include_filters = "#blob-a\r\nxpath://*[contains(@id,'blob-b')]"
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<html><body>
<div id="blob-a">Blob A</div>
<div id="blob-b">Blob B</div>
@@ -168,12 +169,12 @@ def test_check_multiple_filters(client, live_server, measure_memory_usage):
# The filter exists, but did not contain anything useful
# Mainly used when the filter contains just an IMG, this can happen when someone selects an image in the visual-selector
# Tests fetcher can throw a "ReplyWithContentButNoText" exception after applying filter and extracting text
def test_filter_is_empty_help_suggestion(client, live_server, measure_memory_usage):
def test_filter_is_empty_help_suggestion(client, live_server, measure_memory_usage, datastore_path):
include_filters = "#blob-a"
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<html><body>
<div id="blob-a">
<img src="something.jpg">
@@ -216,7 +217,7 @@ def test_filter_is_empty_help_suggestion(client, live_server, measure_memory_usa
### Just an empty selector, no image
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<html><body>
<div id="blob-a">
<!-- doo doo -->

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python3
"""Test to verify client and live_server share the same datastore"""
def test_client_and_live_server_share_datastore(client, live_server):
"""Verify that client and live_server use the same app and datastore."""
# They should be the SAME object
assert client.application is live_server.app, "client.application and live_server.app should be the SAME object!"
# They should share the same datastore
client_datastore = client.application.config.get('DATASTORE')
server_datastore = live_server.app.config.get('DATASTORE')
assert client_datastore is server_datastore, \
f"Datastores are DIFFERENT objects! client={hex(id(client_datastore))} server={hex(id(server_datastore))}"
print(f"✓ client.application and live_server.app are the SAME object")
print(f"✓ Both use the same DATASTORE at {hex(id(client_datastore))}")
print(f"✓ Datastore path: {client_datastore.datastore_path}")

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import time
import os
from flask import url_for
@@ -10,7 +11,7 @@ from .util import live_server_setup, wait_for_all_checks, delete_all_watches
def set_response_with_multiple_index():
def set_response_with_multiple_index(datastore_path):
data= """<!DOCTYPE html>
<html>
<body>
@@ -36,11 +37,11 @@ def set_response_with_multiple_index():
</body>
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(data)
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<header>
<h2>Header</h2>
@@ -65,11 +66,11 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<header>
<h2>Header changed</h2>
@@ -94,7 +95,7 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
@@ -146,10 +147,10 @@ across multiple lines
)
def test_element_removal_full(client, live_server, measure_memory_usage):
def test_element_removal_full(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
@@ -194,7 +195,7 @@ def test_element_removal_full(client, live_server, measure_memory_usage):
client.get(url_for("ui.ui_views.diff_history_page", uuid="first"))
# Make a change to header/footer/nav
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -208,9 +209,9 @@ def test_element_removal_full(client, live_server, measure_memory_usage):
assert b"unviewed" not in res.data
# Re #2752
def test_element_removal_nth_offset_no_shift(client, live_server, measure_memory_usage):
def test_element_removal_nth_offset_no_shift(client, live_server, measure_memory_usage, datastore_path):
set_response_with_multiple_index()
set_response_with_multiple_index(datastore_path=datastore_path)
subtractive_selectors_data = [
### css style ###
"""body > table > tr:nth-child(1) > th:nth-child(2)

View File

@@ -5,26 +5,27 @@ import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, extract_UUID_from_client
import pytest
import os
def set_html_response():
def set_html_response(datastore_path):
test_return_data = """
<html><body><span class="nav_second_img_text">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;铸大国重器,挺制造脊梁,致力能源未来,赋能美好生活。
</span>
</body></html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
# In the case the server does not issue a charset= or doesnt have content_type header set
def test_check_encoding_detection(client, live_server, measure_memory_usage):
set_html_response()
def test_check_encoding_detection(client, live_server, measure_memory_usage, datastore_path):
set_html_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', content_type="text/html", _external=True)
@@ -51,8 +52,8 @@ def test_check_encoding_detection(client, live_server, measure_memory_usage):
# In the case the server does not issue a charset= or doesnt have content_type header set
def test_check_encoding_detection_missing_content_type_header(client, live_server, measure_memory_usage):
set_html_response()
def test_check_encoding_detection_missing_content_type_header(client, live_server, measure_memory_usage, datastore_path):
set_html_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import time
import os
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
@@ -8,9 +9,9 @@ from .util import live_server_setup, wait_for_all_checks, delete_all_watches
def _runner_test_http_errors(client, live_server, http_code, expected_text):
def _runner_test_http_errors(client, live_server, http_code, expected_text, datastore_path):
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Now you going to get a {} error code\n".format(http_code))
@@ -46,17 +47,15 @@ def _runner_test_http_errors(client, live_server, http_code, expected_text):
delete_all_watches(client)
def test_http_error_handler(client, live_server, measure_memory_usage):
_runner_test_http_errors(client, live_server, 403, 'Access denied')
_runner_test_http_errors(client, live_server, 404, 'Page not found')
_runner_test_http_errors(client, live_server, 500, '(Internal server error) received')
_runner_test_http_errors(client, live_server, 400, 'Error - Request returned a HTTP error code 400')
def test_http_error_handler(client, live_server, measure_memory_usage, datastore_path):
_runner_test_http_errors(client, live_server, 403, 'Access denied', datastore_path=datastore_path)
_runner_test_http_errors(client, live_server, 404, 'Page not found', datastore_path=datastore_path)
_runner_test_http_errors(client, live_server, 500, '(Internal server error) received', datastore_path=datastore_path)
_runner_test_http_errors(client, live_server, 400, 'Error - Request returned a HTTP error code 400', datastore_path=datastore_path)
delete_all_watches(client)
# Just to be sure error text is properly handled
def test_DNS_errors(client, live_server, measure_memory_usage):
# Give the endpoint time to spin up
time.sleep(1)
def test_DNS_errors(client, live_server, measure_memory_usage, datastore_path):
# Add our URL to the import page
res = client.post(
@@ -84,12 +83,9 @@ def test_DNS_errors(client, live_server, measure_memory_usage):
delete_all_watches(client)
# Re 1513
def test_low_level_errors_clear_correctly(client, live_server, measure_memory_usage):
# Give the endpoint time to spin up
time.sleep(1)
def test_low_level_errors_clear_correctly(client, live_server, measure_memory_usage, datastore_path):
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html><body><div id=here>Hello world</div></body></html>")
# Add our URL to the import page

View File

@@ -4,14 +4,15 @@ import time
from flask import url_for
from urllib.request import urlopen
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks
import os
sleep_time_for_fetch_thread = 3
def test_check_extract_text_from_diff(client, live_server, measure_memory_usage):
def test_check_extract_text_from_diff(client, live_server, measure_memory_usage, datastore_path):
import time
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Now it's {} seconds since epoch, time flies!".format(str(time.time())))
# live_server_setup(live_server) # Setup on conftest per function
@@ -33,7 +34,7 @@ def test_check_extract_text_from_diff(client, live_server, measure_memory_usage)
# Give the thread time to pick it up
print("Bumping snapshot and checking.. ", n)
last_date = str(time.time())
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("Now it's {} seconds since epoch, time flies!".format(last_date))
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -3,11 +3,12 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
import os
from ..html_tools import *
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -20,12 +21,12 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -39,13 +40,13 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_multiline_response():
def set_multiline_response(datastore_path):
test_return_data = """<html>
<body>
@@ -61,18 +62,18 @@ def set_multiline_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_check_filter_multiline(client, live_server, measure_memory_usage):
def test_check_filter_multiline(client, live_server, measure_memory_usage, datastore_path):
## live_server_setup(live_server) # Setup on conftest per function
set_multiline_response()
set_multiline_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -119,11 +120,11 @@ def test_check_filter_multiline(client, live_server, measure_memory_usage):
# but the last one, which also says 'lines' shouldnt be here (non-greedy match checking)
assert b'aaand something lines' not in res.data
def test_check_filter_and_regex_extract(client, live_server, measure_memory_usage):
def test_check_filter_and_regex_extract(client, live_server, measure_memory_usage, datastore_path):
include_filters = ".changetext"
set_original_response()
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -159,7 +160,7 @@ def test_check_filter_and_regex_extract(client, live_server, measure_memory_usag
assert b'not at the start of the expression' not in res.data
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -198,7 +199,7 @@ def test_check_filter_and_regex_extract(client, live_server, measure_memory_usag
def test_regex_error_handling(client, live_server, measure_memory_usage):
def test_regex_error_handling(client, live_server, measure_memory_usage, datastore_path):

View File

@@ -8,7 +8,7 @@ from .util import set_original_response, live_server_setup, wait_for_notificatio
from changedetectionio.model import App
def set_response_without_filter():
def set_response_without_filter(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -20,12 +20,12 @@ def set_response_without_filter():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_response_with_filter():
def set_response_with_filter(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -37,11 +37,11 @@ def set_response_with_filter():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def test_filter_doesnt_exist_then_exists_should_get_notification(client, live_server, measure_memory_usage):
def test_filter_doesnt_exist_then_exists_should_get_notification(client, live_server, measure_memory_usage, datastore_path):
# Filter knowingly doesn't exist, like someone setting up a known filter to see if some cinema tickets are on sale again
# And the page has that filter available
# Then I should get a notification
@@ -50,7 +50,7 @@ def test_filter_doesnt_exist_then_exists_should_get_notification(client, live_se
# Give the endpoint time to spin up
time.sleep(1)
set_response_without_filter()
set_response_without_filter(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -105,20 +105,20 @@ def test_filter_doesnt_exist_then_exists_should_get_notification(client, live_se
follow_redirects=True
)
assert b"Updated watch." in res.data
wait_for_notification_endpoint_output()
wait_for_notification_endpoint_output(datastore_path=datastore_path)
# Shouldn't exist, shouldn't have fired
assert not os.path.isfile("test-datastore/notification.txt")
assert not os.path.isfile(os.path.join(datastore_path, "notification.txt"))
# Now the filter should exist
set_response_with_filter()
set_response_with_filter(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_notification_endpoint_output()
wait_for_notification_endpoint_output(datastore_path=datastore_path)
assert os.path.isfile("test-datastore/notification.txt")
assert os.path.isfile(os.path.join(datastore_path, "notification.txt"))
with open("test-datastore/notification.txt", 'r') as f:
with open(os.path.join(datastore_path, "notification.txt"), 'r') as f:
notification = f.read()
assert 'Ticket now on sale' in notification
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))

View File

@@ -5,7 +5,7 @@ from .util import set_original_response, wait_for_all_checks, wait_for_notifica
from ..notification import valid_notification_formats
def set_response_with_filter():
def set_response_with_filter(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -17,14 +17,14 @@ def set_response_with_filter():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def run_filter_test(client, live_server, content_filter, app_notification_format):
def run_filter_test(client, live_server, content_filter, app_notification_format, datastore_path):
# Response WITHOUT the filter ID element
set_original_response()
set_original_response(datastore_path=datastore_path)
live_server.app.config['DATASTORE'].data['settings']['application']['notification_format'] = app_notification_format
# Goto the edit page, add our ignore text
@@ -38,10 +38,16 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
url_for("ui.form_delete", uuid="all"),
follow_redirects=True
)
if os.path.isfile("test-datastore/notification.txt"):
os.unlink("test-datastore/notification.txt")
notification_file = os.path.join(datastore_path, "notification.txt")
if os.path.isfile(notification_file):
os.unlink(notification_file)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
res = client.get(url_for("watchlist.index"))
assert b'No website watches configured' not in res.data
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -79,6 +85,7 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
data=watch_data,
follow_redirects=True
)
assert b"Updated watch." in res.data
wait_for_all_checks(client)
assert live_server.app.config['DATASTORE'].data['watching'][uuid]['consecutive_filter_failures'] == 0, "No filter = No filter failure"
@@ -95,7 +102,7 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
# It should have checked once so far and given this error (because we hit SAVE)
wait_for_all_checks(client)
assert not os.path.isfile("test-datastore/notification.txt")
assert not os.path.isfile(notification_file)
# Hitting [save] would have triggered a recheck, and we have a filter, so this would be ONE failure
assert live_server.app.config['DATASTORE'].data['watching'][uuid]['consecutive_filter_failures'] == 1, "Should have been checked once"
@@ -110,20 +117,20 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
assert b'Warning, no filters were found' in res.data
assert not os.path.isfile("test-datastore/notification.txt")
assert not os.path.isfile(notification_file)
time.sleep(1)
assert live_server.app.config['DATASTORE'].data['watching'][uuid]['consecutive_filter_failures'] == 5
time.sleep(2)
# One more check should trigger the _FILTER_FAILURE_THRESHOLD_ATTEMPTS_DEFAULT threshold
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
wait_for_notification_endpoint_output()
wait_for_notification_endpoint_output(datastore_path=datastore_path)
# Now it should exist and contain our "filter not found" alert
assert os.path.isfile("test-datastore/notification.txt")
with open("test-datastore/notification.txt", 'r') as f:
assert os.path.isfile(notification_file)
with open(notification_file, 'r') as f:
notification = f.read()
assert 'Your configured CSS/xPath filters' in notification
@@ -146,19 +153,19 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
# Remove it and prove that it doesn't trigger when not expected
# It should register a change, but no 'filter not found'
os.unlink("test-datastore/notification.txt")
set_response_with_filter()
os.unlink(notification_file)
set_response_with_filter(datastore_path)
# Try several times, it should NOT have 'filter not found'
for i in range(0, ATTEMPT_THRESHOLD_SETTING + 2):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
wait_for_notification_endpoint_output()
wait_for_notification_endpoint_output(datastore_path=datastore_path)
# It should have sent a notification, but..
assert os.path.isfile("test-datastore/notification.txt")
assert os.path.isfile(notification_file)
# but it should not contain the info about a failed filter (because there was none in this case)
with open("test-datastore/notification.txt", 'r') as f:
with open(notification_file, 'r') as f:
notification = f.read()
assert not 'CSS/xPath filter was not present in the page' in notification
@@ -170,22 +177,22 @@ def run_filter_test(client, live_server, content_filter, app_notification_format
url_for("ui.form_delete", uuid="all"),
follow_redirects=True
)
os.unlink("test-datastore/notification.txt")
os.unlink(notification_file)
def test_check_include_filters_failure_notification(client, live_server, measure_memory_usage):
def test_check_include_filters_failure_notification(client, live_server, measure_memory_usage, datastore_path):
# # live_server_setup(live_server) # Setup on conftest per function
run_filter_test(client=client, live_server=live_server, content_filter='#nope-doesnt-exist', app_notification_format=valid_notification_formats.get('htmlcolor'))
run_filter_test(client=client, live_server=live_server, content_filter='#nope-doesnt-exist', app_notification_format=valid_notification_formats.get('htmlcolor'), datastore_path=datastore_path)
# Check markup send conversion didnt affect plaintext preference
run_filter_test(client=client, live_server=live_server, content_filter='#nope-doesnt-exist', app_notification_format=valid_notification_formats.get('text'))
run_filter_test(client=client, live_server=live_server, content_filter='#nope-doesnt-exist', app_notification_format=valid_notification_formats.get('text'), datastore_path=datastore_path)
def test_check_xpath_filter_failure_notification(client, live_server, measure_memory_usage):
def test_check_xpath_filter_failure_notification(client, live_server, measure_memory_usage, datastore_path):
# # live_server_setup(live_server) # Setup on conftest per function
run_filter_test(client=client, live_server=live_server, content_filter='//*[@id="nope-doesnt-exist"]', app_notification_format=valid_notification_formats.get('htmlcolor'))
run_filter_test(client=client, live_server=live_server, content_filter='//*[@id="nope-doesnt-exist"]', app_notification_format=valid_notification_formats.get('htmlcolor'), datastore_path=datastore_path)
# Test that notification is never sent
def test_basic_markup_from_text(client, live_server, measure_memory_usage):
def test_basic_markup_from_text(client, live_server, measure_memory_usage, datastore_path):
# Test the notification error templates convert to HTML if needed (link activate)
from ..notification.handler import markup_text_links_to_html
x = markup_text_links_to_html("hello https://google.com")

View File

@@ -6,10 +6,10 @@ from .util import live_server_setup, wait_for_all_checks, extract_rss_token_from
import os
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -20,11 +20,11 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -35,13 +35,13 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def test_setup_group_tag(client, live_server, measure_memory_usage):
def test_setup_group_tag(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
# Add a tag with some config, import a tag and it should roughly work
res = client.post(
@@ -116,7 +116,7 @@ def test_setup_group_tag(client, live_server, measure_memory_usage):
)
assert b"1 Imported" in res.data
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
rss_token = extract_rss_token_from_UI(client)
@@ -129,7 +129,7 @@ def test_setup_group_tag(client, live_server, measure_memory_usage):
assert b"first-imported=1" in res.data
delete_all_watches(client)
def test_tag_import_singular(client, live_server, measure_memory_usage):
def test_tag_import_singular(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_endpoint', _external=True)
@@ -148,7 +148,7 @@ def test_tag_import_singular(client, live_server, measure_memory_usage):
assert res.data.count(b'test-tag') == 1
delete_all_watches(client)
def test_tag_add_in_ui(client, live_server, measure_memory_usage):
def test_tag_add_in_ui(client, live_server, measure_memory_usage, datastore_path):
#
res = client.post(
@@ -164,9 +164,9 @@ def test_tag_add_in_ui(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_group_tag_notification(client, live_server, measure_memory_usage):
def test_group_tag_notification(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)
res = client.post(
@@ -207,16 +207,16 @@ def test_group_tag_notification(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
time.sleep(3)
assert os.path.isfile("test-datastore/notification.txt")
assert os.path.isfile(os.path.join(datastore_path, "notification.txt"))
# Verify what was sent as a notification, this file should exist
with open("test-datastore/notification.txt", "r") as f:
with open(os.path.join(datastore_path, "notification.txt"), "r") as f:
notification_submission = f.read()
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))
# Did we see the URL that had a change, in the notification?
# Diff was correctly executed
@@ -231,7 +231,7 @@ def test_group_tag_notification(client, live_server, measure_memory_usage):
#@todo Test that each of multiple notifications with different settings
delete_all_watches(client)
def test_limit_tag_ui(client, live_server, measure_memory_usage):
def test_limit_tag_ui(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_random_content_endpoint', _external=True)
@@ -269,7 +269,7 @@ def test_limit_tag_ui(client, live_server, measure_memory_usage):
res = client.get(url_for("tags.delete_all"), follow_redirects=True)
assert b'All tags deleted' in res.data
def test_clone_tag_on_import(client, live_server, measure_memory_usage):
def test_clone_tag_on_import(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_endpoint', _external=True)
res = client.post(
@@ -294,7 +294,7 @@ def test_clone_tag_on_import(client, live_server, measure_memory_usage):
assert res.data.count(b'another-tag') == 3
delete_all_watches(client)
def test_clone_tag_on_quickwatchform_add(client, live_server, measure_memory_usage):
def test_clone_tag_on_quickwatchform_add(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_endpoint', _external=True)
@@ -324,7 +324,7 @@ def test_clone_tag_on_quickwatchform_add(client, live_server, measure_memory_usa
res = client.get(url_for("tags.delete_all"), follow_redirects=True)
assert b'All tags deleted' in res.data
def test_order_of_filters_tag_filter_and_watch_filter(client, live_server, measure_memory_usage):
def test_order_of_filters_tag_filter_and_watch_filter(client, live_server, measure_memory_usage, datastore_path):
# Add a tag with some config, import a tag and it should roughly work
res = client.post(
@@ -378,7 +378,7 @@ def test_order_of_filters_tag_filter_and_watch_filter(client, live_server, measu
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(d)
test_url = url_for('test_endpoint', _external=True)

View File

@@ -7,7 +7,7 @@ from flask import url_for
from .util import wait_for_all_checks, delete_all_watches
from urllib.parse import urlparse, parse_qs
def test_consistent_history(client, live_server, measure_memory_usage):
def test_consistent_history(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
workers = int(os.getenv("FETCH_WORKERS", 10))
r = range(1, 10+workers)
@@ -80,9 +80,9 @@ def test_consistent_history(client, live_server, measure_memory_usage):
assert '"default"' not in f.read(), "'default' probably shouldnt be here, it came from when the 'default' Watch vars were accidently being saved"
def test_check_text_history_view(client, live_server, measure_memory_usage):
def test_check_text_history_view(client, live_server, measure_memory_usage, datastore_path):
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html>test-one</html>")
# Add our URL to the import page
@@ -94,7 +94,7 @@ def test_check_text_history_view(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# Set second version, Make a change
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html>test-two</html>")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -105,7 +105,7 @@ def test_check_text_history_view(client, live_server, measure_memory_usage):
assert b'test-two' in res.data
# Set third version, Make a change
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html>test-three</html>")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -5,8 +5,9 @@ from flask import url_for
from .util import live_server_setup, wait_for_all_checks
from changedetectionio import html_tools
from . util import extract_UUID_from_client
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -19,13 +20,13 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_ignore(client, live_server, measure_memory_usage):
def test_ignore(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_original_ignore_response()
set_original_ignore_response(datastore_path)
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -55,9 +56,9 @@ def test_ignore(client, live_server, measure_memory_usage):
assert b'csrftoken' in res.data
def test_strip_ignore_lines(client, live_server, measure_memory_usage):
def test_strip_ignore_lines(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_original_ignore_response()
set_original_ignore_response(datastore_path)
# Goto the settings page, add our ignore text

View File

@@ -4,6 +4,7 @@ import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
from changedetectionio import html_tools
import os
@@ -31,7 +32,7 @@ def test_strip_text_func():
stripped_content = html_tools.strip_ignore_text(test_content, ignore)
assert stripped_content == "Some initial text\n\nWhich is across multiple lines\n\n\n\nSo let's see what happens."
def set_original_ignore_response(ver_stamp="123"):
def set_original_ignore_response(datastore_path, ver_stamp="123"):
test_return_data = f"""<html>
<body>
Some initial text<br>
@@ -44,11 +45,11 @@ def set_original_ignore_response(ver_stamp="123"):
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_original_ignore_response(ver_stamp="123"):
def set_modified_original_ignore_response(datastore_path, ver_stamp="123"):
test_return_data = f"""<html>
<body>
Some NEW nice initial text<br>
@@ -63,12 +64,12 @@ def set_modified_original_ignore_response(ver_stamp="123"):
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# Is the same but includes ZZZZZ, 'ZZZZZ' is the last line in ignore_text
def set_modified_ignore_response(ver_stamp="123"):
def set_modified_ignore_response(datastore_path, ver_stamp="123"):
test_return_data = f"""<html>
<body>
Some initial text<br>
@@ -82,17 +83,17 @@ def set_modified_ignore_response(ver_stamp="123"):
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# Ignore text now just removes it entirely, is a LOT more simpler code this way
def test_check_ignore_text_functionality(client, live_server, measure_memory_usage):
def test_check_ignore_text_functionality(client, live_server, measure_memory_usage, datastore_path):
# Use a mix of case in ZzZ to prove it works case-insensitive.
ignore_text = "XXXXX\r\nYYYYY\r\nzZzZZ\r\nnew ignore stuff"
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Add our URL to the import page
@@ -130,7 +131,7 @@ def test_check_ignore_text_functionality(client, live_server, measure_memory_usa
assert b'/test-endpoint' in res.data
# Make a change
set_modified_ignore_response()
set_modified_ignore_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -145,7 +146,7 @@ def test_check_ignore_text_functionality(client, live_server, measure_memory_usa
# Just to be sure.. set a regular modified change..
set_modified_original_ignore_response()
set_modified_original_ignore_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -162,10 +163,10 @@ def test_check_ignore_text_functionality(client, live_server, measure_memory_usa
delete_all_watches(client)
# When adding some ignore text, it should not trigger a change, even if something else on that line changes
def _run_test_global_ignore(client, as_source=False, extra_ignore=""):
def _run_test_global_ignore(client, datastore_path, as_source=False, extra_ignore=""):
ignore_text = "XXXXX\r\nYYYYY\r\nZZZZZ\r\n"+extra_ignore
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Goto the settings page, add our ignore text
res = client.post(
@@ -222,7 +223,7 @@ def _run_test_global_ignore(client, as_source=False, extra_ignore=""):
# Make a change which includes the ignore text, it should be ignored and no 'change' triggered
# It adds text with "ZZZZzzzz" and "ZZZZ" is in the ignore list
# And tweaks the ver_stamp which should be picked up by global regex ignore
set_modified_ignore_response(ver_stamp=time.time())
set_modified_ignore_response(ver_stamp=time.time(), datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -236,7 +237,7 @@ def _run_test_global_ignore(client, as_source=False, extra_ignore=""):
assert b'/test-endpoint' in res.data
# Just to be sure.. set a regular modified change that will trigger it
set_modified_original_ignore_response()
set_modified_original_ignore_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -244,10 +245,10 @@ def _run_test_global_ignore(client, as_source=False, extra_ignore=""):
delete_all_watches(client)
def test_check_global_ignore_text_functionality(client, live_server, measure_memory_usage):
def test_check_global_ignore_text_functionality(client, live_server, measure_memory_usage, datastore_path):
_run_test_global_ignore(client, as_source=False)
_run_test_global_ignore(client, as_source=False, datastore_path=datastore_path)
def test_check_global_ignore_text_functionality_as_source(client, live_server, measure_memory_usage):
def test_check_global_ignore_text_functionality_as_source(client, live_server, measure_memory_usage, datastore_path):
_run_test_global_ignore(client, as_source=True, extra_ignore='/\?v=\d/')
_run_test_global_ignore(client, as_source=True, extra_ignore='/\?v=\d/', datastore_path=datastore_path)

View File

@@ -4,9 +4,10 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -17,13 +18,13 @@ def set_original_ignore_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# Should be the same as set_original_ignore_response() but with a different
# Should be the same as set_original_ignore_response(datastore_path=datastore_path) but with a different
# link
def set_modified_ignore_response():
def set_modified_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -34,10 +35,10 @@ def set_modified_ignore_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_render_anchor_tag_content_true(client, live_server, measure_memory_usage):
def test_render_anchor_tag_content_true(client, live_server, measure_memory_usage, datastore_path):
"""Testing that the link changes are detected when
render_anchor_tag_content setting is set to true"""
sleep_time_for_fetch_thread = 3
@@ -46,7 +47,7 @@ def test_render_anchor_tag_content_true(client, live_server, measure_memory_usag
time.sleep(1)
# set original html text
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Goto the settings page, choose to ignore links (dont select/send "application-render_anchor_tag_content")
res = client.post(
@@ -72,7 +73,7 @@ def test_render_anchor_tag_content_true(client, live_server, measure_memory_usag
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
# set a new html text with a modified link
set_modified_ignore_response()
set_modified_ignore_response(datastore_path=datastore_path)
wait_for_all_checks(client)
# Trigger a check

View File

@@ -3,12 +3,13 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks
import os
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -19,11 +20,11 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_some_changed_response():
def set_some_changed_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -34,17 +35,17 @@ def set_some_changed_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_normal_page_check_works_with_ignore_status_code(client, live_server, measure_memory_usage):
def test_normal_page_check_works_with_ignore_status_code(client, live_server, measure_memory_usage, datastore_path):
# Give the endpoint time to spin up
time.sleep(1)
set_original_response()
set_original_response(datastore_path=datastore_path)
# Goto the settings page, add our ignore text
res = client.post(
@@ -65,7 +66,7 @@ def test_normal_page_check_works_with_ignore_status_code(client, live_server, me
wait_for_all_checks(client)
set_some_changed_response()
set_some_changed_response(datastore_path=datastore_path)
wait_for_all_checks(client)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -80,10 +81,10 @@ def test_normal_page_check_works_with_ignore_status_code(client, live_server, me
# Tests the whole stack works with staus codes ignored
def test_403_page_check_works_with_ignore_status_code(client, live_server, measure_memory_usage):
def test_403_page_check_works_with_ignore_status_code(client, live_server, measure_memory_usage, datastore_path):
sleep_time_for_fetch_thread = 3
set_original_response()
set_original_response(datastore_path=datastore_path)
# Give the endpoint time to spin up
time.sleep(1)
@@ -109,7 +110,7 @@ def test_403_page_check_works_with_ignore_status_code(client, live_server, measu
wait_for_all_checks(client)
# Make a change
set_some_changed_response()
set_some_changed_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -3,12 +3,13 @@
import time
from flask import url_for
from . util import live_server_setup
import os
# Should be the same as set_original_ignore_response() but with a little more whitespacing
def set_original_ignore_response_but_with_whitespace():
# Should be the same as set_original_ignore_response(datastore_path=datastore_path) but with a little more whitespacing
def set_original_ignore_response_but_with_whitespace(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -26,11 +27,11 @@ def set_original_ignore_response_but_with_whitespace():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -42,19 +43,19 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# If there was only a change in the whitespacing, then we shouldnt have a change detected
def test_check_ignore_whitespace(client, live_server, measure_memory_usage):
def test_check_ignore_whitespace(client, live_server, measure_memory_usage, datastore_path):
sleep_time_for_fetch_thread = 3
# Give the endpoint time to spin up
time.sleep(1)
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Goto the settings page, add our ignore text
res = client.post(
@@ -77,7 +78,7 @@ def test_check_ignore_whitespace(client, live_server, measure_memory_usage):
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
set_original_ignore_response_but_with_whitespace()
set_original_ignore_response_but_with_whitespace(datastore_path)
time.sleep(sleep_time_for_fetch_thread)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -8,10 +8,10 @@ from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_import(client, live_server, measure_memory_usage):
def test_import(client, live_server, measure_memory_usage, datastore_path):
# Give the endpoint time to spin up
wait_for_all_checks(client)
@@ -34,7 +34,7 @@ https://example.com tag1, other tag"""
res = client.get( url_for("watchlist.index"))
res = client.get( url_for("watchlist.index"))
def xtest_import_skip_url(client, live_server, measure_memory_usage):
def xtest_import_skip_url(client, live_server, measure_memory_usage, datastore_path):
# Give the endpoint time to spin up
@@ -57,7 +57,7 @@ def xtest_import_skip_url(client, live_server, measure_memory_usage):
# Clear flask alerts
res = client.get( url_for("watchlist.index"))
def test_import_distillio(client, live_server, measure_memory_usage):
def test_import_distillio(client, live_server, measure_memory_usage, datastore_path):
distill_data='''
{
@@ -123,7 +123,7 @@ def test_import_distillio(client, live_server, measure_memory_usage):
# Clear flask alerts
res = client.get(url_for("watchlist.index"))
def test_import_custom_xlsx(client, live_server, measure_memory_usage):
def test_import_custom_xlsx(client, live_server, measure_memory_usage, datastore_path):
"""Test can upload a excel spreadsheet and the watches are created correctly"""
@@ -171,7 +171,7 @@ def test_import_custom_xlsx(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_import_watchete_xlsx(client, live_server, measure_memory_usage):
def test_import_watchete_xlsx(client, live_server, measure_memory_usage, datastore_path):
"""Test can upload a excel spreadsheet and the watches are created correctly"""

View File

@@ -7,11 +7,11 @@ from .util import live_server_setup, wait_for_all_checks
from ..jinja2_custom import render
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# # live_server_setup(live_server) # Setup on conftest per function
# If there was only a change in the whitespacing, then we shouldnt have a change detected
def test_jinja2_in_url_query(client, live_server, measure_memory_usage):
def test_jinja2_in_url_query(client, live_server, measure_memory_usage, datastore_path):
# Add our URL to the import page
@@ -36,7 +36,7 @@ def test_jinja2_in_url_query(client, live_server, measure_memory_usage):
assert b'date=2' in res.data
# Test for issue #1493 - jinja2-time offset functionality
def test_jinja2_time_offset_in_url_query(client, live_server, measure_memory_usage):
def test_jinja2_time_offset_in_url_query(client, live_server, measure_memory_usage, datastore_path):
"""Test that jinja2 time offset expressions work in watch URLs (issue #1493)."""
# Add our URL to the import page with time offset expression
@@ -66,7 +66,7 @@ def test_jinja2_time_offset_in_url_query(client, live_server, measure_memory_usa
# https://techtonics.medium.com/secure-templating-with-jinja2-understanding-ssti-and-jinja2-sandbox-environment-b956edd60456
def test_jinja2_security_url_query(client, live_server, measure_memory_usage):
def test_jinja2_security_url_query(client, live_server, measure_memory_usage, datastore_path):
# Add our URL to the import page
test_url = url_for('test_return_query', _external=True)

View File

@@ -6,6 +6,7 @@ from flask import url_for
from markupsafe import escape
from . util import live_server_setup, wait_for_all_checks, delete_all_watches
import pytest
import os
jq_support = True
try:
@@ -92,7 +93,7 @@ def test_unittest_inline_extract_body():
text = html_tools.extract_json_as_string(content, "json:$.testKey")
assert text == '42'
def set_original_ext_response():
def set_original_ext_response(datastore_path):
data = """
[
{
@@ -109,11 +110,11 @@ def set_original_ext_response():
]
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(data)
return None
def set_modified_ext_response():
def set_modified_ext_response(datastore_path):
# This should get reformatted
data = """ [ { "isPriceLowered": false, "status": "Sold", "statusOrig": "sold" }, {
"_id": "5e7b3e1fb3262d306323ff1e",
@@ -124,11 +125,11 @@ def set_modified_ext_response():
]
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(data)
return None
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """
{
"employees": [
@@ -149,12 +150,12 @@ def set_original_response():
"available": true
}
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_json_response_with_html():
def set_json_response_with_html(datastore_path):
test_return_data = """
{
"test": [
@@ -164,11 +165,11 @@ def set_json_response_with_html():
]
}
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """
{
"employees": [
@@ -190,15 +191,15 @@ def set_modified_response():
}
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def test_check_json_without_filter(client, live_server, measure_memory_usage):
def test_check_json_without_filter(client, live_server, measure_memory_usage, datastore_path):
# Request a JSON document from a application/json source containing HTML
# and be sure it doesn't get chewed up by instriptis
set_json_response_with_html()
set_json_response_with_html(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', content_type="application/json", _external=True)
@@ -219,8 +220,8 @@ def test_check_json_without_filter(client, live_server, measure_memory_usage):
delete_all_watches(client)
def check_json_filter(json_filter, client, live_server):
set_original_response()
def check_json_filter(json_filter, client, live_server, datastore_path):
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
@@ -240,7 +241,7 @@ def check_json_filter(json_filter, client, live_server):
# Give the thread time to pick it up
wait_for_all_checks(client)
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -260,19 +261,19 @@ def check_json_filter(json_filter, client, live_server):
delete_all_watches(client)
def test_check_jsonpath_filter(client, live_server, measure_memory_usage):
check_json_filter('json:boss.name', client, live_server)
def test_check_jsonpath_filter(client, live_server, measure_memory_usage, datastore_path):
check_json_filter('json:boss.name', client, live_server, datastore_path=datastore_path)
def test_check_jq_filter(client, live_server, measure_memory_usage):
def test_check_jq_filter(client, live_server, measure_memory_usage, datastore_path):
if jq_support:
check_json_filter('jq:.boss.name', client, live_server)
check_json_filter('jq:.boss.name', client, live_server, datastore_path=datastore_path)
def test_check_jqraw_filter(client, live_server, measure_memory_usage):
def test_check_jqraw_filter(client, live_server, measure_memory_usage, datastore_path):
if jq_support:
check_json_filter('jqraw:.boss.name', client, live_server)
check_json_filter('jqraw:.boss.name', client, live_server, datastore_path=datastore_path)
def check_json_filter_bool_val(json_filter, client, live_server):
set_original_response()
def check_json_filter_bool_val(json_filter, client, live_server, datastore_path):
set_original_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', content_type="application/json", _external=True)
@@ -281,7 +282,7 @@ def check_json_filter_bool_val(json_filter, client, live_server):
wait_for_all_checks(client)
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -294,24 +295,24 @@ def check_json_filter_bool_val(json_filter, client, live_server):
delete_all_watches(client)
def test_check_jsonpath_filter_bool_val(client, live_server, measure_memory_usage):
check_json_filter_bool_val("json:$['available']", client, live_server)
def test_check_jsonpath_filter_bool_val(client, live_server, measure_memory_usage, datastore_path):
check_json_filter_bool_val("json:$['available']", client, live_server, datastore_path=datastore_path)
def test_check_jq_filter_bool_val(client, live_server, measure_memory_usage):
def test_check_jq_filter_bool_val(client, live_server, measure_memory_usage, datastore_path):
if jq_support:
check_json_filter_bool_val("jq:.available", client, live_server)
check_json_filter_bool_val("jq:.available", client, live_server, datastore_path=datastore_path)
def test_check_jqraw_filter_bool_val(client, live_server, measure_memory_usage):
def test_check_jqraw_filter_bool_val(client, live_server, measure_memory_usage, datastore_path):
if jq_support:
check_json_filter_bool_val("jq:.available", client, live_server)
check_json_filter_bool_val("jq:.available", client, live_server, datastore_path=datastore_path)
# Re #265 - Extended JSON selector test
# Stuff to consider here
# - Selector should be allowed to return empty when it doesnt match (people might wait for some condition)
# - The 'diff' tab could show the old and new content
# - Form should let us enter a selector that doesnt (yet) match anything
def check_json_ext_filter(json_filter, client, live_server):
set_original_ext_response()
def check_json_ext_filter(json_filter, client, live_server, datastore_path):
set_original_ext_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', content_type="application/json", _external=True)
@@ -343,7 +344,7 @@ def check_json_ext_filter(json_filter, client, live_server):
# Give the thread time to pick it up
wait_for_all_checks(client)
# Make a change
set_modified_ext_response()
set_modified_ext_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -376,10 +377,10 @@ def check_json_ext_filter(json_filter, client, live_server):
delete_all_watches(client)
def test_ignore_json_order(client, live_server, measure_memory_usage):
def test_ignore_json_order(client, live_server, measure_memory_usage, datastore_path):
# A change in order shouldn't trigger a notification
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write('{"hello" : 123, "world": 123}')
@@ -390,7 +391,7 @@ def test_ignore_json_order(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write('{"world" : 123, "hello": 123}')
# Trigger a check
@@ -401,7 +402,7 @@ def test_ignore_json_order(client, live_server, measure_memory_usage):
assert b'has-unread-changes' not in res.data
# Just to be sure it still works
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write('{"world" : 123, "hello": 124}')
# Trigger a check
@@ -413,10 +414,10 @@ def test_ignore_json_order(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_correct_header_detect(client, live_server, measure_memory_usage):
def test_correct_header_detect(client, live_server, measure_memory_usage, datastore_path):
# Like in https://github.com/dgtlmoon/changedetection.io/pull/1593
# Specify extra html that JSON is sometimes wrapped in - when using SockpuppetBrowser / Puppeteer / Playwrightetc
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write('<html><body>{ "world": 123, "hello" : 123}')
# Add our URL to the import page
@@ -450,18 +451,18 @@ def test_correct_header_detect(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_check_jsonpath_ext_filter(client, live_server, measure_memory_usage):
check_json_ext_filter('json:$[?(@.status==Sold)]', client, live_server)
def test_check_jsonpath_ext_filter(client, live_server, measure_memory_usage, datastore_path):
check_json_ext_filter('json:$[?(@.status==Sold)]', client, live_server, datastore_path=datastore_path)
def test_check_jq_ext_filter(client, live_server, measure_memory_usage):
def test_check_jq_ext_filter(client, live_server, measure_memory_usage, datastore_path):
if jq_support:
check_json_ext_filter('jq:.[] | select(.status | contains("Sold"))', client, live_server)
check_json_ext_filter('jq:.[] | select(.status | contains("Sold"))', client, live_server, datastore_path=datastore_path)
def test_check_jqraw_ext_filter(client, live_server, measure_memory_usage):
def test_check_jqraw_ext_filter(client, live_server, measure_memory_usage, datastore_path):
if jq_support:
check_json_ext_filter('jq:.[] | select(.status | contains("Sold"))', client, live_server)
check_json_ext_filter('jq:.[] | select(.status | contains("Sold"))', client, live_server, datastore_path=datastore_path)
def test_jsonpath_BOM_utf8(client, live_server, measure_memory_usage):
def test_jsonpath_BOM_utf8(client, live_server, measure_memory_usage, datastore_path):
from .. import html_tools
# JSON string with BOM and correct double-quoted keys

View File

@@ -2,9 +2,10 @@
from flask import url_for
from changedetectionio.tests.util import live_server_setup, wait_for_all_checks, extract_UUID_from_client, delete_all_watches
import os
def set_response():
def set_response(datastore_path):
data = """<html>
<body>Awesome, you made it<br>
@@ -15,12 +16,12 @@ something to trigger<br>
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(data)
def test_content_filter_live_preview(client, live_server, measure_memory_usage):
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()
set_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)

View File

@@ -3,9 +3,10 @@
from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks, delete_all_watches
import time
import os
def set_nonrenderable_response():
def set_nonrenderable_response(datastore_path):
test_return_data = """<html>
<head><title>modified head title</title></head>
<!-- like when some angular app was broken and doesnt render or whatever -->
@@ -13,20 +14,20 @@ def set_nonrenderable_response():
</body>
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
time.sleep(1)
return None
def set_zero_byte_response():
with open("test-datastore/endpoint-content.txt", "w") as f:
def set_zero_byte_response(datastore_path):
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("")
time.sleep(1)
return None
def test_check_basic_change_detection_functionality(client, live_server, measure_memory_usage):
set_original_response()
def test_check_basic_change_detection_functionality(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# live_server_setup(live_server) # Setup on conftest per function
# Add our URL to the import page
@@ -55,7 +56,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
)
# this should not trigger a change, because no good text could be converted from the HTML
set_nonrenderable_response()
set_nonrenderable_response(datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -84,7 +85,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure
'application-fetch_backend': "html_requests"},
follow_redirects=True
)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -100,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

View File

@@ -21,9 +21,9 @@ from ..model import USE_SYSTEM_DEFAULT_NOTIFICATION_FORMAT_FOR_WATCH
# Hard to just add more live server URLs when one test is already running (I think)
# So we add our test here (was in a different file)
def test_check_notification(client, live_server, measure_memory_usage):
def test_check_notification(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
# Re 360 - new install should have defaults set
res = client.get(url_for("settings.settings_page"))
@@ -83,8 +83,7 @@ def test_check_notification(client, live_server, measure_memory_usage):
uuid = next(iter(live_server.app.config['DATASTORE'].data['watching']))
datastore = 'test-datastore'
with open(os.path.join(datastore, str(uuid), 'last-screenshot.png'), 'wb') as f:
with open(os.path.join(datastore_path, str(uuid), 'last-screenshot.png'), 'wb') as f:
f.write(base64.b64decode(testimage_png))
# Goto the edit page, add our ignore text
@@ -138,7 +137,7 @@ def test_check_notification(client, live_server, measure_memory_usage):
## Now recheck, and it should have sent the notification
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -151,9 +150,9 @@ def test_check_notification(client, live_server, measure_memory_usage):
# Verify what was sent as a notification, this file should exist
with open("test-datastore/notification.txt", "r") as f:
with open(os.path.join(datastore_path, "notification.txt"), "r") as f:
notification_submission = f.read()
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))
# Did we see the URL that had a change, in the notification?
# Diff was correctly executed
@@ -197,18 +196,18 @@ def test_check_notification(client, live_server, measure_memory_usage):
# This should insert the {current_snapshot}
set_more_modified_response()
set_more_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
time.sleep(3)
# Verify what was sent as a notification, this file should exist
with open("test-datastore/notification.txt", "r") as f:
with open(os.path.join(datastore_path, "notification.txt"), "r") as f:
notification_submission = f.read()
assert "Ohh yeah awesome" in notification_submission
# Prove that "content constantly being marked as Changed with no Updating causes notification" is not a thing
# https://github.com/dgtlmoon/changedetection.io/discussions/192
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -217,13 +216,13 @@ def test_check_notification(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
assert os.path.exists("test-datastore/notification.txt") == False
assert os.path.exists(os.path.join(datastore_path, "notification.txt")) == False
res = client.get(url_for("settings.notification_logs"))
# be sure we see it in the output log
assert b'New ChangeDetection.io Notification - ' + test_url.encode('utf-8') in res.data
set_original_response()
set_original_response(datastore_path=datastore_path)
res = client.post(
url_for("ui.ui_edit.edit_page", uuid="first"),
data={
@@ -243,7 +242,7 @@ def test_check_notification(client, live_server, measure_memory_usage):
time.sleep(2)
# Verify what was sent as a notification, this file should exist
with open("test-datastore/notification.txt", "r") as f:
with open(os.path.join(datastore_path, "notification.txt"), "r") as f:
notification_submission = f.read()
assert "fallback-title" in notification_submission
assert "fallback-body" in notification_submission
@@ -254,7 +253,7 @@ def test_check_notification(client, live_server, measure_memory_usage):
follow_redirects=True
)
def test_notification_validation(client, live_server, measure_memory_usage):
def test_notification_validation(client, live_server, measure_memory_usage, datastore_path):
time.sleep(1)
@@ -292,7 +291,7 @@ def test_notification_validation(client, live_server, measure_memory_usage):
)
def test_notification_urls_jinja2_apprise_integration(client, live_server, measure_memory_usage):
def test_notification_urls_jinja2_apprise_integration(client, live_server, measure_memory_usage, datastore_path):
#
# https://github.com/caronc/apprise/wiki/Notify_Custom_JSON#header-manipulation
@@ -314,14 +313,14 @@ def test_notification_urls_jinja2_apprise_integration(client, live_server, measu
assert b'Settings updated' in res.data
def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_memory_usage):
def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_memory_usage, datastore_path):
# test_endpoint - that sends the contents of a file
# test_notification_endpoint - that takes a POST and writes it to file (test-datastore/notification.txt)
# CUSTOM JSON BODY CHECK for POST://
set_original_response()
set_original_response(datastore_path=datastore_path)
# https://github.com/caronc/apprise/wiki/Notify_Custom_JSON#header-manipulation
test_notification_url = url_for('test_notification_endpoint', _external=True).replace('http://', 'post://')+"?status_code=204&watch_uuid={{ watch_uuid }}&xxx={{ watch_url }}&now={% now 'Europe/London', '%Y-%m-%d' %}&+custom-header=123&+second=hello+world%20%22space%22"
@@ -352,7 +351,7 @@ def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_me
watch_uuid = next(iter(live_server.app.config['DATASTORE'].data['watching']))
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -364,7 +363,7 @@ def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_me
res = client.get(url_for("watchlist.index"))
assert b'notification-error' not in res.data
with open("test-datastore/notification.txt", 'r') as f:
with open(os.path.join(datastore_path, "notification.txt"), 'r') as f:
x = f.read()
j = json.loads(x)
assert j['url'].startswith('http://localhost')
@@ -373,8 +372,8 @@ def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_me
# URL check, this will always be converted to lowercase
assert os.path.isfile("test-datastore/notification-url.txt")
with open("test-datastore/notification-url.txt", 'r') as f:
assert os.path.isfile(os.path.join(datastore_path, "notification-url.txt"))
with open(os.path.join(datastore_path, "notification-url.txt"), 'r') as f:
notification_url = f.read()
assert 'xxx=http' in notification_url
# apprise style headers should be stripped
@@ -385,18 +384,18 @@ def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_me
assert f'watch_uuid={watch_uuid}' in notification_url
with open("test-datastore/notification-headers.txt", 'r') as f:
with open(os.path.join(datastore_path, "notification-headers.txt"), 'r') as f:
notification_headers = f.read()
assert 'custom-header: 123' in notification_headers.lower()
assert 'second: hello world "space"' in notification_headers.lower()
# Should always be automatically detected as JSON content type even when we set it as 'Plain Text' (default)
assert os.path.isfile("test-datastore/notification-content-type.txt")
with open("test-datastore/notification-content-type.txt", 'r') as f:
assert os.path.isfile(os.path.join(datastore_path, "notification-content-type.txt"))
with open(os.path.join(datastore_path, "notification-content-type.txt"), 'r') as f:
assert 'application/json' in f.read()
os.unlink("test-datastore/notification-url.txt")
os.unlink(os.path.join(datastore_path, "notification-url.txt"))
client.get(
url_for("ui.form_delete", uuid="all"),
@@ -405,12 +404,12 @@ def test_notification_custom_endpoint_and_jinja2(client, live_server, measure_me
#2510
def test_global_send_test_notification(client, live_server, measure_memory_usage):
def test_global_send_test_notification(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
if os.path.isfile("test-datastore/notification.txt"):
os.unlink("test-datastore/notification.txt") \
set_original_response(datastore_path=datastore_path)
if os.path.isfile(os.path.join(datastore_path, "notification.txt")):
os.unlink(os.path.join(datastore_path, "notification.txt")) \
# 1995 UTF-8 content should be encoded
test_body = 'change detection is cool 网站监测 内容更新了'
@@ -451,11 +450,11 @@ def test_global_send_test_notification(client, live_server, measure_memory_usage
assert res.status_code != 400
assert res.status_code != 500
with open("test-datastore/notification.txt", 'r') as f:
with open(os.path.join(datastore_path, "notification.txt"), 'r') as f:
x = f.read()
assert test_body in x
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))
######### Test group/tag settings
res = client.post(
@@ -470,7 +469,7 @@ def test_global_send_test_notification(client, live_server, measure_memory_usage
# Give apprise time to fire
time.sleep(4)
with open("test-datastore/notification.txt", 'r') as f:
with open(os.path.join(datastore_path, "notification.txt"), 'r') as f:
x = f.read()
# Should come from notification.py default handler when there is no notification body to pull from
assert 'change detection is cool 网站监测 内容更新了' in x
@@ -511,12 +510,12 @@ def test_global_send_test_notification(client, live_server, measure_memory_usage
def _test_color_notifications(client, notification_body_token):
def _test_color_notifications(client, notification_body_token, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
if os.path.isfile("test-datastore/notification.txt"):
os.unlink("test-datastore/notification.txt")
if os.path.isfile(os.path.join(datastore_path, "notification.txt")):
os.unlink(os.path.join(datastore_path, "notification.txt"))
test_notification_url = url_for('test_notification_endpoint', _external=True).replace('http://', 'post://')+"?xxx={{ watch_url }}&+custom-header=123"
@@ -548,7 +547,7 @@ def _test_color_notifications(client, notification_body_token):
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -557,7 +556,7 @@ def _test_color_notifications(client, notification_body_token):
wait_for_all_checks(client)
time.sleep(3)
with open("test-datastore/notification.txt", 'r') as f:
with open(os.path.join(datastore_path, "notification.txt"), 'r') as f:
x = f.read()
s = f'<span style="{HTML_CHANGED_STYLE}" role="note" aria-label="Changed text" title="Changed text">Which is across multiple lines'
assert s in x
@@ -569,6 +568,7 @@ def _test_color_notifications(client, notification_body_token):
)
# Just checks the format of the colour notifications was correct
def test_html_color_notifications(client, live_server, measure_memory_usage):
_test_color_notifications(client, '{{diff}}')
_test_color_notifications(client, '{{diff_full}}')
def test_html_color_notifications(client, live_server, measure_memory_usage, datastore_path):
_test_color_notifications(client, '{{diff}}',datastore_path=datastore_path)
_test_color_notifications(client, '{{diff_full}}',datastore_path=datastore_path)

View File

@@ -4,10 +4,10 @@ from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks
import logging
def test_check_notification_error_handling(client, live_server, measure_memory_usage):
def test_check_notification_error_handling(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_original_response()
set_original_response(datastore_path=datastore_path)
# Set a URL and fetch it, then set a notification URL which is going to give errors
test_url = url_for('test_endpoint', _external=True)
@@ -19,7 +19,7 @@ def test_check_notification_error_handling(client, live_server, measure_memory_u
assert b"Watch added" in res.data
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
working_notification_url = url_for('test_notification_endpoint', _external=True).replace('http', 'json')
broken_notification_url = "jsons://broken-url-xxxxxxxx123/test"
@@ -73,9 +73,9 @@ def test_check_notification_error_handling(client, live_server, measure_memory_u
assert found_name_resolution_error
# And the working one, which is after the 'broken' one should still have fired
with open("test-datastore/notification.txt", "r") as f:
with open(os.path.join(datastore_path, "notification.txt"), "r") as f:
notification_submission = f.read()
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))
assert 'xxxxx' in notification_submission
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)

View File

@@ -3,9 +3,10 @@
import time
from flask import url_for
from .util import live_server_setup
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
<span>The price is</span><span>$<!-- -->90<!-- -->.<!-- -->74</span>
@@ -14,12 +15,12 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_obfuscations(client, live_server, measure_memory_usage):
set_original_ignore_response()
def test_obfuscations(client, live_server, measure_memory_usage, datastore_path):
set_original_ignore_response(datastore_path)
# live_server_setup(live_server) # Setup on conftest per function
time.sleep(1)
# Add our URL to the import page

View File

@@ -3,15 +3,16 @@
import time
from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks
import os
# `subtractive_selectors` should still work in `source:` type requests
def test_fetch_pdf(client, live_server, measure_memory_usage):
def test_fetch_pdf(client, live_server, measure_memory_usage, datastore_path):
import shutil
import os
shutil.copy("tests/test.pdf", "test-datastore/endpoint-test.pdf")
first_version_size = os.path.getsize("test-datastore/endpoint-test.pdf")
shutil.copy("tests/test.pdf", os.path.join(datastore_path, "endpoint-test.pdf"))
first_version_size = os.path.getsize(os.path.join(datastore_path, "endpoint-test.pdf"))
test_url = url_for('test_pdf_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -35,14 +36,14 @@ def test_fetch_pdf(client, live_server, measure_memory_usage):
# So we know if the file changes in other ways
import hashlib
original_md5 = hashlib.md5(open("test-datastore/endpoint-test.pdf", 'rb').read()).hexdigest().upper()
original_md5 = hashlib.md5(open(os.path.join(datastore_path, "endpoint-test.pdf"), 'rb').read()).hexdigest().upper()
# We should have one
assert len(original_md5) >0
# And it's going to be in the document
assert f'Document checksum - {original_md5}' in snapshot_contents
shutil.copy("tests/test2.pdf", "test-datastore/endpoint-test.pdf")
changed_md5 = hashlib.md5(open("test-datastore/endpoint-test.pdf", 'rb').read()).hexdigest().upper()
shutil.copy("tests/test2.pdf", os.path.join(datastore_path, "endpoint-test.pdf"))
changed_md5 = hashlib.md5(open(os.path.join(datastore_path, "endpoint-test.pdf"), 'rb').read()).hexdigest().upper()
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
@@ -76,9 +77,9 @@ def test_fetch_pdf(client, live_server, measure_memory_usage):
# new snapshot was also OK, no HTML
snapshot_contents = watch.get_history_snapshot(dates[1])
assert 'html' not in snapshot_contents.lower()
assert f'Original file size - {os.path.getsize("test-datastore/endpoint-test.pdf")}' in snapshot_contents
assert f'Original file size - {os.path.getsize(os.path.join(datastore_path, "endpoint-test.pdf"))}' in snapshot_contents
assert f'here is a change' in snapshot_contents
assert os.path.getsize("test-datastore/endpoint-test.pdf") != first_version_size # And the disk change worked
assert os.path.getsize(os.path.join(datastore_path, "endpoint-test.pdf")) != first_version_size # And the disk change worked

View File

@@ -3,12 +3,13 @@
import time
from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks
import os
# `subtractive_selectors` should still work in `source:` type requests
def test_fetch_pdf(client, live_server, measure_memory_usage):
def test_fetch_pdf(client, live_server, measure_memory_usage, datastore_path):
import shutil
shutil.copy("tests/test.pdf", "test-datastore/endpoint-test.pdf")
shutil.copy("tests/test.pdf", os.path.join(datastore_path, "endpoint-test.pdf"))
# live_server_setup(live_server) # Setup on conftest per function
test_url = url_for('test_pdf_endpoint', _external=True)
@@ -29,14 +30,14 @@ def test_fetch_pdf(client, live_server, measure_memory_usage):
# So we know if the file changes in other ways
import hashlib
original_md5 = hashlib.md5(open("test-datastore/endpoint-test.pdf", 'rb').read()).hexdigest().upper()
original_md5 = hashlib.md5(open(os.path.join(datastore_path, "endpoint-test.pdf"), 'rb').read()).hexdigest().upper()
# We should have one
assert len(original_md5) > 0
# And it's going to be in the document
assert b'Document checksum - ' + bytes(str(original_md5).encode('utf-8')) in res.data
shutil.copy("tests/test2.pdf", "test-datastore/endpoint-test.pdf")
changed_md5 = hashlib.md5(open("test-datastore/endpoint-test.pdf", 'rb').read()).hexdigest().upper()
shutil.copy("tests/test2.pdf", os.path.join(datastore_path, "endpoint-test.pdf"))
changed_md5 = hashlib.md5(open(os.path.join(datastore_path, "endpoint-test.pdf"), 'rb').read()).hexdigest().upper()
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data

View File

@@ -8,7 +8,7 @@ from . util import set_original_response, set_modified_response, live_server_set
# Hard to just add more live server URLs when one test is already running (I think)
# So we add our test here (was in a different file)
def test_headers_in_request(client, live_server, measure_memory_usage):
def test_headers_in_request(client, live_server, measure_memory_usage, datastore_path):
#ve_server_setup(live_server)
# Add our URL to the import page
test_url = url_for('test_headers', _external=True)
@@ -76,7 +76,8 @@ def test_headers_in_request(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_body_in_request(client, live_server, measure_memory_usage):
def test_body_in_request(client, live_server, measure_memory_usage, datastore_path):
import os
# Add our URL to the import page
test_url = url_for('test_body', _external=True)
@@ -141,7 +142,7 @@ def test_body_in_request(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
watches_with_body = 0
with open('test-datastore/url-watches.json') as f:
with open(os.path.join(datastore_path, 'url-watches.json')) as f:
app_struct = json.load(f)
for uuid in app_struct['watching']:
if app_struct['watching'][uuid]['body']==body_value:
@@ -165,7 +166,8 @@ def test_body_in_request(client, live_server, measure_memory_usage):
assert b"Body must be empty when Request Method is set to GET" in res.data
delete_all_watches(client)
def test_method_in_request(client, live_server, measure_memory_usage):
def test_method_in_request(client, live_server, measure_memory_usage, datastore_path):
import os
# Add our URL to the import page
test_url = url_for('test_method', _external=True)
if os.getenv('PLAYWRIGHT_DRIVER_URL'):
@@ -223,7 +225,7 @@ def test_method_in_request(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
watches_with_method = 0
with open('test-datastore/url-watches.json') as f:
with open(os.path.join(datastore_path, 'url-watches.json')) as f:
app_struct = json.load(f)
for uuid in app_struct['watching']:
if app_struct['watching'][uuid]['method'] == 'PATCH':
@@ -235,7 +237,7 @@ def test_method_in_request(client, live_server, measure_memory_usage):
delete_all_watches(client)
# Re #2408 - user-agent override test, also should handle case-insensitive header deduplication
def test_ua_global_override(client, live_server, measure_memory_usage):
def test_ua_global_override(client, live_server, measure_memory_usage, datastore_path):
## live_server_setup(live_server) # Setup on conftest per function
test_url = url_for('test_headers', _external=True)
@@ -286,8 +288,9 @@ def test_ua_global_override(client, live_server, measure_memory_usage):
assert b"html-requests-user-agent" not in res.data
delete_all_watches(client)
def test_headers_textfile_in_request(client, live_server, measure_memory_usage):
def test_headers_textfile_in_request(client, live_server, measure_memory_usage, datastore_path):
import os
# Add our URL to the import page
webdriver_ua = "Hello fancy webdriver UA 1.0"
@@ -343,14 +346,14 @@ def test_headers_textfile_in_request(client, live_server, measure_memory_usage):
assert b"Updated watch." in res.data
wait_for_all_checks(client)
with open('test-datastore/headers-testtag.txt', 'w') as f:
with open(os.path.join(datastore_path, 'headers-testtag.txt'), 'w') as f:
f.write("tag-header: test\r\nurl-header: http://example.com")
with open('test-datastore/headers.txt', 'w') as f:
with open(os.path.join(datastore_path, 'headers.txt'), 'w') as f:
f.write("global-header: nice\r\nnext-global-header: nice\r\nurl-header-global: http://example.com/global")
uuid = next(iter(live_server.app.config['DATASTORE'].data['watching']))
with open(f'test-datastore/{uuid}/headers.txt', 'w') as f:
with open(os.path.join(datastore_path, uuid, 'headers.txt'), 'w') as f:
f.write("watch-header: nice\r\nurl-header-watch: http://example.com/watch")
wait_for_all_checks(client)
@@ -368,8 +371,8 @@ def test_headers_textfile_in_request(client, live_server, measure_memory_usage):
assert b"Extra headers file found and will be added to this watch" in res.data
# Not needed anymore
os.unlink('test-datastore/headers.txt')
os.unlink('test-datastore/headers-testtag.txt')
os.unlink(os.path.join(datastore_path, 'headers.txt'))
os.unlink(os.path.join(datastore_path, 'headers-testtag.txt'))
# The service should echo back the request verb
res = client.get(
@@ -395,7 +398,7 @@ def test_headers_textfile_in_request(client, live_server, measure_memory_usage):
# unlink headers.txt on start/stop
delete_all_watches(client)
def test_headers_validation(client, live_server, measure_memory_usage):
def test_headers_validation(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_headers', _external=True)

View File

@@ -21,8 +21,7 @@ out_of_stock_props = [
'<script type="application/ld+json">{"@context":"http://schema.org","@type":"WebSite","url":"https://www.medimops.de/","potentialAction":{"@type":"SearchAction","target":"https://www.medimops.de/produkte-C0/?fcIsSearch=1&searchparam={searchparam}","query-input":"required name=searchparam"}}</script><script type="application/ld+json">{"@context":"http://schema.org","@type":"Product","name":"Horsetrader: Robert Sangster and the Rise and Fall of the Sport of Kings","image":"https://images2.medimops.eu/product/43a982/M00002551322-large.jpg","productID":"isbn:9780002551328","gtin13":"9780002551328","category":"Livres en langue étrangère","offers":{"@type":"Offer","priceCurrency":"EUR","price":$$PRICE$$,"itemCondition":"UsedCondition","availability":"OutOfStock"},"brand":{"@type":"Thing","name":"Patrick Robinson","url":"https://www.momox-shop.fr/,patrick-robinson/"}}</script>'
]
def set_original_response(props_markup='', price="121.95"):
def set_original_response(datastore_path, props_markup='', price="121.95"):
props_markup=props_markup.replace('$$PRICE$$', price)
test_return_data = f"""<html>
<body>
@@ -36,28 +35,19 @@ def set_original_response(props_markup='', price="121.95"):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
time.sleep(1)
return None
# def test_setup(client, live_server, measure_memory_usage):
# live_server_setup(live_server) # Setup on conftest per function
def test_restock_itemprop_basic(client, live_server, measure_memory_usage):
def test_restock_itemprop_basic(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_endpoint', _external=True)
# By default it should enable ('in_stock_processing') == 'all_changes'
for p in instock_props:
set_original_response(props_markup=p)
set_original_response(props_markup=p, 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'},
@@ -73,7 +63,7 @@ def test_restock_itemprop_basic(client, live_server, measure_memory_usage):
for p in out_of_stock_props:
set_original_response(props_markup=p)
set_original_response(props_markup=p, datastore_path=datastore_path)
client.post(
url_for("ui.ui_views.form_quick_watch_add"),
data={"url": test_url, "tags": '', 'processor': 'restock_diff'},
@@ -86,13 +76,13 @@ def test_restock_itemprop_basic(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_itemprop_price_change(client, live_server, measure_memory_usage):
def test_itemprop_price_change(client, live_server, measure_memory_usage, datastore_path):
# Out of the box 'Follow price changes' should be ON
test_url = url_for('test_endpoint', _external=True)
set_original_response(props_markup=instock_props[0], price="190.95")
set_original_response(props_markup=instock_props[0], price="190.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'},
@@ -105,7 +95,7 @@ def test_itemprop_price_change(client, live_server, measure_memory_usage):
assert b'190.95' in res.data
# basic price change, look for notification
set_original_response(props_markup=instock_props[0], price='180.45')
set_original_response(props_markup=instock_props[0], price='180.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -116,7 +106,7 @@ def test_itemprop_price_change(client, live_server, measure_memory_usage):
# turning off price change trigger, but it should show the new price, with no change notification
set_original_response(props_markup=instock_props[0], price='120.45')
set_original_response(props_markup=instock_props[0], price='120.45', datastore_path=datastore_path)
res = client.post(
url_for("ui.ui_edit.edit_page", uuid="first"),
data={"restock_settings-follow_price_changes": "", "url": test_url, "tags": "", "headers": "", 'fetch_backend': "html_requests", "time_between_check_use_default": "y"},
@@ -132,13 +122,13 @@ def test_itemprop_price_change(client, live_server, measure_memory_usage):
delete_all_watches(client)
def _run_test_minmax_limit(client, extra_watch_edit_form):
def _run_test_minmax_limit(client, extra_watch_edit_form, 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")
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'},
@@ -166,7 +156,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
client.get(url_for("ui.mark_all_viewed"))
# price changed to something greater than min (900), BUT less than max (1100).. should be no change
set_original_response(props_markup=instock_props[0], price='1000.45')
set_original_response(props_markup=instock_props[0], price='1000.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -177,7 +167,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
assert b'has-unread-changes' not in res.data
# price changed to something LESS than min (900), SHOULD be a change
set_original_response(props_markup=instock_props[0], price='890.45')
set_original_response(props_markup=instock_props[0], price='890.45', datastore_path=datastore_path)
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
@@ -190,7 +180,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
# 2715 - Price detection (once it crosses the "lower" threshold) again with a lower price - should trigger again!
set_original_response(props_markup=instock_props[0], price='820.45')
set_original_response(props_markup=instock_props[0], price='820.45', datastore_path=datastore_path)
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
wait_for_all_checks(client)
@@ -200,7 +190,7 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
client.get(url_for("ui.mark_all_viewed"))
# price changed to something MORE than max (1100.10), SHOULD be a change
set_original_response(props_markup=instock_props[0], price='1890.45')
set_original_response(props_markup=instock_props[0], price='1890.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -211,16 +201,16 @@ def _run_test_minmax_limit(client, extra_watch_edit_form):
delete_all_watches(client)
def test_restock_itemprop_minmax(client, live_server, measure_memory_usage):
def test_restock_itemprop_minmax(client, live_server, measure_memory_usage, datastore_path):
extras = {
"restock_settings-follow_price_changes": "y",
"restock_settings-price_change_min": 900.0,
"restock_settings-price_change_max": 1100.10
}
_run_test_minmax_limit(client, extra_watch_edit_form=extras)
_run_test_minmax_limit(client, extra_watch_edit_form=extras, datastore_path=datastore_path)
def test_restock_itemprop_with_tag(client, live_server, measure_memory_usage):
def test_restock_itemprop_with_tag(client, live_server, measure_memory_usage, datastore_path):
res = client.post(
@@ -245,18 +235,18 @@ def test_restock_itemprop_with_tag(client, live_server, measure_memory_usage):
"tags": "test-tag"
}
_run_test_minmax_limit(client, extra_watch_edit_form=extras)
_run_test_minmax_limit(client, extra_watch_edit_form=extras,datastore_path=datastore_path)
def test_itemprop_percent_threshold(client, live_server, measure_memory_usage):
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")
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'},
@@ -283,7 +273,7 @@ def test_itemprop_percent_threshold(client, live_server, measure_memory_usage):
# Basic change should not trigger
set_original_response(props_markup=instock_props[0], price='960.45')
set_original_response(props_markup=instock_props[0], price='960.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -291,7 +281,7 @@ def test_itemprop_percent_threshold(client, live_server, measure_memory_usage):
assert b'has-unread-changes' not in res.data
# Bigger INCREASE change than the threshold should trigger
set_original_response(props_markup=instock_props[0], price='1960.45')
set_original_response(props_markup=instock_props[0], price='1960.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -301,7 +291,7 @@ def test_itemprop_percent_threshold(client, live_server, measure_memory_usage):
# Small decrease should NOT trigger
client.get(url_for("ui.mark_all_viewed"))
set_original_response(props_markup=instock_props[0], price='1950.45')
set_original_response(props_markup=instock_props[0], price='1950.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
@@ -315,14 +305,14 @@ def test_itemprop_percent_threshold(client, live_server, measure_memory_usage):
def test_change_with_notification_values(client, live_server, measure_memory_usage):
def test_change_with_notification_values(client, live_server, measure_memory_usage, datastore_path):
if os.path.isfile("test-datastore/notification.txt"):
os.unlink("test-datastore/notification.txt")
if os.path.isfile(os.path.join(datastore_path, "notification.txt")):
os.unlink(os.path.join(datastore_path, "notification.txt"))
test_url = url_for('test_endpoint', _external=True)
set_original_response(props_markup=instock_props[0], price='960.45')
set_original_response(props_markup=instock_props[0], price='960.45', datastore_path=datastore_path)
notification_url = url_for('test_notification_endpoint', _external=True).replace('http', 'json')
@@ -363,34 +353,34 @@ def test_change_with_notification_values(client, live_server, measure_memory_usa
assert b"Settings updated." in res.data
set_original_response(props_markup=instock_props[0], price='960.45')
set_original_response(props_markup=instock_props[0], price='960.45', datastore_path=datastore_path)
# A change in price, should trigger a change by default
set_original_response(props_markup=instock_props[0], price='1950.45')
set_original_response(props_markup=instock_props[0], price='1950.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"))
wait_for_all_checks(client)
wait_for_notification_endpoint_output()
assert os.path.isfile("test-datastore/notification.txt"), "Notification received"
with open("test-datastore/notification.txt", 'r') as f:
wait_for_notification_endpoint_output(datastore_path=datastore_path)
assert os.path.isfile(os.path.join(datastore_path, "notification.txt")), "Notification received"
with open(os.path.join(datastore_path, "notification.txt"), 'r') as f:
notification = f.read()
assert "new price 1950.45" in notification
assert "title new price 1950.45" in notification
## Now test the "SEND TEST NOTIFICATION" is working
os.unlink("test-datastore/notification.txt")
os.unlink(os.path.join(datastore_path, "notification.txt"))
uuid = next(iter(live_server.app.config['DATASTORE'].data['watching']))
res = client.post(url_for("ui.ui_notification.ajax_callback_send_notification_test", watch_uuid=uuid), data={}, follow_redirects=True)
time.sleep(5)
assert os.path.isfile("test-datastore/notification.txt"), "Notification received"
assert os.path.isfile(os.path.join(datastore_path, "notification.txt")), "Notification received"
def test_data_sanity(client, live_server, measure_memory_usage):
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")
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'},
@@ -429,7 +419,7 @@ def test_data_sanity(client, live_server, measure_memory_usage):
delete_all_watches(client)
# All examples should give a prive of 666.66
def test_special_prop_examples(client, live_server, measure_memory_usage):
def test_special_prop_examples(client, live_server, measure_memory_usage, datastore_path):
import glob
@@ -439,7 +429,7 @@ def test_special_prop_examples(client, live_server, measure_memory_usage):
assert files
for test_example_filename in files:
with open(test_example_filename, 'r') as example_f:
with open("test-datastore/endpoint-content.txt", "w") as test_f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as test_f:
test_f.write(f"<html><body>{example_f.read()}</body></html>")
# Now fetch it and check the price worked

View File

@@ -1,12 +1,12 @@
#!/usr/bin/env python3
import os
import time
from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks, extract_rss_token_from_UI, \
extract_UUID_from_client, delete_all_watches
def set_original_cdata_xml():
def set_original_cdata_xml(datastore_path):
test_return_data = """<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Gizi</title>
@@ -45,12 +45,12 @@ def set_original_cdata_xml():
</rss>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_html_content(content):
def set_html_content(datastore_path, content):
test_return_data = f"""<html>
<body>
Some initial text<br>
@@ -62,16 +62,16 @@ def set_html_content(content):
"""
# Write as UTF-8 encoded bytes
with open("test-datastore/endpoint-content.txt", "wb") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "wb") as f:
f.write(test_return_data.encode('utf-8'))
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_rss_and_token(client, live_server, measure_memory_usage):
def test_rss_and_token(client, live_server, measure_memory_usage, datastore_path):
# # live_server_setup(live_server) # Setup on conftest per function
set_original_response()
set_original_response(datastore_path=datastore_path)
rss_token = extract_rss_token_from_UI(client)
# Add our URL to the import page
@@ -84,7 +84,7 @@ def test_rss_and_token(client, live_server, measure_memory_usage):
assert b"1 Imported" in res.data
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
time.sleep(1)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -106,10 +106,10 @@ def test_rss_and_token(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_basic_cdata_rss_markup(client, live_server, measure_memory_usage):
def test_basic_cdata_rss_markup(client, live_server, measure_memory_usage, datastore_path):
set_original_cdata_xml()
set_original_cdata_xml(datastore_path)
# Rarely do endpoints give the right header, usually just text/xml, so we check also for <rss
# This also triggers the automatic CDATA text parser so the RSS goes back a nice content list
test_url = url_for('test_endpoint', content_type="text/xml; charset=UTF-8", _external=True)
@@ -130,10 +130,10 @@ def test_basic_cdata_rss_markup(client, live_server, measure_memory_usage):
assert b'The days of Terminator' in res.data
delete_all_watches(client)
def test_rss_xpath_filtering(client, live_server, measure_memory_usage):
def test_rss_xpath_filtering(client, live_server, measure_memory_usage, datastore_path):
set_original_cdata_xml()
set_original_cdata_xml(datastore_path)
test_url = url_for('test_endpoint', content_type="application/atom+xml; charset=UTF-8", _external=True)
@@ -179,7 +179,7 @@ def test_rss_xpath_filtering(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_rss_bad_chars_breaking(client, live_server, measure_memory_usage):
def test_rss_bad_chars_breaking(client, live_server, measure_memory_usage, datastore_path):
"""This should absolutely trigger the RSS builder to go into worst state mode
- source: prefix means no html conversion (which kinda filters out the bad stuff)
@@ -190,7 +190,7 @@ def test_rss_bad_chars_breaking(client, live_server, measure_memory_usage):
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
ten_kb_string = "A" * 10_000
f.write(ten_kb_string)
@@ -204,7 +204,7 @@ def test_rss_bad_chars_breaking(client, live_server, measure_memory_usage):
wait_for_all_checks(client)
# Set the bad content
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
jpeg_bytes = "\xff\xd8\xff\xe0\x00\x10XXXXXXXX\x00\x01\x02\x00\x00\x01\x00\x01\x00\x00" # JPEG header
jpeg_bytes += "A" * 10_000

View File

@@ -1,12 +1,14 @@
#!/usr/bin/env python3
import time
import os
from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks, extract_rss_token_from_UI, \
extract_UUID_from_client, delete_all_watches
def set_original_cdata_xml():
def set_original_cdata_xml(datastore_path):
test_return_data = """<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Security Bulletins on wetscale</title>
@@ -40,13 +42,13 @@ def set_original_cdata_xml():
</rss>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_rss_reader_mode(client, live_server, measure_memory_usage):
set_original_cdata_xml()
def test_rss_reader_mode(client, live_server, measure_memory_usage, datastore_path):
set_original_cdata_xml(datastore_path=datastore_path)
# Rarely do endpoints give the right header, usually just text/xml, so we check also for <rss
# This also triggers the automatic CDATA text parser so the RSS goes back a nice content list
@@ -71,8 +73,8 @@ def test_rss_reader_mode(client, live_server, measure_memory_usage):
assert 'PubDate: Thu, 07 Aug 2025 00:00:00 GMT' in snapshot_contents
delete_all_watches(client)
def test_rss_reader_mode_with_css_filters(client, live_server, measure_memory_usage):
set_original_cdata_xml()
def test_rss_reader_mode_with_css_filters(client, live_server, measure_memory_usage, datastore_path):
set_original_cdata_xml(datastore_path=datastore_path)
# Rarely do endpoints give the right header, usually just text/xml, so we check also for <rss
# This also triggers the automatic CDATA text parser so the RSS goes back a nice content list

View File

@@ -9,10 +9,10 @@ from .util import live_server_setup, wait_for_all_checks, extract_UUID_from_cli
from ..forms import REQUIRE_ATLEAST_ONE_TIME_PART_MESSAGE_DEFAULT, REQUIRE_ATLEAST_ONE_TIME_PART_WHEN_NOT_GLOBAL_DEFAULT
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_check_basic_scheduler_functionality(client, live_server, measure_memory_usage):
def test_check_basic_scheduler_functionality(client, live_server, measure_memory_usage, datastore_path):
days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
test_url = url_for('test_random_content_endpoint', _external=True)
@@ -90,7 +90,7 @@ def test_check_basic_scheduler_functionality(client, live_server, measure_memory
delete_all_watches(client)
def test_check_basic_global_scheduler_functionality(client, live_server, measure_memory_usage):
def test_check_basic_global_scheduler_functionality(client, live_server, measure_memory_usage, datastore_path):
days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
test_url = url_for('test_random_content_endpoint', _external=True)
@@ -172,7 +172,7 @@ def test_check_basic_global_scheduler_functionality(client, live_server, measure
delete_all_watches(client)
def test_validation_time_interval_field(client, live_server, measure_memory_usage):
def test_validation_time_interval_field(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -4,7 +4,7 @@ import time
def test_basic_search(client, live_server, measure_memory_usage):
def test_basic_search(client, live_server, measure_memory_usage, datastore_path):
urls = ['https://localhost:12300?first-result=1',
@@ -37,7 +37,7 @@ def test_basic_search(client, live_server, measure_memory_usage):
assert urls[1].encode('utf-8') not in res.data
def test_search_in_tag_limit(client, live_server, measure_memory_usage):
def test_search_in_tag_limit(client, live_server, measure_memory_usage, datastore_path):
urls = ['https://localhost:12300?first-result=1 tag-one',

View File

@@ -7,7 +7,7 @@ from .util import live_server_setup, wait_for_all_checks, delete_all_watches
from .. import strtobool
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<head><title>head title</title></head>
<body>
@@ -20,11 +20,11 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def test_bad_access(client, live_server, measure_memory_usage):
def test_bad_access(client, live_server, measure_memory_usage, datastore_path):
res = client.post(
url_for("imports.import_page"),
@@ -111,7 +111,7 @@ def _runner_test_various_file_slash(client, file_uri):
delete_all_watches(client)
def test_file_slash_access(client, live_server, measure_memory_usage):
def test_file_slash_access(client, live_server, measure_memory_usage, datastore_path):
# file: is NOT permitted by default, so it will be caught by ALLOW_FILE_URI check
@@ -121,7 +121,7 @@ def test_file_slash_access(client, live_server, measure_memory_usage):
# _runner_test_various_file_slash(client, file_uri=f"file:/{test_file_path}")
# _runner_test_various_file_slash(client, file_uri=f"file:{test_file_path}") # CVE-2024-56509
def test_xss(client, live_server, measure_memory_usage):
def test_xss(client, live_server, measure_memory_usage, datastore_path):
from changedetectionio.notification import (
default_notification_format
@@ -142,12 +142,12 @@ def test_xss(client, live_server, measure_memory_usage):
assert b"&lt;img" in res.data
# Check that even forcing an update directly still doesnt get to the frontend
set_original_response()
set_original_response(datastore_path=datastore_path)
XSS_HACK = 'javascript:alert(document.domain)'
uuid = client.application.config.get('DATASTORE').add_watch(url=url_for('test_endpoint', _external=True))
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
@@ -162,8 +162,8 @@ def test_xss(client, live_server, measure_memory_usage):
assert XSS_HACK.encode('utf-8') not in res.data and res.status_code == 200
def test_xss_watch_last_error(client, live_server, measure_memory_usage):
set_original_response()
def test_xss_watch_last_error(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
res = client.post(
url_for("imports.import_page"),

View File

@@ -9,8 +9,9 @@ import re
sleep_time_for_fetch_thread = 3
def test_share_watch(client, live_server, measure_memory_usage):
set_original_response()
def test_share_watch(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# live_server_setup(live_server) # Setup on conftest per function
test_url = url_for('test_endpoint', _external=True)

View File

@@ -9,8 +9,9 @@ sleep_time_for_fetch_thread = 3
def test_check_basic_change_detection_functionality_source(client, live_server, measure_memory_usage):
set_original_response()
def test_check_basic_change_detection_functionality_source(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
test_url = 'source:'+url_for('test_endpoint', _external=True)
# Add our URL to the import page
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -30,7 +31,7 @@ def test_check_basic_change_detection_functionality_source(client, live_server,
assert b'foobar-detection' in res.data
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Force recheck
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -52,8 +53,9 @@ def test_check_basic_change_detection_functionality_source(client, live_server,
# `subtractive_selectors` should still work in `source:` type requests
def test_check_ignore_elements(client, live_server, measure_memory_usage):
set_original_response()
def test_check_ignore_elements(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
time.sleep(1)
test_url = 'source:'+url_for('test_endpoint', _external=True)
# Add our URL to the import page

View File

@@ -3,9 +3,10 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -17,11 +18,11 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_original_ignore_response():
def set_modified_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some NEW nice initial text<br>
@@ -33,11 +34,11 @@ def set_modified_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_with_trigger_text_response():
def set_modified_with_trigger_text_response(datastore_path):
test_return_data = """<html>
<body>
Some NEW nice initial text<br>
@@ -51,16 +52,16 @@ def set_modified_with_trigger_text_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_trigger_functionality(client, live_server, measure_memory_usage):
def test_trigger_functionality(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
trigger_text = "Add to cart"
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Add our URL to the import page
@@ -106,7 +107,7 @@ def test_trigger_functionality(client, live_server, measure_memory_usage):
assert b'/test-endpoint' in res.data
# Make a change
set_modified_original_ignore_response()
set_modified_original_ignore_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -117,7 +118,7 @@ def test_trigger_functionality(client, live_server, measure_memory_usage):
assert b'has-unread-changes' not in res.data
# Now set the content which contains the trigger text
set_modified_with_trigger_text_response()
set_modified_with_trigger_text_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)

View File

@@ -3,9 +3,10 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -17,16 +18,16 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_trigger_regex_functionality(client, live_server, measure_memory_usage):
def test_trigger_regex_functionality(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -53,7 +54,7 @@ def test_trigger_regex_functionality(client, live_server, measure_memory_usage):
# so that we set the state to 'has-unread-changes' after all the edits
client.get(url_for("ui.ui_views.diff_history_page", uuid="first"))
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("some new noise")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -63,7 +64,7 @@ def test_trigger_regex_functionality(client, live_server, measure_memory_usage):
res = client.get(url_for("watchlist.index"))
assert b'has-unread-changes' not in res.data
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("regex test123<br>\nsomething 123")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -3,9 +3,10 @@
import time
from flask import url_for
from . util import live_server_setup, delete_all_watches
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -17,17 +18,17 @@ def set_original_ignore_response():
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def test_trigger_regex_functionality_with_filter(client, live_server, measure_memory_usage):
def test_trigger_regex_functionality_with_filter(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
sleep_time_for_fetch_thread = 3
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Give the endpoint time to spin up
time.sleep(1)
@@ -57,7 +58,7 @@ def test_trigger_regex_functionality_with_filter(client, live_server, measure_me
client.get(url_for("ui.ui_views.diff_history_page", uuid="first"))
# Check that we have the expected text.. but it's not in the css filter we want
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html>some new noise with cool stuff2 ok</html>")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -68,7 +69,7 @@ def test_trigger_regex_functionality_with_filter(client, live_server, measure_me
assert b'has-unread-changes' not in res.data
# now this should trigger something
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("<html>some new noise with <span id=in-here>cool stuff6</span> ok</html>")
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)

View File

@@ -5,7 +5,7 @@ from .util import set_original_response, set_modified_response, live_server_setu
from ..forms import REQUIRE_ATLEAST_ONE_TIME_PART_WHEN_NOT_GLOBAL_DEFAULT, REQUIRE_ATLEAST_ONE_TIME_PART_MESSAGE_DEFAULT
def test_recheck_time_field_validation_global_settings(client, live_server, measure_memory_usage):
def test_recheck_time_field_validation_global_settings(client, live_server, measure_memory_usage, datastore_path):
"""
Tests that the global settings time field has atleast one value for week/day/hours/minute/seconds etc entered
class globalSettingsRequestForm(Form):
@@ -27,7 +27,7 @@ def test_recheck_time_field_validation_global_settings(client, live_server, meas
assert REQUIRE_ATLEAST_ONE_TIME_PART_MESSAGE_DEFAULT.encode('utf-8') in res.data
def test_recheck_time_field_validation_single_watch(client, live_server, measure_memory_usage):
def test_recheck_time_field_validation_single_watch(client, live_server, measure_memory_usage, datastore_path):
"""
Tests that the global settings time field has atleast one value for week/day/hours/minute/seconds etc entered
class globalSettingsRequestForm(Form):
@@ -95,9 +95,10 @@ def test_recheck_time_field_validation_single_watch(client, live_server, measure
assert b"Updated watch." in res.data
assert REQUIRE_ATLEAST_ONE_TIME_PART_WHEN_NOT_GLOBAL_DEFAULT.encode('utf-8') not in res.data
def test_checkbox_open_diff_in_new_tab(client, live_server, measure_memory_usage):
def test_checkbox_open_diff_in_new_tab(client, live_server, measure_memory_usage, datastore_path):
set_original_response()
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
res = client.post(
url_for("imports.import_page"),
@@ -109,7 +110,7 @@ def test_checkbox_open_diff_in_new_tab(client, live_server, measure_memory_usage
wait_for_all_checks(client)
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Test case 1 - checkbox is enabled in settings
res = client.post(
@@ -168,9 +169,9 @@ def test_checkbox_open_diff_in_new_tab(client, live_server, measure_memory_usage
# Cleanup everything
delete_all_watches(client)
def test_page_title_listing_behaviour(client, live_server, measure_memory_usage):
def test_page_title_listing_behaviour(client, live_server, measure_memory_usage, datastore_path):
set_original_response(extra_title="custom html")
set_original_response(extra_title="custom html", datastore_path=datastore_path)
# either the manually entered title/description or the page link should be visible
res = client.post(
@@ -243,11 +244,11 @@ def test_page_title_listing_behaviour(client, live_server, measure_memory_usage)
assert b"head titlecustom html" in res.data
def test_ui_viewed_unread_flag(client, live_server, measure_memory_usage):
def test_ui_viewed_unread_flag(client, live_server, measure_memory_usage, datastore_path):
import time
set_original_response(extra_title="custom html")
set_original_response(datastore_path=datastore_path, extra_title="custom html")
# Add our URL to the import page
res = client.post(
@@ -259,7 +260,7 @@ def test_ui_viewed_unread_flag(client, live_server, measure_memory_usage):
assert b"2 Imported" in res.data
wait_for_all_checks(client)
set_modified_response()
set_modified_response(datastore_path=datastore_path)
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 2 watches for rechecking.' in res.data
wait_for_all_checks(client)

View File

@@ -3,9 +3,10 @@
import time
from flask import url_for
from .util import live_server_setup, wait_for_all_checks, delete_all_watches
import os
def set_original_ignore_response():
def set_original_ignore_response(datastore_path):
test_return_data = """<html>
<body>
<p>Some initial text</p>
@@ -17,12 +18,12 @@ def set_original_ignore_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# The same but just re-ordered the text
def set_modified_swapped_lines():
def set_modified_swapped_lines(datastore_path):
# Re-ordered and with some whitespacing, should get stripped() too.
test_return_data = """<html>
<body>
@@ -33,10 +34,10 @@ def set_modified_swapped_lines():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_swapped_lines_with_extra_text_for_sorting():
def set_modified_swapped_lines_with_extra_text_for_sorting(datastore_path):
test_return_data = """<html>
<body>
<p>&nbsp;Which is across multiple lines</p>
@@ -50,11 +51,11 @@ def set_modified_swapped_lines_with_extra_text_for_sorting():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
def set_modified_with_trigger_text_response():
def set_modified_with_trigger_text_response(datastore_path):
test_return_data = """<html>
<body>
<p>Some initial text</p>
@@ -65,17 +66,17 @@ def set_modified_with_trigger_text_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
def test_unique_lines_functionality(client, live_server, measure_memory_usage):
def test_unique_lines_functionality(client, live_server, measure_memory_usage, datastore_path):
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -96,7 +97,7 @@ def test_unique_lines_functionality(client, live_server, measure_memory_usage):
assert b'has-unread-changes' not in res.data
# Make a change
set_modified_swapped_lines()
set_modified_swapped_lines(datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -109,17 +110,17 @@ def test_unique_lines_functionality(client, live_server, measure_memory_usage):
assert b'has-unread-changes' not in res.data
# Now set the content which contains the new text and re-ordered existing text
set_modified_with_trigger_text_response()
set_modified_with_trigger_text_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("watchlist.index"))
assert b'has-unread-changes' in res.data
delete_all_watches(client)
def test_sort_lines_functionality(client, live_server, measure_memory_usage):
def test_sort_lines_functionality(client, live_server, measure_memory_usage, datastore_path):
set_modified_swapped_lines_with_extra_text_for_sorting()
set_modified_swapped_lines_with_extra_text_for_sorting(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -162,10 +163,10 @@ def test_sort_lines_functionality(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_extra_filters(client, live_server, measure_memory_usage):
def test_extra_filters(client, live_server, measure_memory_usage, datastore_path):
set_original_ignore_response()
set_original_ignore_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)

View File

@@ -4,8 +4,9 @@ from urllib.request import urlopen
from . util import set_original_response, set_modified_response, live_server_setup
def test_check_watch_field_storage(client, live_server, measure_memory_usage):
set_original_response()
def test_check_watch_field_storage(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# live_server_setup(live_server) # Setup on conftest per function
test_url = "http://somerandomsitewewatch.com"

View File

@@ -4,9 +4,10 @@
from flask import url_for
from .util import wait_for_all_checks, delete_all_watches
from ..processors.magic import RSS_XML_CONTENT_TYPES
import os
def set_rss_atom_feed_response(header=''):
def set_rss_atom_feed_response(datastore_path, header='', ):
test_return_data = f"""{header}<!-- Generated on Wed, 08 Oct 2025 08:42:33 -0700, really really honestly -->
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
@@ -33,14 +34,14 @@ def set_rss_atom_feed_response(header=''):
</channel>
</rss>"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_original_response():
def set_original_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -53,12 +54,12 @@ def set_original_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<body>
Some initial text<br>
@@ -71,14 +72,14 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
# Handle utf-8 charset replies https://github.com/dgtlmoon/changedetection.io/pull/613
def test_check_xpath_filter_utf8(client, live_server, measure_memory_usage):
def test_check_xpath_filter_utf8(client, live_server, measure_memory_usage, datastore_path):
filter = '//item/*[self::description]'
d = '''<?xml version="1.0" encoding="UTF-8"?>
@@ -108,7 +109,7 @@ def test_check_xpath_filter_utf8(client, live_server, measure_memory_usage):
</channel>
</rss>'''
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(d)
# Add our URL to the import page
@@ -129,7 +130,7 @@ def test_check_xpath_filter_utf8(client, live_server, measure_memory_usage):
# Handle utf-8 charset replies https://github.com/dgtlmoon/changedetection.io/pull/613
def test_check_xpath_text_function_utf8(client, live_server, measure_memory_usage):
def test_check_xpath_text_function_utf8(client, live_server, measure_memory_usage, datastore_path):
filter = '//item/title/text()'
d = '''<?xml version="1.0" encoding="UTF-8"?>
@@ -157,7 +158,7 @@ def test_check_xpath_text_function_utf8(client, live_server, measure_memory_usag
</channel>
</rss>'''
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(d)
# Add our URL to the import page
@@ -187,10 +188,10 @@ def test_check_xpath_text_function_utf8(client, live_server, measure_memory_usag
delete_all_watches(client)
def test_check_markup_xpath_filter_restriction(client, live_server, measure_memory_usage):
def test_check_markup_xpath_filter_restriction(client, live_server, measure_memory_usage, datastore_path):
xpath_filter = "//*[contains(@class, 'sametext')]"
set_original_response()
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -216,7 +217,7 @@ def test_check_markup_xpath_filter_restriction(client, live_server, measure_memo
client.get(url_for("ui.ui_views.diff_history_page", uuid="first"), follow_redirects=True)
# Make a change
set_modified_response()
set_modified_response(datastore_path=datastore_path)
# Trigger a check
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -228,7 +229,7 @@ def test_check_markup_xpath_filter_restriction(client, live_server, measure_memo
delete_all_watches(client)
def test_xpath_validation(client, live_server, measure_memory_usage):
def test_xpath_validation(client, live_server, measure_memory_usage, datastore_path):
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -244,7 +245,7 @@ def test_xpath_validation(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_xpath23_prefix_validation(client, live_server, measure_memory_usage):
def test_xpath23_prefix_validation(client, live_server, measure_memory_usage, datastore_path):
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -259,7 +260,7 @@ def test_xpath23_prefix_validation(client, live_server, measure_memory_usage):
assert b"is not a valid XPath expression" in res.data
delete_all_watches(client)
def test_xpath1_lxml(client, live_server, measure_memory_usage):
def test_xpath1_lxml(client, live_server, measure_memory_usage, datastore_path):
d = '''<?xml version="1.0" encoding="UTF-8"?>
@@ -287,7 +288,7 @@ def test_xpath1_lxml(client, live_server, measure_memory_usage):
</channel>
</rss>'''.encode('utf-8')
with open("test-datastore/endpoint-content.txt", "wb") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "wb") as f:
f.write(d)
@@ -319,7 +320,7 @@ def test_xpath1_lxml(client, live_server, measure_memory_usage):
#####
def test_xpath1_validation(client, live_server, measure_memory_usage):
def test_xpath1_validation(client, live_server, measure_memory_usage, datastore_path):
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
@@ -336,10 +337,10 @@ def test_xpath1_validation(client, live_server, measure_memory_usage):
# actually only really used by the distll.io importer, but could be handy too
def test_check_with_prefix_include_filters(client, live_server, measure_memory_usage):
def test_check_with_prefix_include_filters(client, live_server, measure_memory_usage, datastore_path):
delete_all_watches(client)
set_original_response()
set_original_response(datastore_path=datastore_path)
wait_for_all_checks(client)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -368,10 +369,10 @@ def test_check_with_prefix_include_filters(client, live_server, measure_memory_u
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_various_rules(client, live_server, measure_memory_usage):
def test_various_rules(client, live_server, measure_memory_usage, datastore_path):
# Just check these don't error
## live_server_setup(live_server) # Setup on conftest per function
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write("""<html>
<body>
Some initial text<br>
@@ -412,13 +413,13 @@ def test_various_rules(client, live_server, measure_memory_usage):
delete_all_watches(client)
def test_xpath_20(client, live_server, measure_memory_usage):
def test_xpath_20(client, live_server, measure_memory_usage, datastore_path):
test_url = url_for('test_endpoint', _external=True)
uuid = client.application.config.get('DATASTORE').add_watch(url=test_url)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
set_original_response()
set_original_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)
res = client.post(
@@ -446,8 +447,8 @@ def test_xpath_20(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_xpath_20_function_count(client, live_server, measure_memory_usage):
set_original_response()
def test_xpath_20_function_count(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -479,8 +480,8 @@ def test_xpath_20_function_count(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_xpath_20_function_count2(client, live_server, measure_memory_usage):
set_original_response()
def test_xpath_20_function_count2(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -512,8 +513,8 @@ def test_xpath_20_function_count2(client, live_server, measure_memory_usage):
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def test_xpath_20_function_string_join_matches(client, live_server, measure_memory_usage):
set_original_response()
def test_xpath_20_function_string_join_matches(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -546,7 +547,7 @@ def test_xpath_20_function_string_join_matches(client, live_server, measure_memo
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
def _subtest_xpath_rss(client, content_type='text/html'):
def _subtest_xpath_rss(client, datastore_path, content_type='text/html'):
# Add our URL to the import page
test_url = url_for('test_endpoint', content_type=content_type, _external=True)
@@ -584,8 +585,8 @@ def _subtest_xpath_rss(client, content_type='text/html'):
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
# Be sure all-in-the-wild types of RSS feeds work with xpath
def test_rss_xpath(client, live_server, measure_memory_usage):
def test_rss_xpath(client, live_server, measure_memory_usage, datastore_path):
for feed_header in ['', '<?xml version="1.0" encoding="utf-8"?>']:
set_rss_atom_feed_response(header=feed_header)
set_rss_atom_feed_response(header=feed_header, datastore_path=datastore_path)
for content_type in RSS_XML_CONTENT_TYPES:
_subtest_xpath_rss(client, content_type=content_type)
_subtest_xpath_rss(client, content_type=content_type, datastore_path=datastore_path)

View File

@@ -1,12 +1,13 @@
#!/usr/bin/env python3
from operator import truediv
from flask import make_response, request
from flask import make_response, request, current_app
from flask import url_for
import logging
import time
import os
def set_original_response(extra_title=''):
def set_original_response(datastore_path, extra_title=''):
test_return_data = f"""<html>
<head><title>head title{extra_title}</title></head>
<body>
@@ -19,11 +20,11 @@ def set_original_response(extra_title=''):
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_modified_response():
def set_modified_response(datastore_path):
test_return_data = """<html>
<head><title>modified head title</title></head>
<body>
@@ -35,11 +36,11 @@ def set_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_longer_modified_response():
def set_longer_modified_response(datastore_path):
test_return_data = """<html>
<head><title>modified head title</title></head>
<body>
@@ -49,16 +50,17 @@ def set_longer_modified_response():
So let's see what happens. <br>
So let's see what happens. <br>
So let's see what happens. <br>
So let's see what happens. <br>
So let's see what happens. <br>
</body>
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_more_modified_response():
def set_more_modified_response(datastore_path):
test_return_data = """<html>
<head><title>modified head title</title></head>
<body>
@@ -71,27 +73,28 @@ def set_more_modified_response():
</html>
"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def set_empty_text_response():
def set_empty_text_response(datastore_path):
test_return_data = """<html><body></body></html>"""
with open("test-datastore/endpoint-content.txt", "w") as f:
with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f:
f.write(test_return_data)
return None
def wait_for_notification_endpoint_output():
def wait_for_notification_endpoint_output(datastore_path):
'''Apprise can take a few seconds to fire'''
#@todo - could check the apprise object directly instead of looking for this file
from os.path import isfile
notification_file = os.path.join(datastore_path, "notification.txt")
for i in range(1, 20):
time.sleep(1)
if isfile("test-datastore/notification.txt"):
if isfile(notification_file):
return True
return False
@@ -207,7 +210,8 @@ def new_live_server_setup(live_server):
return resp
# Tried using a global var here but didn't seem to work, so reading from a file instead.
with open("test-datastore/endpoint-content.txt", "rb") as f:
datastore_path = current_app.config.get('TEST_DATASTORE_PATH', 'test-datastore')
with open(os.path.join(datastore_path, "endpoint-content.txt"), "rb") as f:
resp = make_response(f.read(), status_code)
if uppercase_headers:
resp.headers['CONTENT-TYPE'] = ctype if ctype else 'text/html'
@@ -246,21 +250,22 @@ def new_live_server_setup(live_server):
# Where we POST to as a notification, also use a space here to test URL escaping is OK across all tests that use this. ( #2868 )
@live_server.app.route('/test_notification_endpoint', methods=['POST', 'GET'])
def test_notification_endpoint():
datastore_path = current_app.config.get('TEST_DATASTORE_PATH', 'test-datastore')
with open("test-datastore/notification.txt", "wb") as f:
with open(os.path.join(datastore_path, "notification.txt"), "wb") as f:
# Debug method, dump all POST to file also, used to prove #65
data = request.stream.read()
if data != None:
f.write(data)
with open("test-datastore/notification-url.txt", "w") as f:
with open(os.path.join(datastore_path, "notification-url.txt"), "w") as f:
f.write(request.url)
with open("test-datastore/notification-headers.txt", "w") as f:
with open(os.path.join(datastore_path, "notification-headers.txt"), "w") as f:
f.write(str(request.headers))
if request.content_type:
with open("test-datastore/notification-content-type.txt", "w") as f:
with open(os.path.join(datastore_path, "notification-content-type.txt"), "w") as f:
f.write(request.content_type)
print("\n>> Test notification endpoint was hit.\n", data)
@@ -285,9 +290,10 @@ def new_live_server_setup(live_server):
@live_server.app.route('/endpoint-test.pdf')
def test_pdf_endpoint():
datastore_path = current_app.config.get('TEST_DATASTORE_PATH', 'test-datastore')
# Tried using a global var here but didn't seem to work, so reading from a file instead.
with open("test-datastore/endpoint-test.pdf", "rb") as f:
with open(os.path.join(datastore_path, "endpoint-test.pdf"), "rb") as f:
resp = make_response(f.read(), 200)
resp.headers['Content-Type'] = 'application/pdf'
return resp

View File

@@ -4,12 +4,12 @@ import os
from flask import url_for
from ..util import live_server_setup, wait_for_all_checks
# def test_setup(client, live_server, measure_memory_usage):
# def test_setup(client, live_server, measure_memory_usage, datastore_path):
# live_server_setup(live_server) # Setup on conftest per function
# Add a site in paused mode, add an invalid filter, we should still have visual selector data ready
def test_visual_selector_content_ready(client, live_server, measure_memory_usage):
def test_visual_selector_content_ready(client, live_server, measure_memory_usage, datastore_path):
import os
import json
@@ -54,11 +54,11 @@ def test_visual_selector_content_ready(client, live_server, measure_memory_usage
assert b"user-agent: mycustomagent" in res.data
assert os.path.isfile(os.path.join('test-datastore', uuid, 'last-screenshot.png')), "last-screenshot.png should exist"
assert os.path.isfile(os.path.join('test-datastore', uuid, 'elements.deflate')), "xpath elements.deflate data should exist"
assert os.path.isfile(os.path.join(datastore_path, uuid, 'last-screenshot.png')), "last-screenshot.png should exist"
assert os.path.isfile(os.path.join(datastore_path, uuid, 'elements.deflate')), "xpath elements.deflate data should exist"
# Open it and see if it roughly looks correct
with open(os.path.join('test-datastore', uuid, 'elements.deflate'), 'rb') as f:
with open(os.path.join(datastore_path, uuid, 'elements.deflate'), 'rb') as f:
import zlib
compressed_data = f.read()
decompressed_data = zlib.decompress(compressed_data)
@@ -86,7 +86,7 @@ def test_visual_selector_content_ready(client, live_server, measure_memory_usage
follow_redirects=True
)
def test_basic_browserstep(client, live_server, measure_memory_usage):
def test_basic_browserstep(client, live_server, measure_memory_usage, datastore_path):
assert os.getenv('PLAYWRIGHT_DRIVER_URL'), "Needs PLAYWRIGHT_DRIVER_URL set for this test"
@@ -142,7 +142,7 @@ def test_basic_browserstep(client, live_server, measure_memory_usage):
assert b"testheader: yes" in res.data
assert b"user-agent: mycustomagent" in res.data
def test_non_200_errors_report_browsersteps(client, live_server, measure_memory_usage):
def test_non_200_errors_report_browsersteps(client, live_server, measure_memory_usage, datastore_path):
four_o_four_url = url_for('test_endpoint', status_code=404, _external=True)

View File

@@ -144,3 +144,5 @@ pre_commit >= 4.2.0
# For events between checking and socketio updates
blinker
pytest-xdist