Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace nose with pytest #34778

Merged
merged 38 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
77ca2d2
Remove pytest compatibility module
millerdev Sep 9, 2024
aba41f6
Initial pytest implementation
millerdev Sep 7, 2024
ec95345
Remove nose test settings
millerdev Apr 19, 2024
18b98e9
Show helpful error on ./manage.py test
millerdev Jun 11, 2024
4d44b95
Adapt patches nose plugin to pytest
millerdev Sep 4, 2024
40b26c2
Adapt redislocks nose plugin to pytest
millerdev Sep 4, 2024
3d22e5c
Add pytest-unmagic plugin for fixtures
millerdev Oct 23, 2024
e56d177
Adapt classCleanup tests to pytest
millerdev May 28, 2024
2efd892
Uninstall ddtrace ModuleWatchdog when testing
millerdev Sep 5, 2024
66663ce
Adapt reusedb feature to pytest - some tests passing
millerdev Oct 17, 2024
8372914
Use ExitStack for cleaner test database tear down
millerdev May 8, 2024
c3b3c75
Rename methods and function
millerdev May 8, 2024
1ae6ea1
Move DeferredDatabaseContext methods to functions
millerdev May 8, 2024
a834219
Implement db blocker for Couch
millerdev Sep 4, 2024
aa24be1
Setup databases on first db unblock
millerdev Jul 29, 2024
9613cdf
Do not unblock db for SimpleTestCase tests
millerdev Jul 26, 2024
3d5c1a1
Observe pytest-django's database options
millerdev Jun 11, 2024
a513405
Adapt dividedwerun nose plugin to pytest
millerdev Sep 4, 2024
0ca69fd
Remove djangomigrations plugin
millerdev May 28, 2024
069391e
Add test markers: es_test, sharded, slow
millerdev Sep 7, 2024
9b8137f
Remove obsolete and disabled nose plugins
millerdev May 29, 2024
912e55c
Move timelimit decorator to its own module
millerdev Sep 17, 2024
421f770
Adapt (part of) timing nose plugin to pytest
millerdev May 30, 2024
9b523cd
More nose.tools: assert_raises, assert_equal, ...
millerdev Jun 11, 2024
e305b74
Add 'skip_setup_users' marker
millerdev Sep 7, 2024
68219e5
Convert "yield" tests to parametrized tests
millerdev Jun 13, 2024
5ae9b5e
Remove nose test utilities module
millerdev Jun 14, 2024
c58537c
Align test discovery with nose
millerdev Sep 5, 2024
214546f
Fix parametrized test that hit Couch
millerdev Jun 14, 2024
2253349
make requirements
millerdev Jun 14, 2024
e7650e0
Switch github actions from nose to pytest
millerdev Jun 14, 2024
509dddc
Ignore unclosed file warnings in tests
millerdev Jul 24, 2024
05d1a10
Work around pytest capture plugin
millerdev Jul 30, 2024
e33e25f
Adapt champ tests to pytest
millerdev Aug 6, 2024
cd7c0a8
Adapt inddex tests to pytest
millerdev Sep 2, 2024
946173a
Adapt up_nrhm tests to pytest
millerdev Sep 2, 2024
ca33bd1
Update testing documentation: nose -> pytest
millerdev Oct 21, 2024
7ebdc62
Merge branch 'master' into dm/pytest
millerdev Oct 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
/corehq/sql_db/ @snopoke @calellowitz
/corehq/sql_proxy_accessors/ @snopoke
/corehq/sql_proxy_standby_accessors/ @snopoke
/corehq/tests/nose.py @millerdev
/corehq/tests/noseplugins/ @millerdev
/corehq/tests/ @millerdev
/corehq/util/couch.py @esoergel
/corehq/util/couch_helpers.py @millerdev
/corehq/util/datadog/lockmeter.py @millerdev
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ jobs:
fail-fast: false
matrix:
include:
- {TEST: python, NOSE_DIVIDED_WE_RUN: '05'}
- {TEST: python, NOSE_DIVIDED_WE_RUN: '6a'}
- {TEST: python, NOSE_DIVIDED_WE_RUN: 'bf'}
- {TEST: python, DIVIDED_WE_RUN: '05'}
- {TEST: python, DIVIDED_WE_RUN: '6a'}
- {TEST: python, DIVIDED_WE_RUN: 'bf'}
- {TEST: python-sharded-and-javascript}
env:
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
Expand All @@ -46,11 +46,11 @@ jobs:
- name: Run tests
env:
TEST: ${{ matrix.TEST }}
NOSE_DIVIDED_WE_RUN: ${{ matrix.NOSE_DIVIDED_WE_RUN }}
DIVIDED_WE_RUN: ${{ matrix.DIVIDED_WE_RUN }}
JS_SETUP: yes
KAFKA_HOSTNAME: kafka
STRIPE_PRIVATE_KEY: ${{ secrets.STRIPE_PRIVATE_KEY }}
run: scripts/docker test --noinput --stop -v --divided-we-run=${{ matrix.NOSE_DIVIDED_WE_RUN }} --divide-depth=1 --with-timing --with-flaky --threshold=10 --max-test-time=29
run: scripts/docker test --exitfirst -vv --reusedb=1 --divided-we-run=${{ matrix.DIVIDED_WE_RUN }} --showlocals --max-test-time=29 -p no:cacheprovider
- name: "Codecov upload"
env:
TOKEN: ${{ secrets.CODECOV_TOKEN }}
Expand Down
49 changes: 49 additions & 0 deletions .pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[pytest]
minversion = 8.1

addopts =
--strict-markers
-pcorehq.tests.pytest_hooks
# HQ has its own (incompatible) warnings system
-pno:warnings
markers =
es_test: marker for elasticsearch tests
sharded: tests to be run against shard databases
skip_setup_users: skip user setup in importer tests
slow: marks tests as slow (deselect with -m 'not slow')

empty_parameter_set_mark = fail_at_collect
xfail_strict = true

norecursedirs =
.*
*.egg
artifacts
docker
git-hooks
locale
node_modules
requirements
scripts
sharedfiles
staticfiles

python_files =
test_*.py
tests.py
*/tests/*.py

pythonpath =
.
corehq/ex-submodules
# 'submodules' is for langcodes
submodules
submodules/commcare-translations
submodules/couchdbkit-aggregate
submodules/django-digest-src
submodules/django-no-exceptions
submodules/python-digest
submodules/xml2json

required_plugins = pytest-django
DJANGO_SETTINGS_MODULE = testsettings
16 changes: 8 additions & 8 deletions DEV_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1038,8 +1038,8 @@ Or, to drop the current test DB and create a fresh one
./manage.py test corehq.apps.app_manager --reusedb=reset
```

See `corehq.tests.nose.HqdbContext` ([source](corehq/tests/nose.py)) for full
description of `REUSE_DB` and `--reusedb`.
See `corehq.tests.pytest_plugins.reusedb` ([source](corehq/tests/pytest_plugins/reusedb.py))
for full description of `REUSE_DB` and `--reusedb`.


### Accessing the test shell and database
Expand Down Expand Up @@ -1102,21 +1102,21 @@ ignore:unclosed:ResourceWarning'
Personal whitelist items may also be added in localsettings.py.


### Running tests by tag
### Running tests by marker

You can run all tests with a certain tag as follows:
You can run all tests with a certain marker as follows:

```sh
./manage.py test --attr=tag
pytest -m MARKER
```

Available tags:
Available markers:

- slow: especially slow tests
- sharded: tests that should get run on the sharded test runner
- es_test: Elasticsearch tests

See http://nose.readthedocs.io/en/latest/plugins/attrib.html for more details.
See https://docs.pytest.org/en/stable/example/markers.html for more details.


### Running on DB tests or Non-DB tests
Expand All @@ -1131,7 +1131,7 @@ See http://nose.readthedocs.io/en/latest/plugins/attrib.html for more details.

### Running only failed tests

See https://github.com/nose-devs/nose/blob/master/nose/plugins/testid.py
See https://docs.pytest.org/en/stable/how-to/cache.html


## Javascript tests
Expand Down
2 changes: 1 addition & 1 deletion corehq/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ tabs
Menu structure for CommCare HQ.
tests
Contains a few tests for high-level functionality like locks, as well as tooling to run tests with
`nose <https://nose.readthedocs.io/en/latest/>`_, an extension of ``unittest``.
`pytest <https://docs.pytest.org/en/stable/>`_.
toggles.py
Toggles allow limiting functionality based on user or domain. Also see ``ex-submodules/toggle`` and ``corehq.apps.toggle_ui``.
util
Expand Down
15 changes: 12 additions & 3 deletions corehq/apps/change_feed/tests/test_data_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,17 @@ def sms_data():

@sharded
class DocumentStoreDbTests(TestCase):
pass

def test_couch_document_store(self):
# this one is not included with generate_cases below because
# get_db() should not be called during test collection
_test_document_store(
self,
CouchDocumentStore,
(get_db(), 'domain', 'doc_type'),
couch_data,
'_id',
)


def _test_document_store(self, doc_store_cls, doc_store_args, data_context, id_field):
Expand All @@ -216,15 +226,14 @@ def _test_document_store(self, doc_store_cls, doc_store_args, data_context, id_f


@generate_cases([
(CouchDocumentStore, (get_db(), 'domain', 'doc_type'), couch_data, '_id'),
(CaseDocumentStore, ('domain',), case_data, '_id'),
(FormDocumentStore, ('domain',), form_data, '_id'),
(LocationDocumentStore, ('domain',), location_data, 'location_id'),
(LedgerV2DocumentStore, ('domain',), ledger_data, '_id'),
(SyncLogDocumentStore, (), synclog_data, '_id'),
(SMSDocumentStore, (), sms_data, '_id'),
], DocumentStoreDbTests)
def test_documet_store(*args):
def test_document_store(*args):
_test_document_store(*args)


Expand Down
2 changes: 1 addition & 1 deletion corehq/apps/es/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def checkQuery(self, query, expected_json, is_raw_query=False, validate_query=Tr
@nottest
def es_test(test=None, requires=None, setup_class=False):
"""Decorator for Elasticsearch tests.
The decorator sets the ``es_test`` nose attribute and optionally performs
The decorator sets the ``es_test`` pytest marker and optionally performs
index setup/cleanup before and after the test(s).

:param test: A test class, method, or function -- only used via the
Expand Down
1 change: 0 additions & 1 deletion corehq/apps/es/transient_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ def populate_doc_adapter_map():
from pillowtop.tests.utils import TEST_ES_TYPE, TEST_ES_MAPPING, TEST_ES_INDEX
add_dynamic_adapter("PillowTop", TEST_ES_INDEX, TEST_ES_TYPE, TEST_ES_MAPPING)

import corehq.tests.pytest_compat # noqa: F401 - to be removed after switch to pytest
from corehq.apps.es.tests.utils import TEST_ES_INFO, TEST_ES_MAPPING
add_dynamic_adapter("UtilES", TEST_ES_INFO.alias, TEST_ES_INFO.type,
TEST_ES_MAPPING)
Expand Down
17 changes: 10 additions & 7 deletions corehq/ex-submodules/casexml/apps/phone/tests/test_restore_user.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from unittest.mock import Mock, patch

import pytest
from nose.tools import assert_equal
from unmagic import use

from corehq.apps.users.models import CommCareUser, DomainMembership, WebUser
from corehq.apps.users.tests.util import patch_user_data_db_layer
Expand All @@ -24,11 +26,12 @@ def test_get_commtrack_location_id():
assert_equal(loc_id, '1')


@patch_user_data_db_layer
def test_user_types():
for user, expected_type in [
(WebUser(), 'web'),
(CommCareUser(domain=DOMAIN), 'commcare'),
]:
@pytest.mark.parametrize("user, expected_type", [
(WebUser(), 'web'),
(CommCareUser(domain=DOMAIN), 'commcare'),
])
@use("db")
def test_user_types(user, expected_type):
with patch_user_data_db_layer():
user_type = user.to_ota_restore_user(DOMAIN).user_session_data['commcare_user_type']
yield assert_equal, user_type, expected_type
assert_equal(user_type, expected_type)
5 changes: 3 additions & 2 deletions corehq/ex-submodules/dimagi/utils/tests/test_decorators.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import sys
import inspect
from io import StringIO
from unittest.mock import patch

Expand All @@ -15,7 +15,8 @@ def test_profile_decorator():
def func(arg):
args.append(arg)

with patch.object(sys.stderr, "write", output.write):
sys_stderr = inspect.signature(profile).parameters["stream"].default
with patch.object(sys_stderr, "write", output.write):
func(1)
eq(args, [1])
eq(output.getvalue(), Regex(r"test_decorators.py:\d+\(func\)"))
Expand Down
Loading
Loading