示例#1
0
    def test_update_not_required(self, get_controllers):
        """Ensure we don't trigger the update if one isn't required or if check mode is enabled"""
        self._set_args()

        # make_update_body will report that no change is required, so we should see no call to the API.
        inst = NetAppESeriesIscsiInterface()
        with self.assertRaises(AnsibleExitJson) as result:
            with mock.patch(self.REQ_FUNC, return_value=(200, "")) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst,
                                           'make_update_body',
                                           return_value=(False, {})):
                        inst.update()
        request.assert_not_called()
        self.assertFalse(result.exception.args[0]['changed'],
                         msg="No change was expected.")

        # Since check_mode is enabled, we will run everything normally, but not make a request to the API
        #  to perform the actual change.
        inst = NetAppESeriesIscsiInterface()
        inst.check_mode = True
        with self.assertRaises(AnsibleExitJson) as result:
            with mock.patch(self.REQ_FUNC, return_value=(200, "")) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst,
                                           'make_update_body',
                                           return_value=(True, {})):
                        inst.update()
        request.assert_not_called()
        self.assertTrue(result.exception.args[0]['changed'],
                        msg="A change was expected.")
    def setUp(self):
        class Inventory():
            cache = dict()

        class PopenResult():
            returncode = 0
            stdout = b""
            stderr = b""

            def communicate(self):
                return (self.stdout, self.stderr)

        self.popen_result = PopenResult()
        self.inventory = Inventory()
        self.loader = mock.MagicMock()
        self.loader.load = mock.MagicMock()

        inv_loader = PluginLoader('InventoryModule',
                                  'ansible.plugins.inventory',
                                  C.DEFAULT_INVENTORY_PLUGIN_PATH,
                                  'inventory_plugins')
        self.inventory_module = inv_loader.get('script')
        self.inventory_module.set_options()

        def register_patch(name):
            patcher = mock.patch(name)
            self.addCleanup(patcher.stop)
            return patcher.start()

        self.popen = register_patch('subprocess.Popen')
        self.popen.return_value = self.popen_result

        self.BaseInventoryPlugin = register_patch(
            'ansible.plugins.inventory.BaseInventoryPlugin')
        self.BaseInventoryPlugin.get_cache_prefix.return_value = 'abc123'
示例#3
0
    def test_upsert_object_neither_added_nor_edited(self, extract_model_mock,
                                                    edit_mock, add_mock,
                                                    get_operation_mock,
                                                    is_upsert_supported_mock):
        op_name = mock.MagicMock()
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = True
        error = FtdConfigurationError("Obj duplication error")
        error.obj = mock.MagicMock()

        add_mock.side_effect = error
        edit_mock.side_effect = FtdConfigurationError("Some object edit error")

        self.assertRaises(FtdConfigurationError, self._resource.upsert_object,
                          op_name, params)

        is_upsert_supported_mock.assert_called_once_with(op_name)
        extract_model_mock.assert_called_once_with(op_name)
        get_operation_mock.assert_called_once_with(
            extract_model_mock.return_value)
        add_mock.assert_called_once_with(get_operation_mock.return_value,
                                         params)
        edit_mock.assert_called_once_with(get_operation_mock.return_value,
                                          error.obj, params)
    def test_edit_upserted_object(self, _set_default_mock, copy_properties_mock, edit_object_mock, get_operation_mock):
        model_operations = mock.MagicMock()
        existing_object = mock.MagicMock()
        params = {
            'path_params': {},
            'data': {}
        }

        result = self._resource._edit_upserted_object(model_operations, existing_object, params)

        assert result == edit_object_mock.return_value

        _set_default_mock.assert_has_calls([
            mock.call(params, 'path_params', {}),
            mock.call(params, 'data', {})
        ])
        get_operation_mock.assert_called_once_with(
            self._resource._operation_checker.is_edit_operation,
            model_operations
        )
        copy_properties_mock.assert_called_once_with(
            existing_object,
            params['data']
        )
        edit_object_mock.assert_called_once_with(
            get_operation_mock.return_value,
            params
        )
示例#5
0
    def test_get_list_of_supported_api_versions_with_positive_response(self):
        http_response_mock = mock.MagicMock()
        http_response_mock.getvalue.return_value = '{"supportedVersions": ["v1"]}'

        send_mock = mock.MagicMock(return_value=(None, http_response_mock))
        with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
            supported_versions = self.ftd_plugin._get_supported_api_versions()
            assert supported_versions == ['v1']
示例#6
0
    def test_get_list_of_supported_api_versions_with_failed_http_request(self):
        error_msg = "Invalid Credentials"
        fp = mock.MagicMock()
        fp.read.return_value = '{{"error-msg": "{0}"}}'.format(error_msg)
        send_mock = mock.MagicMock(side_effect=HTTPError('url', 400, 'msg', 'hdrs', fp))
        with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
            with self.assertRaises(ConnectionError) as res:
                self.ftd_plugin._get_supported_api_versions()

        assert error_msg in str(res.exception)
    def test_add_upserted_object_with_no_add_operation(self, add_object_mock, get_operation_mock):
        model_operations = mock.MagicMock()
        get_operation_mock.return_value = None

        with pytest.raises(FtdConfigurationError) as exc_info:
            self._resource._add_upserted_object(model_operations, mock.MagicMock())
        assert ADD_OPERATION_NOT_SUPPORTED_ERROR in str(exc_info.value)

        get_operation_mock.assert_called_once_with(self._resource._operation_checker.is_add_operation, model_operations)
        add_object_mock.assert_not_called()
示例#8
0
    def test_get_list_of_supported_api_versions_with_buggy_response(self):
        error_msg = "Non JSON value"
        http_response_mock = mock.MagicMock()
        http_response_mock.getvalue.return_value = error_msg

        send_mock = mock.MagicMock(return_value=(None, http_response_mock))

        with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
            with self.assertRaises(ConnectionError) as res:
                self.ftd_plugin._get_supported_api_versions()
        assert error_msg in str(res.exception)
示例#9
0
 def test_lookup_login_url_with_failed_request(self, display_mock, api_request_mock, get_known_token_paths_mock):
     payload = mock.MagicMock()
     url = mock.MagicMock()
     get_known_token_paths_mock.return_value = [url]
     api_request_mock.side_effect = ConnectionError('Error message')
     self.assertRaises(
         ConnectionError,
         self.ftd_plugin._lookup_login_url,
         payload
     )
     assert display_mock.vvvv.called
    def test_add_upserted_object(self, add_object_mock, get_operation_mock):
        model_operations = mock.MagicMock()
        params = mock.MagicMock()
        add_op_name = get_operation_mock.return_value

        assert add_object_mock.return_value == self._resource._add_upserted_object(model_operations, params)

        get_operation_mock.assert_called_once_with(
            self._resource._operation_checker.is_add_operation,
            model_operations)
        add_object_mock.assert_called_once_with(add_op_name, params)
示例#11
0
    def test_lookup_login_url_with_positive_result(self, set_api_token_mock, api_request_mock,
                                                   get_known_token_paths_mock):
        payload = mock.MagicMock()
        url = mock.MagicMock()
        get_known_token_paths_mock.return_value = [url]
        response_mock = mock.MagicMock()
        api_request_mock.return_value = response_mock

        resp = self.ftd_plugin._lookup_login_url(payload)

        set_api_token_mock.assert_called_once_with(url)
        assert resp == response_mock
示例#12
0
    def test_upsert_object_not_supported(self, extract_model_mock, edit_mock,
                                         add_mock, get_operation_mock,
                                         is_upsert_supported_mock):
        op_name = mock.MagicMock()
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = False

        self.assertRaises(FtdInvalidOperationNameError,
                          self._resource.upsert_object, op_name, params)

        is_upsert_supported_mock.assert_called_once_with(op_name)
        extract_model_mock.assert_not_called()
        get_operation_mock.assert_not_called()
        add_mock.assert_not_called()
        edit_mock.assert_not_called()
 def setUp(self, fetch_system_info_mock):
     self._conn = mock.MagicMock()
     self._resource = BaseConfigurationResource(self._conn)
     fetch_system_info_mock.return_value = {
         'databaseInfo': {
             'buildVersion': '6.3.0'
         }
     }
示例#14
0
 def test_lookup_login_url_with_empty_response(self, get_known_token_paths_mock):
     payload = mock.MagicMock()
     get_known_token_paths_mock.return_value = []
     self.assertRaises(
         ConnectionError,
         self.ftd_plugin._lookup_login_url,
         payload
     )
    def test_get_operation_name(self):
        operation_a = mock.MagicMock()
        operation_b = mock.MagicMock()

        def checker_wrapper(expected_object):
            def checker(obj, *args, **kwargs):
                return obj == expected_object

            return checker

        operations = {
            operation_a: "spec",
            operation_b: "spec"
        }

        assert operation_a == self._resource._get_operation_name(checker_wrapper(operation_a), operations)
        assert operation_b == self._resource._get_operation_name(checker_wrapper(operation_b), operations)
        assert self._resource._get_operation_name(checker_wrapper(None), operations) is None
    def test_upsert_object_returned_without_modifications(self, edit_mock, add_mock, find_object, get_operation_mock,
                                                          is_upsert_supported_mock, equal_objects_mock):
        params = mock.MagicMock()
        existing_obj = mock.MagicMock()

        is_upsert_supported_mock.return_value = True
        find_object.return_value = existing_obj
        equal_objects_mock.return_value = True

        result = self._resource.upsert_object('upsertFoo', params)

        assert result == existing_obj
        self._conn.get_model_spec.assert_called_once_with('Foo')
        get_operation_mock.assert_called_once_with('Foo')
        is_upsert_supported_mock.assert_called_once_with(get_operation_mock.return_value)
        add_mock.assert_not_called()
        equal_objects_mock.assert_called_once_with(existing_obj, params[ParamName.DATA])
        edit_mock.assert_not_called()
示例#17
0
    def test_upsert_object_succesfully_added(self, extract_model_mock,
                                             edit_mock, add_mock,
                                             get_operation_mock,
                                             is_upsert_supported_mock):
        op_name = mock.MagicMock()
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = True

        result = self._resource.upsert_object(op_name, params)

        assert result == add_mock.return_value
        is_upsert_supported_mock.assert_called_once_with(op_name)
        extract_model_mock.assert_called_once_with(op_name)
        get_operation_mock.assert_called_once_with(
            extract_model_mock.return_value)
        add_mock.assert_called_once_with(get_operation_mock.return_value,
                                         params)
        edit_mock.assert_not_called()
    def test_upsert_object_with_fatal_error_during_edit(self, edit_mock, add_mock, find_object, get_operation_mock,
                                                        is_upsert_supported_mock, equal_objects_mock):
        params = mock.MagicMock()
        existing_obj = mock.MagicMock()

        is_upsert_supported_mock.return_value = True
        find_object.return_value = existing_obj
        equal_objects_mock.return_value = False
        edit_mock.side_effect = FtdConfigurationError("Some object edit error")

        self.assertRaises(
            FtdConfigurationError,
            self._resource.upsert_object, 'upsertFoo', params
        )

        is_upsert_supported_mock.assert_called_once_with(get_operation_mock.return_value)
        self._conn.get_model_spec.assert_called_once_with('Foo')
        get_operation_mock.assert_called_once_with('Foo')
        find_object.assert_called_once_with('Foo', params)
        add_mock.assert_not_called()
        edit_mock.assert_called_once_with(get_operation_mock.return_value, existing_obj, params)
示例#19
0
    def test_is_upsert_operation_supported(self, extract_model_mock,
                                           is_upsert_supported_mock,
                                           get_operation_spec_mock):
        op_name = mock.MagicMock()

        result = self._resource.is_upsert_operation_supported(op_name)

        assert result == is_upsert_supported_mock.return_value
        extract_model_mock.assert_called_once_with(op_name)
        get_operation_spec_mock.assert_called_once_with(
            extract_model_mock.return_value)
        is_upsert_supported_mock.assert_called_once_with(
            get_operation_spec_mock.return_value)
示例#20
0
    def test_update_fail(self, get_controllers, make_body):
        """Ensure we fail correctly on receiving a normal failure from the API."""
        self._set_args()

        inst = NetAppESeriesIscsiInterface()
        # Test a 422 error with a non-busy status
        with self.assertRaisesRegexp(AnsibleFailJson,
                                     r".*?Failed to modify.*") as result:
            with mock.patch(self.REQ_FUNC,
                            return_value=(422, mock.MagicMock())) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    inst.update()
        request.assert_called_once()

        # Test a 401 (authentication) error
        with self.assertRaisesRegexp(AnsibleFailJson,
                                     r".*?Failed to modify.*") as result:
            with mock.patch(self.REQ_FUNC,
                            return_value=(401, mock.MagicMock())) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    inst.update()
        request.assert_called_once()

        # Test with a connection failure
        with self.assertRaisesRegexp(AnsibleFailJson,
                                     r".*?Connection failure.*") as result:
            with mock.patch(self.REQ_FUNC, side_effect=Exception()) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    inst.update()
        request.assert_called_once()
示例#21
0
    def test_upsert_object_succesfully_edited(self, extract_model_mock,
                                              edit_mock, add_mock,
                                              get_operation_mock,
                                              is_upsert_supported_mock):
        op_name = mock.MagicMock()
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = True
        error = FtdConfigurationError("Obj duplication error")
        error.obj = mock.MagicMock()

        add_mock.side_effect = error

        result = self._resource.upsert_object(op_name, params)

        assert result == edit_mock.return_value
        is_upsert_supported_mock.assert_called_once_with(op_name)
        extract_model_mock.assert_called_once_with(op_name)
        get_operation_mock.assert_called_once_with(
            extract_model_mock.return_value)
        add_mock.assert_called_once_with(get_operation_mock.return_value,
                                         params)
        edit_mock.assert_called_once_with(get_operation_mock.return_value,
                                          error.obj, params)
示例#22
0
    def test_update(self, get_controllers):
        """Validate the good path"""
        self._set_args()

        inst = NetAppESeriesIscsiInterface()
        with self.assertRaises(AnsibleExitJson):
            with mock.patch(self.REQ_FUNC, return_value=(200, "")) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst,
                                           'make_update_body',
                                           return_value=(True, {})):
                        inst.update()
        request.assert_called_once()
    def test_upsert_object_successfully_added(self, edit_mock, add_mock, find_object, get_operation_mock,
                                              is_upsert_supported_mock):
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = True
        find_object.return_value = None

        result = self._resource.upsert_object('upsertFoo', params)

        assert result == add_mock.return_value
        self._conn.get_model_spec.assert_called_once_with('Foo')
        is_upsert_supported_mock.assert_called_once_with(get_operation_mock.return_value)
        get_operation_mock.assert_called_once_with('Foo')
        find_object.assert_called_once_with('Foo', params)
        add_mock.assert_called_once_with(get_operation_mock.return_value, params)
        edit_mock.assert_not_called()
示例#24
0
    def test_update_fail_busy(self, get_controllers):
        """Ensure we fail correctly on receiving a busy response from the API."""
        self._set_args()

        inst = NetAppESeriesIscsiInterface()
        with self.assertRaisesRegexp(AnsibleFailJson, r".*?busy.*") as result:
            with mock.patch(self.REQ_FUNC,
                            return_value=(422, dict(retcode="3"))) as request:
                with mock.patch.object(inst,
                                       'get_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst,
                                           'make_update_body',
                                           return_value=(True, {})):
                        inst.update()
        request.assert_called_once()
    def test_upsert_object_when_model_not_supported(self, edit_mock, add_mock, find_object, get_operation_mock,
                                                    is_upsert_supported_mock):
        params = mock.MagicMock()
        self._conn.get_model_spec.return_value = None

        self.assertRaises(
            FtdInvalidOperationNameError,
            self._resource.upsert_object, 'upsertNonExisting', params
        )

        self._conn.get_model_spec.assert_called_once_with('NonExisting')
        get_operation_mock.assert_not_called()
        is_upsert_supported_mock.assert_not_called()
        find_object.assert_not_called()
        add_mock.assert_not_called()
        edit_mock.assert_not_called()
    def test_upsert_object_with_fatal_error_during_add(self, edit_mock, add_mock, find_object, get_operation_mock,
                                                       is_upsert_supported_mock):
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = True
        find_object.return_value = None

        error = FtdConfigurationError("Obj duplication error")
        add_mock.side_effect = error

        self.assertRaises(
            FtdConfigurationError,
            self._resource.upsert_object, 'upsertFoo', params
        )

        is_upsert_supported_mock.assert_called_once_with(get_operation_mock.return_value)
        self._conn.get_model_spec.assert_called_once_with('Foo')
        get_operation_mock.assert_called_once_with('Foo')
        find_object.assert_called_once_with('Foo', params)
        add_mock.assert_called_once_with(get_operation_mock.return_value, params)
        edit_mock.assert_not_called()
示例#27
0
 def test_set_api_token_path(self):
     url = mock.MagicMock()
     self.ftd_plugin._set_api_token_path(url)
     assert self.ftd_plugin._get_api_token_path() == url
示例#28
0
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_env_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=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=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_NAME, 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_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')

    @patch('os.path.basename', mock.Mock(return_value='test.txt'))
    @patch('httpapi_plugins.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_NAME, open_mock):
            resp = self.ftd_plugin.upload_file('/tmp/test.txt', '/files')

        assert {'id': '123'} == resp
        exp_headers = dict(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('httpapi_plugins.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_NAME, 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_operation_spec_by_model_name(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

    def test_get_list_of_supported_api_versions_with_failed_http_request(self):
        error_msg = "Invalid Credentials"
        fp = mock.MagicMock()
        fp.read.return_value = '{{"error-msg": "{0}"}}'.format(error_msg)
        send_mock = mock.MagicMock(side_effect=HTTPError('url', 400, 'msg', 'hdrs', fp))
        with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
            with self.assertRaises(ConnectionError) as res:
                self.ftd_plugin._get_supported_api_versions()

        assert error_msg in str(res.exception)

    def test_get_list_of_supported_api_versions_with_buggy_response(self):
        error_msg = "Non JSON value"
        http_response_mock = mock.MagicMock()
        http_response_mock.getvalue.return_value = error_msg

        send_mock = mock.MagicMock(return_value=(None, http_response_mock))

        with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
            with self.assertRaises(ConnectionError) as res:
                self.ftd_plugin._get_supported_api_versions()
        assert error_msg in str(res.exception)

    def test_get_list_of_supported_api_versions_with_positive_response(self):
        http_response_mock = mock.MagicMock()
        http_response_mock.getvalue.return_value = '{"supportedVersions": ["v1"]}'

        send_mock = mock.MagicMock(return_value=(None, http_response_mock))
        with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
            supported_versions = self.ftd_plugin._get_supported_api_versions()
            assert supported_versions == ['v1']

    @patch('httpapi_plugins.ftd.HttpApi._get_api_token_path', mock.MagicMock(return_value=None))
    @patch('httpapi_plugins.ftd.HttpApi._get_known_token_paths')
    def test_lookup_login_url_with_empty_response(self, get_known_token_paths_mock):
        payload = mock.MagicMock()
        get_known_token_paths_mock.return_value = []
        self.assertRaises(
            ConnectionError,
            self.ftd_plugin._lookup_login_url,
            payload
        )

    @patch('httpapi_plugins.ftd.HttpApi._get_known_token_paths')
    @patch('httpapi_plugins.ftd.HttpApi._send_login_request')
    @patch('httpapi_plugins.ftd.display')
    def test_lookup_login_url_with_failed_request(self, display_mock, api_request_mock, get_known_token_paths_mock):
        payload = mock.MagicMock()
        url = mock.MagicMock()
        get_known_token_paths_mock.return_value = [url]
        api_request_mock.side_effect = ConnectionError('Error message')
        self.assertRaises(
            ConnectionError,
            self.ftd_plugin._lookup_login_url,
            payload
        )
        assert display_mock.vvvv.called

    @patch('httpapi_plugins.ftd.HttpApi._get_api_token_path', mock.MagicMock(return_value=None))
    @patch('httpapi_plugins.ftd.HttpApi._get_known_token_paths')
    @patch('httpapi_plugins.ftd.HttpApi._send_login_request')
    @patch('httpapi_plugins.ftd.HttpApi._set_api_token_path')
    def test_lookup_login_url_with_positive_result(self, set_api_token_mock, api_request_mock,
                                                   get_known_token_paths_mock):
        payload = mock.MagicMock()
        url = mock.MagicMock()
        get_known_token_paths_mock.return_value = [url]
        response_mock = mock.MagicMock()
        api_request_mock.return_value = response_mock

        resp = self.ftd_plugin._lookup_login_url(payload)

        set_api_token_mock.assert_called_once_with(url)
        assert resp == response_mock

    @patch('httpapi_plugins.ftd.HttpApi._get_supported_api_versions')
    def test_get_known_token_paths_with_positive_response(self, get_list_of_supported_api_versions_mock):
        test_versions = ['v1', 'v2']
        get_list_of_supported_api_versions_mock.return_value = test_versions
        result = self.ftd_plugin._get_known_token_paths()
        assert result == [TOKEN_PATH_TEMPLATE.format(version) for version in test_versions]

    @patch('httpapi_plugins.ftd.HttpApi._get_supported_api_versions')
    def test_get_known_token_paths_with_failed_api_call(self, get_list_of_supported_api_versions_mock):
        get_list_of_supported_api_versions_mock.side_effect = ConnectionError('test errro message')
        result = self.ftd_plugin._get_known_token_paths()
        assert result == [TOKEN_PATH_TEMPLATE.format(version) for version in DEFAULT_API_VERSIONS]

    def test_set_api_token_path(self):
        url = mock.MagicMock()
        self.ftd_plugin._set_api_token_path(url)
        assert self.ftd_plugin._get_api_token_path() == url
示例#29
0
def virt_net_obj(dummy_libvirt):
    return virt_net.VirtNetwork('qemu:///nowhere', mock.MagicMock())
 def setUp(self):
     self._conn = mock.MagicMock()
     self._resource = BaseConfigurationResource(self._conn)