Example #1
0
def get_app(debug):
    app = WerkzeugServer(root_path='/api/v1/',
                         root_version='0.9',
                         debug=debug,
                         get_user=getUser,
                         cors_allow_list=['*'])

    config = Model(name='config',
                   field_list=[],
                   transaction_class=BlankTransaction)
    config.checkAuth = lambda user, verb, id_list: True
    app.root_namespace.addElement(config)

    info = Action(name='getContractorInfo',
                  return_paramater=Paramater(type='Map'),
                  func=contractorInfo)
    info.checkAuth = lambda user, verb, id_list: True
    config.addAction(info)

    app.registerNamespace('/', 'mcp.User')
    app.registerNamespace('/', 'mcp.Resource')
    app.registerNamespace('/', 'mcp.Project')
    app.registerNamespace('/', 'mcp.Processor')

    app.validate()

    return app
Example #2
0
def test_call():
  converter = Converter( None )
  field_list = []
  field_list.append( Field( name='field1', type='String', length=50 ) )
  field_list.append( Field( name='field2', type='Integer' ) )
  model = Model( name='model1', transaction_class=TestTransaction, field_list=field_list )
  transaction = model.transaction_class()

  action1 = Action( name='act1', return_paramater=Paramater( type='String' ), func=lambda: 'hello' )
  resp = action1.call( converter, transaction, None, {}, None, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CALL', 'Multi-Object': 'False' }
  assert resp.data == 'hello'

  action2 = Action( name='act2', return_paramater=Paramater( type='String' ), paramater_list=[ Paramater( name='p1', type='String', default='alice' ) ], func=lambda p1: 'hello "{0}"'.format( p1 ) )
  # with pytest.raises( InvalidRequest ):  # should we be ignorning data?
  #  resp = action2.call( converter, transaction, None, { 'p1': 'bob', 'nope': 'sue' }, None, False )

  resp = action2.call( converter, transaction, None, {}, None, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CALL', 'Multi-Object': 'False' }
  assert resp.data == 'hello "alice"'

  resp = action2.call( converter, transaction, None, { 'p1': 'bob' }, None, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CALL', 'Multi-Object': 'False' }
  assert resp.data == 'hello "bob"'

  action3 = Action( name='act3', return_paramater=Paramater( type='String' ), func=lambda a: 'hello "{0}"'.format( a ), static=False )
  model.addAction( action3 )
  with pytest.raises( InvalidRequest ):
    action3.call( converter, transaction, None, { 'a': 'bob' }, None, False )

  resp = action3.call( converter, transaction, [ 'sue' ], {}, None, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CALL', 'Multi-Object': 'False' }
  assert resp.data == 'hello "{\'_extra_\': \'get "sue"\'}"'

  with pytest.raises( ObjectNotFound ):
    action3.call( converter, transaction, [ 'NOT FOUND' ], {}, None, False )

  action4 = Action( name='act4', func=lambda: 'hello' )
  resp = action4.call( converter, transaction, [], {}, None, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CALL', 'Multi-Object': 'False' }
  assert resp.data is None

  action9 = Action( name='act9', return_paramater=Paramater( type='String' ), paramater_list=[ Paramater( name='p1', type='String' ), Paramater( name='p2', type='_USER_' ) ], func=lambda p1, p2: '{0}: {1}'.format( p1, p2 ) )
  resp = action9.call( converter, transaction, None, { 'p1': 'stuff' }, 'Me The User', False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CALL', 'Multi-Object': 'False' }
  assert resp.data == 'stuff: Me The User'
Example #3
0
    def decorator( cls ):

      name = cls.__qualname__

      model = Model( name=name, transaction_class=NullTransaction, field_list=[], list_filter_map={}, constant_set_map={}, not_allowed_verb_list=[ 'LIST', 'GET', 'CREATE', 'UPDATE', 'DELETE' ] )
      self.model_list.append( model )
      return cls
Example #4
0
def test_werkzeug_server():
    server = WerkzeugServer(root_path='/api/',
                            root_version='0.0',
                            debug=True,
                            get_user=getUser)
    ns = Namespace(name='ns1', version='0.1', converter=None)
    ns.addElement(Model(name='model1', field_list=[], transaction_class=None))
    server.registerNamespace('/', ns)

    env = {
        'PATH_INFO': '/api/',
        'HTTP_CINP_VERSION': '1.0',
        'REQUEST_METHOD': 'DESCRIBE',
        'wsgi.url_scheme': 'http',
        'wsgi.input_terminated': True,
        'wsgi.input': FakeBody('')
    }
    wresp = server.handle(env)
    assert wresp.status_code == 200
    assert wresp.headers == Headers([
        ('Cache-Control', 'max-age=0'), ('Cinp-Version', '1.0'),
        ('Content-Type', 'application/json;charset=utf-8'),
        ('Content-Length', '120'), ('Verb', 'DESCRIBE'), ('Type', 'Namespace')
    ])
    assert json.loads(str(wresp.data, 'utf-8')) == {
        'multi-uri-max': 100,
        'api-version': '0.0',
        'path': '/api/',
        'namespaces': ['/api/ns1/'],
        'models': [],
        'name': 'root'
    }
Example #5
0
def test_user():
  server = Server( root_path='/api/', root_version='0.0', debug=True )
  server.getUser = getUser
  ns1 = Namespace( name='ns1', version='0.1', converter=None )
  ns1.checkAuth = checkAuth
  field_list = []
  model1 = Model( name='model1', field_list=field_list, transaction_class=TestTransaction )
  model1.checkAuth = checkAuth
  action1 = Action( name='act', return_paramater=Paramater( type='String' ), func=fake_func )
  action1.checkAuth = checkAuth
  model1.addAction( action1 )
  ns1.addElement( model1 )
  server.registerNamespace( '/', ns1 )

  req = Request( 'GET', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'GET', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__, 'AUTH-ID': 'nope', 'AUTH-TOKEN': 'nope' } )
  res = server.handle( req )
  assert res.http_code == 401

  req = Request( 'GET', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__, 'AUTH-ID': 'good', 'AUTH-TOKEN': 'nope' } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'GET', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__, 'AUTH-ID': 'nope', 'AUTH-TOKEN': 'bad' } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'GET', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__, 'AUTH-ID': 'super', 'AUTH-TOKEN': 'super' } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'GET', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__, 'AUTH-ID': 'me', 'AUTH-TOKEN': 'me' } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'GET', '/api/ns1/model1:me:', { 'CINP-VERSION': __CINP_VERSION__, 'AUTH-ID': 'me', 'AUTH-TOKEN': 'me' } )
  res = server.handle( req )
  assert res.http_code == 200
Example #6
0
def test_multi():
  server = Server( root_path='/api/', root_version='0.0', debug=True )
  ns1 = Namespace( name='ns1', version='0.1', converter=None )
  ns1.checkAuth = lambda user, verb, id_list: True
  model1 = Model( name='model1', field_list=[], transaction_class=TestTransaction )
  model1.checkAuth = lambda user, verb, id_list: True
  ns1.addElement( model1 )
  server.registerNamespace( '/', ns1 )

  req = Request( 'GET', '/api/ns1/model1:abc:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200
  assert res.header_map == { 'Cache-Control': 'no-cache', 'Cinp-Version': '0.9', 'Verb': 'GET', 'Multi-Object': 'False' }
  assert res.data == { '_extra_': 'get "abc"' }

  req = Request( 'GET', '/api/ns1/model1:abc:def:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200
  assert res.header_map == { 'Cache-Control': 'no-cache', 'Cinp-Version': '0.9', 'Verb': 'GET', 'Multi-Object': 'True' }
  assert res.data == { '/api/ns1/model1:abc:': { '_extra_': 'get "abc"' }, '/api/ns1/model1:def:': { '_extra_': 'get "def"' } }

  req = Request( 'GET', '/api/ns1/model1:abc:', { 'CINP-VERSION': __CINP_VERSION__, 'MULTI-OBJECT': 'true' } )
  res = server.handle( req )
  assert res.http_code == 200
  assert res.header_map == { 'Cache-Control': 'no-cache', 'Cinp-Version': '0.9', 'Verb': 'GET', 'Multi-Object': 'True' }
  assert res.data == { '/api/ns1/model1:abc:': { '_extra_': 'get "abc"' } }

  req = Request( 'GET', '/api/ns1/model1:abc:def:', { 'CINP-VERSION': __CINP_VERSION__, 'MULTI-OBJECT': 'true' } )
  res = server.handle( req )
  assert res.http_code == 200
  assert res.header_map == { 'Cache-Control': 'no-cache', 'Cinp-Version': '0.9', 'Verb': 'GET', 'Multi-Object': 'True' }
  assert res.data == { '/api/ns1/model1:abc:': { '_extra_': 'get "abc"' }, '/api/ns1/model1:def:': { '_extra_': 'get "def"' } }

  req = Request( 'GET', '/api/ns1/model1:abc:def:', { 'CINP-VERSION': __CINP_VERSION__, 'MULTI-OBJECT': 'false' } )
  res = server.handle( req )
  assert res.http_code == 400
  assert res.header_map == { 'Cinp-Version': '0.9' }
  assert res.data == { 'message': 'requested non multi-object, however multiple ids where sent' }
Example #7
0
def test_delete():
  field_list = []
  model = Model( name='model1', field_list=field_list, transaction_class=TestTransaction )
  transaction = model.transaction_class()

  resp = model.delete( transaction, [ 'bob' ] )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'DELETE' }
  assert resp.data is None

  resp = model.delete( transaction, [ 'bob', 'sue', 'martha' ] )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'DELETE' }
  assert resp.data is None

  with pytest.raises( ObjectNotFound ):
    model.delete( transaction, [ 'bob', 'NOT FOUND', 'martha' ] )

  with pytest.raises( ObjectNotFound ):
    model.delete( transaction, [ 'NOT FOUND' ] )
Example #8
0
        def decorator(cls):

            name = cls.__qualname__
            not_allowed_verb_list_ = list(
                set(['LIST', 'GET', 'CREATE', 'UPDATE',
                     'DELETE']).union(set(not_allowed_verb_list or [])))

            model = Model(name=name,
                          transaction_class=DjangoTransaction,
                          field_list=[],
                          list_filter_map={},
                          constant_set_map={},
                          not_allowed_verb_list=not_allowed_verb_list_)
            self.model_list.append(model)
            return cls
Example #9
0
def test_getElement():
  uri = URI( root_path='/api/' )
  root_ns = Namespace( name=None, version='0.0', root_path='/api/', converter=None )
  ns2 = Namespace( name='ns2', version='0.1', converter=None )
  ns3 = Namespace( name='ns3', version='0.2', converter=None )
  ns2_2 = Namespace( name='ns2_2', version='0.1', converter=None )
  root_ns.addElement( ns2 )
  root_ns.addElement( ns3 )
  ns2.addElement( ns2_2 )
  mdl1 = Model( name='mdl1', field_list={}, transaction_class=TestTransaction )
  mdl2 = Model( name='mdl2', field_list={}, transaction_class=TestTransaction )
  root_ns.addElement( mdl1 )
  ns2_2.addElement( mdl2 )
  act1 = Action( name='act1', return_paramater=Paramater( type='String' ), paramater_list=[ Paramater( name='bob', type='Float' ) ], static=False, func=fake_func )
  act2 = Action( name='act2', return_paramater=Paramater( type='String' ), paramater_list=[ Paramater( name='stuff', type='Boolean' ) ], func=fake_func )
  mdl1.addAction( act1 )
  mdl2.addAction( act2 )

  assert root_ns.getElement( uri.split( '/api/', root_optional=True ) ) == root_ns
  assert root_ns.getElement( uri.split( '/api/ns2/', root_optional=True ) ) == ns2
  assert root_ns.getElement( uri.split( '/api/ns3/', root_optional=True ) ) == ns3
  assert root_ns.getElement( uri.split( '/api/ns2/ns2_2/', root_optional=True ) ) == ns2_2
  assert root_ns.getElement( uri.split( '/', root_optional=True ) ) == root_ns
  assert root_ns.getElement( uri.split( '/ns2/', root_optional=True ) ) == ns2
  assert root_ns.getElement( uri.split( '/ns3/', root_optional=True ) ) == ns3
  assert root_ns.getElement( uri.split( '/ns2/ns2_2/', root_optional=True ) ) == ns2_2
  assert root_ns.getElement( uri.split( '/api/mdl1', root_optional=True ) ) == mdl1
  assert root_ns.getElement( uri.split( '/api/ns2/ns2_2/mdl2', root_optional=True ) ) == mdl2
  assert root_ns.getElement( uri.split( '/mdl1', root_optional=True ) ) == mdl1
  assert root_ns.getElement( uri.split( '/ns2/ns2_2/mdl2', root_optional=True ) ) == mdl2
  assert root_ns.getElement( uri.split( '/api/mdl1(act1)', root_optional=True ) ) == act1
  assert root_ns.getElement( uri.split( '/api/ns2/ns2_2/mdl2(act2)', root_optional=True ) ) == act2
  assert root_ns.getElement( uri.split( '/mdl1(act1)', root_optional=True ) ) == act1
  assert root_ns.getElement( uri.split( '/ns2/ns2_2/mdl2(act2)', root_optional=True ) ) == act2

  with pytest.raises( ValueError ):
    root_ns.getElement( '/api/' )

  assert root_ns.getElement( uri.split( '/api/nsX/' ) ) is None
  assert root_ns.getElement( uri.split( '/api/ns2/mdlX' ) ) is None
  assert root_ns.getElement( uri.split( '/api/mdl1(actX)' ) ) is None
Example #10
0
        def decorator(cls):
            name = cls.__qualname__
            not_allowed_verb_list_ = list(
                set(['LIST', 'GET', 'CREATE', 'UPDATE',
                     'DELETE']).union(set(not_allowed_verb_list or [])))

            try:
                doc = cls.__doc__.strip()
            except AttributeError:
                doc = None

            model = Model(name=name,
                          doc=doc,
                          id_field_name=None,
                          transaction_class=DjangoTransaction,
                          field_list=[],
                          list_filter_map={},
                          constant_set_map={},
                          not_allowed_verb_list=not_allowed_verb_list_)
            self.model_list.append(model)
            return cls
Example #11
0
def test_server():
  server = Server( root_path='/api/', root_version='0.0', debug=True )
  ns1 = Namespace( name='ns1', version='0.1', converter=None )
  ns1.checkAuth = lambda user, verb, id_list: True
  model1 = Model( name='model1', field_list=[], transaction_class=TestTransaction )
  model1.checkAuth = lambda user, verb, id_list: True
  ns1.addElement( model1 )
  model2 = Model( name='model2', field_list=[], transaction_class=TestTransaction )
  model2.checkAuth = lambda user, verb, id_list: True
  ns1.addElement( model2 )
  server.registerNamespace( '/', ns1 )

  ns2 = Namespace( name='ns2', version='0.2', converter=None )
  server.registerNamespace( '/api/', ns2 )

  req = Request( 'OPTIONS', '/api/', {} )
  res = server.handle( req )
  assert res.http_code == 200
  assert res.header_map == { 'Allow': 'OPTIONS, DESCRIBE', 'Cache-Control': 'max-age=0', 'Cinp-Version': '0.9' }

  path = '/api/'
  desc_ref = sort_dsc( { 'name': 'root', 'path': '/api/', 'api-version': '0.0', 'namespaces': [ '/api/ns1/', '/api/ns2/' ], 'models': [], 'multi-uri-max': 100 } )
  assert sort_dsc( server.root_namespace.getElement( server.uri.split( path ) ).describe( ns1.converter ).data ) == desc_ref
  req = Request( 'DESCRIBE', path, { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200
  assert sort_dsc( res.data ) == desc_ref
  assert res.header_map == { 'Type': 'Namespace', 'Verb': 'DESCRIBE', 'Cache-Control': 'max-age=0', 'Cinp-Version': '0.9' }

  path = '/api/ns1/'
  desc_ref = sort_dsc( { 'name': 'ns1', 'path': '/api/ns1/', 'api-version': '0.1', 'namespaces': [], 'models': [ '/api/ns1/model1', '/api/ns1/model2' ], 'multi-uri-max': 100 } )
  assert sort_dsc( server.root_namespace.getElement( server.uri.split( path ) ).describe( ns1.converter ).data ) == desc_ref
  req = Request( 'DESCRIBE', path, { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200
  assert sort_dsc( res.data ) == desc_ref
  assert res.header_map == { 'Type': 'Namespace', 'Verb': 'DESCRIBE', 'Cache-Control': 'max-age=0', 'Cinp-Version': '0.9' }

  path = '/api/ns1/model1'
  desc_ref = sort_dsc( { 'name': 'model1', 'path': '/api/ns1/model1', 'fields': [], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] } )
  assert sort_dsc( server.root_namespace.getElement( server.uri.split( path ) ).describe( ns1.converter ).data ) == desc_ref
  req = Request( 'DESCRIBE', path, { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200
  assert sort_dsc( res.data ) == desc_ref
  assert res.header_map == { 'Type': 'Model', 'Verb': 'DESCRIBE', 'Cache-Control': 'max-age=0', 'Cinp-Version': '0.9' }
Example #12
0
def test_action():
  ns = Namespace( name=None, version='0.0', root_path='/api/', converter=None )
  model = Model( name='model1', transaction_class=TestTransaction, field_list=[] )
  ns.addElement( model )

  action1 = Action( name='act1', return_paramater=Paramater( type='String' ), func=fake_func )
  assert sort_dsc( action1.describe( ns.converter ).data ) == { 'name': 'act1', 'return-type': { 'type': 'String' }, 'paramaters': [], 'static': True, 'path': None }
  model.addAction( action1 )
  assert sort_dsc( action1.describe( action1.parent.parent.converter ).data ) == { 'name': 'act1', 'return-type': { 'type': 'String' }, 'paramaters': [], 'static': True, 'path': '/api/model1(act1)' }

  action2 = Action( name='act2', return_paramater=Paramater( type='Integer' ), static=False, func=fake_func )
  assert sort_dsc( action2.describe( ns.converter ).data ) == { 'name': 'act2', 'return-type': { 'type': 'Integer' }, 'paramaters': [], 'static': False, 'path': None }

  action3 = Action( name='act3', return_paramater=Paramater( type='Boolean' ), paramater_list=[ Paramater( name='bob', type='Float' ) ], static=False, func=fake_func )
  model.addAction( action3 )
  assert sort_dsc( action3.describe( action3.parent.parent.converter ).data ) == { 'name': 'act3', 'return-type': { 'type': 'Boolean' }, 'paramaters': [ { 'name': 'bob', 'type': 'Float' } ], 'static': False, 'path': '/api/model1(act3)' }

  assert action3.describe( action3.parent.parent.converter ).header_map == { 'Cache-Control': 'max-age=0', 'Verb': 'DESCRIBE', 'Type': 'Action' }

  assert action3.options().header_map == { 'Allow': 'OPTIONS, DESCRIBE, CALL' }
  assert action3.options().data is None
Example #13
0
        def decorator(cls):
            global __MODEL_REGISTRY__

            name = cls.__qualname__
            meta = cls._meta
            field_list = []
            hide_field_list_ = hide_field_list or []
            show_field_list_ = show_field_list or []
            property_list_ = property_list or []
            read_only_list_ = read_only_list or []
            if hide_field_list_ and show_field_list_:
                raise ValueError(
                    'hide_field_list and show_field_list are Mutually Exclusive'
                )

            for django_field in meta.fields + meta.many_to_many:
                if django_field.auto_created:
                    continue

                if hide_field_list_ and django_field.name in hide_field_list_:
                    continue

                if show_field_list_ and django_field.name not in show_field_list_:
                    continue

                kwargs = {
                    'name':
                    django_field.name,
                    'doc':
                    str(django_field.help_text)
                    if django_field.help_text else None,
                    'required':
                    not django_field.blank,
                    'choice_list': [item[0] for item in django_field.choices]
                    if django_field.choices else None,
                    'default':
                    django_field.default
                    if django_field.default != fields.NOT_PROVIDED else None
                }

                if django_field.editable and django_field.name not in read_only_list_:
                    kwargs['mode'] = 'RC' if django_field.primary_key else 'RW'
                else:
                    kwargs['mode'] = 'RO'

                internal_type = django_field.get_internal_type()
                try:
                    cinp_type = django_field.cinp_type
                    internal_type = None
                except AttributeError:
                    cinp_type = None

                if internal_type in (
                        'CharField', 'TextField',
                        'GenericIPAddressField') or cinp_type == 'String':
                    kwargs['type'] = 'String'
                    kwargs['length'] = django_field.max_length

                elif internal_type in ('DecimalField', 'IntegerField',
                                       'SmallIntegerField',
                                       'PositiveIntegerField',
                                       'PositiveSmallIntegerField',
                                       'AutField') or cinp_type == 'Integer':
                    kwargs['type'] = 'Integer'

                elif internal_type in ('FloatField', ) or cinp_type == 'Float':
                    kwargs['type'] = 'Float'

                elif internal_type in ('BooleanField', 'NullBooleanField'
                                       ) or cinp_type == 'Boolean':
                    kwargs['type'] = 'Boolean'

                elif internal_type in ('DateField', 'DateTimeField',
                                       'TimeField') or cinp_type == 'DateTime':
                    kwargs['type'] = 'DateTime'

                elif internal_type in [] or cinp_type == 'Map':
                    kwargs['type'] = 'Map'

                elif internal_type in ('FileField',
                                       'ImageField') or cinp_type == 'File':
                    kwargs['type'] = 'File'
                    kwargs[
                        'allowed_scheme_list'] = None  # find some meta location to pass this in

                elif internal_type in (
                        'ForeignKey', 'ManyToManyField',
                        'OneToOneField') or cinp_type == 'Modal':
                    kwargs['type'] = 'Model'

                    try:
                        (mode, is_array,
                         model) = field_model_resolver(django_field)

                    except ValueError:  # model_resolver had issues, try late resolving
                        kwargs['model'] = django_field
                        kwargs['model_resolve'] = field_model_resolver

                    else:
                        if mode is not None:
                            kwargs['mode'] = mode

                        if is_array is not None:
                            kwargs['is_array'] = is_array

                        kwargs['model'] = model

                else:
                    raise ValueError(
                        'Unknown Field type "{0}"'.format(internal_type))

                if 'is_array' not in kwargs:
                    try:
                        kwargs['is_array'] = django_field.cinp_is_array
                    except AttributeError:
                        pass

                field_list.append(Field(**kwargs))

            for item in property_list_:
                if isinstance(item, dict):
                    kwargs = {
                        'name': item.get('name'),
                        'doc': item.get('doc', None),
                        'required': False,
                        'default': None,
                        'mode': 'RO',
                        'type': item.get('type', 'String'),
                        'choice_list': item.get('choices', None),
                        'is_array': item.get('is_array', False)
                    }

                    paramater_model_name = item.get('model', None)
                    if paramater_model_name is not None:
                        try:
                            model = paramater_model_resolver(
                                paramater_model_name)
                        except ValueError:  # model_resolver had issues, try late resolving
                            kwargs['model'] = paramater_model_name
                            kwargs[
                                'model_resolve'] = property_model_resolver  # yes we are sending different than we called
                        else:
                            kwargs['model'] = model

                else:
                    kwargs = {
                        'name': item,
                        'doc': None,
                        'required': False,
                        'default': None,
                        'mode': 'RO',
                        'type': 'String'
                    }

                field_list.append(Field(**kwargs))

            filter_map = {}
            filter_funcs_map = {}
            for filter_name in self.list_filter_map.get(name, {}):
                filter_funcs_map[filter_name] = self.list_filter_map[name][
                    filter_name][0]
                filter_map[filter_name] = self.list_filter_map[name][
                    filter_name][1]

            try:
                doc = cls.__doc__.strip()
            except AttributeError:
                doc = None

            model = Model(name=name,
                          doc=doc,
                          transaction_class=DjangoTransaction,
                          field_list=field_list,
                          list_filter_map=filter_map,
                          constant_set_map=constant_set_map,
                          not_allowed_verb_list=not_allowed_verb_list)
            model._django_model = cls
            model._django_filter_funcs_map = filter_funcs_map
            self.model_list.append(model)
            __MODEL_REGISTRY__['{0}.{1}'.format(cls.__module__,
                                                cls.__qualname__)] = model
            MAP_TYPE_CONVERTER[
                cls.__name__] = lambda a: model.path + ':{0}:'.format(a.pk)
            return cls
Example #14
0
def test_model():
  ns = Namespace( name=None, version='0.0', root_path='/api/', converter=None )

  model1 = Model( name='model1', transaction_class=TestTransaction, field_list=[] )
  assert sort_dsc( ns.describe( ns.converter ).data ) == { 'name': 'root', 'path': '/api/', 'api-version': '0.0', 'namespaces': [], 'models': [], 'multi-uri-max': 100 }
  assert sort_dsc( model1.describe( ns.converter ).data ) == { 'name': 'model1', 'path': None, 'fields': [], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] }
  ns.addElement( model1 )
  assert sort_dsc( ns.describe( ns.converter ).data ) == { 'name': 'root', 'path': '/api/', 'api-version': '0.0', 'namespaces': [], 'models': [ '/api/model1' ], 'multi-uri-max': 100 }
  assert sort_dsc( model1.describe( model1.parent.converter ).data ) == { 'name': 'model1', 'path': '/api/model1', 'fields': [], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] }

  field_list = []
  field_list.append( Field( name='field1', type='String', length=50 ) )
  field_list.append( Field( name='field2', type='Integer', mode='RO' ) )

  model2 = Model( name='model2', transaction_class=TestTransaction, field_list=field_list )
  assert sort_dsc( ns.describe( ns.converter ).data ) == { 'name': 'root', 'path': '/api/', 'api-version': '0.0', 'namespaces': [], 'models': [ '/api/model1' ], 'multi-uri-max': 100 }
  assert sort_dsc( model1.describe( model1.parent.converter ).data ) == { 'name': 'model1', 'path': '/api/model1', 'fields': [], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] }
  assert sort_dsc( model2.describe( ns.converter ).data ) == { 'name': 'model2', 'path': None, 'fields': [ { 'type': 'String', 'length': 50, 'name': 'field1', 'mode': 'RW', 'required': True, }, { 'type': 'Integer', 'name': 'field2', 'mode': 'RO', 'required': True } ], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] }
  ns.addElement( model2 )
  assert sort_dsc( ns.describe( ns.converter ).data ) == { 'name': 'root', 'path': '/api/', 'api-version': '0.0', 'namespaces': [], 'models': [ '/api/model1', '/api/model2' ], 'multi-uri-max': 100 }
  assert sort_dsc( model1.describe( model1.parent.converter ).data ) == { 'name': 'model1', 'path': '/api/model1', 'fields': [], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] }
  assert sort_dsc( model2.describe( model2.parent.converter ).data ) == { 'name': 'model2', 'path': '/api/model2', 'fields': [ { 'type': 'String', 'length': 50, 'name': 'field1', 'mode': 'RW', 'required': True }, { 'type': 'Integer', 'name': 'field2', 'mode': 'RO', 'required': True } ], 'actions': [], 'constants': {}, 'list-filters': {}, 'not-allowed-methods': [] }

  assert model2.describe( model2.parent.converter ).header_map == { 'Cache-Control': 'max-age=0', 'Verb': 'DESCRIBE', 'Type': 'Model' }

  assert model2.options().header_map == { 'Allow': 'OPTIONS, DESCRIBE, GET, LIST, CREATE, UPDATE, DELETE' }
  assert model2.options().data is None
Example #15
0
def test_not_allowed_verbs():
  server = Server( root_path='/api/', root_version='0.0', debug=True )
  ns1 = Namespace( name='ns1', version='0.1', converter=Converter( URI( '/api/' ) ) )
  ns1.checkAuth = lambda user, verb, id_list: True
  field_list = []
  field_list.append( Field( name='field1', type='String', length=50 ) )
  model1 = Model( name='model1', field_list=field_list, not_allowed_verb_list=[], transaction_class=TestTransaction )
  model2 = Model( name='model2', field_list=field_list, not_allowed_verb_list=[ 'GET', 'LIST', 'CALL', 'CREATE', 'UPDATE', 'DELETE', 'DESCRIBE' ], transaction_class=TestTransaction )
  model1.checkAuth = lambda user, verb, id_list: True
  model2.checkAuth = lambda user, verb, id_list: True
  action1 = Action( name='act', return_paramater=Paramater( type='String' ), func=fake_func )
  action2 = Action( name='act', return_paramater=Paramater( type='String' ), func=fake_func )
  action1.checkAuth = lambda user, verb, id_list: True
  action2.checkAuth = lambda user, verb, id_list: True
  model1.addAction( action1 )
  model2.addAction( action2 )
  ns1.addElement( model1 )
  ns1.addElement( model2 )
  server.registerNamespace( '/', ns1 )

  with pytest.raises( ValueError ):
    Model( name='modelX', field_list=[], not_allowed_verb_list=[ 'OPTIONS' ], transaction_class=TestTransaction )

  with pytest.raises( ValueError ):
    Model( name='modelX', field_list=[], not_allowed_verb_list=[ 'ASDF' ], transaction_class=TestTransaction )

  req = Request( 'OPTIONS', '/api/ns1/model1', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'OPTIONS', '/api/ns1/model2', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'DESCRIBE', '/api/ns1/model1', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'DESCRIBE', '/api/ns1/model2', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'GET', '/api/ns1/model1:asd:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'GET', '/api/ns1/model2:asd:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'LIST', '/api/ns1/model1', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'LIST', '/api/ns1/model2', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'CREATE', '/api/ns1/model1', { 'CINP-VERSION': __CINP_VERSION__ } )
  req.data = { 'field1': 'stuff' }
  res = server.handle( req )
  assert res.http_code == 201

  req = Request( 'CREATE', '/api/ns1/model2', { 'CINP-VERSION': __CINP_VERSION__ } )
  req.data = { 'field1': 'stuff' }
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'UPDATE', '/api/ns1/model1:sdf:', { 'CINP-VERSION': __CINP_VERSION__ } )
  req.data = { 'field1': 'stuff' }
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'UPDATE', '/api/ns1/model2:sdf:', { 'CINP-VERSION': __CINP_VERSION__ } )
  req.data = { 'field1': 'stuff' }
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'DELETE', '/api/ns1/model1:asd:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'DELETE', '/api/ns1/model2:asd:', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 403

  req = Request( 'CALL', '/api/ns1/model1(act)', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 200

  req = Request( 'CALL', '/api/ns1/model2(act)', { 'CINP-VERSION': __CINP_VERSION__ } )
  res = server.handle( req )
  assert res.http_code == 403
Example #16
0
def test_saninity_checks():
  server = Server( root_path='/api/', root_version='0.0' )
  ns = Namespace( name='ns', version='0.1', converter=None )
  model = Model( name='model', field_list=[], transaction_class=TestTransaction )
  ns.addElement( model )
  action = Action( name='action', return_paramater=Paramater( type='String' ), func=fake_func )
  model.addAction( action )
  server.registerNamespace( '/', ns )

  res = server.dispatch( Request( 'BOB', '/api/', { 'CINP-VERSION': '0.9' } ) )
  assert res.http_code == 400
  assert res.data == { 'message': 'Invalid Verb (HTTP Method) "BOB"' }

  res = server.dispatch( Request( 'DESCRIBE', 'invalid', { 'CINP-VERSION': '0.9' } ) )
  assert res.http_code == 400
  assert res.data == { 'message': 'Unable to Parse "invalid"' }

  res = server.dispatch( Request( 'DESCRIBE', '/api/ns/model:' + ':'.join( 'id' * 101 ) + ':', { 'CINP-VERSION': '0.9' } ) )
  assert res.http_code == 400
  assert res.data == { 'message': 'id_list longer than supported length of "100"' }

  res = server.dispatch( Request( 'DESCRIBE', '/api/nope', { 'CINP-VERSION': '0.9' } ) )
  assert res.http_code == 404
  assert res.data == { 'message': 'path not found "/api/nope"' }

  res = server.handle( Request( 'DESCRIBE', '/api/', {} ) )
  assert res.http_code == 400
  assert res.data == { 'message': 'Invalid CInP Protocol Version' }

  res = server.handle( Request( 'DESCRIBE', '/api/', { 'Cinp-Version': '0' } ) )
  assert res.http_code == 400
  assert res.data == { 'message': 'Invalid CInP Protocol Version' }

  with pytest.raises( ValueError ):  # checkAuth not implemented, for this round of tests we call good
    server.dispatch( Request( 'DESCRIBE', '/api/ns/model(action)', { 'CINP-VERSION': '0.9' } ) )

  for verb in ( 'GET', 'LIST', 'CREATE', 'UPDATE', 'DELETE' ):
    res = server.dispatch( Request( verb, '/api/ns/model(action)', { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Invalid verb "{0}" for request with action'.format( verb ) }

  for verb in ( 'GET', 'LIST', 'CREATE', 'UPDATE', 'DELETE' ):
    res = server.dispatch( Request( verb, '/api/ns/model:id:(action)', { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Invalid verb "{0}" for request with action'.format( verb ) }

  for uri in ( '/api/', '/api/ns/', '/api/ns/model', '/api/ns/model:id:' ):
    res = server.dispatch( Request( 'CALL', uri, { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Verb "CALL" requires action'.format( verb ) }

  for verb in ( 'LIST', 'CREATE', 'DESCRIBE' ):
    res = server.dispatch( Request( verb, '/api/ns/model:id:', { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Invalid Verb "{0}" for request with id'.format( verb ) }

  for verb in ( 'GET', 'UPDATE', 'DELETE' ):
    res = server.dispatch( Request( verb, '/api/ns/model', { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Verb "{0}" requires id'.format( verb ) }

  for verb in ( 'GET', 'DELETE' ):
    req = Request( verb, '/api/ns/model:d:', { 'CINP-VERSION': '0.9' } )
    req.data = { 'some': 'data' }
    res = server.dispatch( req )
    assert res.http_code == 400
    assert res.data == { 'message': 'Invalid verb "{0}" for request with data'.format( verb ) }

  for verb in ( 'DESCRIBE', ):
    req = Request( verb, '/api/ns/model', { 'CINP-VERSION': '0.9' } )
    req.data = { 'some': 'data' }
    res = server.dispatch( req )
    assert res.http_code == 400
    assert res.data == { 'message': 'Invalid verb "{0}" for request with data'.format( verb ) }

  for verb in ( 'UPDATE', ):
    res = server.dispatch( Request( verb, '/api/ns/model:id:', { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Verb "{0}" requires data'.format( verb ) }

  for verb in ( 'CREATE', ):
    res = server.dispatch( Request( verb, '/api/ns/model', { 'CINP-VERSION': '0.9' } ) )
    assert res.http_code == 400
    assert res.data == { 'message': 'Verb "{0}" requires data'.format( verb ) }

  for verb in ( 'LIST', 'CREATE' ):  # also 'GET', 'UPDATE', 'DELETE' which also requires an Id which requires a model so already covered
    req = Request( verb, '/api/ns/', { 'CINP-VERSION': '0.9' } )
    req.data = { 'some': 'data' }
    res = server.dispatch( req )
    assert res.http_code == 400
    assert res.data == { 'message': 'Verb "{0}" requires model'.format( verb ) }
Example #17
0
def test_create():
  converter = Converter( None )
  field_list = []
  field_list.append( Field( name='field1', mode='RW', type='String', length=50 ) )
  field_list.append( Field( name='field2', mode='RW', type='Integer' ) )
  field_list.append( Field( name='field3', mode='RW', type='String', length=20, required=False, default='Hello World' ) )
  field_list.append( Field( name='field4', mode='RO', type='String', length=20, required=False, default='Not Me' ) )
  model = Model( name='model1', field_list=field_list, transaction_class=TestTransaction )
  transaction = model.transaction_class()

  resp = model.create( converter, transaction, { 'field1': 'hello', 'field2': 5 } )
  assert resp.http_code == 201
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CREATE', 'Object-Id': 'None:new_id:' }
  assert resp.data == { '_extra_': 'created', 'field1': 'hello', 'field2': 5, 'field3': 'Hello World' }

  resp = model.create( converter, transaction, { 'field1': 'by', 'field2': 30, 'field3': 'good by' } )
  assert resp.http_code == 201
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'CREATE', 'Object-Id': 'None:new_id:' }
  assert resp.data == { '_extra_': 'created', 'field1': 'by', 'field2': 30, 'field3': 'good by' }

  with pytest.raises( InvalidRequest ):
    model.create( converter, transaction, { 'field1': 'hello', 'field2': 'sdf' } )

  with pytest.raises( InvalidRequest ):
    model.create( converter, transaction, { 'field1': 'hello' } )

  with pytest.raises( InvalidRequest ):
    model.create( converter, transaction, {} )

  with pytest.raises( InvalidRequest ):
    model.create( converter, transaction, { 'field1': 'hello', 'field2': 'sdf', 'fieldX': 'bad' } )

  with pytest.raises( InvalidRequest ):
    model.create( converter, transaction, { 'field1': 'INVALID', 'field2': 5 } )

  with pytest.raises( ServerError ):
    model.create( converter, transaction, { 'field1': 'BAD', 'field2': 5 } )
Example #18
0
def test_update():
  converter = Converter( None )
  field_list = []
  field_list.append( Field( name='field1', mode='RW', type='String', length=50 ) )
  field_list.append( Field( name='field2', mode='RO', type='Integer' ) )
  model = Model( name='model1', field_list=field_list, transaction_class=TestTransaction )
  transaction = model.transaction_class()

  resp = model.update( converter, transaction, [ 'bob' ], {}, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'UPDATE', 'Multi-Object': 'False' }
  assert resp.data == { '_extra_': 'update "bob"' }

  resp = model.update( converter, transaction, [ 'bob' ], { 'field1': 'goodies' }, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'UPDATE', 'Multi-Object': 'False' }
  assert resp.data == { '_extra_': 'update "bob"', 'field1': 'goodies' }

  with pytest.raises( InvalidRequest ):
    resp = model.update( converter, transaction, [ 'bob' ], { 'field2': 42 }, False )

  with pytest.raises( InvalidRequest ):
    resp = model.update( converter, transaction, [ 'NOT FOUND' ], { 'field2': 42 }, False )

  with pytest.raises( ObjectNotFound ):
    resp = model.update( converter, transaction, [ 'NOT FOUND' ], { 'field1': 'goodies' }, False )

  resp = model.update( converter, transaction, [ 'bob', 'martha', 'sue' ], { 'field1': 'goodies' }, False )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'UPDATE', 'Multi-Object': 'False' }
  assert resp.data == { '_extra_': 'update "bob"', 'field1': 'goodies' }  # this is right, if multi is false, we ignore the rest of the ids, upstream takes care of making sure that dosen't happen

  resp = model.update( converter, transaction, [ 'bob' ], { 'field1': 'goodies' }, True )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'UPDATE', 'Multi-Object': 'True' }
  assert resp.data == { 'None:bob:': { '_extra_': 'update "bob"', 'field1': 'goodies' } }

  resp = model.update( converter, transaction, [ 'bob', 'martha', 'sue' ], { 'field1': 'goodies' }, True )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'UPDATE', 'Multi-Object': 'True' }
  assert resp.data == { 'None:bob:': { '_extra_': 'update "bob"', 'field1': 'goodies' }, 'None:martha:': { '_extra_': 'update "martha"', 'field1': 'goodies' }, 'None:sue:': { '_extra_': 'update "sue"', 'field1': 'goodies' } }
Example #19
0
def test_list():
  converter = Converter( None )
  field_list = []
  list_filter_map = {}
  list_filter_map[ 'lots' ] = { 'more': Paramater( name='more', type='String', length=10 ) }
  list_filter_map[ 'bad' ] = {}
  model = Model( name='model1', field_list=field_list, list_filter_map=list_filter_map, transaction_class=TestTransaction )
  transaction = model.transaction_class()

  resp = model.list( converter, transaction, {}, {} )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'LIST', 'Position': '0', 'Count': '2', 'Total': '2', 'Id-Only': 'False' }
  assert resp.data == [ 'None:a:', 'None:b:' ]

  resp = model.list( converter, transaction, { 'more': 'bob' }, { 'FILTER': 'lots', 'POSITION': '23', 'COUNT': '45' } )
  assert resp.http_code == 200
  assert resp.header_map == { 'Cache-Control': 'no-cache', 'Verb': 'LIST', 'Position': '50', 'Count': '8', 'Total': '100', 'Id-Only': 'False' }
  assert resp.data == [ 'None:a:', 'None:b:', 'None:c:', 'None:d:', 'None:bob:', 'None:at 23:', 'None:for 45:', 'None:combined 68:' ]

  with pytest.raises( InvalidRequest ):
    model.list( converter, transaction, { 'more': 'bob' }, { 'FILTER': 'lots', 'POSITION': 'sdf', 'COUNT': '45' } )

  with pytest.raises( InvalidRequest ):
    model.list( converter, transaction, { 'more': 'bob' }, { 'FILTER': 'lots', 'POSITION': '23', 'COUNT': 'rf' } )

  with pytest.raises( InvalidRequest ):
    model.list( converter, transaction, {}, { 'FILTER': 'not exist' } )

  with pytest.raises( InvalidRequest ):
    model.list( converter, transaction, {}, { 'FILTER': 'bad' } )