diff --git a/dspace/settings_test.py b/dspace/settings_test.py new file mode 100644 index 0000000..987940d --- /dev/null +++ b/dspace/settings_test.py @@ -0,0 +1,13 @@ +"""Настройки для тестов: боевой режим (DEBUG=False), но без SSL-редиректа и внешних сервисов.""" +import os + +os.environ.setdefault('DJANGO_SECRET_KEY', 'test-secret-key-not-for-production') +os.environ.setdefault('DJANGO_DEBUG', 'False') +os.environ.setdefault('DJANGO_SECURE_SSL_REDIRECT', 'False') +os.environ.setdefault('DJANGO_ALLOWED_HOSTS', 'testserver,localhost') + +from .settings import * # noqa: E402,F403 + +STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' +PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher'] +EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' diff --git a/main/tests.py b/main/tests.py deleted file mode 100644 index 4929020..0000000 --- a/main/tests.py +++ /dev/null @@ -1,2 +0,0 @@ - -# Create your tests here. diff --git a/main/tests/__init__.py b/main/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main/tests/conftest.py b/main/tests/conftest.py new file mode 100644 index 0000000..2fd3570 --- /dev/null +++ b/main/tests/conftest.py @@ -0,0 +1,22 @@ +import pytest + +from main.models import Article, SiteSettings + + +@pytest.fixture(autouse=True) +def no_network(monkeypatch): + """Никаких реальных запросов наружу: ping поисковиков и т. п.""" + calls = [] + monkeypatch.setattr('main.signals.requests.get', lambda *a, **kw: calls.append((a, kw))) + monkeypatch.setattr('main.signals.requests.post', lambda *a, **kw: calls.append((a, kw))) + return calls + + +@pytest.fixture +def article(db): + return Article.objects.create(title='Первая статья', post='Текст статьи', excerpt='Кратко') + + +@pytest.fixture +def site_settings(db): + return SiteSettings.load() diff --git a/main/tests/test_pages.py b/main/tests/test_pages.py new file mode 100644 index 0000000..659085d --- /dev/null +++ b/main/tests/test_pages.py @@ -0,0 +1,46 @@ +import pytest +from django.urls import reverse + +from main.models import ArticleView + +UA = 'Mozilla/5.0 (X11; Linux x86_64) Firefox/131.0' + + +@pytest.mark.django_db +@pytest.mark.parametrize('name', ['index', 'about', 'projects', 'achievements', 'contacts', 'blog']) +def test_page_opens(client, name): + assert client.get(reverse(name), HTTP_USER_AGENT=UA).status_code == 200 + + +@pytest.mark.django_db +def test_sitemap_and_robots(client, article): + assert client.get('/sitemap.xml').status_code == 200 + + +@pytest.mark.django_db +def test_article_counts_unique_views(client, article): + url = article.get_absolute_url() + client.get(url, HTTP_USER_AGENT=UA) + client.get(url, HTTP_USER_AGENT=UA) + article.refresh_from_db() + assert article.views == 2 + assert ArticleView.objects.filter(article=article).count() == 1 + + +@pytest.mark.django_db +def test_bots_do_not_create_unique_views(client, article): + client.get(article.get_absolute_url(), HTTP_USER_AGENT='Googlebot/2.1') + assert not ArticleView.objects.exists() + + +@pytest.mark.django_db +def test_visitor_cookie_is_signed_and_httponly(client): + response = client.get(reverse('index'), HTTP_USER_AGENT=UA) + cookie = response.cookies['dspace_vid'] + assert cookie['httponly'] + assert ':' in cookie.value + + +@pytest.mark.django_db +def test_unknown_page_returns_404(client): + assert client.get('/no-such-page/', HTTP_USER_AGENT=UA).status_code == 404 diff --git a/main/tests/test_security.py b/main/tests/test_security.py new file mode 100644 index 0000000..9fef6a3 --- /dev/null +++ b/main/tests/test_security.py @@ -0,0 +1,73 @@ +from unittest import mock + +import pytest + +from main.forms import CommentForm, ContactForm +from main.middleware import client_ip_hash, is_bot +from main.models import is_public_http_url +from main.signals import build_telegram_text +from main.templatetags.custom_filters import render_tech_badge + + +def test_comment_form_strips_scripts_and_keeps_allowed_tags(): + form = CommentForm(data={'content': 'жирный https://example.com'}) + assert form.is_valid() + content = form.cleaned_data['content'] + assert '') + assert '