예제 #1
0
    def setUp(self):
        self.mapper = Mock(Mapper)
        self.mapper.for_decoding.return_value = {'foo': 'bar'}

        self.serializer = Mock(Serializer)
        self.parser = Mock(Parser)
        self.builder = Mock(Builder)

        self.converter = Converter(mapper=self.mapper,
                                   serializer=self.serializer,
                                   parser=self.parser,
                                   builder=self.builder)
예제 #2
0
def load(core_rest_api):
    user_blueprint = core_rest_api.blueprint('users')
    document = core_rest_api.content_parser.document(
        Field('user_id', Int()),
        Field('line_id', Int()),
        Field('main_user', Boolean()),
        Field('main_line', Boolean())
    )
    converter = Converter.association(document, UserLine,
                                      links={'users': 'user_id',
                                             'lines': 'line_id'},
                                      rename={'parent_id': 'user_id'})

    service = UserLineService(user_line_services, user_dao, line_dao)
    resource = CollectionAssociationResource(service, converter)

    chain = DecoratorChain(core_rest_api, user_blueprint)

    (chain
     .get('/<int:parent_id>/lines')
     .decorate(resource.list_association))

    (chain
     .create('/<int:parent_id>/lines')
     .decorate(resource.associate_collection))

    (chain
     .delete('/<int:parent_id>/lines/<int:resource_id>')
     .decorate(resource.dissociate_collection))

    core_rest_api.register(user_blueprint)
예제 #3
0
def load(core_rest_api):
    blueprint = Blueprint('lines', __name__, url_prefix='/%s/lines' % config.API_VERSION)

    document = core_rest_api.content_parser.document(
        Field('id', Int()),
        Field('context', Unicode()),
        Field('name', Unicode()),
        Field('protocol', Unicode()),
        Field('provisioning_extension', Unicode()),
        Field('device_slot', Int()),
        Field('device_id', Unicode()),
    )
    converter = Converter.resource(document, Line)

    line_services.setup_provd_client(core_rest_api.provd_client())

    actions_sip.load(core_rest_api)

    service = LineServiceProxy(line_services)
    resource = CRUDResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.search().decorate(resource.search)
    chain.get().decorate(resource.get)

    core_rest_api.register(blueprint)
예제 #4
0
def load(core_rest_api):
    user_blueprint = core_rest_api.blueprint("users")
    document = core_rest_api.content_parser.document(
        Field("user_id", Int()), Field("cti_profile_id", Int()), Field("enabled", Boolean())
    )
    converter = Converter.association(document, UserCtiProfile, {"users": "user_id", "cti_profiles": "cti_profile_id"})

    @user_blueprint.route("/<int:user_id>/cti", methods=["PUT"])
    @core_rest_api.auth.login_required
    @consumes("application/json")
    def edit_cti_configuration(user_id):
        user_dao.get(user_id)
        user_cti_profile = converter.decode(request)
        user_cti_profile_services.edit(user_cti_profile)
        return Response(status=204)

    @user_blueprint.route("/<int:user_id>/cti", methods=["GET"])
    @core_rest_api.auth.login_required
    @produces("application/json")
    def get_cti_configuration(user_id):
        user_dao.get(user_id)
        user_cti_profile = user_cti_profile_services.get(user_id)
        response = converter.encode(user_cti_profile)
        return Response(response=response, status=200, content_type="application/json")

    core_rest_api.register(user_blueprint)
예제 #5
0
def load(core_rest_api):
    blueprint = Blueprint("voicemails", __name__, url_prefix="/%s/voicemails" % config.API_VERSION)
    document = core_rest_api.content_parser.document(
        Field("id", Int()),
        Field("name", Unicode()),
        Field("number", Unicode(), Regexp.compile(r"\d+", "wrong type. Should be a numeric string")),
        Field("context", Unicode()),
        Field("password", Unicode(), Regexp.compile(r"\d+", "wrong type. Should be a numeric string")),
        Field("email", Unicode()),
        Field("language", Unicode()),
        Field("timezone", Unicode()),
        Field("pager", Unicode()),
        Field("max_messages", Int()),
        Field("attach_audio", Boolean()),
        Field("delete_messages", Boolean()),
        Field("ask_password", Boolean()),
        Field("enabled", Boolean()),
        Field("options", OptionType()),
    )

    converter = Converter.resource(document, Voicemail)
    sysconfd_client = new_client()
    validator = build_validators()

    service = VoicemailService(dao, validator, notifier, sysconfd_client)
    resource = CRUDResource(service, converter)

    DecoratorChain.register_scrud(core_rest_api, blueprint, resource)
예제 #6
0
def load(core_rest_api):
    blueprint = Blueprint('queues', __name__, url_prefix='/%s/queues' % config.API_VERSION)
    document = core_rest_api.content_parser.document(
        Field('queue_id', Int()),
        Field('agent_id', Int()),
        Field('penalty', Int())
    )
    converter = Converter.association(document, QueueMemberAgent,
                                      rename={'parent_id': 'queue_id',
                                              'resource_id': 'agent_id'})

    service = QueueMemberService(dao, validator, notifier)
    resource = QueueMemberAssociationResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)

    (chain
     .get('/<int:parent_id>/members/agents/<int:resource_id>')
     .decorate(resource.get_association))

    (chain
     .edit('/<int:parent_id>/members/agents/<int:resource_id>')
     .decorate(resource.edit_association))

    (chain
     .create('/<int:parent_id>/members/agents')
     .decorate(resource.associate_collection))

    (chain
     .delete('/<int:parent_id>/members/agents/<int:resource_id>')
     .decorate(resource.dissociate_collection))

    core_rest_api.register(blueprint)
예제 #7
0
def load(core_rest_api):
    blueprint = Blueprint('queues',
                          __name__,
                          url_prefix='/%s/queues' % config.API_VERSION)
    document = core_rest_api.content_parser.document(Field('queue_id', Int()),
                                                     Field('agent_id', Int()),
                                                     Field('penalty', Int()))
    converter = Converter.association(document,
                                      QueueMemberAgent,
                                      rename={
                                          'parent_id': 'queue_id',
                                          'resource_id': 'agent_id'
                                      })

    service = QueueMemberService(dao, validator, notifier)
    resource = QueueMemberAssociationResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)

    (chain.get('/<int:parent_id>/members/agents/<int:resource_id>').decorate(
        resource.get_association))

    (chain.edit('/<int:parent_id>/members/agents/<int:resource_id>').decorate(
        resource.edit_association))

    (chain.create('/<int:parent_id>/members/agents').decorate(
        resource.associate_collection))

    (chain.delete(
        '/<int:parent_id>/members/agents/<int:resource_id>').decorate(
            resource.dissociate_collection))

    core_rest_api.register(blueprint)
예제 #8
0
    def test_resource_replaces_resource_name_and_resource_id(self):
        document = Mock()

        class Model(object):
            pass

        converter = Converter.resource(document, Model, 'resource_name', 'resource_id')

        assert_that(converter.serializer.resources, has_entry('resource_name', 'resource_id'))
예제 #9
0
def load(core_rest_api):
    document = core_rest_api.content_parser.document(
        Field('id', Unicode()),
        Field('ip', Unicode()),
        Field('mac', Unicode()),
        Field('sn', Unicode()),
        Field('plugin', Unicode()),
        Field('vendor', Unicode()),
        Field('model', Unicode()),
        Field('version', Unicode()),
        Field('description', Unicode()),
        Field('status', Unicode()),
        Field('template_id', Unicode()),
        Field('options', Dict())
    )

    blueprint = Blueprint('devices', __name__, url_prefix='/%s/devices' % config.API_VERSION)

    converter = Converter.resource(document, Device)

    provd_client = core_rest_api.provd_client()

    device_dao = builder.build_dao(provd_client)
    device_service = builder.build_service(device_dao)
    device_updater = builder.build_device_updater(device_dao)
    association_service = builder.build_line_device_associator(device_updater)

    resource = DeviceResource(device_service, association_service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.search().decorate(resource.search)
    chain.get('/<resource_id>').decorate(resource.get)
    chain.create().decorate(resource.create)
    chain.edit('/<resource_id>').decorate(resource.edit)
    chain.delete('/<resource_id>').decorate(resource.delete)

    (chain
     .get('/<device_id>/synchronize')
     .decorate(resource.synchronize))

    (chain
     .get('/<device_id>/autoprov')
     .decorate(resource.autoprov))

    (chain
     .limit_localhost()
     .get('/<device_id>/associate_line/<int:line_id>')
     .decorate(resource.associate_line))

    (chain
     .limit_localhost()
     .get('/<device_id>/remove_line/<int:line_id>')
     .decorate(resource.remove_line))

    core_rest_api.register(blueprint)
예제 #10
0
def load(core_rest_api):
    blueprint = Blueprint('infos', __name__, url_prefix='/%s/infos' % config.API_VERSION)
    document = core_rest_api.content_parser.document(Field('uuid', Unicode()))

    converter = Converter.resource(document, Infos, 'infos', 'uuid')
    resource = InfoResource(dao, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.get('').decorate(resource.get)

    core_rest_api.register(blueprint)
예제 #11
0
def load(core_rest_api):
    blueprint = Blueprint('infos', __name__, url_prefix='/%s/infos' % config.API_VERSION)
    document = core_rest_api.content_parser.document(Field('uuid', Unicode()))

    converter = Converter.resource(document, Infos, 'infos', 'uuid')
    resource = InfoResource(dao, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.get('').decorate(resource.get)

    core_rest_api.register(blueprint)
예제 #12
0
def build_association_converter(content_parser):
    document = content_parser.document(
        Field('user_id', Int()),
        Field('template_id', Int())
    )

    converter = Converter.association(document, UserTemplate,
                                      links={'users': 'user_id',
                                             'func_key_templates': 'template_id'})

    return converter
예제 #13
0
    def setUp(self):
        self.mapper = Mock(Mapper)
        self.mapper.for_decoding.return_value = {'foo': 'bar'}

        self.serializer = Mock(Serializer)
        self.parser = Mock(Parser)
        self.builder = Mock(Builder)

        self.converter = Converter(mapper=self.mapper,
                                   serializer=self.serializer,
                                   parser=self.parser,
                                   builder=self.builder)
예제 #14
0
def load(core_rest_api):
    blueprint = Blueprint('users', __name__, url_prefix='/%s/users' % config.API_VERSION)

    user_document = core_rest_api.content_parser.document(
        Field('id', Int()),
        Field('uuid', Unicode()),
        Field('firstname', Unicode()),
        Field('lastname', Unicode()),
        Field('caller_id', Unicode()),
        Field('outgoing_caller_id', Unicode()),
        Field('username', Unicode()),
        Field('password', Unicode()),
        Field('music_on_hold', Unicode()),
        Field('mobile_phone_number', Unicode()),
        Field('userfield', Unicode()),
        Field('timezone', Unicode()),
        Field('language', Unicode()),
        Field('description', Unicode()),
        Field('preprocess_subroutine', Unicode())
    )

    directory_document = core_rest_api.content_parser.document(
        Field('id', Int()),
        Field('line_id', Int()),
        Field('agent_id', Int()),
        Field('firstname', Unicode()),
        Field('lastname', Unicode()),
        Field('exten', Unicode()),
        Field('mobile_phone_number', Unicode()),
        Field('userfield', Unicode()),
        Field('description', Unicode()),
    )

    user_converter = Converter.resource(user_document, User)
    directory_converter = Converter(parser=DocumentParser(directory_document),
                                    mapper=DocumentMapper(directory_document, UserDirectory),
                                    serializer=DirectorySerializer(),
                                    builder=ModelBuilder(directory_document, UserDirectory))

    resource = UserResource(user_services, user_converter, directory_converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.search().decorate(resource.search)
    chain.get().decorate(resource.get)
    chain.get('/<uuid:resource_uuid>').decorate(resource.get_by_uuid)
    chain.create().decorate(resource.create)
    chain.edit().decorate(resource.edit)
    chain.edit('/<uuid:resource_uuid>').decorate(resource.edit_by_uuid)
    chain.delete().decorate(resource.delete)
    chain.delete('/<uuid:resource_uuid>').decorate(resource.delete_by_uuid)

    core_rest_api.register(blueprint)
예제 #15
0
    def test_resource_creates_resource_converter(self):
        document = Mock()

        class Model(object):
            pass

        converter = Converter.resource(document, Model)

        assert_that(converter.parser, instance_of(DocumentParser))
        assert_that(converter.mapper, instance_of(DocumentMapper))
        assert_that(converter.serializer, instance_of(ResourceSerializer))
        assert_that(converter.builder, instance_of(ModelBuilder))
        assert_that(converter.serializer.resources, has_entry('models', 'id'))
예제 #16
0
    def test_association_creates_request_converter(self):
        document = Mock()

        class Model(object):
            pass

        links = {'users': 'user_id', 'lines': 'line_id'}
        converter = Converter.association(document, Model, links)

        assert_that(converter.parser, instance_of(RequestParser))
        assert_that(converter.mapper, instance_of(DocumentMapper))
        assert_that(converter.serializer, instance_of(ResourceSerializer))
        assert_that(converter.builder, instance_of(ModelBuilder))
        assert_that(converter.serializer.resources, has_entries(links))
예제 #17
0
def load(core_rest_api):
    line_blueprint = core_rest_api.blueprint('lines')
    extension_blueprint = core_rest_api.blueprint('extensions')

    document = core_rest_api.content_parser.document(
        Field('line_id', Int()),
        Field('extension_id', Int())
    )
    converter = Converter.association(document, LineExtension,
                                      links={'lines': 'line_id',
                                             'extensions': 'extension_id'},
                                      rename={'parent_id': 'line_id'})

    service = LineExtensionService(line_extension_services, line_dao, extension_dao)
    single_resource = SingleLineExtensionResource(service, converter)
    collection_resource = CollectionAssociationResource(service, converter)

    chain = DecoratorChain(core_rest_api, line_blueprint)

    (chain
     .get('/<int:parent_id>/extensions')
     .decorate(collection_resource.list_association))

    (chain
     .create('/<int:parent_id>/extensions')
     .decorate(collection_resource.associate_collection))

    (chain
     .delete('/<int:parent_id>/extensions/<int:resource_id>')
     .decorate(collection_resource.dissociate_collection))

    (chain
     .get('/<int:parent_id>/extension')
     .decorate(single_resource.get_association))

    (chain
     .create('/<int:parent_id>/extension')
     .decorate(single_resource.associate))

    (chain
     .delete('/<int:parent_id>/extension')
     .decorate(single_resource.dissociate))

    (DecoratorChain(core_rest_api, extension_blueprint)
     .get('/<int:extension_id>/line')
     .decorate(single_resource.get_by_extension))

    core_rest_api.register(line_blueprint)
    core_rest_api.register(extension_blueprint)
예제 #18
0
def load(core_rest_api):
    blueprint = Blueprint('configuration',
                          __name__,
                          url_prefix='/%s/configuration' % config.API_VERSION)
    document = core_rest_api.content_parser.document(Field('enabled', Boolean()))
    converter = Converter.association(document, LiveReload)

    service = LiveReloadService(dao, validator, notifier)
    resource = LiveReloadResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.get('/live_reload').decorate(resource.get)
    chain.edit('/live_reload').decorate(resource.edit)

    core_rest_api.register(blueprint)
예제 #19
0
def load(core_rest_api):
    blueprint = Blueprint('configuration',
                          __name__,
                          url_prefix='/%s/configuration' % config.API_VERSION)
    document = core_rest_api.content_parser.document(Field('enabled', Boolean()))
    converter = Converter.association(document, LiveReload)

    service = LiveReloadService(dao, validator, notifier)
    resource = LiveReloadResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.get('/live_reload').decorate(resource.get)
    chain.edit('/live_reload').decorate(resource.edit)

    core_rest_api.register(blueprint)
예제 #20
0
def load(core_rest_api):
    blueprint = Blueprint('cti_profiles',
                          __name__,
                          url_prefix='/%s/cti_profiles' % config.API_VERSION)
    document = core_rest_api.content_parser.document(Field('id', Int()),
                                                     Field('name', Unicode()))
    converter = Converter.resource(document, CtiProfile, 'cti_profiles')

    service = CtiProfileService(dao)
    resource = CtiProfileResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.search().decorate(resource.search)
    chain.get().decorate(resource.get)

    core_rest_api.register(blueprint)
예제 #21
0
def load(core_rest_api):
    blueprint = Blueprint('cti_profiles', __name__, url_prefix='/%s/cti_profiles' % config.API_VERSION)
    document = core_rest_api.content_parser.document(
        Field('id', Int()),
        Field('name', Unicode())
    )
    converter = Converter.resource(document, CtiProfile, 'cti_profiles')

    service = CtiProfileService(dao)
    resource = CRUDResource(service, converter)

    chain = DecoratorChain(core_rest_api, blueprint)
    chain.search().decorate(resource.search)
    chain.get().decorate(resource.get)

    core_rest_api.register(blueprint)
예제 #22
0
def load(core_rest_api):
    blueprint = Blueprint('lines_sip', __name__, url_prefix='/%s/lines_sip' % config.API_VERSION)
    document = core_rest_api.content_parser.document(
        Field('id', Int()),
        Field('context', Unicode()),
        Field('username', Unicode()),
        Field('secret', Unicode()),
        Field('provisioning_extension', Unicode()),
        Field('device_slot', Int()),
        Field('callerid', Unicode()),
    )
    converter = Converter.resource(document, LineSIP, 'lines_sip')

    service = LineSIPServiceProxy(line_services)
    resource = CRUDResource(service, converter)

    DecoratorChain.register_scrud(core_rest_api, blueprint, resource)
예제 #23
0
def load(core_rest_api):
    blueprint = Blueprint('extensions',
                          __name__,
                          url_prefix='/%s/extensions' % config.API_VERSION)

    document = core_rest_api.content_parser.document(
        Field('id', Int()),
        Field('exten', Unicode()),
        Field('context', Unicode()),
        Field('commented', Boolean())
    )
    converter = Converter.resource(document, Extension)

    service = ExtensionService(dao, line_extension_dao, line_dao, validator, notifier)
    resource = CRUDResource(service, converter, ['type'])

    DecoratorChain.register_scrud(core_rest_api, blueprint, resource)
예제 #24
0
def load(core_rest_api):
    user_blueprint = core_rest_api.blueprint('users')
    vm_blueprint = core_rest_api.blueprint('voicemails')

    document = core_rest_api.content_parser.document(
        Field('user_id', Int()),
        Field('voicemail_id', Int()),
        Field('enabled', Boolean())
    )
    converter = Converter.association(document, UserVoicemail,
                                      links={'users': 'user_id',
                                             'voicemails': 'voicemail_id'},
                                      rename={'parent_id': 'user_id'})
    validator = build_validator()

    service = UserVoicemailService(user_dao,
                                   voicemail_dao,
                                   user_voicemail_dao,
                                   validator,
                                   notifier)
    resource = UserVoicemailResource(service, converter)

    user_chain = DecoratorChain(core_rest_api, user_blueprint)
    vm_chain = DecoratorChain(core_rest_api, vm_blueprint)

    (user_chain
     .get('/<int:parent_id>/voicemail')
     .decorate(resource.get_association))

    (user_chain
     .create('/<int:parent_id>/voicemail')
     .decorate(resource.associate))

    (user_chain
     .delete('/<int:parent_id>/voicemail')
     .decorate(resource.dissociate))

    (vm_chain
     .get('/<int:voicemail_id>/users')
     .decorate(resource.list_associations_by_child))

    core_rest_api.register(user_blueprint)
    core_rest_api.register(vm_blueprint)
예제 #25
0
def load(core_rest_api):
    blueprint = Blueprint('voicemails',
                          __name__,
                          url_prefix='/%s/voicemails' % config.API_VERSION)
    document = core_rest_api.content_parser.document(
        Field('id', Int()), Field('name', Unicode()),
        Field('number', Unicode()), Field('context', Unicode()),
        Field('password', Unicode()), Field('email', Unicode()),
        Field('language', Unicode()), Field('timezone', Unicode()),
        Field('pager', Unicode()), Field('max_messages', Int()),
        Field('attach_audio', Boolean()), Field('delete_messages', Boolean()),
        Field('ask_password', Boolean()), Field('enabled', Boolean()),
        Field('options', OptionType()))

    converter = Converter.resource(document, Voicemail)

    service = build_service()
    resource = VoicemailResource(service, converter)

    DecoratorChain.register_scrud(core_rest_api, blueprint, resource)
예제 #26
0
class TestConverter(unittest.TestCase):
    def setUp(self):
        self.mapper = Mock(Mapper)
        self.mapper.for_decoding.return_value = {'foo': 'bar'}

        self.serializer = Mock(Serializer)
        self.parser = Mock(Parser)
        self.builder = Mock(Builder)

        self.converter = Converter(mapper=self.mapper,
                                   serializer=self.serializer,
                                   parser=self.parser,
                                   builder=self.builder)

    def test_when_encoding_then_maps_model_using_mapper(self):
        model = Mock()

        self.converter.encode(model)

        self.mapper.for_encoding.assert_called_once_with(model)

    def test_when_encoding_then_serializes_mapping(self):
        model = Mock()
        mapped_model = self.mapper.for_encoding.return_value
        serialized_model = self.serializer.serialize.return_value

        result = self.converter.encode(model)

        assert_that(result, equal_to(serialized_model))
        self.serializer.serialize.assert_called_once_with(mapped_model)

    def test_when_encoding_list_then_maps_each_item(self):
        model1 = Mock()
        model2 = Mock()

        self.converter.encode_list([model1, model2])

        self.mapper.for_encoding.assert_any_call(model1)
        self.mapper.for_encoding.assert_any_call(model2)

    def test_when_encoding_list_then_serializes_mapped_items(self):
        model1 = Mock()
        model2 = Mock()

        mapped_model1 = Mock()
        mapped_model2 = Mock()

        def mock_mapper(item):
            if item == model1:
                return mapped_model1
            if item == model2:
                return mapped_model2

        self.mapper.for_encoding.side_effect = mock_mapper
        serialized_models = self.serializer.serialize_list.return_value

        result = self.converter.encode_list([model1, model2], total=5)

        assert_that(result, equal_to(serialized_models))
        self.serializer.serialize_list.assert_called_once_with(
            [mapped_model1, mapped_model2], total=5)

    def test_when_decoding_then_parses_request_using_parser(self):
        request = Mock()

        self.converter.decode(request)

        self.parser.parse.assert_called_once_with(request)

    def test_when_decoding_then_maps_parsed_request(self):
        request = Mock()

        parsed_request = self.parser.parse.return_value

        self.converter.decode(request)

        self.mapper.for_decoding.assert_called_once_with(parsed_request)

    def test_when_decoding_then_builds_model_using_mapping(self):
        request = Mock()
        expected_model = self.builder.create.return_value

        result = self.converter.decode(request)

        assert_that(result, equal_to(expected_model))
        self.builder.create.assert_called_once_with(
            self.mapper.for_decoding.return_value)

    def test_when_updating_then_request_parsed(self):
        request = Mock()
        model = Mock()

        self.converter.update(request, model)

        self.parser.parse.assert_called_once_with(request)

    def test_when_updating_then_request_mapped(self):
        request = Mock()
        model = Mock()
        parsed_request = self.parser.parse.return_value

        self.converter.update(request, model)

        self.mapper.for_decoding.assert_called_with(parsed_request)

    def test_when_updating_then_updates_using_mapped_request(self):
        request = Mock()
        model = Mock()
        mapped_request = self.mapper.for_decoding.return_value

        self.converter.update(request, model)

        self.builder.update.assert_called_once_with(model, mapped_request)
예제 #27
0
class TestConverter(unittest.TestCase):

    def setUp(self):
        self.mapper = Mock(Mapper)
        self.mapper.for_decoding.return_value = {'foo': 'bar'}

        self.serializer = Mock(Serializer)
        self.parser = Mock(Parser)
        self.builder = Mock(Builder)

        self.converter = Converter(mapper=self.mapper,
                                   serializer=self.serializer,
                                   parser=self.parser,
                                   builder=self.builder)

    def test_when_encoding_then_maps_model_using_mapper(self):
        model = Mock()

        self.converter.encode(model)

        self.mapper.for_encoding.assert_called_once_with(model)

    def test_when_encoding_then_serializes_mapping(self):
        model = Mock()
        mapped_model = self.mapper.for_encoding.return_value
        serialized_model = self.serializer.serialize.return_value

        result = self.converter.encode(model)

        assert_that(result, equal_to(serialized_model))
        self.serializer.serialize.assert_called_once_with(mapped_model)

    def test_when_encoding_list_then_maps_each_item(self):
        model1 = Mock()
        model2 = Mock()

        self.converter.encode_list([model1, model2])

        self.mapper.for_encoding.assert_any_call(model1)
        self.mapper.for_encoding.assert_any_call(model2)

    def test_when_encoding_list_then_serializes_mapped_items(self):
        model1 = Mock()
        model2 = Mock()

        mapped_model1 = Mock()
        mapped_model2 = Mock()

        def mock_mapper(item):
            if item == model1:
                return mapped_model1
            if item == model2:
                return mapped_model2

        self.mapper.for_encoding.side_effect = mock_mapper
        serialized_models = self.serializer.serialize_list.return_value

        result = self.converter.encode_list([model1, model2], total=5)

        assert_that(result, equal_to(serialized_models))
        self.serializer.serialize_list.assert_called_once_with([mapped_model1, mapped_model2], total=5)

    def test_when_decoding_then_parses_request_using_parser(self):
        request = Mock()

        self.converter.decode(request)

        self.parser.parse.assert_called_once_with(request)

    def test_when_decoding_then_maps_parsed_request(self):
        request = Mock()

        parsed_request = self.parser.parse.return_value

        self.converter.decode(request)

        self.mapper.for_decoding.assert_called_once_with(parsed_request)

    def test_when_decoding_then_builds_model_using_mapping(self):
        request = Mock()
        expected_model = self.builder.create.return_value

        result = self.converter.decode(request)

        assert_that(result, equal_to(expected_model))
        self.builder.create.assert_called_once_with(self.mapper.for_decoding.return_value)

    def test_when_updating_then_request_parsed(self):
        request = Mock()
        model = Mock()

        self.converter.update(request, model)

        self.parser.parse.assert_called_once_with(request)

    def test_when_updating_then_request_mapped(self):
        request = Mock()
        model = Mock()
        parsed_request = self.parser.parse.return_value

        self.converter.update(request, model)

        self.mapper.for_decoding.assert_called_with(parsed_request)

    def test_when_updating_then_updates_using_mapped_request(self):
        request = Mock()
        model = Mock()
        mapped_request = self.mapper.for_decoding.return_value

        self.converter.update(request, model)

        self.builder.update.assert_called_once_with(model, mapped_request)

    def test_resource_creates_resource_converter(self):
        document = Mock()

        class Model(object):
            pass

        converter = Converter.resource(document, Model)

        assert_that(converter.parser, instance_of(DocumentParser))
        assert_that(converter.mapper, instance_of(DocumentMapper))
        assert_that(converter.serializer, instance_of(ResourceSerializer))
        assert_that(converter.builder, instance_of(ModelBuilder))
        assert_that(converter.serializer.resources, has_entry('models', 'id'))

    def test_resource_replaces_resource_name_and_resource_id(self):
        document = Mock()

        class Model(object):
            pass

        converter = Converter.resource(document, Model, 'resource_name', 'resource_id')

        assert_that(converter.serializer.resources, has_entry('resource_name', 'resource_id'))

    def test_association_creates_request_converter(self):
        document = Mock()

        class Model(object):
            pass

        links = {'users': 'user_id', 'lines': 'line_id'}
        converter = Converter.association(document, Model, links)

        assert_that(converter.parser, instance_of(RequestParser))
        assert_that(converter.mapper, instance_of(DocumentMapper))
        assert_that(converter.serializer, instance_of(ResourceSerializer))
        assert_that(converter.builder, instance_of(ModelBuilder))
        assert_that(converter.serializer.resources, has_entries(links))