From c457718a4d2f323e3ff30bcd44a4bbec2e30d5cf Mon Sep 17 00:00:00 2001 From: Jamie Lennox Date: Thu, 1 Sep 2016 14:43:38 +0800 Subject: [PATCH] Use requests-mock for testing Instead of directly mocking out the HTTPClient use requests-mock to stub the information that is going over the wire instead of what is being passed to HTTPClient. This ensures that the HTTPClient is always tested as well. Change-Id: I988fb432ced6d4946ab5301ac58fa0d7148bbb79 --- mistralclient/tests/unit/base.py | 50 +----- mistralclient/tests/unit/v2/base.py | 5 +- .../tests/unit/v2/test_action_executions.py | 35 ++--- mistralclient/tests/unit/v2/test_actions.py | 148 ++++++++---------- .../tests/unit/v2/test_environments.py | 35 +++-- .../tests/unit/v2/test_executions.py | 66 ++++---- mistralclient/tests/unit/v2/test_members.py | 36 ++--- mistralclient/tests/unit/v2/test_services.py | 5 +- mistralclient/tests/unit/v2/test_tasks.py | 67 ++++---- mistralclient/tests/unit/v2/test_workbooks.py | 117 +++++++------- mistralclient/tests/unit/v2/test_workflows.py | 92 +++++------ test-requirements.txt | 1 + 12 files changed, 293 insertions(+), 364 deletions(-) diff --git a/mistralclient/tests/unit/base.py b/mistralclient/tests/unit/base.py index e64b3a37..32a0023d 100644 --- a/mistralclient/tests/unit/base.py +++ b/mistralclient/tests/unit/base.py @@ -12,59 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json - import mock from oslotest import base - - -class FakeResponse(object): - """Fake response for testing Mistral Client.""" - - def __init__(self, status_code, content=None): - self.status_code = status_code - self.content = content - self.headers = {} - - def json(self): - return json.loads(self.content) +from requests_mock.contrib import fixture class BaseClientTest(base.BaseTestCase): _client = None - def mock_http_get(self, content, status_code=200): - if isinstance(content, dict): - content = json.dumps(content) - - self._client.http_client.get = mock.MagicMock( - return_value=FakeResponse(status_code, content)) - - return self._client.http_client.get - - def mock_http_post(self, content, status_code=201): - if isinstance(content, dict): - content = json.dumps(content) - - self._client.http_client.post = mock.MagicMock( - return_value=FakeResponse(status_code, content)) - - return self._client.http_client.post - - def mock_http_put(self, content, status_code=200): - if isinstance(content, dict): - content = json.dumps(content) - - self._client.http_client.put = mock.MagicMock( - return_value=FakeResponse(status_code, content)) - - return self._client.http_client.put - - def mock_http_delete(self, status_code=204): - self._client.http_client.delete = mock.MagicMock( - return_value=FakeResponse(status_code)) - - return self._client.http_client.delete + def setUp(self): + super(BaseClientTest, self).setUp() + self.requests_mock = self.useFixture(fixture.Fixture()) class BaseCommandTest(base.BaseTestCase): diff --git a/mistralclient/tests/unit/v2/base.py b/mistralclient/tests/unit/v2/base.py index 68c00e28..ef4f0607 100644 --- a/mistralclient/tests/unit/v2/base.py +++ b/mistralclient/tests/unit/v2/base.py @@ -18,11 +18,14 @@ from mistralclient.tests.unit import base class BaseClientV2Test(base.BaseClientTest): + + TEST_URL = 'http://mistral.example.com' + def setUp(self): super(BaseClientV2Test, self).setUp() self._client = client.Client(project_name="test", - mistral_url="test") + mistral_url=self.TEST_URL) self.workbooks = self._client.workbooks self.executions = self._client.executions self.tasks = self._client.tasks diff --git a/mistralclient/tests/unit/v2/test_action_executions.py b/mistralclient/tests/unit/v2/test_action_executions.py index 985dcb14..f47a9887 100644 --- a/mistralclient/tests/unit/v2/test_action_executions.py +++ b/mistralclient/tests/unit/v2/test_action_executions.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json - from mistralclient.api.v2 import action_executions from mistralclient.tests.unit.v2 import base @@ -33,7 +31,10 @@ URL_TEMPLATE_ID = '/action_executions/%s' class TestActionExecutions(base.BaseClientV2Test): def test_create(self): - mock = self.mock_http_post(content=ACTION_EXEC) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json=ACTION_EXEC, + status_code=201) + body = { 'name': ACTION_EXEC['name'] } @@ -48,10 +49,12 @@ class TestActionExecutions(base.BaseClientV2Test): self.action_executions, ACTION_EXEC ).to_dict(), action_execution.to_dict()) - mock.assert_called_once_with(URL_TEMPLATE, json.dumps(body)) + self.assertEqual(body, self.requests_mock.last_request.json()) def test_update(self): - mock = self.mock_http_put(content=ACTION_EXEC) + url = self.TEST_URL + URL_TEMPLATE_ID % ACTION_EXEC['id'] + self.requests_mock.put(url, json=ACTION_EXEC) + body = { 'state': ACTION_EXEC['state'] } @@ -73,15 +76,11 @@ class TestActionExecutions(base.BaseClientV2Test): action_execution.to_dict() ) - mock.assert_called_once_with( - URL_TEMPLATE_ID % ACTION_EXEC['id'], - json.dumps(body) - ) + self.assertEqual(body, self.requests_mock.last_request.json()) def test_list(self): - mock = self.mock_http_get( - content={'action_executions': [ACTION_EXEC]} - ) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'action_executions': [ACTION_EXEC]}) action_execution_list = self.action_executions.list() @@ -95,10 +94,9 @@ class TestActionExecutions(base.BaseClientV2Test): self.assertEqual(expected, action_execution.to_dict()) - mock.assert_called_once_with(URL_TEMPLATE) - def test_get(self): - mock = self.mock_http_get(content=ACTION_EXEC) + url = self.TEST_URL + URL_TEMPLATE_ID % ACTION_EXEC['id'] + self.requests_mock.get(url, json=ACTION_EXEC) action_execution = self.action_executions.get(ACTION_EXEC['id']) @@ -109,11 +107,8 @@ class TestActionExecutions(base.BaseClientV2Test): self.assertEqual(expected, action_execution.to_dict()) - mock.assert_called_once_with(URL_TEMPLATE_ID % ACTION_EXEC['id']) - def test_delete(self): - mock = self.mock_http_delete(status_code=204) + url = self.TEST_URL + URL_TEMPLATE_ID % ACTION_EXEC['id'] + self.requests_mock.delete(url, status_code=204) self.action_executions.delete(ACTION_EXEC['id']) - - mock.assert_called_once_with(URL_TEMPLATE_ID % ACTION_EXEC['id']) diff --git a/mistralclient/tests/unit/v2/test_actions.py b/mistralclient/tests/unit/v2/test_actions.py index 8e9ca62a..8eb4cb3d 100644 --- a/mistralclient/tests/unit/v2/test_actions.py +++ b/mistralclient/tests/unit/v2/test_actions.py @@ -61,21 +61,23 @@ URL_TEMPLATE_VALIDATE = '/actions/validate' class TestActionsV2(base.BaseClientV2Test): def test_create(self): - mock = self.mock_http_post(content={'actions': [ACTION]}) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json={'actions': [ACTION]}, + status_code=201) actions = self.actions.create(ACTION_DEF) self.assertIsNotNone(actions) self.assertEqual(ACTION_DEF, actions[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + self.assertEqual('text/plain', last_request.headers['content-type']) + self.assertEqual(ACTION_DEF, last_request.text) def test_create_with_file(self): - mock = self.mock_http_post(content={'actions': [ACTION]}) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json={'actions': [ACTION]}, + status_code=201) # The contents of action_v2.yaml must be identical to ACTION_DEF path = pkg.resource_filename( @@ -88,42 +90,43 @@ class TestActionsV2(base.BaseClientV2Test): self.assertIsNotNone(actions) self.assertEqual(ACTION_DEF, actions[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + self.assertEqual('text/plain', last_request.headers['content-type']) + self.assertEqual(ACTION_DEF, last_request.text) def test_update_with_id(self): - mock = self.mock_http_put(content={'actions': [ACTION]}) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE_NAME % 123, + json={'actions': [ACTION]}) actions = self.actions.update(ACTION_DEF, id=123) self.assertIsNotNone(actions) self.assertEqual(ACTION_DEF, actions[0].definition) - mock.assert_called_once_with( - '/actions/123?scope=private', - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual('scope=private', last_request.query) + self.assertEqual('text/plain', last_request.headers['content-type']) + self.assertEqual(ACTION_DEF, last_request.text) def test_update(self): - mock = self.mock_http_put(content={'actions': [ACTION]}) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE, + json={'actions': [ACTION]}) actions = self.actions.update(ACTION_DEF) self.assertIsNotNone(actions) self.assertEqual(ACTION_DEF, actions[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual('scope=private', last_request.query) + self.assertEqual('text/plain', last_request.headers['content-type']) + self.assertEqual(ACTION_DEF, last_request.text) def test_update_with_file_uri(self): - mock = self.mock_http_put(content={'actions': [ACTION]}) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE, + json={'actions': [ACTION]}) # The contents of action_v2.yaml must be identical to ACTION_DEF path = pkg.resource_filename( @@ -139,14 +142,14 @@ class TestActionsV2(base.BaseClientV2Test): self.assertIsNotNone(actions) self.assertEqual(ACTION_DEF, actions[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + self.assertEqual('scope=private', last_request.query) + self.assertEqual('text/plain', last_request.headers['content-type']) + self.assertEqual(ACTION_DEF, last_request.text) def test_list(self): - mock = self.mock_http_get(content={'actions': [ACTION]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'actions': [ACTION]}) action_list = self.actions.list() @@ -159,12 +162,10 @@ class TestActionsV2(base.BaseClientV2Test): action.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE) - def test_list_with_pagination(self): - mock = self.mock_http_get( - content={'actions': [ACTION], 'next': '/actions?fake'} - ) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'actions': [ACTION], + 'next': '/actions?fake'}) action_list = self.actions.list( limit=1, @@ -174,13 +175,16 @@ class TestActionsV2(base.BaseClientV2Test): self.assertEqual(1, len(action_list)) + last_request = self.requests_mock.last_request + # The url param order is unpredictable. - self.assertIn('limit=1', mock.call_args[0][0]) - self.assertIn('sort_keys=created_at', mock.call_args[0][0]) - self.assertIn('sort_dirs=asc', mock.call_args[0][0]) + self.assertEqual(['1'], last_request.qs['limit']) + self.assertEqual(['created_at'], last_request.qs['sort_keys']) + self.assertEqual(['asc'], last_request.qs['sort_dirs']) def test_get(self): - mock = self.mock_http_get(content=ACTION) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE_NAME % 'action', + json=ACTION) action = self.actions.get('action') @@ -190,20 +194,17 @@ class TestActionsV2(base.BaseClientV2Test): action.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'action') - def test_delete(self): - mock = self.mock_http_delete(status_code=204) + url = self.TEST_URL + URL_TEMPLATE_NAME % 'action' + m = self.requests_mock.delete(url, status_code=204) self.actions.delete('action') - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'action') + self.assertEqual(1, m.call_count) def test_validate(self): - mock = self.mock_http_post( - status_code=200, - content={'valid': True} - ) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + json={'valid': True}) result = self.actions.validate(ACTION_DEF) @@ -211,17 +212,13 @@ class TestActionsV2(base.BaseClientV2Test): self.assertIn('valid', result) self.assertTrue(result['valid']) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + self.assertEqual(ACTION_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_validate_with_file(self): - mock = self.mock_http_post( - status_code=200, - content={'valid': True} - ) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + json={'valid': True}) # The contents of action_v2.yaml must be identical to ACTION_DEF path = pkg.resource_filename( @@ -235,19 +232,14 @@ class TestActionsV2(base.BaseClientV2Test): self.assertIn('valid', result) self.assertTrue(result['valid']) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + self.assertEqual(ACTION_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_validate_failed(self): - mock_result = { - "valid": False, - "error": "mocked error message" - } - - mock = self.mock_http_post(status_code=200, content=mock_result) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + json={"valid": False, + "error": "mocked error message"}) result = self.actions.validate(INVALID_ACTION_DEF) @@ -257,14 +249,13 @@ class TestActionsV2(base.BaseClientV2Test): self.assertIn('error', result) self.assertIn("mocked error message", result['error']) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - INVALID_ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + self.assertEqual('text/plain', last_request.headers['content-type']) def test_validate_api_failed(self): - mock = self.mock_http_post(status_code=500, content={}) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + status_code=500, + json={}) self.assertRaises( api_base.APIException, @@ -272,8 +263,7 @@ class TestActionsV2(base.BaseClientV2Test): ACTION_DEF ) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - ACTION_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual('text/plain', last_request.headers['content-type']) + self.assertEqual(ACTION_DEF, last_request.text) diff --git a/mistralclient/tests/unit/v2/test_environments.py b/mistralclient/tests/unit/v2/test_environments.py index becc67db..74168fea 100644 --- a/mistralclient/tests/unit/v2/test_environments.py +++ b/mistralclient/tests/unit/v2/test_environments.py @@ -43,7 +43,9 @@ class TestEnvironmentsV2(base.BaseClientV2Test): def test_create(self): data = copy.deepcopy(ENVIRONMENT) - mock = self.mock_http_post(content=data) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + status_code=201, + json=data) env = self.environments.create(**data) self.assertIsNotNone(env) @@ -51,7 +53,7 @@ class TestEnvironmentsV2(base.BaseClientV2Test): expected_data = copy.deepcopy(data) expected_data['variables'] = json.dumps(expected_data['variables']) - mock.assert_called_once_with(URL_TEMPLATE, json.dumps(expected_data)) + self.assertEqual(expected_data, self.requests_mock.last_request.json()) def test_create_with_json_file_uri(self): # The contents of env_v2.json must be equivalent to ENVIRONMENT @@ -68,7 +70,9 @@ class TestEnvironmentsV2(base.BaseClientV2Test): ) ) - mock = self.mock_http_post(content=data) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + status_code=201, + json=data) file_input = {'file': uri} env = self.environments.create(**file_input) @@ -77,7 +81,7 @@ class TestEnvironmentsV2(base.BaseClientV2Test): expected_data = copy.deepcopy(data) expected_data['variables'] = json.dumps(expected_data['variables']) - mock.assert_called_once_with(URL_TEMPLATE, json.dumps(expected_data)) + self.assertEqual(expected_data, self.requests_mock.last_request.json()) def test_create_without_name(self): data = copy.deepcopy(ENVIRONMENT) @@ -92,7 +96,7 @@ class TestEnvironmentsV2(base.BaseClientV2Test): def test_update(self): data = copy.deepcopy(ENVIRONMENT) - mock = self.mock_http_put(content=data) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE, json=data) env = self.environments.update(**data) self.assertIsNotNone(env) @@ -100,7 +104,7 @@ class TestEnvironmentsV2(base.BaseClientV2Test): expected_data = copy.deepcopy(data) expected_data['variables'] = json.dumps(expected_data['variables']) - mock.assert_called_once_with(URL_TEMPLATE, json.dumps(expected_data)) + self.assertEqual(expected_data, self.requests_mock.last_request.json()) def test_update_with_yaml_file(self): # The contents of env_v2.json must be equivalent to ENVIRONMENT @@ -113,8 +117,8 @@ class TestEnvironmentsV2(base.BaseClientV2Test): utils.get_contents_if_file(path) ) ) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE, json=data) - mock = self.mock_http_put(content=data) file_input = {'file': path} env = self.environments.update(**file_input) @@ -123,7 +127,7 @@ class TestEnvironmentsV2(base.BaseClientV2Test): expected_data = copy.deepcopy(data) expected_data['variables'] = json.dumps(expected_data['variables']) - mock.assert_called_once_with(URL_TEMPLATE, json.dumps(expected_data)) + self.assertEqual(expected_data, self.requests_mock.last_request.json()) def test_update_without_name(self): data = copy.deepcopy(ENVIRONMENT) @@ -136,7 +140,8 @@ class TestEnvironmentsV2(base.BaseClientV2Test): self.assertEqual(400, e.error_code) def test_list(self): - mock = self.mock_http_get(content={'environments': [ENVIRONMENT]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'environments': [ENVIRONMENT]}) environment_list = self.environments.list() @@ -149,10 +154,9 @@ class TestEnvironmentsV2(base.BaseClientV2Test): env.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE) - def test_get(self): - mock = self.mock_http_get(content=ENVIRONMENT) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE_NAME % 'env', + json=ENVIRONMENT) env = self.environments.get('env') @@ -162,11 +166,8 @@ class TestEnvironmentsV2(base.BaseClientV2Test): env.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'env') - def test_delete(self): - mock = self.mock_http_delete(status_code=204) + self.requests_mock.delete(self.TEST_URL + URL_TEMPLATE_NAME % 'env', + status_code=204) self.environments.delete('env') - - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'env') diff --git a/mistralclient/tests/unit/v2/test_executions.py b/mistralclient/tests/unit/v2/test_executions.py index c62e1d5f..77296e3d 100644 --- a/mistralclient/tests/unit/v2/test_executions.py +++ b/mistralclient/tests/unit/v2/test_executions.py @@ -56,7 +56,10 @@ URL_TEMPLATE_ID = '/executions/%s' class TestExecutionsV2(base.BaseClientV2Test): def test_create(self): - mock = self.mock_http_post(content=EXEC) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json=EXEC, + status_code=201) + body = { 'workflow_name': EXEC['workflow_name'], 'description': '', @@ -75,11 +78,13 @@ class TestExecutionsV2(base.BaseClientV2Test): ex.to_dict() ) - self.assertEqual(URL_TEMPLATE, mock.call_args[0][0]) - self.assertDictEqual(body, json.loads(mock.call_args[0][1])) + self.assertDictEqual(body, self.requests_mock.last_request.json()) def test_create_with_workflow_id(self): - mock = self.mock_http_post(content=EXEC) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json=EXEC, + status_code=201) + body = { 'workflow_id': EXEC['workflow_id'], 'description': '', @@ -98,15 +103,17 @@ class TestExecutionsV2(base.BaseClientV2Test): ex.to_dict() ) - self.assertEqual(URL_TEMPLATE, mock.call_args[0][0]) - self.assertDictEqual(body, json.loads(mock.call_args[0][1])) + self.assertDictEqual(body, self.requests_mock.last_request.json()) def test_create_failure1(self): - self.mock_http_post(content=EXEC) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json=EXEC, + status_code=201) self.assertRaises(api_base.APIException, self.executions.create, '') def test_update(self): - mock = self.mock_http_put(content=EXEC) + url = self.TEST_URL + URL_TEMPLATE_ID % EXEC['id'] + self.requests_mock.put(url, json=EXEC) body = { 'state': EXEC['state'] } @@ -120,11 +127,11 @@ class TestExecutionsV2(base.BaseClientV2Test): ex.to_dict() ) - self.assertEqual(URL_TEMPLATE_ID % EXEC['id'], mock.call_args[0][0]) - self.assertDictEqual(body, json.loads(mock.call_args[0][1])) + self.assertDictEqual(body, self.requests_mock.last_request.json()) def test_update_env(self): - mock = self.mock_http_put(content=EXEC) + url = self.TEST_URL + URL_TEMPLATE_ID % EXEC['id'] + self.requests_mock.put(url, json=EXEC) body = { 'state': EXEC['state'], 'params': { @@ -145,11 +152,11 @@ class TestExecutionsV2(base.BaseClientV2Test): ex.to_dict() ) - self.assertEqual(URL_TEMPLATE_ID % EXEC['id'], mock.call_args[0][0]) - self.assertDictEqual(body, json.loads(mock.call_args[0][1])) + self.assertDictEqual(body, self.requests_mock.last_request.json()) def test_list(self): - mock = self.mock_http_get(content={'executions': [EXEC, SUB_WF_EXEC]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'executions': [EXEC, SUB_WF_EXEC]}) execution_list = self.executions.list() @@ -165,12 +172,10 @@ class TestExecutionsV2(base.BaseClientV2Test): execution_list[1].to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE) - def test_list_with_pagination(self): - mock = self.mock_http_get( - content={'executions': [EXEC], 'next': '/executions?fake'} - ) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'executions': [EXEC], + 'next': '/executions?fake'}) execution_list = self.executions.list( limit=1, @@ -180,13 +185,16 @@ class TestExecutionsV2(base.BaseClientV2Test): self.assertEqual(1, len(execution_list)) + last_request = self.requests_mock.last_request + # The url param order is unpredictable. - self.assertIn('limit=1', mock.call_args[0][0]) - self.assertIn('sort_keys=created_at', mock.call_args[0][0]) - self.assertIn('sort_dirs=asc', mock.call_args[0][0]) + self.assertEqual(['1'], last_request.qs['limit']) + self.assertEqual(['created_at'], last_request.qs['sort_keys']) + self.assertEqual(['asc'], last_request.qs['sort_dirs']) def test_get(self): - mock = self.mock_http_get(content=EXEC) + url = self.TEST_URL + URL_TEMPLATE_ID % EXEC['id'] + self.requests_mock.get(url, json=EXEC) ex = self.executions.get(EXEC['id']) @@ -195,10 +203,9 @@ class TestExecutionsV2(base.BaseClientV2Test): ex.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_ID % EXEC['id']) - def test_get_sub_wf_ex(self): - mock = self.mock_http_get(content=SUB_WF_EXEC) + url = self.TEST_URL + URL_TEMPLATE_ID % SUB_WF_EXEC['id'] + self.requests_mock.get(url, json=SUB_WF_EXEC) ex = self.executions.get(SUB_WF_EXEC['id']) @@ -207,11 +214,8 @@ class TestExecutionsV2(base.BaseClientV2Test): ex.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_ID % SUB_WF_EXEC['id']) - def test_delete(self): - mock = self.mock_http_delete(status_code=204) + url = self.TEST_URL + URL_TEMPLATE_ID % EXEC['id'] + self.requests_mock.delete(url, status_code=204) self.executions.delete(EXEC['id']) - - mock.assert_called_once_with(URL_TEMPLATE_ID % EXEC['id']) diff --git a/mistralclient/tests/unit/v2/test_members.py b/mistralclient/tests/unit/v2/test_members.py index d02ed94e..a3245eb7 100644 --- a/mistralclient/tests/unit/v2/test_members.py +++ b/mistralclient/tests/unit/v2/test_members.py @@ -13,7 +13,6 @@ # limitations under the License. import copy -import json from mistralclient.tests.unit.v2 import base @@ -34,7 +33,9 @@ WORKFLOW_MEMBER_URL = '/workflows/%s/members/%s' % ( class TestWorkflowMembers(base.BaseClientV2Test): def test_create(self): - mock = self.mock_http_post(content=MEMBER) + self.requests_mock.post(self.TEST_URL + WORKFLOW_MEMBERS_URL, + json=MEMBER, + status_code=201) mb = self.members.create( MEMBER['resource_id'], @@ -44,16 +45,15 @@ class TestWorkflowMembers(base.BaseClientV2Test): self.assertIsNotNone(mb) - mock.assert_called_once_with( - WORKFLOW_MEMBERS_URL, - json.dumps({'member_id': MEMBER['member_id']}) - ) + self.assertDictEqual({'member_id': MEMBER['member_id']}, + self.requests_mock.last_request.json()) def test_update(self): updated_member = copy.copy(MEMBER) updated_member['status'] = 'accepted' - mock = self.mock_http_put(content=updated_member) + self.requests_mock.put(self.TEST_URL + WORKFLOW_MEMBER_URL, + json=updated_member) mb = self.members.update( MEMBER['resource_id'], @@ -63,22 +63,20 @@ class TestWorkflowMembers(base.BaseClientV2Test): self.assertIsNotNone(mb) - mock.assert_called_once_with( - WORKFLOW_MEMBER_URL, - json.dumps({"status": "accepted"}) - ) + self.assertDictEqual({"status": "accepted"}, + self.requests_mock.last_request.json()) def test_list(self): - mock = self.mock_http_get(content={'members': [MEMBER]}) + self.requests_mock.get(self.TEST_URL + WORKFLOW_MEMBERS_URL, + json={'members': [MEMBER]}) mbs = self.members.list(MEMBER['resource_id'], MEMBER['resource_type']) self.assertEqual(1, len(mbs)) - mock.assert_called_once_with(WORKFLOW_MEMBERS_URL) - def test_get(self): - mock = self.mock_http_get(content=MEMBER) + self.requests_mock.get(self.TEST_URL + WORKFLOW_MEMBER_URL, + json=MEMBER) mb = self.members.get( MEMBER['resource_id'], @@ -88,15 +86,11 @@ class TestWorkflowMembers(base.BaseClientV2Test): self.assertIsNotNone(mb) - mock.assert_called_once_with(WORKFLOW_MEMBER_URL) - def test_delete(self): - mock = self.mock_http_delete(status_code=204) - + self.requests_mock.delete(self.TEST_URL + WORKFLOW_MEMBER_URL, + status_code=204) self.members.delete( MEMBER['resource_id'], MEMBER['resource_type'], MEMBER['member_id'] ) - - mock.assert_called_once_with(WORKFLOW_MEMBER_URL) diff --git a/mistralclient/tests/unit/v2/test_services.py b/mistralclient/tests/unit/v2/test_services.py index d37a3e8f..40b24ab7 100644 --- a/mistralclient/tests/unit/v2/test_services.py +++ b/mistralclient/tests/unit/v2/test_services.py @@ -26,7 +26,8 @@ URL_TEMPLATE = '/services' class TestServicesV2(base.BaseClientV2Test): def test_list(self): - mock = self.mock_http_get(content={'services': [SERVICE]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'services': [SERVICE]}) service_list = self.services.list() @@ -38,5 +39,3 @@ class TestServicesV2(base.BaseClientV2Test): services.Service(self.services, SERVICE).to_dict(), srv.to_dict() ) - - mock.assert_called_once_with(URL_TEMPLATE) diff --git a/mistralclient/tests/unit/v2/test_tasks.py b/mistralclient/tests/unit/v2/test_tasks.py index d606b4c9..93d93702 100644 --- a/mistralclient/tests/unit/v2/test_tasks.py +++ b/mistralclient/tests/unit/v2/test_tasks.py @@ -37,7 +37,8 @@ URL_TEMPLATE_ID = '/tasks/%s' class TestTasksV2(base.BaseClientV2Test): def test_list(self): - mock = self.mock_http_get(content={'tasks': [TASK]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'tasks': [TASK]}) task_list = self.tasks.list() @@ -48,10 +49,10 @@ class TestTasksV2(base.BaseClientV2Test): tasks.Task(self.tasks, TASK).to_dict(), task.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE) def test_get(self): - mock = self.mock_http_get(content=TASK) + url = self.TEST_URL + URL_TEMPLATE_ID % TASK['id'] + self.requests_mock.get(url, json=TASK) task = self.tasks.get(TASK['id']) @@ -59,10 +60,10 @@ class TestTasksV2(base.BaseClientV2Test): tasks.Task(self.tasks, TASK).to_dict(), task.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_ID % TASK['id']) def test_rerun(self): - mock = self.mock_http_put(content=TASK) + url = self.TEST_URL + URL_TEMPLATE_ID % TASK['id'] + self.requests_mock.put(url, json=TASK) task = self.tasks.rerun(TASK['id']) @@ -71,19 +72,16 @@ class TestTasksV2(base.BaseClientV2Test): task.to_dict() ) - self.assertEqual(1, mock.call_count) - self.assertEqual(URL_TEMPLATE_ID % TASK['id'], mock.call_args[0][0]) - self.assertDictEqual( - { - 'reset': True, - 'state': 'RUNNING', - 'id': TASK['id'] - }, - json.loads(mock.call_args[0][1]) - ) + body = { + 'reset': True, + 'state': 'RUNNING', + 'id': TASK['id'] + } + self.assertDictEqual(body, self.requests_mock.last_request.json()) def test_rerun_no_reset(self): - mock = self.mock_http_put(content=TASK) + url = self.TEST_URL + URL_TEMPLATE_ID % TASK['id'] + self.requests_mock.put(url, json=TASK) task = self.tasks.rerun(TASK['id'], reset=False) @@ -92,19 +90,16 @@ class TestTasksV2(base.BaseClientV2Test): task.to_dict() ) - self.assertEqual(1, mock.call_count) - self.assertEqual(URL_TEMPLATE_ID % TASK['id'], mock.call_args[0][0]) - self.assertDictEqual( - { - 'reset': False, - 'state': 'RUNNING', - 'id': TASK['id'] - }, - json.loads(mock.call_args[0][1]) - ) + body = { + 'reset': False, + 'state': 'RUNNING', + 'id': TASK['id'] + } + self.assertDictEqual(body, self.requests_mock.last_request.json()) def test_rerun_update_env(self): - mock = self.mock_http_put(content=TASK) + url = self.TEST_URL + URL_TEMPLATE_ID % TASK['id'] + self.requests_mock.put(url, json=TASK) task = self.tasks.rerun(TASK['id'], env={'k1': 'foobar'}) @@ -113,14 +108,10 @@ class TestTasksV2(base.BaseClientV2Test): task.to_dict() ) - self.assertEqual(1, mock.call_count) - self.assertEqual(URL_TEMPLATE_ID % TASK['id'], mock.call_args[0][0]) - self.assertDictEqual( - { - 'reset': True, - 'state': 'RUNNING', - 'id': TASK['id'], - 'env': json.dumps({'k1': 'foobar'}) - }, - json.loads(mock.call_args[0][1]) - ) + body = { + 'reset': True, + 'state': 'RUNNING', + 'id': TASK['id'], + 'env': json.dumps({'k1': 'foobar'}) + } + self.assertDictEqual(body, self.requests_mock.last_request.json()) diff --git a/mistralclient/tests/unit/v2/test_workbooks.py b/mistralclient/tests/unit/v2/test_workbooks.py index 5427b229..59a59416 100644 --- a/mistralclient/tests/unit/v2/test_workbooks.py +++ b/mistralclient/tests/unit/v2/test_workbooks.py @@ -70,21 +70,24 @@ URL_TEMPLATE_VALIDATE = '/workbooks/validate' class TestWorkbooksV2(base.BaseClientV2Test): def test_create(self): - mock = self.mock_http_post(content=WORKBOOK) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json=WORKBOOK, + status_code=201) wb = self.workbooks.create(WB_DEF) self.assertIsNotNone(wb) self.assertEqual(WB_DEF, wb.definition) - mock.assert_called_once_with( - URL_TEMPLATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_create_with_file_uri(self): - mock = self.mock_http_post(content=WORKBOOK) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, + json=WORKBOOK, + status_code=201) # The contents of wb_v2.yaml must be identical to WB_DEF path = pkg.resource_filename( @@ -100,28 +103,26 @@ class TestWorkbooksV2(base.BaseClientV2Test): self.assertIsNotNone(wb) self.assertEqual(WB_DEF, wb.definition) - mock.assert_called_once_with( - URL_TEMPLATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_update(self): - mock = self.mock_http_put(content=WORKBOOK) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE, json=WORKBOOK) wb = self.workbooks.update(WB_DEF) self.assertIsNotNone(wb) self.assertEqual(WB_DEF, wb.definition) - mock.assert_called_once_with( - URL_TEMPLATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_update_with_file(self): - mock = self.mock_http_put(content=WORKBOOK) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE, json=WORKBOOK) # The contents of wb_v2.yaml must be identical to WB_DEF path = pkg.resource_filename( @@ -134,14 +135,14 @@ class TestWorkbooksV2(base.BaseClientV2Test): self.assertIsNotNone(wb) self.assertEqual(WB_DEF, wb.definition) - mock.assert_called_once_with( - URL_TEMPLATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_list(self): - mock = self.mock_http_get(content={'workbooks': [WORKBOOK]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'workbooks': [WORKBOOK]}) workbook_list = self.workbooks.list() @@ -154,10 +155,9 @@ class TestWorkbooksV2(base.BaseClientV2Test): wb.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE) - def test_get(self): - mock = self.mock_http_get(content=WORKBOOK) + url = self.TEST_URL + URL_TEMPLATE_NAME % 'wb' + self.requests_mock.get(url, json=WORKBOOK) wb = self.workbooks.get('wb') @@ -167,20 +167,15 @@ class TestWorkbooksV2(base.BaseClientV2Test): wb.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'wb') - def test_delete(self): - mock = self.mock_http_delete(status_code=204) + url = self.TEST_URL + URL_TEMPLATE_NAME % 'wb' + self.requests_mock.delete(url, status_code=204) self.workbooks.delete('wb') - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'wb') - def test_validate(self): - mock = self.mock_http_post( - status_code=200, - content={'valid': True} - ) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + json={'valid': True}) result = self.workbooks.validate(WB_DEF) @@ -188,17 +183,14 @@ class TestWorkbooksV2(base.BaseClientV2Test): self.assertIn('valid', result) self.assertTrue(result['valid']) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_validate_with_file(self): - mock = self.mock_http_post( - status_code=200, - content={'valid': True} - ) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + json={'valid': True}) # The contents of wb_v2.yaml must be identical to WB_DEF path = pkg.resource_filename( @@ -212,11 +204,10 @@ class TestWorkbooksV2(base.BaseClientV2Test): self.assertIn('valid', result) self.assertTrue(result['valid']) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_validate_failed(self): mock_result = { @@ -225,7 +216,8 @@ class TestWorkbooksV2(base.BaseClientV2Test): "can't be specified both" } - mock = self.mock_http_post(status_code=200, content=mock_result) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + json=mock_result) result = self.workbooks.validate(INVALID_WB_DEF) @@ -238,14 +230,14 @@ class TestWorkbooksV2(base.BaseClientV2Test): "can't be specified both", result['error'] ) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - INVALID_WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(INVALID_WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_validate_api_failed(self): - mock = self.mock_http_post(status_code=500, content={}) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE, + status_code=500) self.assertRaises( api_base.APIException, @@ -253,8 +245,7 @@ class TestWorkbooksV2(base.BaseClientV2Test): WB_DEF ) - mock.assert_called_once_with( - URL_TEMPLATE_VALIDATE, - WB_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WB_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) diff --git a/mistralclient/tests/unit/v2/test_workflows.py b/mistralclient/tests/unit/v2/test_workflows.py index b2a5f407..fb5cac77 100644 --- a/mistralclient/tests/unit/v2/test_workflows.py +++ b/mistralclient/tests/unit/v2/test_workflows.py @@ -46,21 +46,24 @@ URL_TEMPLATE_NAME = '/workflows/%s' class TestWorkflowsV2(base.BaseClientV2Test): def test_create(self): - mock = self.mock_http_post(content={'workflows': [WORKFLOW]}) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_SCOPE, + json={'workflows': [WORKFLOW]}, + status_code=201) wfs = self.workflows.create(WF_DEF) self.assertIsNotNone(wfs) self.assertEqual(WF_DEF, wfs[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - WF_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WF_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_create_with_file(self): - mock = self.mock_http_post(content={'workflows': [WORKFLOW]}) + self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_SCOPE, + json={'workflows': [WORKFLOW]}, + status_code=201) # The contents of wf_v2.yaml must be identical to WF_DEF path = pkg.resource_filename( @@ -73,42 +76,43 @@ class TestWorkflowsV2(base.BaseClientV2Test): self.assertIsNotNone(wfs) self.assertEqual(WF_DEF, wfs[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - WF_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WF_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_update(self): - mock = self.mock_http_put(content={'workflows': [WORKFLOW]}) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE_SCOPE, + json={'workflows': [WORKFLOW]}) wfs = self.workflows.update(WF_DEF) self.assertIsNotNone(wfs) self.assertEqual(WF_DEF, wfs[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - WF_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WF_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_update_with_id(self): - mock = self.mock_http_put(content=WORKFLOW) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE_NAME % '123', + json=WORKFLOW) wf = self.workflows.update(WF_DEF, id='123') self.assertIsNotNone(wf) self.assertEqual(WF_DEF, wf.definition) - mock.assert_called_once_with( - '/workflows/123?scope=private', - WF_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual('scope=private', last_request.query) + self.assertEqual(WF_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_update_with_file_uri(self): - mock = self.mock_http_put(content={'workflows': [WORKFLOW]}) + self.requests_mock.put(self.TEST_URL + URL_TEMPLATE_SCOPE, + json={'workflows': [WORKFLOW]}) # The contents of wf_v2.yaml must be identical to WF_DEF path = pkg.resource_filename( @@ -124,14 +128,14 @@ class TestWorkflowsV2(base.BaseClientV2Test): self.assertIsNotNone(wfs) self.assertEqual(WF_DEF, wfs[0].definition) - mock.assert_called_once_with( - URL_TEMPLATE_SCOPE, - WF_DEF, - headers={'content-type': 'text/plain'} - ) + last_request = self.requests_mock.last_request + + self.assertEqual(WF_DEF, last_request.text) + self.assertEqual('text/plain', last_request.headers['content-type']) def test_list(self): - mock = self.mock_http_get(content={'workflows': [WORKFLOW]}) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'workflows': [WORKFLOW]}) workflows_list = self.workflows.list() @@ -144,12 +148,10 @@ class TestWorkflowsV2(base.BaseClientV2Test): wf.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE) - def test_list_with_pagination(self): - mock = self.mock_http_get( - content={'workflows': [WORKFLOW], 'next': '/workflows?fake'} - ) + self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, + json={'workflows': [WORKFLOW], + 'next': '/workflows?fake'}) workflows_list = self.workflows.list( limit=1, @@ -159,13 +161,16 @@ class TestWorkflowsV2(base.BaseClientV2Test): self.assertEqual(1, len(workflows_list)) + last_request = self.requests_mock.last_request + # The url param order is unpredictable. - self.assertIn('limit=1', mock.call_args[0][0]) - self.assertIn('sort_keys=created_at', mock.call_args[0][0]) - self.assertIn('sort_dirs=asc', mock.call_args[0][0]) + self.assertEqual(['1'], last_request.qs['limit']) + self.assertEqual(['created_at'], last_request.qs['sort_keys']) + self.assertEqual(['asc'], last_request.qs['sort_dirs']) def test_get(self): - mock = self.mock_http_get(content=WORKFLOW) + url = self.TEST_URL + URL_TEMPLATE_NAME % 'wf' + self.requests_mock.get(url, json=WORKFLOW) wf = self.workflows.get('wf') @@ -175,11 +180,8 @@ class TestWorkflowsV2(base.BaseClientV2Test): wf.to_dict() ) - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'wf') - def test_delete(self): - mock = self.mock_http_delete(status_code=204) + url = self.TEST_URL + URL_TEMPLATE_NAME % 'wf' + self.requests_mock.delete(url, status_code=204) self.workflows.delete('wf') - - mock.assert_called_once_with(URL_TEMPLATE_NAME % 'wf') diff --git a/test-requirements.txt b/test-requirements.txt index c9e6caa3..6e90e22b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -8,5 +8,6 @@ sphinx!=1.3b1,<1.3,>=1.2.1 # BSD mock>=2.0 # BSD nose # LGPL oslotest>=1.10.0 # Apache-2.0 +requests-mock>=1.0 # Apache-2.0 tempest>=12.1.0 # Apache-2.0 osprofiler>=1.4.0 # Apache-2.0