Skip to content

Commit

Permalink
Support ability to provide test plan name substring or regex instead …
Browse files Browse the repository at this point in the history
…of test plan id (allankp#127)
  • Loading branch information
amygitsthings committed Feb 28, 2020
1 parent 54deea1 commit 9ba42a8
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,4 @@ Once the all tests are finished they will be updated in TestRail:
| --tr-skip-missing | Skip test cases that are not present in testrun |
| --tr-milestone-id | Identifier of milestone to be assigned to run |
| --tc-custom-comment | Custom comment, to be appended to default comment for test case (config file: custom_comment in TESTCASE section) |
| --tr-plan-regex | Regex to find an existing testplan that appears in TestRail (config file: plan_regex in TESTRUN section) |
8 changes: 7 additions & 1 deletion pytest_testrail/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def pytest_addoption(parser):
default=0,
required=False,
help='Identifier of testplan, that appears in TestRail (config file: plan_id in TESTRUN section). If provided, option "--tr-testrun-name" will be ignored')
group.addoption(
'--tr-plan-regex',
action='store',
required=False,
help='Regex to find an existing testplan, that appears in TestRail (config file: plan_regex in TESTRUN section). If provided, option "--tr-testrun-name" will be ignored')
group.addoption(
'--tr-version',
action='store',
Expand Down Expand Up @@ -148,7 +153,8 @@ def pytest_configure(config):
publish_blocked=config.getoption('--tr-dont-publish-blocked'),
skip_missing=config.getoption('--tr-skip-missing'),
milestone_id=config_manager.getoption('tr-milestone-id', 'milestone_id', 'TESTRUN'),
custom_comment=config_manager.getoption('tc-custom-comment', 'custom_comment', 'TESTCASE')
custom_comment=config_manager.getoption('tc-custom-comment', 'custom_comment', 'TESTCASE'),
plan_regex=config_manager.getoption('tr-plan-regex', 'plan_regex', 'TESTRUN')
),
# Name of plugin instance (allow to be used by other plugins)
name="pytest-testrail-instance"
Expand Down
33 changes: 31 additions & 2 deletions pytest_testrail/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
GET_TESTRUN_URL = 'get_run/{}'
GET_TESTPLAN_URL = 'get_plan/{}'
GET_TESTS_URL = 'get_tests/{}'
GET_ACTIVE_TESTPLANS_URL = 'get_plans/{}&is_completed=0'

COMMENT_SIZE_LIMIT = 4000

Expand Down Expand Up @@ -141,7 +142,7 @@ def get_testrail_keys(items):
class PyTestRailPlugin(object):
def __init__(self, client, assign_user_id, project_id, suite_id, include_all, cert_check, tr_name, tr_description='', run_id=0,
plan_id=0, version='', close_on_complete=False, publish_blocked=True, skip_missing=False,
milestone_id=None, custom_comment=None):
milestone_id=None, custom_comment=None, plan_regex=None):
self.assign_user_id = assign_user_id
self.cert_check = cert_check
self.client = client
Expand All @@ -159,6 +160,7 @@ def __init__(self, client, assign_user_id, project_id, suite_id, include_all, ce
self.skip_missing = skip_missing
self.milestone_id = milestone_id
self.custom_comment = custom_comment
self.testplan_regex = plan_regex

# pytest hooks

Expand All @@ -167,6 +169,8 @@ def pytest_report_header(self, config, startdir):
message = 'pytest-testrail: '
if self.testplan_id:
message += 'existing testplan #{} selected'.format(self.testplan_id)
elif self.testplan_regex:
message += 'existing testplan based on regex {} selected'.format(self.testplan_regex)
elif self.testrun_id:
message += 'existing testrun #{} selected'.format(self.testrun_id)
else:
Expand All @@ -178,7 +182,7 @@ def pytest_collection_modifyitems(self, session, config, items):
items_with_tr_keys = get_testrail_keys(items)
tr_keys = [case_id for item in items_with_tr_keys for case_id in item[1]]

if self.testplan_id and self.is_testplan_available():
if (self.testplan_id or self.testplan_regex) and self.is_testplan_available():
self.testrun_id = 0
elif self.testrun_id and self.is_testrun_available():
self.testplan_id = 0
Expand Down Expand Up @@ -432,6 +436,13 @@ def is_testplan_available(self):
:return: True if testplan exists AND is open
"""
if self.testplan_regex:
result = self.find_available_testplan()
if result:
self.testplan_id = result
else:
print('[{}] Failed to retrieve testplan matching regex: "{}"'.format(TESTRAIL_PREFIX, self.testplan_regex))
return False
response = self.client.send_get(
GET_TESTPLAN_URL.format(self.testplan_id),
cert_check=self.cert_check
Expand Down Expand Up @@ -477,3 +488,21 @@ def get_tests(self, run_id):
print('[{}] Failed to get tests: "{}"'.format(TESTRAIL_PREFIX, error))
return None
return response

def find_available_testplan(self):
"""
:return: id of first testplan that matches self.testplan_regex or None if none matches
"""
response = self.client.send_get(
GET_ACTIVE_TESTPLANS_URL.format(self.project_id),
cert_check=self.cert_check
)
error = self.client.get_error(response)
if error:
print('[{}] Failed to get testplans: "{}"'.format(TESTRAIL_PREFIX, error))
return None
for entry in response:
result = re.search(self.testplan_regex, entry['name'])
if result:
return entry['id']
return None
25 changes: 25 additions & 0 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,16 @@ def test_is_testplan_available(api_client, tr_plugin):
api_client.send_get.return_value = {'is_completed': True}
assert tr_plugin.is_testplan_available() is False

tr_plugin.testplan_id = 0
tr_plugin.testplan_regex = 'my test plan'
api_client.send_get.return_value = [{'name': 'no test plan', 'id': 5}]
assert tr_plugin.is_testplan_available() is False

tr_plugin.testplan_id = 0
tr_plugin.testplan_regex = 'my test plan'
api_client.send_get.side_effect = [[{'name': 'my test plan for milestone 1', 'id': 5}, {'name': 'my test plan for milestone 2', 'id': 7}], {'is_completed': False}]
assert tr_plugin.is_testplan_available() is True


def test_get_available_testruns(api_client, tr_plugin):
""" Test of method `get_available_testruns` """
Expand All @@ -270,6 +280,21 @@ def test_get_available_testruns(api_client, tr_plugin):
assert tr_plugin.get_available_testruns(testplan_id) == [59, 61]


def test_find_available_testplan(api_client, tr_plugin):
""" Test of method `find_available_testplan` """
tr_plugin.testplan_regex = 'my \w+ plan'
api_client.send_get.return_value = [{'name': 'my test plan for milestone 1', 'id': 5}, {'name': 'my test plan for milestone 2', 'id': 7}]
assert tr_plugin.find_available_testplan() == 5

api_client.send_get.return_value = [{'name': 'my test plan for milestone 1', 'id': 5}]
assert tr_plugin.find_available_testplan() == 5

api_client.send_get.return_value = [{'name': 'no matching', 'id': 10}]
assert tr_plugin.find_available_testplan() is None

api_client.send_get.return_value = []
assert tr_plugin.find_available_testplan() is None

def test_close_test_run(api_client, tr_plugin):
tr_plugin.results = [
{'case_id': 1234, 'status_id': TESTRAIL_TEST_STATUS["failed"], 'duration': 2.6, 'defects':None},
Expand Down

0 comments on commit 9ba42a8

Please sign in to comment.