Skip to content

Commit

Permalink
Merge pull request #2 from jasongi/issue/1-pytest
Browse files Browse the repository at this point in the history
refactor tests to just use pytest
  • Loading branch information
jasongi authored Mar 23, 2024
2 parents fb609bf + 3c19b33 commit e9f4522
Show file tree
Hide file tree
Showing 14 changed files with 383 additions and 312 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-suite-unreleased-django.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
pip install --upgrade -r test-requirements.txt
pip install .
- name: Run tests
run: make docker-up && coverage run -m pytest
run: make docker-up && coverage run -m pytest --speedtest
8 changes: 2 additions & 6 deletions .github/workflows/test-suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ jobs:
if: github.event_name == 'push' && github.repository == 'jasongi/collectfasta'
run: coverage run -m pytest
- name: Run tests against docker env
run: make docker-up && coverage run -m pytest
- name: Run speed tests against docker env
run: make test-speed
run: make docker-up && coverage run -m pytest -svv --speedtest


test-3-9:
Expand Down Expand Up @@ -81,6 +79,4 @@ jobs:
if: github.event_name == 'push' && github.repository == 'jasongi/collectfasta'
run: coverage run -m pytest
- name: Run tests against docker env
run: make docker-up && coverage run -m pytest
- name: Run speed tests against docker env
run: make test-speed
run: make docker-up && coverage run -m pytest --speedtest
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ repos:
args: []
additional_dependencies:
- pytest
- pytest-mock
- pytest-django
- typing-extensions
- django-stubs>=1.4.0
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ test:
test-docker: docker-up
pytest -svv; docker compose down

test-docker-all: docker-up
pytest -x --speedtest -svv; docker compose down

test-docker-ff: docker-up
pytest -svv -x; docker compose down

Expand Down
234 changes: 91 additions & 143 deletions collectfasta/tests/command/test_command.py
Original file line number Diff line number Diff line change
@@ -1,252 +1,200 @@
import timeit
from typing import Callable
from typing import Iterator
from unittest import TestCase
from unittest import mock

import pytest
from django.core.exceptions import ImproperlyConfigured
from django.test import override_settings as override_django_settings
from django.test.utils import override_settings
from pytest_mock import MockerFixture

from collectfasta.management.commands.collectstatic import Command
from collectfasta.tests.utils import assert_static_file_number
from collectfasta.tests.conftest import StrategyFixture
from collectfasta.tests.conftest import aws_backends_only
from collectfasta.tests.conftest import cloud_backends_only
from collectfasta.tests.conftest import exclude_two_pass
from collectfasta.tests.conftest import live_test
from collectfasta.tests.conftest import speed_test
from collectfasta.tests.conftest import two_pass_only
from collectfasta.tests.utils import clean_static_dir
from collectfasta.tests.utils import create_static_file
from collectfasta.tests.utils import create_two_referenced_static_files
from collectfasta.tests.utils import live_test
from collectfasta.tests.utils import make_100_files
from collectfasta.tests.utils import make_test
from collectfasta.tests.utils import many
from collectfasta.tests.utils import override_setting
from collectfasta.tests.utils import override_storage_attr
from collectfasta.tests.utils import speed_test

from .utils import call_collectstatic


def generate_storage_variations(
storages: dict, strategies: dict
) -> Iterator[tuple[str, override_settings]]:
for storage_name, storage_settings in storages.items():
for strategy_name, strategy_settings in strategies.items():
yield (
f"{storage_name}_{strategy_name}",
override_django_settings(
STORAGES={"staticfiles": {"BACKEND": storage_settings}},
COLLECTFASTA_STRATEGY=strategy_settings,
),
)


aws_backend_confs = {
**dict(
generate_storage_variations(
{
"boto3": "storages.backends.s3.S3Storage",
"boto3static": "storages.backends.s3.S3StaticStorage",
},
{
"base": "collectfasta.strategies.boto3.Boto3Strategy",
},
)
),
**dict(
generate_storage_variations(
{
"boto3manifest": "storages.backends.s3.S3ManifestStaticStorage",
},
{
"base": "collectfasta.strategies.boto3.Boto3Strategy",
"memory_2pass": "collectfasta.strategies.boto3.Boto3ManifestMemoryStrategy", # noqa E501
"file_2pass": "collectfasta.strategies.boto3.Boto3ManifestFileSystemStrategy", # noqa E501
},
)
),
}


gcloud_backend_confs = {
"gcloud": override_django_settings(
STORAGES={
"staticfiles": {
"BACKEND": "collectfasta.tests.utils.GoogleCloudStorageTest",
},
},
COLLECTFASTA_STRATEGY="collectfasta.strategies.gcloud.GoogleCloudStrategy",
),
}
filesystem_backend_confs = {
"filesystem": override_django_settings(
STORAGES={
"staticfiles": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
},
COLLECTFASTA_STRATEGY="collectfasta.strategies.filesystem.FileSystemStrategy",
),
"cachingfilesystem": override_django_settings(
STORAGES={
"staticfiles": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
},
COLLECTFASTA_STRATEGY=(
"collectfasta.strategies.filesystem.CachingFileSystemStrategy"
),
),
}
all_backend_confs = {
**aws_backend_confs,
**gcloud_backend_confs,
**filesystem_backend_confs,
}

make_test_aws_backends: Callable = many(**aws_backend_confs)
make_test_all_backends: Callable = many(**all_backend_confs)
make_test_cloud_backends: Callable = many(**aws_backend_confs, **gcloud_backend_confs)


@make_test_all_backends
@live_test
def test_basics(case: TestCase) -> None:
def test_basics(strategy: StrategyFixture) -> None:
clean_static_dir()
create_two_referenced_static_files()
assert_static_file_number(2, call_collectstatic(), case)
assert (
f"{strategy.expected_copied_files(2)} static files copied."
in call_collectstatic()
)
# file state should now be cached
case.assertIn("0 static files copied.", call_collectstatic())
assert "0 static files copied." in call_collectstatic()


@make_test_all_backends
@live_test
def test_only_copies_new(case: TestCase) -> None:
def test_only_copies_new(strategy: StrategyFixture) -> None:
clean_static_dir()
create_two_referenced_static_files()
assert_static_file_number(2, call_collectstatic(), case)
assert (
f"{strategy.expected_copied_files(2)} static files copied."
in call_collectstatic()
)
create_two_referenced_static_files()
assert_static_file_number(2, call_collectstatic(), case)
# Since the files were already created and are expected to be cached/not copied again,
# we expect 0 new files to be copied.
assert (
f"{strategy.expected_copied_files(2)} static files copied."
in call_collectstatic()
)


@make_test_all_backends
@live_test
@override_setting("threads", 5)
def test_threads(case: TestCase) -> None:
def test_threads(strategy: StrategyFixture) -> None:
clean_static_dir()
create_two_referenced_static_files()
assert_static_file_number(2, call_collectstatic(), case)
assert (
f"{strategy.expected_copied_files(2)} static files copied."
in call_collectstatic()
)
# file state should now be cached
case.assertIn("0 static files copied.", call_collectstatic())
assert "0 static files copied." in call_collectstatic()


@make_test_cloud_backends
@live_test
@cloud_backends_only
@speed_test
def test_basics_cloud_speed(case: TestCase) -> None:
def test_basics_cloud_speed(strategy: StrategyFixture) -> None:
clean_static_dir()
make_100_files()
assert_static_file_number(100, call_collectstatic(), case)
assert (
f"{strategy.expected_copied_files(100)} static files copied."
in call_collectstatic()
)

def collectstatic_one():
assert_static_file_number(2, call_collectstatic(), case)
assert (
f"{strategy.expected_copied_files(2)} static files copied."
in call_collectstatic()
)

create_two_referenced_static_files()
ittook = timeit.timeit(collectstatic_one, number=1)
print(f"it took {ittook} seconds")


@make_test_cloud_backends
@live_test
@cloud_backends_only
@speed_test
@override_settings(
INSTALLED_APPS=["django.contrib.staticfiles"], COLLECTFASTA_STRATEGY=None
)
def test_no_collectfasta_cloud_speed(case: TestCase) -> None:
def test_no_collectfasta_cloud_speed(strategy: StrategyFixture) -> None:
clean_static_dir()
make_100_files()

case.assertIn("100 static files copied", call_collectstatic())
assert "100 static files copied" in call_collectstatic()

def collectstatic_one():
case.assertIn("2 static files copied", call_collectstatic())
assert "2 static files copied" in call_collectstatic()

create_two_referenced_static_files()
ittook = timeit.timeit(collectstatic_one, number=1)
print(f"it took {ittook} seconds")


@make_test
def test_dry_run(case: TestCase) -> None:
@exclude_two_pass
def test_dry_run(strategy: StrategyFixture) -> None:
clean_static_dir()
create_static_file()
result = call_collectstatic(dry_run=True)
case.assertIn("1 static file copied.", result)
case.assertTrue("Pretending to copy", result)
assert "1 static file copied." in result
assert "Pretending to copy" in result
result = call_collectstatic(dry_run=True)
case.assertIn("1 static file copied.", result)
case.assertTrue("Pretending to copy", result)
case.assertTrue("Pretending to delete", result)
assert "1 static file copied." in result
assert "Pretending to copy" in result
assert "Pretending to delete" in result


@make_test_aws_backends
@two_pass_only
def test_dry_run_two_pass(strategy: StrategyFixture) -> None:
clean_static_dir()
create_static_file()
result = call_collectstatic(dry_run=True)
assert "0 static files copied." in result
assert "Pretending to copy" in result
result = call_collectstatic(dry_run=True)
assert "0 static files copied." in result
assert "Pretending to copy" in result
assert "Pretending to delete" in result


@aws_backends_only
@live_test
@override_storage_attr("gzip", True)
@override_setting("aws_is_gzipped", True)
def test_aws_is_gzipped(case: TestCase) -> None:
def test_aws_is_gzipped(strategy: StrategyFixture) -> None:
clean_static_dir()
create_two_referenced_static_files()
assert_static_file_number(2, call_collectstatic(), case)
assert (
f"{strategy.expected_copied_files(2)} static files copied."
in call_collectstatic()
)

# file state should now be cached
case.assertIn("0 static files copied.", call_collectstatic())
assert "0 static files copied." in call_collectstatic()


@make_test
@override_django_settings(STORAGES={}, COLLECTFASTA_STRATEGY=None)
def test_raises_for_no_configured_strategy(case: TestCase) -> None:
with case.assertRaises(ImproperlyConfigured):
def test_raises_for_no_configured_strategy() -> None:
with pytest.raises(ImproperlyConfigured):
Command._load_strategy()


@make_test_all_backends
@live_test
@mock.patch("collectfasta.strategies.base.Strategy.post_copy_hook", autospec=True)
def test_calls_post_copy_hook(_case: TestCase, post_copy_hook: mock.MagicMock) -> None:
def test_calls_post_copy_hook(strategy: StrategyFixture, mocker: MockerFixture) -> None:
post_copy_hook = mocker.patch(
"collectfasta.strategies.base.Strategy.post_copy_hook", autospec=True
)
clean_static_dir()
(path_one, path_two) = create_two_referenced_static_files()
cmd = Command()
cmd.run_from_argv(["manage.py", "collectstatic", "--noinput"])
post_copy_hook.assert_has_calls(
[
mock.call(mock.ANY, path_one.name, path_one.name, mock.ANY),
mock.call(
mock.ANY,
mocker.call(mocker.ANY, path_one.name, path_one.name, mocker.ANY),
mocker.call(
mocker.ANY,
f"{path_one.name.replace('.html','')}_folder/{path_two.name}",
f"{path_one.name.replace('.html','')}_folder/{path_two.name}",
mock.ANY,
mocker.ANY,
),
],
any_order=True,
)


@make_test_all_backends
@live_test
@mock.patch("collectfasta.strategies.base.Strategy.on_skip_hook", autospec=True)
def test_calls_on_skip_hook(case: TestCase, on_skip_hook: mock.MagicMock) -> None:
def test_calls_on_skip_hook(strategy: StrategyFixture, mocker: MockerFixture) -> None:
on_skip_hook = mocker.patch(
"collectfasta.strategies.base.Strategy.on_skip_hook", autospec=True
)
clean_static_dir()
(path_one, path_two) = create_two_referenced_static_files()
cmd = Command()
cmd.run_from_argv(["manage.py", "collectstatic", "--noinput"])
on_skip_hook.assert_not_called()
cmd.run_from_argv(["manage.py", "collectstatic", "--noinput"])

on_skip_hook.assert_has_calls(
[
mock.call(mock.ANY, path_one.name, path_one.name, mock.ANY),
mock.call(
mock.ANY,
mocker.call(mocker.ANY, path_one.name, path_one.name, mocker.ANY),
mocker.call(
mocker.ANY,
f"{path_one.name.replace('.html','')}_folder/{path_two.name}",
f"{path_one.name.replace('.html','')}_folder/{path_two.name}",
mock.ANY,
mocker.ANY,
),
],
any_order=True,
Expand Down
Loading

0 comments on commit e9f4522

Please sign in to comment.