def test_iterate_over_pageable_resource_with_multiple_pages(self): objects = [ { 'items': ['foo'] }, { 'items': ['bar'] }, { 'items': ['buzz'] }, { 'items': [] }, ] resource_func = mock.Mock(side_effect=objects) items = iterate_over_pageable_resource(resource_func, {'query_params': {}}) assert ['foo'] == list(items) resource_func.reset_mock() resource_func = mock.Mock(side_effect=objects) items = iterate_over_pageable_resource(resource_func, {'query_params': { 'limit': 1 }}) assert ['foo', 'bar', 'buzz'] == list(items)
def test_iterate_over_pageable_resource_should_preserve_query_params(self): resource_func = mock.Mock(return_value={'items': []}) items = iterate_over_pageable_resource(resource_func, {'query_params': {'filter': 'name:123'}}) assert [] == list(items) resource_func.assert_called_once_with(params={'query_params': {'filter': 'name:123', 'offset': 0, 'limit': 10}})
def test_iterate_over_pageable_resource_with_no_items(self): resource_func = mock.Mock(return_value={'items': []}) items = iterate_over_pageable_resource(resource_func, {'query_params': {}}) assert [] == list(items)
def test_iterate_over_pageable_resource_should_pass_with_string_offset_and_limit( self): resource_func = mock.Mock(side_effect=[ { 'items': ['foo'] }, { 'items': [] }, ]) items = iterate_over_pageable_resource( resource_func, {'query_params': { 'offset': '1', 'limit': '1' }}) assert ['foo'] == list(items) resource_func.assert_has_calls([ call(params={'query_params': { 'offset': '1', 'limit': '1' }}), call(params={'query_params': { 'offset': 2, 'limit': '1' }}) ])
def test_iterate_over_pageable_resource_raises_exception_when_server_returned_more_items_than_requested( self): resource_func = mock.Mock(side_effect=[ { 'items': ['foo', 'redundant_bar'] }, { 'items': [] }, ]) with pytest.raises(FtdUnexpectedResponse): list( iterate_over_pageable_resource( resource_func, {'query_params': { 'offset': '1', 'limit': '1' }})) resource_func.assert_has_calls( [call(params={'query_params': { 'offset': '1', 'limit': '1' }})])
def _connection_response(response, status=200): response_mock = mock.Mock() response_mock.getcode.return_value = status response_text = json.dumps( response) if type(response) is dict else response response_data = BytesIO( response_text.encode() if response_text else ''.encode()) return response_mock, response_data
def test_check_compatibility(self, mock__init__): for num, case in enumerate(data_check_compatibility): config = vmware_host_sriov.VmwareAdapterConfigManager() config.module = mock.Mock() config.module.check_mode = False config.module.fail_json.side_effect = fail_json config.__dict__.update(gen_mock_attrs(case["user_input"])) try: result = config.check_compatibility( case["before"], case["user_input"]["esxi_host_name"]) self.assertIsInstance(result, type(case["expected"]), "test=" + str(num)) self.assertEqual(result, case["expected"], "test=" + str(num)) except Exception as e: self.assertIsInstance(e, type(case["expected"]), "test=" + str(num)) self.assertEqual(e.args[0], case["expected"].args[0], "test=" + str(num)) for num, case in enumerate(data_check_compatibility): config = vmware_host_sriov.VmwareAdapterConfigManager() config.module = mock.Mock() config.module.check_mode = False config.module.fail_json.side_effect = fail_json config.__dict__.update(gen_mock_attrs(case["user_input"])) try: result = config.check_compatibility( case["before"], case["user_input"]["esxi_host_name"]) self.assertIsInstance(result, type(case["expected"]), "test=" + str(num)) self.assertEqual(result, case["expected"], "test=" + str(num)) except Exception as e: self.assertIsInstance(e, type(case["expected"]), "test=" + str(num)) self.assertEqual(e.args[0], case["expected"].args[0], "test=" + str(num))
def test_iterate_over_pageable_resource_with_multiple_pages(self): resource_func = mock.Mock(side_effect=[ {'items': ['foo']}, {'items': ['bar']}, {'items': ['buzz']}, {'items': []}, ]) items = iterate_over_pageable_resource(resource_func) assert ['foo', 'bar', 'buzz'] == list(items)
def test_iterate_over_pageable_resource_with_one_page(self): resource_func = mock.Mock(side_effect=[ {'items': ['foo', 'bar']}, {'items': []}, ]) items = iterate_over_pageable_resource(resource_func, {'query_params': {}}) assert ['foo', 'bar'] == list(items) resource_func.assert_has_calls([ call(params={'query_params': {'offset': 0, 'limit': 10}}) ])
def test_iterate_over_pageable_resource_should_preserve_offset(self): resource_func = mock.Mock(side_effect=[ {'items': ['foo']}, {'items': []}, ]) items = iterate_over_pageable_resource(resource_func, {'query_params': {'offset': 3}}) assert ['foo'] == list(items) resource_func.assert_has_calls([ call(params={'query_params': {'offset': 3, 'limit': 10}}), ])
def test_import_key_with_http_proxy(self): m_mock = mock.Mock() m_mock.run_command.return_value = (0, '', '') apt_key.import_key(m_mock, keyring=None, keyserver='keyserver.example.com', key_id='0xDEADBEEF') self.assertEqual( m_mock.run_command.call_args_list[0][0][0], '/usr/bin/apt-key adv --no-tty --keyserver keyserver.example.com' ' --keyserver-options http-proxy=proxy.example.com' ' --recv 0xDEADBEEF')
def test_download_file_should_extract_filename_from_headers(self): filename = 'test_file.txt' response = mock.Mock() response.info.return_value = {'Content-Disposition': 'attachment; filename="%s"' % filename} dummy, response_data = self._connection_response('File content') self.connection_mock.send.return_value = response, response_data open_mock = mock_open() with patch('%s.open' % BUILTINS_NAME, open_mock): self.ftd_plugin.download_file('/files/1', '/tmp/') open_mock.assert_called_once_with('/tmp/%s' % filename, 'wb') open_mock().write.assert_called_once_with(b'File content')
def test_make_diff(self, mock__init__): for num, case in enumerate(data_make_diff): config = vmware_host_sriov.VmwareAdapterConfigManager() config.module = mock.Mock() config.module.check_mode = False config.module.fail_json.side_effect = fail_json config.__dict__.update(gen_mock_attrs(case["user_input"])) result = config.make_diff(case["before"], case["user_input"]["esxi_host_name"]) self.assertIsInstance(result, type(case["expected"]), "test=" + str(num)) self.assertEqual(result, case["expected"], "test=" + str(num))
def setUp(self): self.connection_mock = mock.Mock() self.ftd_plugin = FakeFtdHttpApiPlugin(self.connection_mock) self.ftd_plugin.access_token = 'ACCESS_TOKEN' self.ftd_plugin._load_name = 'httpapi'
def fake_ansible_module(): ret = mock.Mock() ret.params = test_data[3][0] ret.tmpdir = None ret.fail_json.side_effect = FailJsonException() return ret
def fake_connect_to_api(module, return_si=None): return mock.Mock()
def gen_mock_attrs(user_input): mock_attrs = dict(user_input) mock_attrs["results"] = {"before": {}, "after": {}, "changes": {}} mock_host = mock.Mock() mock_attrs["hosts"] = [mock_host] return mock_attrs
def test_virt_net_recreate(virt_net_obj, dummy_libvirt): virt_net_obj.conn.create = mock.Mock() dummy_libvirt.libvirtError.error_code = 'VIR_ERR_NETWORK_EXIST' virt_net_obj.conn.create.side_effect = dummy_libvirt.libvirtError assert virt_net_obj.create("active_net") is None
def setUp(self): self.connection_mock = mock.Mock() self.checkpoint_plugin = FakeCheckpointHttpApiPlugin( self.connection_mock) self.checkpoint_plugin._load_name = 'httpapi'
def test_virt_stop_active(virt_net_obj, monkeypatch): virt_net_obj.conn.destroy = mock.Mock() virt_net_obj.stop('active_net') virt_net_obj.conn.destroy.assert_called_with('active_net')
def test_virt_stop_ignore_inactive(virt_net_obj): virt_net_obj.conn.destroy = mock.Mock() virt_net_obj.stop('inactive_net') virt_net_obj.conn.destroy.assert_not_called()
def test_virt_net_create_already_active(virt_net_obj, dummy_libvirt): virt_net_obj.conn.create = mock.Mock() assert virt_net_obj.create("active_net") is None virt_net_obj.conn.create.assert_not_called()
def test_pkgname_expands(self): foo = ["apt*"] m_mock = mock.Mock() self.assertEqual( expand_pkgspec_from_fnmatches(m_mock, foo, self.fake_cache), ["apt", "apt-utils"])
def test_pkgname_wildcard_version_wildcard(self): foo = ["apt*=1.0*"] m_mock = mock.Mock() self.assertEqual( expand_pkgspec_from_fnmatches(m_mock, foo, self.fake_cache), ['apt', 'apt-utils'])
def test_connect_to_api_validate_certs(monkeypatch, fake_ansible_module): monkeypatch.setattr(vmware_module_utils, 'connect', mock.Mock()) def MockSSLContext(proto): ssl_context.proto = proto return ssl_context # New Python with SSLContext + validate_certs=True vmware_module_utils.connect.reset_mock() ssl_context = mock.Mock() monkeypatch.setattr(vmware_module_utils.ssl, 'SSLContext', MockSSLContext) fake_ansible_module.params['validate_certs'] = True vmware_module_utils.connect_to_api(fake_ansible_module) assert ssl_context.proto == ssl.PROTOCOL_SSLv23 assert ssl_context.verify_mode == ssl.CERT_REQUIRED assert ssl_context.check_hostname is True vmware_module_utils.connect.SmartConnect.assert_called_once_with( host='esxi1', port=443, pwd='Esxi@123$%', user='******', sslContext=ssl_context) # New Python with SSLContext + validate_certs=False vmware_module_utils.connect.reset_mock() ssl_context = mock.Mock() monkeypatch.setattr(vmware_module_utils.ssl, 'SSLContext', MockSSLContext) fake_ansible_module.params['validate_certs'] = False vmware_module_utils.connect_to_api(fake_ansible_module) assert ssl_context.proto == ssl.PROTOCOL_SSLv23 assert ssl_context.verify_mode == ssl.CERT_NONE assert ssl_context.check_hostname is False vmware_module_utils.connect.SmartConnect.assert_called_once_with( host='esxi1', port=443, pwd='Esxi@123$%', user='******', sslContext=ssl_context) # Old Python with no SSLContext + validate_certs=True vmware_module_utils.connect.reset_mock() ssl_context = mock.Mock() ssl_context.proto = None monkeypatch.delattr(vmware_module_utils.ssl, 'SSLContext') fake_ansible_module.params['validate_certs'] = True with pytest.raises(FailJsonException): vmware_module_utils.connect_to_api(fake_ansible_module) assert ssl_context.proto is None fake_ansible_module.fail_json.assert_called_once_with( msg=('pyVim does not support changing verification mode with python ' '< 2.7.9. Either update python or use validate_certs=false.')) assert not vmware_module_utils.connect.SmartConnect.called # Old Python with no SSLContext + validate_certs=False vmware_module_utils.connect.reset_mock() ssl_context = mock.Mock() ssl_context.proto = None monkeypatch.delattr(vmware_module_utils.ssl, 'SSLContext', raising=False) fake_ansible_module.params['validate_certs'] = False vmware_module_utils.connect_to_api(fake_ansible_module) assert ssl_context.proto is None vmware_module_utils.connect.SmartConnect.assert_called_once_with( host='esxi1', port=443, pwd='Esxi@123$%', user='******')
class TestFtdHttpApi(unittest.TestCase): def setUp(self): self.connection_mock = mock.Mock() self.ftd_plugin = FakeFtdHttpApiPlugin(self.connection_mock) self.ftd_plugin.access_token = 'ACCESS_TOKEN' self.ftd_plugin._load_name = 'httpapi' def test_login_should_request_tokens_when_no_refresh_token(self): self.connection_mock.send.return_value = self._connection_response({ 'access_token': 'ACCESS_TOKEN', 'refresh_token': 'REFRESH_TOKEN' }) self.ftd_plugin.login('foo', 'bar') assert 'ACCESS_TOKEN' == self.ftd_plugin.access_token assert 'REFRESH_TOKEN' == self.ftd_plugin.refresh_token assert { 'Authorization': 'Bearer ACCESS_TOKEN' } == self.ftd_plugin.connection._auth expected_body = json.dumps({ 'grant_type': 'password', 'username': '******', 'password': '******' }) self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY) def test_login_should_update_tokens_when_refresh_token_exists(self): self.ftd_plugin.refresh_token = 'REFRESH_TOKEN' self.connection_mock.send.return_value = self._connection_response({ 'access_token': 'NEW_ACCESS_TOKEN', 'refresh_token': 'NEW_REFRESH_TOKEN' }) self.ftd_plugin.login('foo', 'bar') assert 'NEW_ACCESS_TOKEN' == self.ftd_plugin.access_token assert 'NEW_REFRESH_TOKEN' == self.ftd_plugin.refresh_token assert { 'Authorization': 'Bearer NEW_ACCESS_TOKEN' } == self.ftd_plugin.connection._auth expected_body = json.dumps({ 'grant_type': 'refresh_token', 'refresh_token': 'REFRESH_TOKEN' }) self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY) def test_login_should_use_host_variable_when_set(self): temp_token_path = self.ftd_plugin.hostvars['token_path'] self.ftd_plugin.hostvars['token_path'] = '/testFakeLoginUrl' self.connection_mock.send.return_value = self._connection_response({ 'access_token': 'ACCESS_TOKEN', 'refresh_token': 'REFRESH_TOKEN' }) self.ftd_plugin.login('foo', 'bar') self.connection_mock.send.assert_called_once_with('/testFakeLoginUrl', mock.ANY, headers=mock.ANY, method=mock.ANY) self.ftd_plugin.hostvars['token_path'] = temp_token_path def test_login_raises_exception_when_no_refresh_token_and_no_credentials( self): with self.assertRaises(AnsibleConnectionFailure) as res: self.ftd_plugin.login(None, None) assert 'Username and password are required' in str(res.exception) def test_login_raises_exception_when_invalid_response(self): self.connection_mock.send.return_value = self._connection_response( {'no_access_token': 'ACCESS_TOKEN'}) with self.assertRaises(ConnectionError) as res: self.ftd_plugin.login('foo', 'bar') assert 'Server returned response without token info during connection authentication' in str( res.exception) def test_login_raises_exception_when_http_error(self): self.connection_mock.send.side_effect = HTTPError( 'http://testhost.com', 400, '', {}, StringIO('{"message": "Failed to authenticate user"}')) with self.assertRaises(ConnectionError) as res: self.ftd_plugin.login('foo', 'bar') assert 'Failed to authenticate user' in str(res.exception) def test_logout_should_revoke_tokens(self): self.ftd_plugin.access_token = 'ACCESS_TOKEN_TO_REVOKE' self.ftd_plugin.refresh_token = 'REFRESH_TOKEN_TO_REVOKE' self.connection_mock.send.return_value = self._connection_response( None) self.ftd_plugin.logout() assert self.ftd_plugin.access_token is None assert self.ftd_plugin.refresh_token is None expected_body = json.dumps({ 'grant_type': 'revoke_token', 'access_token': 'ACCESS_TOKEN_TO_REVOKE', 'token_to_revoke': 'REFRESH_TOKEN_TO_REVOKE' }) self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY) def test_send_request_should_send_correct_request(self): exp_resp = {'id': '123', 'name': 'foo'} self.connection_mock.send.return_value = self._connection_response( exp_resp) resp = self.ftd_plugin.send_request('/test/{objId}', HTTPMethod.PUT, body_params={'name': 'foo'}, path_params={'objId': '123'}, query_params={'at': 0}) assert { ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: 200, ResponseParams.RESPONSE: exp_resp } == resp self.connection_mock.send.assert_called_once_with( '/test/123?at=0', '{"name": "foo"}', method=HTTPMethod.PUT, headers=EXPECTED_BASE_HEADERS) def test_send_request_should_return_empty_dict_when_no_response_data(self): self.connection_mock.send.return_value = self._connection_response( None) resp = self.ftd_plugin.send_request('/test', HTTPMethod.GET) assert { ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: 200, ResponseParams.RESPONSE: {} } == resp self.connection_mock.send.assert_called_once_with( '/test', None, method=HTTPMethod.GET, headers=EXPECTED_BASE_HEADERS) def test_send_request_should_return_error_info_when_http_error_raises( self): self.connection_mock.send.side_effect = HTTPError( 'http://testhost.com', 500, '', {}, StringIO('{"errorMessage": "ERROR"}')) resp = self.ftd_plugin.send_request('/test', HTTPMethod.GET) assert { ResponseParams.SUCCESS: False, ResponseParams.STATUS_CODE: 500, ResponseParams.RESPONSE: { 'errorMessage': 'ERROR' } } == resp def test_send_request_raises_exception_when_invalid_response(self): self.connection_mock.send.return_value = self._connection_response( 'nonValidJson') with self.assertRaises(ConnectionError) as res: self.ftd_plugin.send_request('/test', HTTPMethod.GET) assert 'Invalid JSON response' in str(res.exception) def test_handle_httperror_should_update_tokens_and_retry_on_auth_errors( self): self.ftd_plugin.refresh_token = 'REFRESH_TOKEN' self.connection_mock.send.return_value = self._connection_response({ 'access_token': 'NEW_ACCESS_TOKEN', 'refresh_token': 'NEW_REFRESH_TOKEN' }) retry = self.ftd_plugin.handle_httperror( HTTPError('http://testhost.com', 401, '', {}, None)) assert retry assert 'NEW_ACCESS_TOKEN' == self.ftd_plugin.access_token assert 'NEW_REFRESH_TOKEN' == self.ftd_plugin.refresh_token def test_handle_httperror_should_not_retry_on_non_auth_errors(self): assert not self.ftd_plugin.handle_httperror( HTTPError('http://testhost.com', 500, '', {}, None)) def test_handle_httperror_should_not_retry_when_ignoring_http_errors(self): self.ftd_plugin._ignore_http_errors = True assert not self.ftd_plugin.handle_httperror( HTTPError('http://testhost.com', 401, '', {}, None)) @patch('os.path.isdir', mock.Mock(return_value=False)) def test_download_file(self): self.connection_mock.send.return_value = self._connection_response( 'File content') open_mock = mock_open() with patch('%s.open' % BUILTINS, open_mock): self.ftd_plugin.download_file('/files/1', '/tmp/test.txt') open_mock.assert_called_once_with('/tmp/test.txt', 'wb') open_mock().write.assert_called_once_with(b'File content') @patch('os.path.isdir', mock.Mock(return_value=True)) def test_download_file_should_extract_filename_from_headers(self): filename = 'test_file.txt' response = mock.Mock() response.info.return_value = { 'Content-Disposition': 'attachment; filename="%s"' % filename } dummy, response_data = self._connection_response('File content') self.connection_mock.send.return_value = response, response_data open_mock = mock_open() with patch('%s.open' % BUILTINS, open_mock): self.ftd_plugin.download_file('/files/1', '/tmp/') open_mock.assert_called_once_with('/tmp/%s' % filename, 'wb') open_mock().write.assert_called_once_with(b'File content') @patch('os.path.basename', mock.Mock(return_value='test.txt')) @patch('ansible.plugins.httpapi.ftd.encode_multipart_formdata', mock.Mock(return_value=('--Encoded data--', 'multipart/form-data'))) def test_upload_file(self): self.connection_mock.send.return_value = self._connection_response( {'id': '123'}) open_mock = mock_open() with patch('%s.open' % BUILTINS, open_mock): resp = self.ftd_plugin.upload_file('/tmp/test.txt', '/files') assert {'id': '123'} == resp exp_headers = dict(EXPECTED_BASE_HEADERS) exp_headers['Content-Length'] = len('--Encoded data--') exp_headers['Content-Type'] = 'multipart/form-data' self.connection_mock.send.assert_called_once_with( '/files', data='--Encoded data--', headers=exp_headers, method=HTTPMethod.POST) open_mock.assert_called_once_with('/tmp/test.txt', 'rb') @patch('os.path.basename', mock.Mock(return_value='test.txt')) @patch('ansible.plugins.httpapi.ftd.encode_multipart_formdata', mock.Mock(return_value=('--Encoded data--', 'multipart/form-data'))) def test_upload_file_raises_exception_when_invalid_response(self): self.connection_mock.send.return_value = self._connection_response( 'invalidJsonResponse') open_mock = mock_open() with patch('%s.open' % BUILTINS, open_mock): with self.assertRaises(ConnectionError) as res: self.ftd_plugin.upload_file('/tmp/test.txt', '/files') assert 'Invalid JSON response' in str(res.exception) @patch.object(FdmSwaggerParser, 'parse_spec') def test_get_operation_spec(self, parse_spec_mock): self.connection_mock.send.return_value = self._connection_response( None) parse_spec_mock.return_value = { SpecProp.OPERATIONS: { 'testOp': 'Specification for testOp' } } assert 'Specification for testOp' == self.ftd_plugin.get_operation_spec( 'testOp') assert self.ftd_plugin.get_operation_spec('nonExistingTestOp') is None @patch.object(FdmSwaggerParser, 'parse_spec') def test_get_model_spec(self, parse_spec_mock): self.connection_mock.send.return_value = self._connection_response( None) parse_spec_mock.return_value = { SpecProp.MODELS: { 'TestModel': 'Specification for TestModel' } } assert 'Specification for TestModel' == self.ftd_plugin.get_model_spec( 'TestModel') assert self.ftd_plugin.get_model_spec('NonExistingTestModel') is None @patch.object(FdmSwaggerParser, 'parse_spec') def test_get_model_spec(self, parse_spec_mock): self.connection_mock.send.return_value = self._connection_response( None) operation1 = {'modelName': 'TestModel'} op_model_name_is_none = {'modelName': None} op_without_model_name = {'url': 'testUrl'} parse_spec_mock.return_value = { SpecProp.MODEL_OPERATIONS: { 'TestModel': { 'testOp1': operation1, 'testOp2': 'spec2' }, 'TestModel2': { 'testOp10': 'spec10', 'testOp20': 'spec20' } }, SpecProp.OPERATIONS: { 'testOp1': operation1, 'testOp10': { 'modelName': 'TestModel2' }, 'testOpWithoutModelName': op_without_model_name, 'testOpModelNameIsNone': op_model_name_is_none } } assert { 'testOp1': operation1, 'testOp2': 'spec2' } == self.ftd_plugin.get_operation_specs_by_model_name('TestModel') assert None is self.ftd_plugin.get_operation_specs_by_model_name( 'testOpModelNameIsNone') assert None is self.ftd_plugin.get_operation_specs_by_model_name( 'testOpWithoutModelName') assert self.ftd_plugin.get_operation_specs_by_model_name( 'nonExistingOperation') is None @staticmethod def _connection_response(response, status=200): response_mock = mock.Mock() response_mock.getcode.return_value = status response_text = json.dumps( response) if type(response) is dict else response response_data = BytesIO( response_text.encode() if response_text else ''.encode()) return response_mock, response_data