def setUp(self): self.client = API() self.mock_user_data = [ { "email": "*****@*****.**", "id": 1, "is_active": 'true', "name": "Han Solo" }, { "email": "*****@*****.**", "id": 2, "is_active": 'true', "name": "Jabba the Hutt" } ]
class TestBase(unittest.TestCase): def setUp(self): self.client = API() def test_set_project_id(self): self.client.set_project_id(20) self.assertEqual(self.client._project_id, 20)
def test_no_env(self): client = API() config = client._conf() self.assertEqual(config['email'], '*****@*****.**') self.assertEqual(config['key'], 'your_api_key') self.assertEqual(config['url'], 'https://<server>') self.assertEqual(client.verify_ssl, True)
class TestHTTPMethod(unittest.TestCase): def setUp(self): self.client = API() @mock.patch('testrail.api.requests.get') def test_get_ok(self, mock_get): mock_response = mock.Mock() return_value = { "announcement": "..", "completed_on": None, "id": 1, "is_completed": False, "name": "Datahub", "show_announcement": True, "url": "http://<server>/index.php?/projects/overview/1" } expected_response = copy.deepcopy(return_value) mock_response.json.return_value = return_value mock_response.status_code = 200 mock_get.return_value = mock_response url = 'https://<server>/index.php?/api/v2/get_project/1' actual_response = self.client._get('get_project/1') mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, auth=('*****@*****.**', 'your_api_key') ) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_bad_no_params(self, mock_get): mock_response = mock.Mock() expected_response = { 'url': 'https://<server>/index.php?/api/v2/get_plan/200', 'status_code': 400, 'payload': None, 'error': 'Invalid or unknown test plan' } url = 'https://<server>/index.php?/api/v2/get_plan/200' mock_response.json.return_value = { 'error': 'Invalid or unknown test plan' } mock_response.status_code = 400 mock_response.url = url mock_get.return_value = mock_response with self.assertRaises(TestRailError) as e: self.client._get('get_plan/200') mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, auth=('*****@*****.**', 'your_api_key') ) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, ast.literal_eval(str(e.exception)))
def setUp(self): self.client = API() self.mock_project_data = [{ "announcement": "..", "completed_on": None, "id": 1, "is_completed": False, "name": "Project1", "show_announcement": True, "url": "http://<server>/index.php?/projects/overview/1" }, { "announcement": "..", "completed_on": False, "id": 2, "is_completed": True, "name": "Project2", "show_announcement": True, "url": "http://<server>/index.php?/projects/overview/2" }] self.projects = copy.deepcopy(self.mock_project_data)
def test_key_env(self): key = 'itgiwiht84inf92GWT' os.environ['TESTRAIL_USER_KEY'] = key client = API() config = client._conf() self.assertEqual(config['email'], '*****@*****.**') self.assertEqual(config['key'], key) self.assertEqual(config['url'], 'https://<server>')
def test_url_env(self): url = 'https://example.com' os.environ['TESTRAIL_URL'] = url client = API() config = client._conf() self.assertEqual(config['email'], '*****@*****.**') self.assertEqual(config['key'], 'your_api_key') self.assertEqual(config['url'], url)
def test_user_env(self): email = '*****@*****.**' os.environ['TESTRAIL_USER_EMAIL'] = email client = API() config = client._conf() self.assertEqual(config['email'], email) self.assertEqual(config['key'], 'your_api_key') self.assertEqual(config['url'], 'https://<server>')
def setUp(self): API.flush_cache() self.mock_result_data = { 'assignedto_id': 1, 'comment': 'All steps passed', 'created_by': 2, 'created_on': 1453504099, 'defects': 'def1, def2, def3', 'elapsed': '1w 3d 6h 2m 30s', 'id': 3, 'status_id': 1, 'test_id': 5, 'version': '1.0RC' } self.mock_user_data = [{ "email": "*****@*****.**", "id": 1, "is_active": True, "name": "Han Solo" }, { "email": "*****@*****.**", "id": 2, "is_active": True, "name": "Jabba the Hutt" }] self.mock_status_data = [{ "color_bright": 12709313, "color_dark": 6667107, "color_medium": 9820525, "id": 1, "is_final": True, "is_system": True, "is_untested": True, "label": "Passed", "name": "passed" }] self.mock_test_data = [{ "assignedto_id": 1, "case_id": 1, "estimate": "1m 5s", "estimate_forecast": None, "id": 5, "priority_id": 2, "run_id": 1, "status_id": 5, "title": "Verify line spacing on multi-page document", "type_id": 4 }] self.result = Result(self.mock_result_data)
def test_plancontainer_created_by_error(self, mock_get): API.flush_cache() mock_response = mock.Mock() mock_response.json.side_effect = [ self.mock_plans_data, self.mock_users ] mock_response.status_code = 200 mock_get.return_value = mock_response user = 3 with self.assertRaises(TestRailError) as e: created_by = self.client.plans().created_by(user) self.assertEqual(str(e.exception), 'Must pass in a User object')
def setUp(self): self.client = API() self.client.set_project_id(1) self.mock_suites_data_1 = [{ "description": "..", "id": 1, "name": "Setup & Installation", "project_id": 1, "url": "http://<server>/index.php?/suites/view/1" }, { "description": "..", "id": 2, "name": "Setup & Installation", "project_id": 1, "url": "http://<server>/index.php?/suites/view/2" }] self.mock_suites_data_2 = [{ "description": "..", "id": 3, "name": "Setup & Installation", "project_id": 2, "url": "http://<server>/index.php?/suites/view/1" }, { "description": "..", "id": 4, "name": "Setup & Installation", "project_id": 2, "url": "http://<server>/index.php?/suites/view/2" }] self.suites_1 = copy.deepcopy(self.mock_suites_data_1) self.suites_2 = copy.deepcopy(self.mock_suites_data_2)
def test_plancontainer_created_by(self, mock_get): API.flush_cache() mock_response = mock.Mock() mock_response.json.side_effect = [ self.mock_plans_data, self.mock_users ] mock_response.status_code = 200 mock_get.return_value = mock_response user = User({'id': 3}) created_by = self.client.plans().created_by(user) self.assertTrue([lambda x: isinstance(x, Plan) for x in created_by]) self.assertEqual(len(created_by), 2) self.assertEqual(created_by[0].id, 33) self.assertEqual(created_by[1].id, 44)
def __init__(self, project_id=0, email=None, key=None, url=None, verify_ssl=True, proxies=None): self.api = API(email=email, key=key, url=url, verify_ssl=verify_ssl, proxies=proxies) self.api.set_project_id(project_id) self._project_id = project_id
def test_no_config_file(self): os.remove(self.config_path) key = 'itgiwiht84inf92GWT' email = '*****@*****.**' url = 'https://example.com' os.environ['TESTRAIL_URL'] = url os.environ['TESTRAIL_USER_KEY'] = key os.environ['TESTRAIL_USER_EMAIL'] = email client = API() config = client._conf() self.assertEqual(config['url'], url) self.assertEqual(config['key'], key) self.assertEqual(config['email'], email) self.assertEqual(client.verify_ssl, True)
def setUp(self): self.client = API() self.mock_user_data = [{ "email": "*****@*****.**", "id": 1, "is_active": 'true', "name": "Han Solo" }, { "email": "*****@*****.**", "id": 2, "is_active": 'true', "name": "Jabba the Hutt" }] self.users = copy.deepcopy(self.mock_user_data)
class Run(TestRailBase): def __init__(self, content=None): self._content = content or dict() self.api = API() @property def assigned_to(self): return User(self.api.user_with_id(self._content.get('assignedto_id'))) @property def blocked_count(self): return self._content.get('blocked_count') @property def cases(self): if self._content.get('case_ids'): cases = list(map(self.api.case_with_id, self._content.get('case_ids'))) return list(map(Case, cases)) else: return list() @cases.setter def cases(self, cases): exc_msg = 'cases must be set to None or a container of Case objects' if cases is None: self._content['case_ids'] = None elif not isinstance(cases, (list, tuple)): raise TestRailError(exc_msg) elif not all([isinstance(case, Case) for case in cases]):
def test_config_no_key(self): os.remove(self.config_path) shutil.copyfile('%s/testrail.conf-nokey' % self.test_dir, self.config_path) with self.assertRaises(TestRailError) as e: API() self.assertEqual(str(e.exception), ('A password or API key must be set in environment ' + 'variable TESTRAIL_USER_KEY or in ~/.testrail.conf'))
def test_config_no_url(self): os.remove(self.config_path) shutil.copyfile('%s/testrail.conf-nourl' % self.test_dir, self.config_path) with self.assertRaises(TestRailError) as e: API() self.assertEqual(str(e.exception), ('A URL must be set in environment ' + 'variable TESTRAIL_URL or in ~/.testrail.conf'))
def test_get_users_cache_timeout(self, mock_get): self.client = API() mock_response = mock.Mock() expected_response = self.users url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.users() timeout = self.client._timeout self.client._users['ts'] = datetime.now() - timedelta(seconds=timeout) actual_response = self.client.users() # verity cache timed out c = mock.call(url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) mock_get.assert_has_calls([c, mock.call().json()] * 2) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response)
def test_get_users_cache_timeout(self, mock_get): self.client = API() mock_response = mock.Mock() expected_response = copy.deepcopy(self.mock_user_data) url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.users() timeout = self.client._timeout self.client._users['ts'] = datetime.now() - timedelta(seconds=timeout) actual_response = self.client.users() # verity cache timed out mock_get.assert_called_twice_with( url, headers={'Content-Type': 'application/json'}, params=None, auth=('*****@*****.**', 'your_api_key') ) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response)
class Entry(TestRailBase): def __init__(self, content): self._content = content self._api = API() @property def id(self): return self._content.get('id') @property def name(self): return self._content.get('name') @property def runs(self): return list(map(EntryRun, self._content.get('runs'))) @property def suite(self): return Suite(self._api.suite_with_id(self._content.get('suite_id')))
def __init__(self, content): self._content = content self._api = API()
def setUp(self): self.client = API()
class TestUser(unittest.TestCase): def setUp(self): self.client = API() self.mock_user_data = [ { "email": "*****@*****.**", "id": 1, "is_active": 'true', "name": "Han Solo" }, { "email": "*****@*****.**", "id": 2, "is_active": 'true', "name": "Jabba the Hutt" } ] def tearDown(self): util.reset_shared_state(self.client) @mock.patch('testrail.api.requests.get') def test_get_users(self, mock_get): mock_response = mock.Mock() expected_response = copy.deepcopy(self.mock_user_data) url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.users() timeout = self.client._timeout # set timeout to 1 second from now delta = timedelta(seconds=timeout-1) self.client._users['ts'] = datetime.now() - delta actual_response = self.client.users() # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, auth=('*****@*****.**', 'your_api_key') ) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_users_cache_timeout(self, mock_get): self.client = API() mock_response = mock.Mock() expected_response = copy.deepcopy(self.mock_user_data) url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.users() timeout = self.client._timeout self.client._users['ts'] = datetime.now() - timedelta(seconds=timeout) actual_response = self.client.users() # verity cache timed out mock_get.assert_called_twice_with( url, headers={'Content-Type': 'application/json'}, params=None, auth=('*****@*****.**', 'your_api_key') ) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response)
class TestSuite(unittest.TestCase): def setUp(self): self.client = API() self.client.set_project_id(1) self.mock_suites_data_1 = [{ "description": "..", "id": 1, "name": "Setup & Installation", "project_id": 1, "url": "http://<server>/index.php?/suites/view/1" }, { "description": "..", "id": 2, "name": "Setup & Installation", "project_id": 1, "url": "http://<server>/index.php?/suites/view/2" }] self.mock_suites_data_2 = [{ "description": "..", "id": 3, "name": "Setup & Installation", "project_id": 2, "url": "http://<server>/index.php?/suites/view/1" }, { "description": "..", "id": 4, "name": "Setup & Installation", "project_id": 2, "url": "http://<server>/index.php?/suites/view/2" }] self.suites_1 = copy.deepcopy(self.mock_suites_data_1) self.suites_2 = copy.deepcopy(self.mock_suites_data_2) def tearDown(self): util.reset_shared_state(self.client) @mock.patch('testrail.api.requests.get') def test_get_suites(self, mock_get): mock_response = mock.Mock() expected_response = self.suites_1 url = 'https://<server>/index.php?/api/v2/get_suites/1' mock_response.json.return_value = self.mock_suites_data_1 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.suites() actual_response = self.client.suites() # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_suites_with_project(self, mock_get): mock_response = mock.Mock() expected_response = self.suites_2 url = 'https://<server>/index.php?/api/v2/get_suites/2' mock_response.json.return_value = self.mock_suites_data_2 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.suites(2) actual_response = self.client.suites(2) # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_suites_invalid_project(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = {} mock_response.status_code = 400 mock_get.return_value = mock_response with self.assertRaises(TestRailError): self.client.suites(20) @mock.patch('testrail.api.requests.get') def test_get_suites_cache_timeout(self, mock_get): mock_response = mock.Mock() expected_response = self.suites_1 url = 'https://<server>/index.php?/api/v2/get_suites/1' mock_response.json.return_value = self.mock_suites_data_1 mock_response.status_code = 200 mock_get.return_value = mock_response self.client.suites() timeout = self.client._timeout self.client._suites[1]['ts'] = datetime.now() - timedelta( seconds=timeout) actual_response = self.client.suites() # verify cache timeout c = mock.call(url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) mock_get.assert_has_calls([c, mock.call().json()] * 2) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_suites_different_projects_no_cache_hit(self, mock_get): mock_response = mock.Mock() expected_response = self.suites_1 url = 'https://<server>/index.php?/api/v2/get_suites/1' url2 = 'https://<server>/index.php?/api/v2/get_suites/2' mock_response.json.return_value = self.mock_suites_data_1 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.suites() actual_response = self.client.suites(2) # verify cache not hit c1 = mock.call(url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) c2 = mock.call(url2, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) mock_get.assert_has_calls( [c1, mock.call().json(), c2, mock.call().json()]) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_suite_with_id(self, mock_get): mock_response = mock.Mock() expected_response = next( filter(lambda x: x if x['id'] == 2 else None, self.suites_1)) url = 'https://<server>/index.php?/api/v2/get_suites/1' mock_response.json.return_value = self.mock_suites_data_1 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.suite_with_id(2) actual_response = self.client.suite_with_id(2) # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_suites_invalid_suite_id(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = {} mock_response.status_code = 200 mock_get.return_value = mock_response with self.assertRaises(TestRailError) as e: self.client.suite_with_id(20) self.assertEqual(str(e.exception), "Suite ID '20' was not found")
class TestRail(object): def __init__(self, project_id=0, email=None, key=None, url=None): self.api = API(email=email, key=key, url=url) self.api.set_project_id(project_id) self._project_id = project_id def set_project_id(self, project_id): self._project_id = project_id self.api.set_project_id(project_id) # Post generics @methdispatch def add(self, obj): raise NotImplementedError @methdispatch def update(self, obj): raise NotImplementedError @methdispatch def close(self, obj): raise NotImplementedError @methdispatch def delete(self, obj): raise NotImplementedError # Project Methods def projects(self): return ProjectContainer(list(map(Project, self.api.projects()))) @methdispatch def project(self): return Project() @project.register(str) @project.register(unicode) @singleresult def _project_by_name(self, name): return filter(lambda p: p.name == name, self.projects()) @project.register(int) @singleresult def _project_by_id(self, project_id): return filter(lambda p: p.id == project_id, self.projects()) # User Methods def users(self): return map(User, self.api.users()) @methdispatch def user(self): return User() @user.register(int) @singleresult def _user_by_id(self, identifier): return filter(lambda u: u.id == identifier, self.users()) @user.register(str) @user.register(unicode) @singleresult def _user_by_email_name(self, identifier): by_email = lambda u: u.email == identifier by_name = lambda u: u.name == identifier f = by_email if re.match('[^@]+@[^@]+\.[^@]+', identifier) else by_name return filter(f, self.users()) def active_users(self): return list(filter(lambda u: u.is_active is True, self.users())) def inactive_users(self): return list(filter(lambda u: u.is_active is False, self.users())) # Suite Methods def suites(self): return map(Suite, self.api.suites(self._project_id)) @methdispatch def suite(self): return Suite() @suite.register(str) @suite.register(unicode) @singleresult def _suite_by_name(self, name): return filter(lambda s: s.name.lower() == name.lower(), self.suites()) @suite.register(int) @singleresult def _suite_by_id(self, suite_id): return filter(lambda s: s.id == suite_id, self.suites()) def active_suites(self): return filter(lambda s: s.is_completed is False, self.suites()) def completed_suites(self): return filter(lambda s: s.is_completed is True, self.suites()) @add.register(Suite) def _add_suite(self, obj): obj.project = obj.project or self.project(self._project_id) return Suite(self.api.add_suite(obj.raw_data())) @update.register(Suite) def _update_suite(self, obj): return Suite(self.api.update_suite(obj.raw_data())) @delete.register(Suite) def _delete_suite(self, obj): return self.api.delete_suite(obj.id) # Milestone Methods def milestones(self): return map(Milestone, self.api.milestones(self._project_id)) @methdispatch def milestone(self): return Milestone() @milestone.register(str) @milestone.register(unicode) @singleresult def _milestone_by_name(self, name): return filter( lambda m: m.name.lower() == name.lower(), self.milestones()) @milestone.register(int) @singleresult def _milestone_by_id(self, milestone_id): return filter(lambda s: s.id == milestone_id, self.milestones()) @add.register(Milestone) def _add_milestone(self, obj): obj.project = obj.project or self.project(self._project_id) return Milestone(self.api.add_milestone(obj.raw_data())) @update.register(Milestone) def _update_milestone(self, obj): return Milestone(self.api.update_milestone(obj.raw_data())) @delete.register(Milestone) def _delete_milestone(self, obj): return self.api.delete_milestone(obj.id) # Plan Methods @methdispatch def plans(self): return PlanContainer(list(map(Plan, self.api.plans(self._project_id)))) @plans.register(Milestone) def _plans_for_milestone(self, obj): plans = filter(lambda p: p.milestone is not None, self.plans()) return PlanContainer(filter(lambda p: p.milestone.id == obj.id, plans)) @methdispatch def plan(self): return Plan() @plan.register(str) @plan.register(unicode) @singleresult def _plan_by_name(self, name): return filter(lambda p: p.name.lower() == name.lower(), self.plans()) @plan.register(int) @singleresult def _plan_by_id(self, plan_id): return filter(lambda p: p.id == plan_id, self.plans()) def completed_plans(self): return filter(lambda p: p.is_completed is True, self.plans()) def active_plans(self): return filter(lambda p: p.is_completed is False, self.plans()) @add.register(Plan) def _add_plan(self, obj, milestone=None): obj.project = obj.project or self.project(self._project_id) obj.milestone = milestone or obj.milestone return Plan(self.api.add_plan(obj.raw_data())) @update.register(Plan) def _update_plan(self, obj): return Plan(self.api.update_plan(obj.raw_data())) @close.register(Plan) def _close_plan(self, obj): return Plan(self.api.close_plan(obj.id)) @delete.register(Plan) def _delete_plan(self, obj): return self.api.delete_plan(obj.id) # Run Methods @methdispatch def runs(self): return RunContainer(list(map(Run, self.api.runs(self._project_id)))) @runs.register(Milestone) def _runs_for_milestone(self, obj): return RunContainer(filter( lambda r: r.milestone.id == obj.id, self.runs())) @runs.register(str) @runs.register(unicode) def _runs_by_name(self, name): # Returns all Runs that match :name, in descending order by ID runs = list(filter(lambda r: r.name.lower() == name.lower(), self.runs())) return sorted(runs, key=lambda r: r.id) @methdispatch def run(self): return Run() @run.register(str) @run.register(unicode) @singleresult def _run_by_name(self, name): # Returns the most recently created Run that matches :name runs = list(filter(lambda r: r.name.lower() == name.lower(), self.runs())) return sorted(runs, key=lambda r: r.id)[:1] @run.register(int) @singleresult def _run_by_id(self, run_id): filter(lambda p: p.id == run_id, self.runs()) @add.register(Run) def _add_run(self, obj): obj.project = obj.project or self.project(self._project_id) return Run(self.api.add_run(obj.raw_data())) @update.register(Run) def _update_run(self, obj): return Run(self.api.update_run(obj.raw_data())) @close.register(Run) def _close_run(self, obj): return Run(self.api.close_run(obj.id)) @delete.register(Run) def _delete_run(self, obj): return self.api.delete_run(obj.id) # Case Methods def cases(self, suite): return map(Case, self.api.cases(self._project_id, suite.id)) @methdispatch def case(self): return Case() @case.register(str) @case.register(unicode) @singleresult def _case_by_title(self, title, suite): return filter( lambda c: c.title.lower() == title.lower(), self.cases(suite)) @case.register(int) @singleresult def _case_by_id(self, case_id, suite=None): if suite is None: pass else: return filter(lambda c: c.id == case_id, self.cases(suite)) @add.register(Case) def _add_case(self, obj): return Case(self.api.add_case(obj.raw_data())) # Test Methods def tests(self, run): return map(Test, self.api.tests(run.id)) @methdispatch def test(self): return Test() @test.register(str) @test.register(unicode) @singleresult def _test_by_name(self, name): return filter(lambda t: t.name.lower() == name.lower(), self.tests()) @test.register(int) @singleresult def _test_by_id(self, test_id, run): return filter( lambda t: t.raw_data()['case_id'] == test_id, self.tests(run)) # Result Methods @methdispatch def results(self): raise TestRailError("Must request results by Run or Test") @results.register(Run) def _results_for_run(self, run): return ResultContainer(list(map(Result, self.api.results_by_run(run.id)))) @results.register(Test) def _results_for_test(self, test): return ResultContainer(list(map(Result, self.api.results_by_test(test.id)))) @methdispatch def result(self): return Result() @add.register(Result) def _add_result(self, obj): self.api.add_result(obj.raw_data()) @add.register(tuple) def _add_results(self, results): obj, value = results if isinstance(obj, Run): self.api.add_results(map(lambda x: x.raw_data(), value), obj.id) # Section Methods def sections(self, suite=None): return map(Section, self.api.sections(suite_id=suite.id)) @methdispatch def section(self): return Section() @section.register(int) def _section_by_id(self, section_id): return Section(self.api.section_with_id(section_id)) @section.register(unicode) @section.register(str) @singleresult def _section_by_name(self, name, suite=None): return filter(lambda s: s.name == name, self.sections(suite)) @add.register(Section) def _add_section(self, section): return Section(self.api.add_section(section.raw_data())) # Status Methods def statuses(self): return map(Status, self.api.statuses()) @methdispatch def status(self): return Status() @status.register(str) @status.register(unicode) @singleresult def _status_by_name(self, name): return filter(lambda s: s.name == name.lower(), self.statuses()) @status.register(int) @singleresult def _status_by_id(self, status_id): return filter(lambda s: s.id == status_id, self.statuses()) def configs(self): return ConfigContainer(map(Config, self.api.configs()))
def setUp(self): self.client = API() self.client.set_project_id(1) self.mock_plans_data_1 = [{ "id": 1, "name": "Test Plan #1", "is_completed": False, "description": "..", "project_id": 1, "milestone_id": 1, "url": "http://<server>/index.php?/plans/view/1", "assignedto_id": None, "blocked_count": 1, "completed_on": None, "created_by": 1, "created_on": 1393845644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }, { "id": 2, "name": "Test Plan #2", "is_completed": False, "description": "..", "project_id": 1, "milestone_id": 2, "url": "http://<server>/index.php?/plans/view/2", "assignedto_id": None, "blocked_count": 1, "completed_on": None, "created_by": 1, "created_on": 1393845644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }] self.mock_plans_data_2 = [{ "id": 3, "name": "Test Plan #3", "is_completed": False, "description": "..", "project_id": 2, "milestone_id": 3, "url": "http://<server>/index.php?/plans/view/3", "assignedto_id": 1, "blocked_count": 2, "completed_on": None, "created_by": 2, "created_on": 1393843644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }, { "id": 4, "name": "Test Plan #4", "is_completed": False, "description": "..", "project_id": 2, "milestone_id": 3, "url": "http://<server>/index.php?/plans/view/4", "assignedto_id": 1, "blocked_count": 2, "completed_on": None, "created_by": 2, "created_on": 1393843644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }] self.plans_1 = copy.deepcopy(self.mock_plans_data_1) self.plans_2 = copy.deepcopy(self.mock_plans_data_2)
class TestProject(unittest.TestCase): def setUp(self): self.client = API() self.mock_project_data = [{ "announcement": "..", "completed_on": None, "id": 1, "is_completed": False, "name": "Project1", "show_announcement": True, "url": "http://<server>/index.php?/projects/overview/1" }, { "announcement": "..", "completed_on": False, "id": 2, "is_completed": True, "name": "Project2", "show_announcement": True, "url": "http://<server>/index.php?/projects/overview/2" }] self.projects = copy.deepcopy(self.mock_project_data) def tearDown(self): util.reset_shared_state(self.client) @mock.patch('testrail.api.requests.get') def test_get_projects(self, mock_get): mock_response = mock.Mock() expected_response = self.projects url = 'https://<server>/index.php?/api/v2/get_projects' mock_response.json.return_value = self.mock_project_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.projects() timeout = self.client._timeout # set timeout to 1 second from now delta = timedelta(seconds=timeout - 1) self.client._users['ts'] = datetime.now() - delta actual_response = self.client.projects() # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_projects_cache_timeout(self, mock_get): mock_response = mock.Mock() expected_response = self.projects url = 'https://<server>/index.php?/api/v2/get_projects' mock_response.json.return_value = self.mock_project_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.projects() timeout = self.client._timeout self.client._projects['ts'] = datetime.now() - timedelta( seconds=timeout) actual_response = self.client.projects() # verify cache hit c = mock.call(url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) mock_get.assert_has_calls([c, mock.call().json()] * 2) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_project_id(self, mock_get): mock_response = mock.Mock() expected_response = next( filter(lambda x: x if x['id'] == 1 else None, self.projects)) url = 'https://<server>/index.php?/api/v2/get_projects' mock_response.json.return_value = self.mock_project_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.project_with_id(1) actual_response = self.client.project_with_id(1) # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_project_invalid_id(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = self.mock_project_data mock_response.status_code = 200 mock_get.return_value = mock_response with self.assertRaises(TestRailError) as e: self.client.project_with_id(300) err_msg = "Project ID '300' was not found" self.assertEqual(err_msg, str(e.exception))
class Case(TestRailBase): def __init__(self, content=None): self._content = content or dict() self.api = API() self._custom_methods = custom_methods(self._content) def __getattr__(self, attr): if attr in self._custom_methods: return self._content.get(self._custom_methods[attr]) raise AttributeError("'{}' object has no attribute '{}'".format( self.__class__.__name__, attr)) @property def created_by(self): user_id = self._content.get('created_by') return User(self.api.user_by_id(user_id)) @property def created_on(self): return datetime.fromtimestamp(int(self._content.get('created_on'))) @property def estimate(self): return self._content.get('estimate') @estimate.setter def estimate(self, value): #TODO should have some logic to validate format of timespa if not isinstance(value, (str, unicode)): raise TestRailError('input must be a string') self._content['estimate'] = value @property def estimated_forecast(self): return self._content.get('estimated_forecast') @property def id(self): return self._content.get('id') @property def milestone(self): m = self.api.milestone_with_id(self._content.get('milestone_id')) return Milestone(m) if m else Milestone() @milestone.setter def milestone(self, value): if not isinstance(value, Milestone): raise TestRailError('input must be a Milestone') self._content['milestone_id'] = value.id @property def priority(self): p = self.api.priority_with_id(self._content.get('priority_id')) return Priority(p) if p else Priority() @priority.setter def priority(self, value): if not isinstance(value, Priority): raise TestRailError('input must be a Priority') self._content['priority_id'] = value.id @property def refs(self): return self._content.get('refs').split(',') @refs.setter def refs(self, value): if not isinstance(value, list): raise TestRailError('input must be a list') self._content['refs'] = ','.join(value) @property def section(self): s = self.api.section_with_id(self._content.get('section_id')) return Section(s) if s else Section() @section.setter def section(self, value): if not isinstance(value, Section): raise TestRailError('input must be a Section') self._content['section_id'] = value.id @property def suite(self): s = self.api.suite_with_id(self._content.get('suite_id')) return Suite(s) if s else Suite() @property def title(self): return self._content.get('title') @title.setter def title(self, value): if not isinstance(value, (str, unicode)): raise TestRailError('input must be a string') self._content['title'] = value @property def type(self): t = self.api.case_type_with_id(self._content.get('type_id')) return CaseType(t) if t else CaseType() @type.setter def type(self, value): if not isinstance(value, CaseType): raise TestRailError('input must be a CaseType') self._content['type_id'] = value.id @property def updated_by(self): user_id = self._content.get('updated_by') return User(self.api.user_by_id(user_id)) @property def updated_on(self): return datetime.fromtimestamp(int(self._content.get('updated_on'))) @property def template(self): # we don't get the template, on needed as a setter raise NotImplementedError @template.setter def template(self, value): if not isinstance(value, Template): raise TestRailError('input must be a Template') self._content['template_id'] = value.id def raw_data(self): return self._content
class TestUser(unittest.TestCase): def setUp(self): self.client = API() self.mock_user_data = [{ "email": "*****@*****.**", "id": 1, "is_active": 'true', "name": "Han Solo" }, { "email": "*****@*****.**", "id": 2, "is_active": 'true', "name": "Jabba the Hutt" }] self.users = copy.deepcopy(self.mock_user_data) def tearDown(self): util.reset_shared_state(self.client) @mock.patch('testrail.api.requests.get') def test_get_users(self, mock_get): mock_response = mock.Mock() expected_response = self.users url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.users() timeout = self.client._timeout # set timeout to 1 second from now delta = timedelta(seconds=timeout - 1) self.client._users['ts'] = datetime.now() - delta actual_response = self.client.users() # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_users_cache_timeout(self, mock_get): self.client = API() mock_response = mock.Mock() expected_response = self.users url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.users() timeout = self.client._timeout self.client._users['ts'] = datetime.now() - timedelta(seconds=timeout) actual_response = self.client.users() # verity cache timed out c = mock.call(url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) mock_get.assert_has_calls([c, mock.call().json()] * 2) self.assertEqual(2, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_user_with_id(self, mock_get): mock_response = mock.Mock() expected_response = next( filter(lambda x: x if x['id'] == 2 else None, self.users)) url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.user_with_id(2) actual_response = self.client.user_with_id(2) # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_user_invalid_id(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response with self.assertRaises(TestRailError) as e: self.client.user_with_id(300) err_msg = "User ID '300' was not found" self.assertEqual(err_msg, str(e.exception)) @mock.patch('testrail.api.requests.get') def test_get_user_with_email(self, mock_get): mock_response = mock.Mock() expected_response = next( filter(lambda x: x if x['email'] == '*****@*****.**' else None, self.users)) url = 'https://<server>/index.php?/api/v2/get_users' mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.user_with_email('*****@*****.**') # verify cache hit actual_response = self.client.user_with_email('*****@*****.**') mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_user_invalid_email(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = self.mock_user_data mock_response.status_code = 200 mock_get.return_value = mock_response with self.assertRaises(TestRailError) as e: self.client.user_with_email('*****@*****.**') err_msg = "User email '*****@*****.**' was not found" self.assertEqual(err_msg, str(e.exception))
def __init__(self, content=None): self._content = content or dict() self.api = API() self._custom_methods = custom_methods(self._content)
def test_ssl_env(self): os.environ['TESTRAIL_VERIFY_SSL'] = 'False' client = API() self.assertEqual(client.verify_ssl, False)
def __init__(self, project_id=0, email=None, key=None, url=None): self.api = API(email=email, key=key, url=url) self.api.set_project_id(project_id) self._project_id = project_id
class TestPlan(unittest.TestCase): def setUp(self): self.client = API() self.client.set_project_id(1) self.mock_plans_data_1 = [{ "id": 1, "name": "Test Plan #1", "is_completed": False, "description": "..", "project_id": 1, "milestone_id": 1, "url": "http://<server>/index.php?/plans/view/1", "assignedto_id": None, "blocked_count": 1, "completed_on": None, "created_by": 1, "created_on": 1393845644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }, { "id": 2, "name": "Test Plan #2", "is_completed": False, "description": "..", "project_id": 1, "milestone_id": 2, "url": "http://<server>/index.php?/plans/view/2", "assignedto_id": None, "blocked_count": 1, "completed_on": None, "created_by": 1, "created_on": 1393845644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }] self.mock_plans_data_2 = [{ "id": 3, "name": "Test Plan #3", "is_completed": False, "description": "..", "project_id": 2, "milestone_id": 3, "url": "http://<server>/index.php?/plans/view/3", "assignedto_id": 1, "blocked_count": 2, "completed_on": None, "created_by": 2, "created_on": 1393843644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }, { "id": 4, "name": "Test Plan #4", "is_completed": False, "description": "..", "project_id": 2, "milestone_id": 3, "url": "http://<server>/index.php?/plans/view/4", "assignedto_id": 1, "blocked_count": 2, "completed_on": None, "created_by": 2, "created_on": 1393843644, "untested_count": 6, "passed_count": 5, "failed_count": 2, "entries": [] }] self.plans_1 = copy.deepcopy(self.mock_plans_data_1) self.plans_2 = copy.deepcopy(self.mock_plans_data_2) def tearDown(self): util.reset_shared_state(self.client) @mock.patch('testrail.api.requests.get') def test_get_plans(self, mock_get): mock_response = mock.Mock() expected_response = self.plans_1 url = "https://<server>/index.php?/api/v2/get_plans/1" mock_response.json.return_value = self.mock_plans_data_1 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.plans() actual_response = self.client.plans() # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_plans_with_project(self, mock_get): mock_response = mock.Mock() expected_response = self.plans_2 url = "https://<server>/index.php?/api/v2/get_plans/2" mock_response.json.return_value = self.mock_plans_data_2 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.plans(2) actual_response = self.client.plans(2) # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_plans_invalid_project(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = {} mock_response.status_code = 400 mock_get.return_value = mock_response with self.assertRaises(TestRailError): self.client.plans(20) @mock.patch('testrail.api.requests.get') def test_get_plan_with_id(self, mock_get): mock_response = mock.Mock() expected_response = next( filter(lambda x: x if x['id'] == 2 else None, self.plans_1)) url = 'https://<server>/index.php?/api/v2/get_plans/1' mock_response.json.return_value = self.mock_plans_data_1 mock_response.status_code = 200 mock_get.return_value = mock_response actual_response = self.client.plan_with_id(2) actual_response = self.client.plan_with_id(2) # verify cache hit mock_get.assert_called_once_with( url, headers={'Content-Type': 'application/json'}, params=None, verify=True, auth=('*****@*****.**', 'your_api_key')) self.assertEqual(1, mock_response.json.call_count) self.assertEqual(expected_response, actual_response) @mock.patch('testrail.api.requests.get') def test_get_plans_invalid_suite_id(self, mock_get): mock_response = mock.Mock() mock_response.json.return_value = {} mock_response.status_code = 200 mock_get.return_value = mock_response with self.assertRaises(TestRailError) as e: self.client.plan_with_id(30) self.assertEqual(str(e.exception), "Plan ID '30' was not found")