mirror of https://github.com/zulip/zulip.git
coverage: Clean up coverage configuration.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
19dee5450d
commit
b5e5728112
|
@ -152,7 +152,7 @@ def communities_view(request: HttpRequest) -> HttpResponse:
|
||||||
org_types.pop("unspecified", None)
|
org_types.pop("unspecified", None)
|
||||||
|
|
||||||
# Change display name of non-profit orgs.
|
# Change display name of non-profit orgs.
|
||||||
if org_types.get("nonprofit"):
|
if org_types.get("nonprofit"): # nocoverage
|
||||||
org_types["nonprofit"]["name"] = "Non-profit"
|
org_types["nonprofit"]["name"] = "Non-profit"
|
||||||
|
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
|
|
|
@ -6,7 +6,7 @@ exclude_lines =
|
||||||
# Don't complain if non-runnable code isn't run:
|
# Don't complain if non-runnable code isn't run:
|
||||||
if False:
|
if False:
|
||||||
# Don't require coverage for base class NotImplementedErrors
|
# Don't require coverage for base class NotImplementedErrors
|
||||||
raise NotImplementedError()
|
raise NotImplementedError
|
||||||
# Don't require coverage for test suite AssertionError -- they're usually for clarity
|
# Don't require coverage for test suite AssertionError -- they're usually for clarity
|
||||||
raise AssertionError
|
raise AssertionError
|
||||||
# Don't require coverage for __str__ statements just used for printing
|
# Don't require coverage for __str__ statements just used for printing
|
||||||
|
@ -31,27 +31,11 @@ data_file=var/.coverage
|
||||||
# overhead but is very useful for finding existing tests for a code path.
|
# overhead but is very useful for finding existing tests for a code path.
|
||||||
dynamic_context=test_function
|
dynamic_context=test_function
|
||||||
|
|
||||||
omit =
|
source =
|
||||||
*/zulip-venv-cache/*
|
analytics/
|
||||||
*/migrations/*
|
confirmation/
|
||||||
*/management/commands/*
|
corporate/
|
||||||
# Parts of the test runner infrastructure
|
pgroonga/
|
||||||
tools/test-backend
|
zerver/
|
||||||
zerver/lib/test_fixtures.py
|
zilencer/
|
||||||
zerver/lib/test_runner.py
|
zproject/
|
||||||
# Has its own independent test suite
|
|
||||||
zerver/openapi/python_examples.py
|
|
||||||
# Debugging tools that don't lend themselves well to unit tests
|
|
||||||
zerver/lib/debug.py
|
|
||||||
# Part of provisioning/populate_db
|
|
||||||
zerver/lib/generate_test_data.py
|
|
||||||
# Excluded because its coverage state is flaky.
|
|
||||||
zerver/tornado/ioloop_logging.py
|
|
||||||
# Zulip's library for use in scripts
|
|
||||||
scripts/lib/zulip_tools.py
|
|
||||||
# Used only for the legacy Zephyr integration, and unlikely to ever be unit-tested
|
|
||||||
zerver/lib/ccache.py
|
|
||||||
# Settings.py files are hard to test
|
|
||||||
zproject/*settings.py
|
|
||||||
# https://github.com/davidhalter/jedi/issues/1122
|
|
||||||
blub
|
|
||||||
|
|
|
@ -31,39 +31,19 @@ import responses
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test.utils import get_runner
|
from django.test.utils import get_runner
|
||||||
|
|
||||||
target_fully_covered = [
|
source_files = [
|
||||||
"analytics/lib/*.py",
|
"analytics/**/*.py",
|
||||||
"analytics/models.py",
|
"confirmation/**/*.py",
|
||||||
"analytics/tests/*.py",
|
"corporate/**/*.py",
|
||||||
"analytics/views/*.py",
|
"pgroonga/**/*.py",
|
||||||
# zerver/ and zerver/lib/ are important core files
|
"zerver/**/*.py",
|
||||||
"zerver/*.py",
|
"zilencer/**/*.py",
|
||||||
"zerver/actions/*.py",
|
"zproject/**/*.py",
|
||||||
"zerver/lib/*.py",
|
|
||||||
"zerver/lib/*/*.py",
|
|
||||||
"zerver/lib/*/*/*.py",
|
|
||||||
"zerver/data_import/*.py",
|
|
||||||
"zerver/templatetags/*.py",
|
|
||||||
"zerver/tornado/*.py",
|
|
||||||
# Billing files require 100% test coverage
|
|
||||||
"corporate/lib/stripe.py",
|
|
||||||
"corporate/views.py",
|
|
||||||
# Test files should have 100% coverage; test code that isn't run
|
|
||||||
# is likely a bug in the test.
|
|
||||||
"zerver/tests/*.py",
|
|
||||||
"corporate/tests/*.py",
|
|
||||||
# As a project, we require 100% test coverage in the views files.
|
|
||||||
"zerver/views/*.py",
|
|
||||||
"zproject/backends.py",
|
|
||||||
"confirmation/*.py",
|
|
||||||
"zerver/webhooks/*/*.py",
|
|
||||||
# Once we have a nice negative tests system, we can add these:
|
|
||||||
# 'zerver/webhooks/*/*.py',
|
|
||||||
# 'zerver/webhooks/*/*/*.py',
|
|
||||||
"zerver/worker/*.py",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
not_yet_fully_covered = [
|
not_yet_fully_covered = [
|
||||||
|
"*/migrations/*.py",
|
||||||
|
"*/management/commands/*.py",
|
||||||
# Analytics fixtures library is used to generate test fixtures;
|
# Analytics fixtures library is used to generate test fixtures;
|
||||||
# isn't properly accounted for in test coverage analysis since it
|
# isn't properly accounted for in test coverage analysis since it
|
||||||
# runs before tests.
|
# runs before tests.
|
||||||
|
@ -100,14 +80,12 @@ not_yet_fully_covered = [
|
||||||
"zerver/lib/fix_unreads.py",
|
"zerver/lib/fix_unreads.py",
|
||||||
"zerver/lib/import_realm.py",
|
"zerver/lib/import_realm.py",
|
||||||
"zerver/lib/logging_util.py",
|
"zerver/lib/logging_util.py",
|
||||||
"zerver/lib/migrate.py",
|
|
||||||
"zerver/lib/profile.py",
|
"zerver/lib/profile.py",
|
||||||
"zerver/lib/queue.py",
|
"zerver/lib/queue.py",
|
||||||
"zerver/lib/sqlalchemy_utils.py",
|
"zerver/lib/sqlalchemy_utils.py",
|
||||||
"zerver/lib/storage.py",
|
"zerver/lib/storage.py",
|
||||||
"zerver/lib/zephyr.py",
|
"zerver/lib/zephyr.py",
|
||||||
"zerver/lib/templates.py",
|
"zerver/lib/templates.py",
|
||||||
"zerver/templatetags/minified_js.py",
|
|
||||||
# Low priority for coverage
|
# Low priority for coverage
|
||||||
"zerver/lib/ccache.py",
|
"zerver/lib/ccache.py",
|
||||||
"zerver/lib/generate_test_data.py",
|
"zerver/lib/generate_test_data.py",
|
||||||
|
@ -115,7 +93,10 @@ not_yet_fully_covered = [
|
||||||
"zerver/lib/test_fixtures.py",
|
"zerver/lib/test_fixtures.py",
|
||||||
"zerver/lib/test_runner.py",
|
"zerver/lib/test_runner.py",
|
||||||
"zerver/lib/test_console_output.py",
|
"zerver/lib/test_console_output.py",
|
||||||
|
"zerver/openapi/curl_param_value_generators.py",
|
||||||
|
"zerver/openapi/javascript_examples.py",
|
||||||
"zerver/openapi/python_examples.py",
|
"zerver/openapi/python_examples.py",
|
||||||
|
"zerver/openapi/test_curl_examples.py",
|
||||||
# Tornado should ideally have full coverage, but we're not there.
|
# Tornado should ideally have full coverage, but we're not there.
|
||||||
"zerver/tornado/descriptors.py",
|
"zerver/tornado/descriptors.py",
|
||||||
"zerver/tornado/django_api.py",
|
"zerver/tornado/django_api.py",
|
||||||
|
@ -142,11 +123,18 @@ not_yet_fully_covered = [
|
||||||
# Cannot have coverage, as tests run in a transaction
|
# Cannot have coverage, as tests run in a transaction
|
||||||
"zerver/lib/safe_session_cached_db.py",
|
"zerver/lib/safe_session_cached_db.py",
|
||||||
"zerver/lib/singleton_bmemcached.py",
|
"zerver/lib/singleton_bmemcached.py",
|
||||||
|
# Branches in Django settings files are hard to test
|
||||||
|
"zproject/computed_settings.py",
|
||||||
|
"zproject/dev_settings.py",
|
||||||
|
"zproject/test_extra_settings.py",
|
||||||
|
# Better tested in a full deployment
|
||||||
|
"zproject/sentry.py",
|
||||||
|
"zproject/wsgi.py",
|
||||||
]
|
]
|
||||||
|
|
||||||
enforce_fully_covered = sorted(
|
enforce_fully_covered = sorted(
|
||||||
{path for target in target_fully_covered for path in glob.glob(target)}
|
{path for target in source_files for path in glob.glob(target, recursive=True)}
|
||||||
- {path for target in not_yet_fully_covered for path in glob.glob(target)}
|
- {path for target in not_yet_fully_covered for path in glob.glob(target, recursive=True)}
|
||||||
)
|
)
|
||||||
|
|
||||||
FAILED_TEST_PATH = "var/last_test_failure.json"
|
FAILED_TEST_PATH = "var/last_test_failure.json"
|
||||||
|
@ -473,7 +461,7 @@ def main() -> None:
|
||||||
for path in not_yet_fully_covered:
|
for path in not_yet_fully_covered:
|
||||||
try:
|
try:
|
||||||
missing_lines = cov.analysis2(path)[3]
|
missing_lines = cov.analysis2(path)[3]
|
||||||
if len(missing_lines) == 0 and path != "zerver/lib/migrate.py":
|
if not missing_lines:
|
||||||
print(
|
print(
|
||||||
f"ERROR: {path} has complete backend test coverage but is still in not_yet_fully_covered."
|
f"ERROR: {path} has complete backend test coverage but is still in not_yet_fully_covered."
|
||||||
)
|
)
|
||||||
|
|
|
@ -386,12 +386,12 @@ def validate_against_openapi_schema(
|
||||||
if (endpoint, method) in EXCLUDE_UNDOCUMENTED_ENDPOINTS:
|
if (endpoint, method) in EXCLUDE_UNDOCUMENTED_ENDPOINTS:
|
||||||
return False
|
return False
|
||||||
# Return true for endpoints with only response documentation remaining
|
# Return true for endpoints with only response documentation remaining
|
||||||
if (endpoint, method) in EXCLUDE_DOCUMENTED_ENDPOINTS:
|
if (endpoint, method) in EXCLUDE_DOCUMENTED_ENDPOINTS: # nocoverage
|
||||||
return True
|
return True
|
||||||
# Check if the response matches its code
|
# Check if the response matches its code
|
||||||
if status_code.startswith("2") and (
|
if status_code.startswith("2") and (
|
||||||
content.get("result", "success").lower() not in ["success", "partially_completed"]
|
content.get("result", "success").lower() not in ["success", "partially_completed"]
|
||||||
):
|
): # nocoverage
|
||||||
raise SchemaError("Response is not 200 but is validating against 200 schema")
|
raise SchemaError("Response is not 200 but is validating against 200 schema")
|
||||||
# Code is not declared but appears in various 400 responses. If
|
# Code is not declared but appears in various 400 responses. If
|
||||||
# common, it can be added to 400 response schema
|
# common, it can be added to 400 response schema
|
||||||
|
|
|
@ -14,7 +14,7 @@ ZULIP_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../
|
||||||
# This is used only by the Puppeteer tests to clear all the cache after each run.
|
# This is used only by the Puppeteer tests to clear all the cache after each run.
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@require_post
|
@require_post
|
||||||
def remove_caches(request: HttpRequest) -> HttpResponse:
|
def remove_caches(request: HttpRequest) -> HttpResponse: # nocoverage
|
||||||
cache = get_cache_backend(None)
|
cache = get_cache_backend(None)
|
||||||
cache.clear()
|
cache.clear()
|
||||||
clear_client_cache()
|
clear_client_cache()
|
||||||
|
|
|
@ -5,7 +5,9 @@ from zerver.lib.camo import is_camo_url_valid
|
||||||
from zerver.lib.thumbnail import generate_thumbnail_url
|
from zerver.lib.thumbnail import generate_thumbnail_url
|
||||||
|
|
||||||
|
|
||||||
def handle_camo_url(request: HttpRequest, digest: str, received_url: str) -> HttpResponse:
|
def handle_camo_url(
|
||||||
|
request: HttpRequest, digest: str, received_url: str
|
||||||
|
) -> HttpResponse: # nocoverage
|
||||||
original_url = bytes.fromhex(received_url).decode()
|
original_url = bytes.fromhex(received_url).decode()
|
||||||
if is_camo_url_valid(digest, original_url):
|
if is_camo_url_valid(digest, original_url):
|
||||||
return redirect(generate_thumbnail_url(original_url))
|
return redirect(generate_thumbnail_url(original_url))
|
||||||
|
|
|
@ -124,7 +124,7 @@ def api_dev_fetch_api_key(request: HttpRequest, username: str = REQ()) -> HttpRe
|
||||||
raise RealmDeactivatedError
|
raise RealmDeactivatedError
|
||||||
if return_data.get("inactive_user"):
|
if return_data.get("inactive_user"):
|
||||||
raise UserDeactivatedError
|
raise UserDeactivatedError
|
||||||
if return_data.get("invalid_subdomain"):
|
if return_data.get("invalid_subdomain"): # nocoverage
|
||||||
raise InvalidSubdomainError
|
raise InvalidSubdomainError
|
||||||
if user_profile is None:
|
if user_profile is None:
|
||||||
# Since we're not actually checking passwords, this condition
|
# Since we're not actually checking passwords, this condition
|
||||||
|
|
|
@ -93,7 +93,7 @@ def get_fixtures(request: HttpRequest, integration_name: str = REQ()) -> HttpRes
|
||||||
valid_integration_name, "".join(fixture.split(".")[:-1])
|
valid_integration_name, "".join(fixture.split(".")[:-1])
|
||||||
)
|
)
|
||||||
|
|
||||||
def fix_name(header: str) -> str:
|
def fix_name(header: str) -> str: # nocoverage
|
||||||
if header.startswith("HTTP_"): # HTTP_ is a prefix intended for Django.
|
if header.startswith("HTTP_"): # HTTP_ is a prefix intended for Django.
|
||||||
return header[len("HTTP_") :]
|
return header[len("HTTP_") :]
|
||||||
return header
|
return header
|
||||||
|
@ -114,7 +114,7 @@ def check_send_webhook_fixture_message(
|
||||||
) -> HttpResponseBase:
|
) -> HttpResponseBase:
|
||||||
try:
|
try:
|
||||||
custom_headers_dict = orjson.loads(custom_headers)
|
custom_headers_dict = orjson.loads(custom_headers)
|
||||||
except orjson.JSONDecodeError as ve:
|
except orjson.JSONDecodeError as ve: # nocoverage
|
||||||
raise JsonableError(f"Custom HTTP headers are not in a valid JSON format. {ve}") # nolint
|
raise JsonableError(f"Custom HTTP headers are not in a valid JSON format. {ve}") # nolint
|
||||||
|
|
||||||
response = send_webhook_fixture_message(url, body, is_json, custom_headers_dict)
|
response = send_webhook_fixture_message(url, body, is_json, custom_headers_dict)
|
||||||
|
@ -130,7 +130,7 @@ def send_all_webhook_fixture_messages(
|
||||||
request: HttpRequest, url: str = REQ(), integration_name: str = REQ()
|
request: HttpRequest, url: str = REQ(), integration_name: str = REQ()
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
valid_integration_name = get_valid_integration_name(integration_name)
|
valid_integration_name = get_valid_integration_name(integration_name)
|
||||||
if not valid_integration_name:
|
if not valid_integration_name: # nocoverage
|
||||||
raise ResourceNotFoundError(f'"{integration_name}" is not a valid webhook integration.')
|
raise ResourceNotFoundError(f'"{integration_name}" is not a valid webhook integration.')
|
||||||
|
|
||||||
fixtures_dir = os.path.join(ZULIP_PATH, f"zerver/webhooks/{valid_integration_name}/fixtures")
|
fixtures_dir = os.path.join(ZULIP_PATH, f"zerver/webhooks/{valid_integration_name}/fixtures")
|
||||||
|
|
|
@ -40,7 +40,7 @@ def generate_demo_realm_name() -> str:
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def register_development_user(request: HttpRequest) -> HttpResponse:
|
def register_development_user(request: HttpRequest) -> HttpResponse:
|
||||||
realm = get_realm_from_request(request)
|
realm = get_realm_from_request(request)
|
||||||
if realm is None:
|
if realm is None: # nocoverage
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
f"{settings.EXTERNAL_URI_SCHEME}{settings.REALM_HOSTS['zulip']}/devtools/register_user/",
|
f"{settings.EXTERNAL_URI_SCHEME}{settings.REALM_HOSTS['zulip']}/devtools/register_user/",
|
||||||
status=307,
|
status=307,
|
||||||
|
|
|
@ -16,7 +16,7 @@ config_file.read("/etc/zulip/zulip.conf")
|
||||||
PRODUCTION = config_file.has_option("machine", "deploy_type")
|
PRODUCTION = config_file.has_option("machine", "deploy_type")
|
||||||
DEVELOPMENT = not PRODUCTION
|
DEVELOPMENT = not PRODUCTION
|
||||||
secrets_file = configparser.RawConfigParser()
|
secrets_file = configparser.RawConfigParser()
|
||||||
if PRODUCTION:
|
if PRODUCTION: # nocoverage
|
||||||
secrets_file.read("/etc/zulip/zulip-secrets.conf")
|
secrets_file.read("/etc/zulip/zulip-secrets.conf")
|
||||||
else:
|
else:
|
||||||
secrets_file.read(os.path.join(DEPLOY_ROOT, "zproject/dev-secrets.conf"))
|
secrets_file.read(os.path.join(DEPLOY_ROOT, "zproject/dev-secrets.conf"))
|
||||||
|
@ -37,7 +37,7 @@ def get_secret(
|
||||||
def get_secret(
|
def get_secret(
|
||||||
key: str, default_value: Optional[str] = None, development_only: bool = False
|
key: str, default_value: Optional[str] = None, development_only: bool = False
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
if development_only and PRODUCTION:
|
if development_only and PRODUCTION: # nocoverage
|
||||||
return default_value
|
return default_value
|
||||||
return secrets_file.get("secrets", key, fallback=default_value)
|
return secrets_file.get("secrets", key, fallback=default_value)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from .default_settings import * # noqa: F403 isort: skip
|
||||||
# Import prod_settings after determining the deployment/machine type
|
# Import prod_settings after determining the deployment/machine type
|
||||||
from .config import PRODUCTION
|
from .config import PRODUCTION
|
||||||
|
|
||||||
if PRODUCTION:
|
if PRODUCTION: # nocoverage
|
||||||
from .prod_settings import * # noqa: F403 isort: skip
|
from .prod_settings import * # noqa: F403 isort: skip
|
||||||
else:
|
else:
|
||||||
# For the Dev VM environment, we use the same settings as the
|
# For the Dev VM environment, we use the same settings as the
|
||||||
|
|
|
@ -10,7 +10,7 @@ from .config import DEVELOPMENT, PRODUCTION, get_secret
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from django_auth_ldap.config import LDAPSearch
|
from django_auth_ldap.config import LDAPSearch
|
||||||
|
|
||||||
if PRODUCTION:
|
if PRODUCTION: # nocoverage
|
||||||
from .prod_settings import EXTERNAL_HOST, ZULIP_ADMINISTRATOR
|
from .prod_settings import EXTERNAL_HOST, ZULIP_ADMINISTRATOR
|
||||||
else:
|
else:
|
||||||
from .dev_settings import EXTERNAL_HOST, ZULIP_ADMINISTRATOR
|
from .dev_settings import EXTERNAL_HOST, ZULIP_ADMINISTRATOR
|
||||||
|
|
|
@ -109,7 +109,7 @@ if use_prod_static:
|
||||||
urls += [
|
urls += [
|
||||||
path("static/<path:path>", serve, {"document_root": settings.STATIC_ROOT}),
|
path("static/<path:path>", serve, {"document_root": settings.STATIC_ROOT}),
|
||||||
]
|
]
|
||||||
else:
|
else: # nocoverage
|
||||||
|
|
||||||
def serve_static(request: HttpRequest, path: str) -> FileResponse:
|
def serve_static(request: HttpRequest, path: str) -> FileResponse:
|
||||||
response = staticfiles_serve(request, path)
|
response = staticfiles_serve(request, path)
|
||||||
|
|
|
@ -225,7 +225,7 @@ from zerver.views.zephyr import webathena_kerberos_login
|
||||||
from zproject import dev_urls
|
from zproject import dev_urls
|
||||||
from zproject.legacy_urls import legacy_urls
|
from zproject.legacy_urls import legacy_urls
|
||||||
|
|
||||||
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED:
|
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED: # nocoverage
|
||||||
from two_factor.gateways.twilio.urls import urlpatterns as tf_twilio_urls
|
from two_factor.gateways.twilio.urls import urlpatterns as tf_twilio_urls
|
||||||
from two_factor.urls import urlpatterns as tf_urls
|
from two_factor.urls import urlpatterns as tf_urls
|
||||||
|
|
||||||
|
@ -785,7 +785,7 @@ urls += [
|
||||||
]
|
]
|
||||||
|
|
||||||
# Front-end Sentry requests tunnel through the server, if enabled
|
# Front-end Sentry requests tunnel through the server, if enabled
|
||||||
if settings.SENTRY_FRONTEND_DSN:
|
if settings.SENTRY_FRONTEND_DSN: # nocoverage
|
||||||
urls += [path("error_tracing", sentry_tunnel)]
|
urls += [path("error_tracing", sentry_tunnel)]
|
||||||
|
|
||||||
# User documentation site
|
# User documentation site
|
||||||
|
@ -818,7 +818,7 @@ urls += [
|
||||||
path("policies/<slug:article>", policy_documentation_view),
|
path("policies/<slug:article>", policy_documentation_view),
|
||||||
]
|
]
|
||||||
|
|
||||||
if not settings.CORPORATE_ENABLED:
|
if not settings.CORPORATE_ENABLED: # nocoverage
|
||||||
# This conditional behavior cannot be tested directly, since
|
# This conditional behavior cannot be tested directly, since
|
||||||
# urls.py is not readily reloaded in Django tests. See the block
|
# urls.py is not readily reloaded in Django tests. See the block
|
||||||
# comment inside apps_view for details.
|
# comment inside apps_view for details.
|
||||||
|
@ -827,7 +827,7 @@ if not settings.CORPORATE_ENABLED:
|
||||||
]
|
]
|
||||||
|
|
||||||
# Two-factor URLs
|
# Two-factor URLs
|
||||||
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED:
|
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED: # nocoverage
|
||||||
urls += [path("", include(tf_urls)), path("", include(tf_twilio_urls))]
|
urls += [path("", include(tf_urls)), path("", include(tf_twilio_urls))]
|
||||||
|
|
||||||
if settings.DEVELOPMENT:
|
if settings.DEVELOPMENT:
|
||||||
|
|
Loading…
Reference in New Issue