Skip to content

Commit

Permalink
Adding a test teardown hook to fixtures (#122)
Browse files Browse the repository at this point in the history
* Adding a test teardown hook to fixtures

* Fixing #84

Also adding a devcontainer
  • Loading branch information
thirtytwobits committed Mar 15, 2020
1 parent a1b4780 commit 85d69c8
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 45 deletions.
20 changes: 20 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "Python dev environment",
"dockerFile": "python.Dockerfile",
"context": "..",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"workspaceFolder": "/workspace",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
"mounts": [
"source=root-vscode-server,target=/root/.vscode-server/extensions,type=volume",
"source=nanaimo-tox,target=/workspace/.tox,type=volume"
],
"extensions": [
"streetsidesoftware.code-spell-checker",
"ms-python.python",
"lextudio.restructuredtext",
],
"postCreateCommand": "tox -e local"
}
3 changes: 3 additions & 0 deletions .devcontainer/python.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM uavcan/toxic:py35-py38-sq

RUN mkdir -p /root/.vscode-server/extensions
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"python.linting.pycodestyleEnabled": false,
"python.linting.enabled": true,
"python.linting.pycodestyleArgs": ["--ignore", "E501,E251,E701"],
"python.testing.cwd": "${workspaceFolder}/test",
"python.testing.cwd": "${workspaceFolder}",
"python.testing.unittestEnabled": false,
"python.testing.nosetestsEnabled": false,
"python.testing.pytestEnabled": false,
"python.testing.pytestEnabled": true,
"python.testing.autoTestDiscoverOnSaveEnabled": false,
"files.exclude": {
"**/.git": true,
Expand Down
13 changes: 11 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@
"label": "nanaimo-pytest",
"type": "shell",
"options": {
"cwd": "${workspaceFolder}/test"
"cwd": "${workspaceFolder}"
},
"command": "python -m pytest --log-cli-level=DEBUG -s",
"command": "python3 -m pytest --log-cli-level=DEBUG -s",
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "tox local",
"type": "shell",
"options": {
"cwd": "${workspaceFolder}"
},
"command": "pip3 install -r requirements.txt",
"problemMatcher": []
}
]
}
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ exclude_lines =
assert False
if False:
if __name__ == .__main__.:
...


[nanaimo]
Expand Down
2 changes: 1 addition & 1 deletion src/nanaimo/builtin/nanaimo_gather.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
else:
fixture_list.append(self.manager.create_fixture(arg, args).gather())

results = await asyncio.gather(*fixture_list, loop=self.loop)
results = await asyncio.gather(*fixture_list)
return nanaimo.Artifacts.combine(*results)


Expand Down
23 changes: 18 additions & 5 deletions src/nanaimo/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ def __init__(self,
self._name = self.get_canonical_name()
self._logger = logging.getLogger(self._name)
if 'loop' in kwargs:
print('WARNING: Passing loop into Fixture is deprecated. (This will be an exception in a future release).')
raise ValueError('Do not pass the loop into the fixture. '
'Fixtures obtain the loop from their FixtureManager.')
if 'gather_timeout_seconds' in kwargs:
gather_timeout_seconds = typing.cast(typing.Optional[float], kwargs['gather_timeout_seconds'])
self._gather_timeout_seconds = gather_timeout_seconds
Expand Down Expand Up @@ -358,6 +359,18 @@ async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
"""
...

# +-----------------------------------------------------------------------+
# | Optional Hooks
# +-----------------------------------------------------------------------+
def on_test_teardown(self, test_name: str) -> None:
"""
Invoked for each fixture after it was used in a test as part of the pytest
:func:`_pytest.hookspec.pytest_runtest_teardown` protocol.
:param test_name: The name of the test the fixture was used with.
"""
pass

# +-----------------------------------------------------------------------+
# | ASYNC HELPERS
# +-----------------------------------------------------------------------+
Expand Down Expand Up @@ -758,18 +771,18 @@ async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
logfile_handler = logging.FileHandler(filename=str(logfile), mode=('a' if logfile_amend else 'w'))
file_formatter = logging.Formatter(fmt=logfile_fmt, datefmt=logfile_datefmt)
logfile_handler.setFormatter(file_formatter)
self._logger.addHandler(logfile_handler)
self.logger.addHandler(logfile_handler)

stdout_filter = self._stdout_filter
stderr_filter = self._stderr_filter

if stdout_filter is not None:
self._logger.addFilter(stdout_filter)
self.logger.addFilter(stdout_filter)
if stderr_filter is not None:
self._logger.addFilter(stderr_filter)
self.logger.addFilter(stderr_filter)

try:
self._logger.debug('About to execute command "%s" in a subprocess shell', cmd)
self.logger.debug('About to execute command "%s" in a subprocess shell', cmd)

proc = await asyncio.create_subprocess_shell(
cmd,
Expand Down
15 changes: 15 additions & 0 deletions src/nanaimo/pytest/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ def runtest(self) -> None:
combined = nanaimo.Artifacts.combine(*results)
assert combined.result_code == 0
getattr(self.session.config, self.nanaimo_results_sneaky_key)[','.join(self._fixture_names)] = combined
for fixture in fixtures:
fixture.on_test_teardown('nait')

def _prunetraceback(self, excinfo):
"""
Expand Down Expand Up @@ -598,6 +600,19 @@ def pytest_runtest_setup(item: pytest.Item) -> None:
display.write(item.name)


def pytest_runtest_teardown(item: pytest.Item, nextitem: pytest.Item) -> None:
"""
See :func:`_pytest.hookspec.pytest_teardown` for documentation.
Also see the "`Writing Plugins <https://docs.pytest.org/en/latest/writing_plugins.html>`_"
guide.
"""
if hasattr(item, 'funcargs'):
args = item.funcargs
for name, value in args.items():
if isinstance(value, nanaimo.fixtures.Fixture):
typing.cast(nanaimo.fixtures.Fixture, value).on_test_teardown(item.name)


def pytest_sessionfinish(session: _pytest.main.Session, exitstatus: int) -> None:
"""
See :func:`_pytest.hookspec.pytest_sessionfinish` for documentation.
Expand Down
2 changes: 1 addition & 1 deletion src/nanaimo/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
# nanaimo (@&&&&####@@*
#

__version__ = '0.2.4'
__version__ = '0.2.5'

__license__ = 'MIT'
22 changes: 0 additions & 22 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,3 @@ def build_output(request): # type: ignore
@pytest.fixture
def nanaimo_bar_from_conftest(nanaimo_fixture_manager, nanaimo_arguments) -> 'nanaimo.fixtures.Fixture':
return nanaimo.builtin.nanaimo_bar.Fixture(nanaimo_fixture_manager, nanaimo_arguments)


class GatherTimeoutFixture(nanaimo.fixtures.Fixture):

@classmethod
def on_visit_test_arguments(cls, arguments: nanaimo.Arguments) -> None:
pass

async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
"""
Sleep forever
"""
while True:
await asyncio.sleep(1)


@pytest.fixture
def gather_timeout_fixture(request: typing.Any) -> nanaimo.fixtures.Fixture:
args = nanaimo.Namespace(request.config.option,
nanaimo.config.ArgumentDefaults(request.config.option),
allow_none_values=False)
return GatherTimeoutFixture(nanaimo.fixtures.FixtureManager(), args)
56 changes: 44 additions & 12 deletions test/test_nanaimo_fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,29 @@ async def test_countdown_sleep(dummy_nanaimo_fixture: nanaimo.fixtures.Fixture)

@pytest.mark.timeout(20)
@pytest.mark.asyncio
async def test_gather_timeout(gather_timeout_fixture: nanaimo.fixtures.Fixture) -> None:
async def test_gather_timeout(event_loop: asyncio.AbstractEventLoop) -> None:
"""
Test the standard fixture timeout.
"""
gather_timeout_fixture.gather_timeout_seconds = 1.0
class GatherTimeoutFixture(nanaimo.fixtures.Fixture):

@classmethod
def on_visit_test_arguments(cls, arguments: nanaimo.Arguments) -> None:
pass

async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
"""
Sleep forever
"""
while True:
await asyncio.sleep(1)

subject = GatherTimeoutFixture(nanaimo.fixtures.FixtureManager(), gather_timeout_seconds=2.0)
assert 2.0 == subject.gather_timeout_seconds
subject.gather_timeout_seconds = 1.0
assert 1.0 == subject.gather_timeout_seconds
with pytest.raises(asyncio.TimeoutError):
await gather_timeout_fixture.gather()
await subject.gather()


@pytest.mark.asyncio
Expand Down Expand Up @@ -230,7 +246,6 @@ def on_construct_command(self, arguments: nanaimo.Namespace, inout_artifacts: na


@pytest.mark.asyncio
@pytest.mark.skip(reason='https://github.com/thirtytwobits/nanaimo/issues/84')
async def test_composite_fixture(event_loop: asyncio.AbstractEventLoop) -> None:
"""
Test creation of a composite fixture.
Expand All @@ -244,21 +259,17 @@ class Composite(nanaimo_bar.Fixture, nanaimo_cmd.Fixture):
def __init__(self, manager: nanaimo.fixtures.FixtureManager,
args: nanaimo.Namespace,
**kwargs: typing.Any) -> None:
nanaimo_bar.Fixture.__init__(self, manager, args, **kwargs)
nanaimo_cmd.Fixture.__init__(self, manager, args, **kwargs)
self._gather = nanaimo_gather.Fixture(manager, args, **kwargs)
super().__init__(manager, args, **kwargs)

@classmethod
def on_visit_test_arguments(cls, arguments: nanaimo.Arguments) -> None:
nanaimo_bar.Fixture.visit_test_arguments(arguments)
nanaimo_cmd.Fixture.visit_test_arguments(arguments)

async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
coroutines = [
nanaimo_bar.Fixture.on_gather(self, args),
nanaimo_cmd.Fixture.on_gather(self, args)
]
return await self._gather.gather(gather_coroutine=coroutines)
cmd_artifacts = await nanaimo_cmd.Fixture.on_gather(self, args)
bar_artifacts = await nanaimo_bar.Fixture.on_gather(self, args)
return nanaimo.Artifacts.combine(cmd_artifacts, bar_artifacts)

composite = Composite(nanaimo.fixtures.FixtureManager(event_loop),
nanaimo.Namespace())
Expand Down Expand Up @@ -297,3 +308,24 @@ def on_construct_command(self, arguments: nanaimo.Namespace, inout_artifacts: na
subject.stdout_filter = stdout
subject.stderr_filter = stderr
assert_success(await subject.gather())


@pytest.mark.asyncio
async def test_loop_into_fixture_arg(event_loop: asyncio.AbstractEventLoop) -> None:
class Dummy(nanaimo.fixtures.Fixture):

def __init__(self, manager: nanaimo.fixtures.FixtureManager,
args: nanaimo.Namespace,
**kwargs: typing.Any) -> None:
super().__init__(manager, args, **kwargs)

def on_visit_test_arguments(cls, arguments: nanaimo.Arguments) -> None:
pass

async def on_gather(self, args: nanaimo.Namespace) -> nanaimo.Artifacts:
return nanaimo.Artifacts()

with pytest.raises(ValueError):
Dummy(nanaimo.fixtures.FixtureManager(event_loop),
nanaimo.Namespace(),
loop=event_loop)
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ deps =
flake8
doc8
pygments
rstcheck
changedir = src
commands =
flake8 --benchmark \
Expand Down Expand Up @@ -192,6 +193,7 @@ deps =
{[testenv:lint]deps}
{[testenv:docs]deps}
{[testenv:mypy]deps}
rope

commands =
python --version

0 comments on commit 85d69c8

Please sign in to comment.