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

reorganize plugin testing code #3319

Merged
merged 31 commits into from
Oct 28, 2019
Merged

Conversation

ltalirz
Copy link
Member

@ltalirz ltalirz commented Sep 12, 2019

fix #2648
fix #2660
fix #3462

The "helper" code for plugin testing is reorganized from a single file fixtures.py (that actually did not contain a single fixture) over multiple files.

  • manage/tests/__init__.py for the manager, which is now called TestManager
    (it has nothing to do with fixtures)
  • unittest_classes.py for test classes & runners for use with unittest
  • pytest_fixtures.py for the fixtures for use with pytest (=the main new content in this PR)

In order to avoid breaking the API, the old way of importing the main classes is still supported (with a corresponding deprecation warning).

Further additions:

  • TestManager can now use either a TemporaryProfileManager (which will set up the postgres cluster etc.) or a ProfileManager (which will use an existing test Profile). The ProfileManager is used automatically when the TEST_AIIDA_PROFILE environment variable is set.
  • Fixes an issue where the temporary postgres cluster could remain running when a test failed

Up for discussion:

  1. The file names unittest_classes.py and pytest_fixtures.py are a bit long.
    I previously tried unittest.py and pytest.py but this caused confusion with the external packages of the same name. Open to alternative suggestions
  2. One of the new fixtures (aiida_localhost_code) is of a different type than the others, since it needs extra parameters. Depending on the needs of a particular code/plugin even the two provided may not be enough.
    I still think it is useful to have - if people feel this should not be in aiida-core, I can also remove it again.

plugin testing code is split up from a single file fixtures.py (that
actually did not contain a single fixture) over multiple files

  * one for the manager, which is now called TestManager
    (it has nothing to do with fixtures)
  * one for test classes & runners for use with unittest
  * one for (newly added) fixtures for use with pytest
@ltalirz ltalirz force-pushed the add-pytest-fixtures2 branch from 957b12d to c1b3f5a Compare September 12, 2019 16:42
@ltalirz
Copy link
Member Author

ltalirz commented Sep 12, 2019

Sorry for the follow-up commits. Tests pass on my fork now, and I'm not planning any further commits. Let me know what you think!

@yakutovicha
Copy link
Contributor

thanks, @ltalirz, I am going to adapt the cp2k plugin to use the fixtures introduced here. Once they work fine I am going to approve your PR.

@yakutovicha
Copy link
Contributor

We should add a possibility to not remove the folder where the calculation was run, useful for the tests.

both unittest test classes and pytest fixtures will now use the backend
defined in the `TEST_AIIDA_BACKEND` environment variable.
for consistency (used nowhere else in the code). + see
https://stackoverflow.com/a/6930223
by specifying the environment variable TEST_AIIDA_PROFILE=profilename
one can use an existing profile instead of setting up a test profile
automatically.
@yakutovicha
Copy link
Contributor

thanks, @ltalirz, for the ebd3f68. I think this feature is absolutely critical to make tests useful for the developers.

@yakutovicha
Copy link
Contributor

yakutovicha commented Sep 17, 2019

after pulling the last changes I get the following error while running pytest for the aiida-cp2k plugin:

self = <aiida.manage.configuration.profile.Profile object at 0x11ea78a10>

    @property
    def default_user(self):
>       return self._attributes[self.KEY_DEFAULT_USER]
E       KeyError: 'default_user_email'

../aiida_core/aiida/manage/configuration/profile.py:124: KeyError

@ltalirz
Copy link
Member Author

ltalirz commented Sep 17, 2019 via email

@sphuber
Copy link
Contributor

sphuber commented Sep 17, 2019

To give an idea of how testing is done in aiida-quantumespresso.

  • Fixtures for pytest are written in this conftest.py file. Some that are added in this PR directly overlap so they could be removed and use directly from aiida-core.
  • There is a fixture to test CalcJob classes. Example usage can be found here for PwCalculation.
  • Similar fixture exists to test Parser implementations. It essentially mocks a completed CalcJobNode with the retrieved folder data node that contains the retrieved files. Example usage for PwParser shows.

The automatic comparison files generation and checking is done through the pytest-regressions plugin which is added as a dependency. With this pytest plugin and the two fixtures, it is really easy to write and run tests for calculation jobs and parsers without actually having to run the calculations. Note of course, as mentioned before, that some tests that actually run the code will still be useful and desirable.

@ltalirz
Copy link
Member Author

ltalirz commented Sep 18, 2019

Just to have everything in one place - below the pointers from @greschd concerning aiida-pytest:

One thing that I’ve found to be helpful is having an option to wait for user input before wiping the test DB. That allows for inspecting the state better before it’s gone. See here: https://github.com/greschd/aiida_pytest/blob/migrate_v1/aiida_pytest/_configure.py#L152

@sphuber
Copy link
Contributor

sphuber commented Oct 18, 2019

@ltalirz was this something that needed to go in before the release?

@ltalirz
Copy link
Member Author

ltalirz commented Oct 18, 2019

I'll continue to work on this today; also to add at least the possibility to use the pytest fixtures together with an existing AiiDA profile.

However, this is not absolutely necessary for the 1.0 release.

@ltalirz
Copy link
Member Author

ltalirz commented Oct 18, 2019

closing this while doing some more work.

@ltalirz ltalirz closed this Oct 18, 2019
@ltalirz
Copy link
Member Author

ltalirz commented Oct 18, 2019

@sphuber Do you remember whether configuring logging is needed here:
https://github.com/aiidateam/aiida-quantumespresso/blob/22d54c868c3c2322a83116476ee369c07bede800/tests/conftest.py#L31-L32

I.e. do you think this is something the fixture manager should do automatically?

@ltalirz
Copy link
Member Author

ltalirz commented Oct 18, 2019

@sphuber
Regarding the generate_calc_job and generate_calc_job_node fixtures: The generate_calc_job fixture seems compact and agnostic and could be added as-is - the generate_calc_job_node fixture less so.
If you would like to include the latter here as well, would you mind making a version that is entirely aiida-qe agnostic?

Finally, as far as I can tell, the fixtures don't make direct use of pytest-regressions (but it's rather in how they are used).
What would be the best way to make it easy for people to use it? Should we just include something in the documentation?

P.S. You have rights to push to my fork, so feel free to proceed however is easiest for you.

 * fix name according to suggestion
 * fix bug in database query

since the code label no longer referred to the full label (including hte
computer), `Code.objects.get(label='network@computer')` would always
turn up empty-handed, causing the utility to create a new code.

Now, we're searching all available codes with the `network` label and
simply take the first one (if it exists).
@sphuber
Copy link
Contributor

sphuber commented Oct 18, 2019

@sphuber Do you remember whether configuring logging is needed here:
https://github.com/aiidateam/aiida-quantumespresso/blob/22d54c868c3c2322a83116476ee369c07bede800/tests/conftest.py#L31-L32

I.e. do you think this is something the fixture manager should do automatically?

I actually happen to have added that just today. It was necessary to get the DbLogHandler loaded in time. Otherwise the logging in Parser classes, that I trigger through the parser_from_node function would not end up triggering the handler, therefore attaching the log messages to the node. The weird thing was that the first test the handlers were not configured, but at the second time it was. So it seems the normal logging configuration pathway was being triggered to late. I didn't have time to figure out why, so put this in for the time being.

ResourceWarning introduced in python 3.2
@ltalirz
Copy link
Member Author

ltalirz commented Oct 24, 2019

@sphuber This would basically be ready for review.

I haven't yet incorporated Dominik's additions - perhaps I'll find time but if not I think this could also be done in a separate PR.

With `autouse=True`, there is no straightforward way for plugin authors
to disable use of a fixture.
While this makes sense for the `aiida_profile` fixture, we've
encountered cases where resetting the database in between tests may lead
to issues.

This problem is solved by keeping the fixture available but requiring
users to depend on it explicitly.
@ltalirz ltalirz force-pushed the add-pytest-fixtures2 branch from 4879d3c to 3b5e9ea Compare October 24, 2019 20:08
Copy link
Contributor

@sphuber sphuber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ltalirz , some questions and comments

aiida/manage/tests/pytest_fixtures.py Outdated Show resolved Hide resolved
aiida/manage/tests/pytest_fixtures.py Outdated Show resolved Hide resolved
aiida/manage/tests/pytest_fixtures.py Outdated Show resolved Hide resolved
aiida/manage/tests/pytest_fixtures.py Show resolved Hide resolved
aiida/manage/tests/pytest_fixtures.py Show resolved Hide resolved
aiida/manage/tests/unittest_classes.py Show resolved Hide resolved
docs/source/developer_guide/plugins/plugin_tests.rst Outdated Show resolved Hide resolved
docs/source/developer_guide/plugins/plugin_tests.rst Outdated Show resolved Hide resolved
Resets collection instance back to its initial state (to be constructed from scratch when next requested).
Useful to clear any internal caches of the collection.
"""
cls._COLLECTIONS = datastructures.LazyStore()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this does what you intend it to do. This will reset the collection for all entities and backend. So when you call User.object.reset it will reset all collections not just that of User. I would really go for the alternative you proposed for now and implement a specific default user reset on the User collection

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, for the moment I've implemented the modification described in #3462

I can still change it if this is thought to be the worse solution.

@yakutovicha
Copy link
Contributor

Just a comment from my side: I used those modifications to test aiida-cp2k plugin and it worked fine on my local machine: aiidateam/aiida-cp2k#49

Beware that on travis the tests still fail because they are based on 1.0.0b6 release of aiida_core.

ltalirz and others added 2 commits October 25, 2019 14:42
Co-Authored-By: Sebastiaan Huber <mail@sphuber.net>
@ltalirz
Copy link
Member Author

ltalirz commented Oct 25, 2019

@sphuber Thanks a lot for the thorough review and the great suggestions.
I've gone through all your comments now & pushed some fixes.

 * rename TEST_AIIDA_PROFILE => AIIDA_TEST_PROFILE
 * rename TEST_AIIDA_BACKEND => AIIDA_TEST_BACKEND
 * add warning when setting AIIDA_TEST_PROFILE while running
   `verdi devel tests`
 * make test profile configurable at the test_manager level,
   so that the context manager can be used without having to mess
   with environment variables.
@ltalirz
Copy link
Member Author

ltalirz commented Oct 25, 2019

@sphuber I've made the changes we discussed.
I still left three comments open - feel free to resolve or to follow up further.

aiida/orm/entities.py Outdated Show resolved Hide resolved
@ltalirz
Copy link
Member Author

ltalirz commented Oct 28, 2019

@sphuber 61d696e includes the modification we discussed (moving the cache reset to the User collection only).

If there's anything else left, let me know!

@ltalirz ltalirz force-pushed the add-pytest-fixtures2 branch from fb1bebc to 4ae8ade Compare October 28, 2019 08:41
@ltalirz ltalirz force-pushed the add-pytest-fixtures2 branch from 4ae8ade to 70c234a Compare October 28, 2019 08:43
@sphuber sphuber merged commit e85e534 into aiidateam:develop Oct 28, 2019
@sphuber
Copy link
Contributor

sphuber commented Oct 28, 2019

Thanks a lot @ltalirz

@greschd
Copy link
Member

greschd commented Oct 28, 2019

@ltalirz I'm just migrating aiida-pytest to match these changes -- is there a nicer way to get at the root directory than through the aiida_profile fixture's aiida_profile._manager.root_dir?

@ltalirz
Copy link
Member Author

ltalirz commented Oct 28, 2019

@greschd probably not - if you have any small suggestions for improvements, now would be a good time to make a PR.

By the way, sorry for not yet having included more from aiida-pytest's features, it was just lack of time on my side. I'll open an issue so that these things don't get lost and we can keep improving the fixtures.

@greschd
Copy link
Member

greschd commented Oct 28, 2019

I haven't had the time to look at it in detail, but from the surface it looks pretty good - better than that hot mess that is aiida-pytest for sure 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

resetting default User cache Make pytest fixtures publically available faster plugin tests
4 participants