"""Unit tests for the client.evergreen module.""" import datetime import unittest import requests from mock import Mock, MagicMock, call, mock_open, patch import buildscripts.client.evergreen as evergreen # pylint: disable=missing-docstring,protected-access,attribute-defined-outside-init,too-many-instance-attributes EVERGREEN = "buildscripts.client.evergreen" class TestReadEvgConfig(unittest.TestCase): def test_read_evg_config(self): evg_yaml = "data1: val1\ndata2: val2" with patch("os.path.isfile", return_value=True),\ patch(EVERGREEN + ".open", mock_open(read_data=evg_yaml)): evg_config = evergreen.read_evg_config() self.assertEqual(evg_config["data1"], "val1") self.assertEqual(evg_config["data2"], "val2") def test_read_evg_config_file_order(self): with patch("os.path.isfile", return_value=False) as mock_isfile,\ patch("os.path.expanduser", side_effect=(lambda path: path)): self.assertIsNone(evergreen.read_evg_config()) self.assertEqual(mock_isfile.call_count, len(evergreen.EVERGREEN_FILES)) calls = [call(evg_file) for evg_file in evergreen.EVERGREEN_FILES] mock_isfile.assert_has_calls(calls) def test_read_evg_config_file_not_found(self): with patch("os.path.isfile", return_value=False): self.assertIsNone(evergreen.read_evg_config()) def test_read_evg_config_last_file(self): evg_files = {"path1": False, "path2": False, "path3": True} evg_paths = ["path1", "path2", "path3"] evg_yaml = "data1: val1\ndata2: val2" with patch("os.path.isfile", lambda path: evg_files[path]),\ patch(EVERGREEN + ".open", mock_open(read_data=evg_yaml)) as mock_openfile,\ patch(EVERGREEN + ".EVERGREEN_FILES", evg_paths): evg_config = evergreen.read_evg_config() mock_openfile.assert_called_once_with("path3", "r") self.assertEqual(evg_config["data1"], "val1") self.assertEqual(evg_config["data2"], "val2") class TestGetEvergreenHeaders(unittest.TestCase): def test_get_evergreen_headers(self): api_key = "mykey" user = "me" evg_config = {"api_key": api_key, "user": user} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_headers = evergreen.get_evergreen_headers() self.assertEqual(api_key, api_headers["api-key"]) self.assertEqual(user, api_headers["api-user"]) def test_get_evergreen_headers_none(self): with patch(EVERGREEN + ".read_evg_config", return_value=None): api_headers = evergreen.get_evergreen_headers() self.assertDictEqual({}, api_headers) def test_get_evergreen_headers_no_data(self): evg_config = {} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_headers = evergreen.get_evergreen_headers() self.assertDictEqual(evg_config, api_headers) def test_get_evergreen_headers_no_user(self): data_key = "data1" data_val = "val1" api_key = "mykey" evg_config = {"api_key": api_key, data_key: data_val} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_headers = evergreen.get_evergreen_headers() self.assertEqual(api_key, api_headers["api-key"]) self.assertNotIn("user", api_headers) self.assertNotIn(data_key, api_headers) def test_get_evergreen_headers_no_api_key(self): data_key = "data1" data_val = "val1" user = "me" evg_config = {"user": user, data_key: data_val} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_headers = evergreen.get_evergreen_headers() self.assertEqual(user, api_headers["api-user"]) self.assertNotIn("api-key", api_headers) self.assertNotIn(data_key, api_headers) class TestGetEvergreenServer(unittest.TestCase): def test_get_evergreen_server(self): api_server_host = "https://myevergreen.com" evg_config = {"api_server_host": api_server_host} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_server = evergreen.get_evergreen_server() self.assertEqual(api_server_host, api_server) def test_get_evergreen_server_none(self): with patch(EVERGREEN + ".read_evg_config", return_value=None): api_server = evergreen.get_evergreen_server() self.assertEqual(evergreen.DEFAULT_API_SERVER, api_server) def test_get_evergreen_server_default(self): evg_config = {} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_server = evergreen.get_evergreen_server() self.assertEqual(evergreen.DEFAULT_API_SERVER, api_server) def test_get_evergreen_server_other_data(self): evg_config = {"api_server_host_bad": "bad"} with patch(EVERGREEN + ".read_evg_config", return_value=evg_config): api_server = evergreen.get_evergreen_server() self.assertEqual(evergreen.DEFAULT_API_SERVER, api_server) class TestGetEvergreenApi(unittest.TestCase): def test_get_evergreen_api(self): api_server = "https://myserver.com" with patch(EVERGREEN + ".get_evergreen_server", return_value=api_server): evg_api = evergreen.get_evergreen_api() self.assertEqual(api_server, evg_api.api_server) self.assertIsNone(evg_api.api_headers) class TestGetHistory(unittest.TestCase): def test_get_history(self): evg_api = evergreen.EvergreenApi() json_data = {"history1": "val1", "history2": "val2"} project = "myproject" params = {"param1": "pval1", "param2": "pval2"} with patch("requests.get") as mock_req_get: mock_req_get.return_value.json.return_value = json_data history_data = evg_api.get_history(project, params) self.assertDictEqual(history_data, json_data) actual_url = mock_req_get.call_args[1]["url"] actual_params = mock_req_get.call_args[1]["params"] self.assertIn(project, actual_url) self.assertIn("test_history", actual_url) self.assertDictEqual(params, actual_params) def test_get_history_raise_for_status(self): evg_api = evergreen.EvergreenApi() project = "myproject" params = {"param1": "pval1", "param2": "pval2"} with patch("requests.get") as mock_req_get: mock_req_get.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError() with self.assertRaises(requests.exceptions.HTTPError): evg_api.get_history(project, params) class TestGetEvergreenApiV2(unittest.TestCase): def test_get_evergreen_api(self): api_server = "https://myserver.com" api_headers = {"header1": "val1", "header2": "val2"} with patch(EVERGREEN + ".get_evergreen_server", return_value=api_server),\ patch(EVERGREEN + ".get_evergreen_headers", return_value=api_headers): evg_api = evergreen.get_evergreen_apiv2() self.assertEqual(api_server, evg_api.api_server) self.assertDictEqual(api_headers, evg_api.api_headers) def test_get_evergreen_api_kwargs(self): api_server = "https://myserver.com" api_headers = {"header1": "val1", "header2": "val2"} num_retries = 99 with patch(EVERGREEN + ".get_evergreen_server", return_value=api_server),\ patch(EVERGREEN + ".get_evergreen_headers", return_value=api_headers): evg_api = evergreen.get_evergreen_apiv2(num_retries=num_retries) self.assertEqual(api_server, evg_api.api_server) self.assertDictEqual(api_headers, evg_api.api_headers) def test_get_evergreen_api_kwargs_override(self): api_server = "https://myserver.com" api_headers = {"header1": "val1", "header2": "val2"} api_server_override = "https://myserver_override.com" api_headers_override = {"header1_override": "val1", "header2_override": "val2"} num_retries = 99 with patch(EVERGREEN + ".get_evergreen_server", return_value=api_server),\ patch(EVERGREEN + ".get_evergreen_headers", return_value=api_headers): with self.assertRaises(TypeError): evergreen.get_evergreen_apiv2(api_server=api_server_override, api_headers=api_headers_override, num_retries=num_retries) def test_get_evergreen_api_bad_kwargs(self): api_server = "https://myserver.com" api_headers = {"header1": "val1", "header2": "val2"} with patch(EVERGREEN + ".get_evergreen_server", return_value=api_server),\ patch(EVERGREEN + ".get_evergreen_headers", return_value=api_headers): with self.assertRaises(TypeError): evergreen.get_evergreen_apiv2(kw1="kw1") class TestCheckType(unittest.TestCase): def test___check_type(self): evergreen._check_type([1, 3], list) evergreen._check_type({"a": 3}, dict) evergreen._check_type("x", str) with self.assertRaises(TypeError): evergreen._check_type({}, list) with self.assertRaises(TypeError): evergreen._check_type([], str) class TestAddListParam(unittest.TestCase): def test__add_list_param(self): params = {} param_name = "myparam" param_list = ["a", "b", "c"] evergreen._add_list_param(params, param_name, param_list) self.assertDictEqual({param_name: ",".join(param_list)}, params) def test__add_list_param_one_item(self): params = {} param_name = "myparam" param_list = ["abc"] evergreen._add_list_param(params, param_name, param_list) self.assertDictEqual({param_name: "abc"}, params) def test__add_list_param_no_list(self): params = {"param1": "abc"} param_name = "myparam" param_list = [] evergreen._add_list_param(params, param_name, param_list) self.assertDictEqual({"param1": "abc"}, params) def test__add_list_param_exists(self): params = {"param1": "abc"} param_name = "param1" param_list = ["x", "y", "z"] with self.assertRaises(RuntimeError): evergreen._add_list_param(params, param_name, param_list) def test__add_list_param_extend(self): params = {"param1": "abc"} param_name = "param2" param_list = ["x", "y", "z"] evergreen._add_list_param(params, param_name, param_list) self.assertDictEqual({"param1": "abc", param_name: ",".join(param_list)}, params) def test__add_list_param_bad_type(self): params = {"param1": "abc"} param_name = "param2" param_list = "mystring" with self.assertRaises(TypeError): evergreen._add_list_param(params, param_name, param_list) def test__add_list_param_none(self): params = {"param1": "abc"} param_name = "param2" param_list = None evergreen._add_list_param(params, param_name, param_list) self.assertDictEqual({"param1": "abc"}, params) class MockEvgApiV2(evergreen.EvergreenApiV2): def __init__(self): #pylint: disable=super-init-not-called self.api_server = "http://myserver.com" self.session = MagicMock() class MyTime(object): def __init__(self, start_time=0, increment=1): self.time = start_time self.increment = increment def cur_time(self): cur_time = self.time self.time += self.increment return cur_time class TestEvergreenApiV2CallApi(unittest.TestCase): def test__call_api(self): url = "https://myurl.com" params = {} response = MagicMock() mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2.session.get.return_value = response self.assertEqual(response, mock_evgapiv2._call_api(url, params)) def test__call_api_long_request(self): url = "https://myurl.com" params = {} response = MagicMock() mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2.session.get.return_value = response increment = 11 mytime = MyTime(increment=increment) with patch("time.time", mytime.cur_time): self.assertEqual(response, mock_evgapiv2._call_api(url, params)) def test__call_api_http_error(self): url = "https://myurl.com" params = {} response = MagicMock() response.raise_for_status.side_effect = requests.exceptions.HTTPError mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2.session.get.return_value = response with self.assertRaises(requests.exceptions.HTTPError): mock_evgapiv2._call_api(url, params) class MockApi(object): def __init__(self, page_results): self._page_idx = 0 self._page_results = page_results def _call_api(self, _url, _params=None): if self._page_idx >= len(self._page_results): raise requests.exceptions.HTTPError response = MagicMock() response.json = MagicMock(return_value=self._page_results[self._page_idx]) self._page_idx += 1 return response def _get_next_url(self, _): return None if self._page_idx == len(self._page_results) else self._page_idx class MockPaginate(object): def __init__(self, page_results): self._page_results = page_results def _paginate(self, url, params=None): self._url = url self._params = params return list(self._paginate_gen(url, params)) def _paginate_gen(self, url, params=None): self._url = url self._params = params for page_result in self._page_results: if isinstance(page_result, list): for result in page_result: yield result else: yield page_result class TestEvergreenApiV2Paginate(unittest.TestCase): def test___paginate_one_page_non_list(self): json_list = [{"key1": "val1", "key2": "val2"}] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = mock_evgapiv2._paginate("https://myurl", None) self.assertEqual(len(all_json_data), 1) self.assertListEqual(all_json_data, json_list) self.assertEqual(mock_api._page_idx, 1) def test___paginate_multi_pages_non_list(self): json_list = [{"key1": "val1"}, {"key2": "val2"}] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = mock_evgapiv2._paginate("https://myurl", None) self.assertEqual(len(all_json_data), 2) self.assertListEqual(all_json_data, json_list) self.assertEqual(mock_api._page_idx, 2) def test___paginate_one_page_multiple_items(self): json_list = [[{"key1": "val1"}, {"key2": "val2"}]] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = mock_evgapiv2._paginate("https://myurl", {"param1": "myparam"}) self.assertEqual(len(all_json_data), 2) self.assertListEqual(all_json_data, json_list[0]) self.assertEqual(mock_api._page_idx, 1) def test___paginate_multi_pages(self): json_list = [[{"key1": "val1"}, {"key2": "val2"}], [{"key3": "val3"}, {"key4": "val4"}], [{"key5": "val5"}]] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = mock_evgapiv2._paginate("https://myurl", None) self.assertEqual(len(all_json_data), 5) self.assertEqual(mock_api._page_idx, 3) for idx, json_data in enumerate([l for sub_list in json_list for l in sub_list]): self.assertEqual(all_json_data[idx], json_data) class TestEvergreenApiV2PaginateGen(unittest.TestCase): def test___paginate_gen_one_page(self): json_list = [{"key1": "val1", "key2": "val2"}] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = list(mock_evgapiv2._paginate_gen("https://myurl", None)) self.assertEqual(len(all_json_data), 1) self.assertListEqual(all_json_data, json_list) self.assertEqual(mock_api._page_idx, 1) def test___paginate_gen_multi_pages_non_list(self): json_list = [{"key1": "val1"}, {"key2": "val2"}] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = list(mock_evgapiv2._paginate_gen("https://myurl", None)) self.assertEqual(len(all_json_data), 2) self.assertListEqual(all_json_data, json_list) self.assertEqual(mock_api._page_idx, 2) def test___paginate_gen_multi_pages_no_response(self): mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._call_api = lambda url, params: None all_json_data = list(mock_evgapiv2._paginate_gen("https://myurl", None)) self.assertEqual(len(all_json_data), 0) def test___paginate_gen_one_page_multiple_items(self): json_list = [[{"key1": "val1"}, {"key2": "val2"}]] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = list(mock_evgapiv2._paginate_gen("https://myurl", {"param1": "myparam"})) self.assertEqual(len(all_json_data), 2) self.assertListEqual(all_json_data, json_list[0]) self.assertEqual(mock_api._page_idx, 1) def test___paginate_gen_multi_pages(self): json_list = [[{"key1": "val1"}, {"key2": "val2"}], [{"key3": "val3"}, {"key4": "val4"}], [{"key5": "val5"}]] mock_evgapiv2 = MockEvgApiV2() mock_api = MockApi(json_list) mock_evgapiv2._call_api = mock_api._call_api mock_evgapiv2._get_next_url = mock_api._get_next_url all_json_data = list(mock_evgapiv2._paginate_gen("https://myurl", None)) self.assertEqual(len(all_json_data), 5) self.assertEqual(mock_api._page_idx, 3) for idx, json_data in enumerate([l for sub_list in json_list for l in sub_list]): self.assertEqual(all_json_data[idx], json_data) class TestEvergreenApiV2GetNextUrl(unittest.TestCase): def test__get_next_url(self): response = Mock() url = "http://myurl.com?q1=a,b,c&q2=xyz" response.links = {"next": {"url": url}} self.assertEqual(evergreen.EvergreenApiV2._get_next_url(response), url) def test__get_next_url_no_url(self): response = Mock() response.links = {"next": {"noturl": "abc"}} self.assertIsNone(evergreen.EvergreenApiV2._get_next_url(response)) def test__get_next_url_no_next(self): response = Mock() response.links = {} self.assertIsNone(evergreen.EvergreenApiV2._get_next_url(response)) class TestEvergreenApiV2TestsByTask(unittest.TestCase): def test_tests_by_task(self): json_list = [{"task1": ["test1", "test2"]}] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate = paginate._paginate task_id = "task1" execution = 909 all_json_data = mock_evgapiv2.tests_by_task(task_id, execution) self.assertListEqual(json_list, all_json_data) self.assertIn(task_id, paginate._url) self.assertIn("execution", paginate._params) self.assertEqual(paginate._params["execution"], execution) def test_tests_by_task_limit(self): json_list = [{"task2": ["test1a", "test2c"]}] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate = paginate._paginate task_id = "task1" execution = 209 limit = 50 all_json_data = mock_evgapiv2.tests_by_task(task_id, execution, limit=limit) self.assertListEqual(json_list, all_json_data) self.assertIn(task_id, paginate._url) self.assertIn("execution", paginate._params) self.assertEqual(paginate._params["execution"], execution) self.assertIn("limit", paginate._params) self.assertEqual(paginate._params["limit"], limit) def test_tests_by_task_status(self): json_list = [{"task1b": ["test13", "test27"]}] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate = paginate._paginate task_id = "task1" execution = 75 limit = 250 status = "passed" all_json_data = mock_evgapiv2.tests_by_task(task_id, execution, limit=limit, status=status) self.assertListEqual(json_list, all_json_data) self.assertIn(task_id, paginate._url) self.assertIn("execution", paginate._params) self.assertEqual(paginate._params["execution"], execution) self.assertIn("limit", paginate._params) self.assertEqual(paginate._params["limit"], limit) self.assertIn("status", paginate._params) self.assertEqual(paginate._params["status"], status) class TestEvergreenApiV2ProjectPatchesGen(unittest.TestCase): def test_project_patches_gen(self): json_list = [[{"create_time": "2019-01-01", "data": "mydata1"}, {"create_time": "2018-12-01", "data": "mydata2"}]] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate_gen = paginate._paginate_gen project = "myproject" all_json_data = list(mock_evgapiv2.project_patches_gen(project)) self.assertEqual(len(all_json_data), 2) self.assertListEqual(json_list[0], all_json_data) self.assertIn(project, paginate._url) def test_project_patches_gen_days_limit(self): limit = 1 json_list = [[{"create_time": "2016-01-01", "data": "mydata1"}, {"create_time": "2017-12-01", "data": "mydata2"}, {"create_time": "2018-01-01", "data": "mydata3"}]] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate_gen = paginate._paginate_gen project = "myproject2" all_json_data = list(mock_evgapiv2.project_patches_gen(project, limit=limit)) self.assertEqual(len(all_json_data), 3) for idx, json_data in enumerate(all_json_data): self.assertDictEqual(json_list[0][idx], json_data) self.assertIn("limit", paginate._params) self.assertIn(project, paginate._url) self.assertEqual(paginate._params["limit"], limit) def test_project_patches_gen_multi_page(self): json_list = [{"create_time": "2015-01-01", "data": "mydata12"}, {"create_time": "2016-12-01", "data": "mydata22"}] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate_gen = paginate._paginate_gen project = "myproject3" all_json_data = list(mock_evgapiv2.project_patches_gen(project)) self.assertEqual(len(all_json_data), 2) self.assertDictEqual(json_list[0], all_json_data[0]) self.assertIn(project, paginate._url) def test_project_patches_gen_no_results(self): json_list = [[]] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate_gen = paginate._paginate_gen project = "myproject4" all_json_data = list(mock_evgapiv2.project_patches_gen(project)) self.assertEqual(len(all_json_data), 0) self.assertIn(project, paginate._url) class TestEvergreenApiV2VersionBuilds(unittest.TestCase): def test_version_builds(self): json_list = [[{"build1": {"build_data": ["a.js"]}}, {"build2": {"build_data": ["b.js"]}}]] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate = paginate._paginate version = "version1" all_json_data = mock_evgapiv2.version_builds(version) self.assertEqual(len(all_json_data), 2) for idx, json_data in enumerate(all_json_data): self.assertDictEqual(json_list[0][idx], json_data) self.assertIn(version, paginate._url) self.assertIsNone(paginate._params) def test_version_builds_gen_multi_page(self): json_list = [[{"build1": {"build_data": ["a.js"]}}, {"build2": {"build_data": ["b.js"]}}], [{"build3": {"build_data": ["c.js"]}}]] paginate = MockPaginate(json_list) mock_evgapiv2 = MockEvgApiV2() mock_evgapiv2._paginate = paginate._paginate version = "version1" all_json_data = mock_evgapiv2.version_builds(version) self.assertEqual(len(all_json_data), 3) json_data_list = [l for sub_list in json_list for l in sub_list] for idx, json_data in enumerate(all_json_data): self.assertDictEqual(json_data_list[idx], json_data) self.assertIn(version, paginate._url) self.assertIsNone(paginate._params)