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'
         }
     }
    def _resource_execute_operation(params, connection):

        with mock.patch.object(BaseConfigurationResource,
                               '_fetch_system_info') as fetch_system_info_mock:
            fetch_system_info_mock.return_value = {
                'databaseInfo': {
                    'buildVersion': '6.3.0'
                }
            }
            resource = BaseConfigurationResource(connection)
            op_name = params['operation']

            resp = resource.execute_operation(op_name, params)

        return resp
def main():
    fields = dict(device_hostname=dict(type='str', required=True),
                  device_username=dict(type='str',
                                       required=False,
                                       default='admin'),
                  device_password=dict(type='str', required=True, no_log=True),
                  device_sudo_password=dict(type='str',
                                            required=False,
                                            no_log=True),
                  device_new_password=dict(type='str',
                                           required=False,
                                           no_log=True),
                  device_ip=dict(type='str', required=False),
                  device_netmask=dict(type='str', required=False),
                  device_gateway=dict(type='str', required=False),
                  device_model=dict(type='str',
                                    required=False,
                                    choices=FtdModel.supported_models()),
                  dns_server=dict(type='str', required=False),
                  search_domains=dict(type='str',
                                      required=False,
                                      default='cisco.com'),
                  console_ip=dict(type='str', required=True),
                  console_port=dict(type='str', required=True),
                  console_username=dict(type='str', required=True),
                  console_password=dict(type='str', required=True,
                                        no_log=True),
                  rommon_file_location=dict(type='str', required=True),
                  image_file_location=dict(type='str', required=True),
                  image_version=dict(type='str', required=True),
                  force_install=dict(type='bool',
                                     required=False,
                                     default=False))
    module = AnsibleModule(argument_spec=fields)
    assert_kick_is_installed(module)

    use_local_connection = module._socket_path is None
    if use_local_connection:
        check_required_params_for_local_connection(module, module.params)
        platform_model = module.params['device_model']
        check_that_model_is_supported(module, platform_model)
    else:
        connection = Connection(module._socket_path)
        resource = BaseConfigurationResource(connection, module.check_mode)
        system_info = get_system_info(resource)

        platform_model = module.params['device_model'] or system_info[
            'platformModel']
        check_that_model_is_supported(module, platform_model)
        check_that_update_is_needed(module, system_info)
        check_management_and_dns_params(resource, module.params)

    ftd_platform = FtdPlatformFactory.create(platform_model, module.params)
    ftd_platform.install_ftd_image(module.params)

    module.exit_json(
        changed=True,
        msg='Successfully installed FTD image %s on the firewall device.' %
        module.params["image_version"])
Exemple #4
0
    def test_stringify_name_filter(self, test_api_version, expected_result,
                                   connection_mock):
        filters = {"name": "object_name"}

        with patch.object(BaseConfigurationResource,
                          '_fetch_system_info') as fetch_system_info_mock:
            fetch_system_info_mock.return_value = {
                'databaseInfo': {
                    'buildVersion': test_api_version
                }
            }
            resource = BaseConfigurationResource(connection_mock, False)

            assert resource._stringify_name_filter(
                filters
            ) == expected_result, "Unexpected result for version %s" % (
                test_api_version)
Exemple #5
0
    def test_module_should_fail_if_validation_error_in_path_params(
            self, connection_mock):
        connection_mock.get_operation_spec.return_value = {
            'method': HTTPMethod.GET,
            'url': '/test',
            'returnMultipleItems': False
        }
        report = {
            'path_params': {
                'required': ['objects[0].type'],
                'invalid_type': [{
                    'path': 'objects[3].id',
                    'expected_type': 'string',
                    'actually_value': 1
                }]
            }
        }
        connection_mock.validate_path_params.return_value = (
            False, json.dumps(report, sort_keys=True, indent=4))

        with pytest.raises(ValidationError) as e_info:
            resource = BaseConfigurationResource(connection_mock, False)
            resource.crud_operation('putTest', {'data': {}})

        result = e_info.value.args[0]

        key = 'Invalid path_params provided'
        assert result[key]
        result[key] = json.loads(result[key])

        assert result == {
            key: {
                'path_params': {
                    'invalid_type': [{
                        'actually_value': 1,
                        'expected_type': 'string',
                        'path': 'objects[3].id'
                    }],
                    'required': ['objects[0].type']
                }
            }
        }
Exemple #6
0
def main():
    fields = dict(operation=dict(type='str', required=True),
                  data=dict(type='dict'),
                  query_params=dict(type='dict'),
                  path_params=dict(type='dict'),
                  register_as=dict(type='str'),
                  filters=dict(type='dict'))
    module = AnsibleModule(argument_spec=fields, supports_check_mode=True)
    params = module.params

    connection = Connection(module._socket_path)
    resource = BaseConfigurationResource(connection, module.check_mode)
    op_name = params['operation']
    try:
        resp = resource.execute_operation(op_name, params)
        module.exit_json(changed=resource.config_changed,
                         response=resp,
                         ansible_facts=construct_ansible_facts(
                             resp, module.params))
    except FtdInvalidOperationNameError as e:
        module.fail_json(msg='Invalid operation name provided: %s' %
                         e.operation_name)
    except FtdConfigurationError as e:
        module.fail_json(
            msg=
            'Failed to execute %s operation because of the configuration error: %s'
            % (op_name, e.msg))
    except FtdServerError as e:
        module.fail_json(
            msg=
            'Server returned an error trying to execute %s operation. Status code: %s. '
            'Server response: %s' % (op_name, e.code, e.response))
    except FtdUnexpectedResponse as e:
        module.fail_json(msg=e.args[0])
    except ValidationError as e:
        module.fail_json(msg=e.args[0])
    except CheckModeException:
        module.exit_json(changed=False)
class TestUpsertOperationUnitTests(unittest.TestCase):
    @mock.patch.object(BaseConfigurationResource, '_fetch_system_info')
    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'
            }
        }

    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

    @mock.patch.object(BaseConfigurationResource, "_get_operation_name")
    @mock.patch.object(BaseConfigurationResource, "add_object")
    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)

    @mock.patch.object(BaseConfigurationResource, "_get_operation_name")
    @mock.patch.object(BaseConfigurationResource, "add_object")
    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()

    @mock.patch.object(BaseConfigurationResource, "_get_operation_name")
    @mock.patch.object(BaseConfigurationResource, "edit_object")
    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.copy_identity_properties'
    )
    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration._set_default'
    )
    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)

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    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()

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.equal_objects'
    )
    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    def test_upsert_object_successfully_edited(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

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

        assert result == edit_mock.return_value
        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_called_once_with(get_operation_mock.return_value,
                                          existing_obj, params)

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.equal_objects'
    )
    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    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()

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    def test_upsert_object_not_supported(self, edit_mock, add_mock,
                                         find_object, get_operation_mock,
                                         is_upsert_supported_mock):
        params = mock.MagicMock()

        is_upsert_supported_mock.return_value = False

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

        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)
        find_object.assert_not_called()
        add_mock.assert_not_called()
        edit_mock.assert_not_called()

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    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()

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.equal_objects'
    )
    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    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)

    @mock.patch(
        'ansible_collections.community.network.plugins.module_utils.network.ftd.configuration.OperationChecker.is_upsert_operation_supported'
    )
    @mock.patch.object(BaseConfigurationResource,
                       "get_operation_specs_by_model_name")
    @mock.patch.object(BaseConfigurationResource,
                       "_find_object_matching_params")
    @mock.patch.object(BaseConfigurationResource, "_add_upserted_object")
    @mock.patch.object(BaseConfigurationResource, "_edit_upserted_object")
    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()
Exemple #8
0
    def test_get_objects_by_filter_with_multiple_filters(
            self, send_request_mock, fetch_system_info_mock, connection_mock):
        objects = [{
            'name': 'obj1',
            'type': 1,
            'foo': {
                'bar': 'buzz'
            }
        }, {
            'name': 'obj2',
            'type': 1,
            'foo': {
                'bar': 'buz'
            }
        }, {
            'name': 'obj3',
            'type': 2,
            'foo': {
                'bar': 'buzz'
            }
        }]

        fetch_system_info_mock.return_value = {
            'databaseInfo': {
                'buildVersion': '6.3.0'
            }
        }

        connection_mock.get_operation_spec.return_value = {
            'method': HTTPMethod.GET,
            'url': '/object/'
        }
        resource = BaseConfigurationResource(connection_mock, False)

        send_request_mock.side_effect = [{'items': objects}, {'items': []}]
        # resource.get_objects_by_filter returns generator so to be able compare generated list with expected list
        # we need evaluate it.
        assert objects == list(resource.get_objects_by_filter('test', {}))
        send_request_mock.assert_has_calls(
            [mock.call('/object/', 'get', {}, {}, {
                'limit': 10,
                'offset': 0
            })])

        send_request_mock.reset_mock()
        send_request_mock.side_effect = [{'items': objects}, {'items': []}]
        # resource.get_objects_by_filter returns generator so to be able compare generated list with expected list
        # we need evaluate it.
        assert [objects[0]] == list(
            resource.get_objects_by_filter(
                'test', {ParamName.FILTERS: {
                    'name': 'obj1'
                }}))
        send_request_mock.assert_has_calls([
            mock.call('/object/', 'get', {}, {}, {
                QueryParams.FILTER: 'name:obj1',
                'limit': 10,
                'offset': 0
            })
        ])

        send_request_mock.reset_mock()
        send_request_mock.side_effect = [{'items': objects}, {'items': []}]
        # resource.get_objects_by_filter returns generator so to be able compare generated list with expected list
        # we need evaluate it.
        assert [objects[1]] == list(
            resource.get_objects_by_filter(
                'test', {
                    ParamName.FILTERS: {
                        'name': 'obj2',
                        'type': 1,
                        'foo': {
                            'bar': 'buz'
                        }
                    }
                }))

        send_request_mock.assert_has_calls([
            mock.call('/object/', 'get', {}, {}, {
                QueryParams.FILTER: 'name:obj2',
                'limit': 10,
                'offset': 0
            })
        ])
Exemple #9
0
    def test_module_should_fail_if_validation_error_in_all_params(
            self, connection_mock):
        connection_mock.get_operation_spec.return_value = {
            'method': HTTPMethod.POST,
            'url': '/test'
        }
        report = {
            'data': {
                'required': ['objects[0].type'],
                'invalid_type': [{
                    'path': 'objects[3].id',
                    'expected_type': 'string',
                    'actually_value': 1
                }]
            },
            'path_params': {
                'required': ['some_param'],
                'invalid_type': [{
                    'path': 'name',
                    'expected_type': 'string',
                    'actually_value': True
                }]
            },
            'query_params': {
                'required': ['other_param'],
                'invalid_type': [{
                    'path': 'f_integer',
                    'expected_type': 'integer',
                    'actually_value': "test"
                }]
            }
        }
        connection_mock.validate_data.return_value = (False,
                                                      json.dumps(
                                                          report['data'],
                                                          sort_keys=True,
                                                          indent=4))
        connection_mock.validate_query_params.return_value = (
            False, json.dumps(report['query_params'], sort_keys=True,
                              indent=4))
        connection_mock.validate_path_params.return_value = (
            False, json.dumps(report['path_params'], sort_keys=True, indent=4))

        with pytest.raises(ValidationError) as e_info:
            resource = BaseConfigurationResource(connection_mock, False)
            resource.crud_operation('putTest', {'data': {}})

        result = e_info.value.args[0]

        key_data = 'Invalid data provided'
        assert result[key_data]
        result[key_data] = json.loads(result[key_data])

        key_path_params = 'Invalid path_params provided'
        assert result[key_path_params]
        result[key_path_params] = json.loads(result[key_path_params])

        key_query_params = 'Invalid query_params provided'
        assert result[key_query_params]
        result[key_query_params] = json.loads(result[key_query_params])

        assert result == {
            key_data: {
                'invalid_type': [{
                    'actually_value': 1,
                    'expected_type': 'string',
                    'path': 'objects[3].id'
                }],
                'required': ['objects[0].type']
            },
            key_path_params: {
                'invalid_type': [{
                    'actually_value': True,
                    'expected_type': 'string',
                    'path': 'name'
                }],
                'required': ['some_param']
            },
            key_query_params: {
                'invalid_type': [{
                    'actually_value': 'test',
                    'expected_type': 'integer',
                    'path': 'f_integer'
                }],
                'required': ['other_param']
            }
        }
Exemple #10
0
    def test_get_objects_by_filter_with_multiple_responses(
            self, send_request_mock, fetch_system_info_mock, connection_mock):
        send_request_mock.side_effect = [{
            'items': [{
                'name': 'obj1',
                'type': 'foo'
            }, {
                'name': 'obj2',
                'type': 'bar'
            }]
        }, {
            'items': [{
                'name': 'obj3',
                'type': 'foo'
            }]
        }, {
            'items': []
        }]
        fetch_system_info_mock.return_value = {
            'databaseInfo': {
                'buildVersion': '6.3.0'
            }
        }
        connection_mock.get_operation_spec.return_value = {
            'method': HTTPMethod.GET,
            'url': '/object/'
        }
        resource = BaseConfigurationResource(connection_mock, False)
        assert [{
            'name': 'obj1',
            'type': 'foo'
        }] == list(
            resource.get_objects_by_filter(
                'test', {ParamName.FILTERS: {
                    'type': 'foo'
                }}))
        send_request_mock.assert_has_calls(
            [mock.call('/object/', 'get', {}, {}, {
                'limit': 10,
                'offset': 0
            })])

        send_request_mock.reset_mock()
        send_request_mock.side_effect = [{
            'items': [{
                'name': 'obj1',
                'type': 'foo'
            }, {
                'name': 'obj2',
                'type': 'bar'
            }]
        }, {
            'items': [{
                'name': 'obj3',
                'type': 'foo'
            }]
        }, {
            'items': []
        }]
        resp = list(
            resource.get_objects_by_filter(
                'test', {
                    ParamName.FILTERS: {
                        'type': 'foo'
                    },
                    ParamName.QUERY_PARAMS: {
                        'limit': 2
                    }
                }))
        assert [{
            'name': 'obj1',
            'type': 'foo'
        }, {
            'name': 'obj3',
            'type': 'foo'
        }] == resp
        send_request_mock.assert_has_calls([
            mock.call('/object/', 'get', {}, {}, {
                'limit': 2,
                'offset': 0
            }),
            mock.call('/object/', 'get', {}, {}, {
                'limit': 2,
                'offset': 2
            })
        ])