Skip to content

Commit 5d379bf

Browse files
Upping the test coverage (#299)
* Upping the test coverage * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * README updates + add click to test requirements * add redis pytest mark on test_missing_redis_client * ruff fixes and pre-commit updates * remove pull_request_target --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent d419d30 commit 5d379bf

15 files changed

Lines changed: 1138 additions & 37 deletions

.github/workflows/ci-test.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ name: Test
33
on:
44
pull_request:
55
branches: [master]
6-
pull_request_target:
7-
branches: [master]
86
push:
97
branches: [master]
108
schedule:

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ repos:
2323
- id: detect-private-key
2424

2525
- repo: https://github.com/crate-ci/typos
26-
rev: v1
26+
rev: v1.34.0
2727
hooks:
2828
- id: typos
2929
# empty to do not write fixes
@@ -55,7 +55,7 @@ repos:
5555
args: ["--print-width=79"]
5656

5757
- repo: https://github.com/astral-sh/ruff-pre-commit
58-
rev: v0.12.2
58+
rev: v0.12.4
5959
hooks:
6060
# use black formatting
6161
- id: ruff-format
@@ -67,10 +67,10 @@ repos:
6767

6868
# it needs to be after formatting hooks because the lines might be changed
6969
- repo: https://github.com/pre-commit/mirrors-mypy
70-
rev: v1.16.1
70+
rev: v1.17.0
7171
hooks:
7272
- id: mypy
73-
files: "src/*"
73+
files: "src/.*"
7474

7575
- repo: https://github.com/tox-dev/pyproject-fmt
7676
rev: v2.6.0

README.rst

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,13 +519,20 @@ Clone:
519519
git clone git@github.com:python-cachier/cachier.git
520520
521521
522-
Install in development mode with test dependencies:
522+
Install in development mode with test dependencies for local cores (memory and pickle) only:
523523

524524
.. code-block:: bash
525525
526526
cd cachier
527527
pip install -e . -r tests/requirements.txt
528528
529+
Each additional core (MongoDB, Redis, SQL) requires additional dependencies. To install all dependencies for all cores, run:
530+
531+
.. code-block:: bash
532+
533+
pip install -r tests/mongodb_requirements.txt
534+
pip install -r tests/redis_requirements.txt
535+
pip install -r tests/sql_requirements.txt
529536
530537
Running the tests
531538
-----------------
@@ -630,7 +637,23 @@ To test all cachier backends (MongoDB, Redis, SQL, Memory, Pickle) locally with
630637
# Keep containers running for debugging
631638
./scripts/test-local.sh all -k
632639
633-
The unified test script automatically manages Docker containers, installs required dependencies, and runs the appropriate test suites. See ``scripts/README-local-testing.md`` for detailed documentation.
640+
# Test specific test files with selected backends
641+
./scripts/test-local.sh mongo -f tests/test_mongo_core.py
642+
643+
# Test multiple files across all backends
644+
./scripts/test-local.sh all -f tests/test_main.py -f tests/test_redis_core_coverage.py
645+
646+
The unified test script automatically manages Docker containers, installs required dependencies, and runs the appropriate test suites. The ``-f`` / ``--files`` option allows you to run specific test files instead of the entire test suite. See ``scripts/README-local-testing.md`` for detailed documentation.
647+
648+
649+
Running pre-commit hooks locally
650+
--------------------------------
651+
652+
After you've installed test dependencies, you can run pre-commit hooks locally by using the following command:
653+
654+
.. code-block:: bash
655+
656+
pre-commit run --all-files
634657
635658
636659
Adding documentation

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ license = { file = "LICENSE" }
2424
authors = [
2525
{ name = "Shay Palachy Affek", email = 'shay.palachy@gmail.com' },
2626
]
27+
requires-python = ">=3.9"
2728
classifiers = [
2829
"Development Status :: 4 - Beta",
2930
"Intended Audience :: Developers",
@@ -188,8 +189,8 @@ branch = true
188189
# dynamic_context = "test_function"
189190
omit = [
190191
"tests/*",
191-
"cachier/_version.py",
192-
"cachier/__init__.py",
192+
"src/cachier/_version.py",
193+
"src/cachier/__init__.py",
193194
"**/scripts/**",
194195
]
195196
[tool.coverage.report]

scripts/README-local-testing.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ This guide explains how to run cachier tests locally with Docker containers for
4040
- `-v, --verbose` - Show verbose pytest output
4141
- `-k, --keep-running` - Keep Docker containers running after tests
4242
- `-h, --html-coverage` - Generate HTML coverage report
43+
- `-f, --files` - Specify test files to run (can be used multiple times)
4344
- `--help` - Show help message
4445

4546
## Examples
@@ -86,6 +87,15 @@ make test-sql-local
8687

8788
# Using environment variable
8889
CACHIER_TEST_CORES="mongo redis" ./scripts/test-local.sh
90+
91+
# Test specific files with MongoDB backend
92+
./scripts/test-local.sh mongo -f tests/test_mongo_core.py
93+
94+
# Test multiple files across all backends
95+
./scripts/test-local.sh all -f tests/test_main.py -f tests/test_redis_core_coverage.py
96+
97+
# Combine file selection with other options
98+
./scripts/test-local.sh redis sql -f tests/test_sql_core.py -v -k
8999
```
90100

91101
### Docker Compose

scripts/test-local.sh

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ COVERAGE_REPORT="term"
2525
KEEP_RUNNING=false
2626
SELECTED_CORES=""
2727
INCLUDE_LOCAL_CORES=false
28+
TEST_FILES=""
2829

2930
# Function to print colored messages
3031
print_message() {
@@ -54,6 +55,7 @@ OPTIONS:
5455
-v, --verbose Show verbose output
5556
-k, --keep-running Keep containers running after tests
5657
-h, --html-coverage Generate HTML coverage report
58+
-f, --files Specify test files to run (can be used multiple times)
5759
--help Show this help message
5860
5961
EXAMPLES:
@@ -62,6 +64,7 @@ EXAMPLES:
6264
$0 all # Run all backend tests
6365
$0 external -k # Run external backends, keep containers
6466
$0 mongo memory -v # Run MongoDB and memory tests verbosely
67+
$0 all -f tests/test_main.py -f tests/test_redis_core_coverage.py # Run specific test files
6568
6669
ENVIRONMENT:
6770
You can also set cores via CACHIER_TEST_CORES environment variable:
@@ -85,6 +88,16 @@ while [[ $# -gt 0 ]]; do
8588
COVERAGE_REPORT="html"
8689
shift
8790
;;
91+
-f|--files)
92+
shift
93+
if [[ $# -eq 0 ]] || [[ "$1" == -* ]]; then
94+
print_message $RED "Error: -f/--files requires a file argument"
95+
usage
96+
exit 1
97+
fi
98+
TEST_FILES="$TEST_FILES $1"
99+
shift
100+
;;
88101
--help)
89102
usage
90103
exit 0
@@ -193,14 +206,14 @@ check_docker() {
193206
echo ""
194207
echo "After starting Docker, wait a few seconds and try running this script again."
195208
echo ""
196-
209+
197210
# Show the actual docker error for debugging
198211
echo "Technical details:"
199212
docker ps 2>&1 | sed 's/^/ /'
200213
echo ""
201214
exit 1
202215
fi
203-
216+
204217
print_message $GREEN "✓ Docker is installed and running"
205218
}
206219

@@ -473,27 +486,48 @@ main() {
473486
done
474487

475488
# Run pytest
476-
# Check if we selected all cores - if so, run all tests without marker filtering
477-
all_cores="memory mongo pickle redis sql"
478-
selected_sorted=$(echo "$SELECTED_CORES" | tr ' ' '\n' | sort | tr '\n' ' ' | xargs)
479-
all_sorted=$(echo "$all_cores" | tr ' ' '\n' | sort | tr '\n' ' ' | xargs)
480-
481-
if [ "$selected_sorted" = "$all_sorted" ]; then
482-
print_message $BLUE "Running: pytest (all tests, including unmarked)"
483-
if [ "$VERBOSE" = true ]; then
484-
pytest -v --cov=cachier --cov-report=$COVERAGE_REPORT
485-
else
486-
pytest --cov=cachier --cov-report=$COVERAGE_REPORT
489+
# Build pytest command
490+
PYTEST_CMD="pytest"
491+
492+
# Add test files if specified
493+
if [ -n "$TEST_FILES" ]; then
494+
PYTEST_CMD="$PYTEST_CMD $TEST_FILES"
495+
print_message $BLUE "Test files specified: $TEST_FILES"
496+
fi
497+
498+
# Add markers if needed (only if no specific test files were given)
499+
if [ -z "$TEST_FILES" ]; then
500+
# Check if we selected all cores - if so, run all tests without marker filtering
501+
all_cores="memory mongo pickle redis sql"
502+
selected_sorted=$(echo "$SELECTED_CORES" | tr ' ' '\n' | sort | tr '\n' ' ' | xargs)
503+
all_sorted=$(echo "$all_cores" | tr ' ' '\n' | sort | tr '\n' ' ' | xargs)
504+
505+
if [ "$selected_sorted" != "$all_sorted" ]; then
506+
PYTEST_CMD="$PYTEST_CMD -m \"$pytest_markers\""
487507
fi
488508
else
489-
print_message $BLUE "Running: pytest -m \"$pytest_markers\""
490-
if [ "$VERBOSE" = true ]; then
491-
pytest -v -m "$pytest_markers" --cov=cachier --cov-report=$COVERAGE_REPORT
492-
else
493-
pytest -m "$pytest_markers" --cov=cachier --cov-report=$COVERAGE_REPORT
509+
# When test files are specified, still apply markers if not running all cores
510+
all_cores="memory mongo pickle redis sql"
511+
selected_sorted=$(echo "$SELECTED_CORES" | tr ' ' '\n' | sort | tr '\n' ' ' | xargs)
512+
all_sorted=$(echo "$all_cores" | tr ' ' '\n' | sort | tr '\n' ' ' | xargs)
513+
514+
if [ "$selected_sorted" != "$all_sorted" ]; then
515+
PYTEST_CMD="$PYTEST_CMD -m \"$pytest_markers\""
494516
fi
495517
fi
496518

519+
# Add verbose flag if needed
520+
if [ "$VERBOSE" = true ]; then
521+
PYTEST_CMD="$PYTEST_CMD -v"
522+
fi
523+
524+
# Add coverage options
525+
PYTEST_CMD="$PYTEST_CMD --cov=cachier --cov-report=$COVERAGE_REPORT"
526+
527+
# Print and run the command
528+
print_message $BLUE "Running: $PYTEST_CMD"
529+
eval $PYTEST_CMD
530+
497531
TEST_EXIT_CODE=$?
498532

499533
if [ $TEST_EXIT_CODE -eq 0 ]; then

tests/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ pygments
1010
# the memory core tests dataframe caching
1111
pandas
1212
pympler
13+
# for cli tests
14+
click
15+
# to run pre-commit hooks localy
16+
pre-commit

tests/test_base_core.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Additional tests for base core to improve coverage."""
2+
3+
from unittest.mock import patch
4+
5+
from cachier.cores.base import _BaseCore
6+
7+
8+
class ConcreteCachingCore(_BaseCore):
9+
"""Concrete implementation of _BaseCore for testing."""
10+
11+
def get_entry_by_key(self, key, reload=False):
12+
"""Retrieve an entry by its key."""
13+
return key, None
14+
15+
def set_entry(self, key, func_res):
16+
"""Store an entry in the cache."""
17+
return True
18+
19+
def mark_entry_being_calculated(self, key):
20+
"""Mark an entry as being calculated."""
21+
pass
22+
23+
def mark_entry_not_calculated(self, key):
24+
"""Mark an entry as not being calculated."""
25+
pass
26+
27+
def wait_on_entry_calc(self, key):
28+
"""Wait for an entry calculation to complete."""
29+
return None
30+
31+
def clear_cache(self):
32+
"""Clear the cache."""
33+
pass
34+
35+
def clear_being_calculated(self):
36+
"""Clear entries that are being calculated."""
37+
pass
38+
39+
def delete_stale_entries(self, stale_after):
40+
"""Delete stale entries from the cache."""
41+
pass
42+
43+
44+
def test_estimate_size_fallback():
45+
"""Test _estimate_size falls back to sys.getsizeof when asizeof fails."""
46+
# Test lines 101-102: exception handling in _estimate_size
47+
core = ConcreteCachingCore(
48+
hash_func=None, wait_for_calc_timeout=10, entry_size_limit=1000
49+
)
50+
51+
# Mock asizeof to raise exception
52+
with patch(
53+
"cachier.cores.base.asizeof.asizeof",
54+
side_effect=Exception("asizeof failed"),
55+
):
56+
# Should fall back to sys.getsizeof
57+
size = core._estimate_size("test_value")
58+
assert size > 0 # sys.getsizeof should return a positive value
59+
60+
61+
def test_should_store_exception():
62+
"""Test _should_store returns True when size estimation fails."""
63+
# Test lines 109-110: exception handling in _should_store
64+
core = ConcreteCachingCore(
65+
hash_func=None, wait_for_calc_timeout=10, entry_size_limit=1000
66+
)
67+
68+
# Mock both size estimation methods to fail
69+
patch1 = patch(
70+
"cachier.cores.base.asizeof.asizeof",
71+
side_effect=Exception("asizeof failed"),
72+
)
73+
patch2 = patch("sys.getsizeof", side_effect=Exception("getsizeof failed"))
74+
with patch1, patch2:
75+
# Should return True (allow storage) when size can't be determined
76+
assert core._should_store("test_value") is True

tests/test_config.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Additional tests for config module to improve coverage."""
2+
3+
import pytest
4+
5+
from cachier.config import get_default_params, set_default_params
6+
7+
8+
def test_set_default_params_deprecated():
9+
"""Test that set_default_params shows deprecation warning."""
10+
# Test lines 103-111: deprecation warning
11+
with pytest.warns(
12+
DeprecationWarning,
13+
match="set_default_params.*deprecated.*set_global_params",
14+
):
15+
set_default_params(stale_after=60)
16+
17+
18+
def test_get_default_params_deprecated():
19+
"""Test that get_default_params shows deprecation warning."""
20+
# Test lines 143-151: deprecation warning
21+
with pytest.warns(
22+
DeprecationWarning,
23+
match="get_default_params.*deprecated.*get_global_params",
24+
):
25+
assert get_default_params() is not None

0 commit comments

Comments
 (0)