Skip to content

Commit

Permalink
Add support for --show-trello-cards to generate report
Browse files Browse the repository at this point in the history
  • Loading branch information
jlaska committed Nov 20, 2015
1 parent c9954bb commit 1eedae1
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 15 deletions.
2 changes: 1 addition & 1 deletion pytest_trello/__init__.py
@@ -1,3 +1,3 @@
__version__ = '0.0.6'
__version__ = '0.0.7'
__author__ = "James Laska"
__author_email__ = "<jlaska@ansible.com>"
61 changes: 59 additions & 2 deletions pytest_trello/plugin.py
Expand Up @@ -2,9 +2,22 @@
import logging
import yaml
import pytest
import py
import trello
import requests.exceptions
from _pytest.python import getlocation
from _pytest.resultlog import generic_path

try:
from logging import NullHandler
except ImportError:
from logging import Handler
class NullHandler(Handler):
def emit(self, record):
pass

log = logging.getLogger(__name__)
log.addHandler(NullHandler())

"""
pytest-trello
Expand All @@ -17,8 +30,6 @@
:license: MIT, see LICENSE for more details.
"""


log = logging.getLogger(__name__)
_card_cache = {}
DEFAULT_TRELLO_COMPLETED = ['Done', 'Archived']

Expand Down Expand Up @@ -51,12 +62,18 @@ def pytest_addoption(parser):
metavar='TRELLO_COMPLETED',
default=[],
help='Any cards in TRELLO_COMPLETED are considered complete (default: %s)' % DEFAULT_TRELLO_COMPLETED)
group.addoption('--show-trello-cards',
action='store_true',
dest='show_trello_cards',
default=False,
help='Show a list of all trello card markers.')


def pytest_configure(config):
'''
Validate --trello-* parameters.
'''
log.debug("pytest_configure() called")

# Add marker
config.addinivalue_line("markers", """trello(*cards): Trello card integration""")
Expand Down Expand Up @@ -105,6 +122,42 @@ def pytest_configure(config):
)


def pytest_cmdline_main(config):
'''Check show_fixture_duplicates option to show fixture duplicates.'''
log.debug("pytest_cmdline_main() called")
if config.option.show_trello_cards:
from _pytest.main import wrap_session
wrap_session(config, __show_trello_cards)
return 0


def __show_trello_cards(config, session):
'''Generate a report that includes all linked trello cards, and their status.'''
session.perform_collect()
curdir = py.path.local()

trello_helper = config.pluginmanager.getplugin("trello_helper")

card_cache = dict()
for i, item in enumerate(filter(lambda i: i.get_marker("trello") is not None, session.items)):
cards = item.funcargs.get('cards', [])
for card in cards:
if card not in card_cache:
card_cache[card] = list()
card_cache[card].append(generic_path(item))

reporter = config.pluginmanager.getplugin("terminalreporter")
reporter.section("trello card report")
if card_cache:
for card, gpaths in card_cache.items():
reporter.write("{0} ".format(card.url), bold=True)
reporter.write_line("[{0}] {1}".format(card.list.name, card.name))
for gpath in gpaths:
reporter.write_line(" * %s" % gpath)
else:
reporter.write_line("No trello cards collected")


class TrelloCard(object):
'''Object representing a trello card.
'''
Expand Down Expand Up @@ -162,6 +215,7 @@ def name(self):


class TrelloCardList(object):
'''Object representing a list of trello cards.'''
def __init__(self, api, *cards, **kwargs):
self.api = api
self.cards = cards
Expand All @@ -176,10 +230,12 @@ def __iter__(self):

class TrelloPytestPlugin(object):
def __init__(self, api, **kwargs):
log.debug("TrelloPytestPlugin initialized")
self.api = api
self.completed_lists = kwargs.get('completed_lists', [])

def pytest_runtest_setup(self, item):
log.debug("pytest_runtest_setup() called")
if 'trello' not in item.keywords:
return

Expand All @@ -204,6 +260,7 @@ def pytest_runtest_setup(self, item):
"\n ".join(["{0} [{1}] {2}".format(card.url, card.list.name, card.name) for card in incomplete_cards])))

def pytest_collection_modifyitems(self, session, config, items):
log.debug("pytest_collection_modifyitems() called")
reporter = config.pluginmanager.getplugin("terminalreporter")
reporter.write("collected", bold=True)
for i, item in enumerate(filter(lambda i: i.get_marker("trello") is not None, items)):
Expand Down
101 changes: 89 additions & 12 deletions test_pytest_trello.py
@@ -1,5 +1,9 @@
# -*- coding: utf-8 -*-
import pytest
import inspect
import re

from _pytest.main import EXIT_OK, EXIT_NOTESTSCOLLECTED


pytest_plugins = 'pytester',
Expand Down Expand Up @@ -139,6 +143,7 @@ def test_plugin_help(testdir):
'* --trello-api-key=TRELLO_API_KEY',
'* --trello-api-token=TRELLO_API_TOKEN',
'* --trello-completed=TRELLO_COMPLETED',
'* --show-trello-cards *',
])


Expand All @@ -156,7 +161,7 @@ def test_param_trello_cfg_with_no_such_file(testdir, option, monkeypatch_trello,
'''Verifies pytest-trello ignores any bogus files passed to --trello-cfg'''

result = testdir.runpytest(*['--trello-cfg', 'asdfasdf'])
assert result.ret == 5
assert result.ret == EXIT_NOTESTSCOLLECTED

# FIXME - assert actual log.warning message
# No trello configuration file found matching:
Expand All @@ -170,7 +175,7 @@ def test_param_trello_cfg_containing_no_data(testdir, option, monkeypatch_trello

# Run with parameter (expect pass)
result = testdir.runpytest(*['--trello-cfg', str(cfg_file)])
assert result.ret == 0
assert result.ret == EXIT_OK

# FIXME - assert actual log.warning message
# No trello configuration file found matching:
Expand Down Expand Up @@ -198,7 +203,7 @@ def test_func():
assert True
""" % OPEN_CARDS[0]
result = testdir.inline_runsource(src, *['--trello-cfg', str(cfg_file)])
assert result.ret == 0
assert result.ret == EXIT_OK
assert_outcome(result, passed=1)


Expand All @@ -217,7 +222,7 @@ def test_param_trello_api_key_with_value(testdir, option, monkeypatch_trello, ca
'''Verifies success when passing --trello-api-key an option'''

result = testdir.runpytest(*['--trello-api-key', 'asdf'])
assert result.ret == 5
assert result.ret == EXIT_NOTESTSCOLLECTED

# TODO - would be good to assert some output

Expand All @@ -235,7 +240,7 @@ def test_param_trello_api_token_with_value(testdir, option, monkeypatch_trello,
'''Verifies success when passing --trello-api-token an option'''

result = testdir.runpytest(*['--trello-api-token', 'asdf'])
assert result.ret == 5
assert result.ret == EXIT_NOTESTSCOLLECTED

# TODO - would be good to assert some output

Expand All @@ -249,7 +254,7 @@ def test_func():
assert True
""")
result = testdir.runpytest(*option.args)
assert result.ret == 0
assert result.ret == EXIT_OK
assert result.parseoutcomes()['passed'] == 1


Expand All @@ -276,7 +281,7 @@ def test_func():
assert True
""" % OPEN_CARDS[0]
# result = testdir.runpytest(*option.args)
# assert result.ret == 0
# assert result.ret == EXIT_OK
# assert result.parseoutcomes()['xpassed'] == 1
result = testdir.inline_runsource(src, *option.args)
assert_outcome(result, xpassed=1)
Expand All @@ -293,7 +298,7 @@ def test_func():
""" % OPEN_CARDS
# testdir.makepyfile(src)
# result = testdir.runpytest(*option.args)
# assert result.ret == 0
# assert result.ret == EXIT_OK
# assert result.parseoutcomes()['xpassed'] == 1
result = testdir.inline_runsource(src, *option.args)
assert_outcome(result, xpassed=1)
Expand All @@ -310,7 +315,7 @@ def test_func():
""" % OPEN_CARDS[0]
# testdir.makepyfile(src)
# result = testdir.runpytest(*option.args)
# assert result.ret == 0
# assert result.ret == EXIT_OK
# assert result.parseoutcomes()['xfailed'] == 1
result = testdir.inline_runsource(src, *option.args)
assert_outcome(result, xfailed=1)
Expand All @@ -327,7 +332,7 @@ def test_func():
""" % OPEN_CARDS
# testdir.makepyfile(src)
# result = testdir.runpytest(*option.args)
# assert result.ret == 0
# assert result.ret == EXIT_OK
# assert result.parseoutcomes()['xfailed'] == 1
result = testdir.inline_runsource(src, *option.args)
assert_outcome(result, xfailed=1)
Expand Down Expand Up @@ -378,7 +383,7 @@ def test_func():
""" % ALL_CARDS
# testdir.makepyfile(src)
# result = testdir.runpytest(*option.args)
# assert result.ret == 0
# assert result.ret == EXIT_OK
# assert result.parseoutcomes()['xfailed'] == 1
result = testdir.inline_runsource(src, *option.args)
assert_outcome(result, xfailed=1)
Expand All @@ -395,7 +400,7 @@ def test_func():
""" % OPEN_CARDS[0]
# testdir.makepyfile(src)
# result = testdir.runpytest(*option.args)
# assert result.ret == 0
# assert result.ret == EXIT_OK
# assert result.parseoutcomes()['skipped'] == 1
result = testdir.inline_runsource(src, *option.args)
assert_outcome(result, skipped=1)
Expand Down Expand Up @@ -437,3 +442,75 @@ def test_bar():

stdout, stderr = capsys.readouterr()
assert 'collected %s trello markers' % (len(CLOSED_CARDS) + len(OPEN_CARDS)) in stdout


def test_show_trello_report_with_no_cards(testdir, option, monkeypatch_trello, capsys):
'''Verifies when a test succeeds with an open trello card'''

src = """
import pytest
def test_func():
assert True
"""

# Run pytest
args = option.args + ['--show-trello-cards',]
result = testdir.inline_runsource(src, *args)

# Assert exit code
assert result.ret == EXIT_OK

# Assert no tests ran
assert_outcome(result)

# Assert expected trello card report output
stdout, stderr = capsys.readouterr()
assert '= trello card report =' in stdout
assert 'No trello cards collected' in stdout


def test_show_trello_report_with_cards(testdir, option, monkeypatch_trello, capsys):
'''Verifies when a test succeeds with an open trello card'''

# Used for later introspection
cls = 'Test_Foo'
module = inspect.stack()[0][3]
method = 'test_func'

src = """
import pytest
class Test_Class():
@pytest.mark.trello(*%s)
def test_method():
assert True
@pytest.mark.trello(*%s)
def test_func():
assert True
""" % (CLOSED_CARDS, OPEN_CARDS)

# Run pytest
args = option.args + ['--show-trello-cards',]
result = testdir.inline_runsource(src, *args)

# Assert exit code
assert result.ret == EXIT_OK

# Assert no tests ran
assert_outcome(result)

# Assert expected trello card report output
stdout, stderr = capsys.readouterr()

# Assert expected banner
assert re.search(r'^={1,} trello card report ={1,}', stdout, re.MULTILINE)

# Assert expected cards in output
for card in CLOSED_CARDS:
assert re.search(r'^%s \[Done\]' % card, stdout, re.MULTILINE)
for card in OPEN_CARDS:
assert re.search(r'^%s \[Not Done\]' % card, stdout, re.MULTILINE)

# this is weird, oh well
assert ' * {0}0/{0}.py:Test_Class().test_method'.format(module) in stdout
assert ' * {0}0/{0}.py:test_func'.format(module) in stdout

0 comments on commit 1eedae1

Please sign in to comment.