def test_abbr_nested(): class app(morepath.App): pass class Model(object): pass @app.path(path='/', model=Model) def get_model(): return Model() with app.view(model=Model) as view: @view() def default(self, request): return "Default" with view(name='extra') as view: @view() def get(self, request): return "Get" @view(request_method='POST') def post(self, request): return "Post" c = Client(app()) response = c.get('/') assert response.body == b'Default' response = c.get('/extra') assert response.body == b'Get' response = c.post('/extra') assert response.body == b'Post'
def test_default_datetime_converter(): class app(morepath.App): pass class Model(object): def __init__(self, d): self.d = d from datetime import datetime @app.path(model=Model, path='/') def get_model(d=datetime(2011, 1, 1, 10, 30)): return Model(d) @app.view(model=Model) def default(self, request): return "View: %s" % self.d @app.view(model=Model, name='link') def link(self, request): return request.link(self) c = Client(app()) response = c.get('/?d=20121110T144530') assert response.body == b"View: 2012-11-10 14:45:30" response = c.get('/') assert response.body == b"View: 2011-01-01 10:30:00" response = c.get('/link?d=20121110T144500') assert response.body == b'http://localhost/?d=20121110T144500' response = c.get('/link') assert response.body == b'http://localhost/?d=20110101T103000' c.get('/?d=broken', status=400)
def test_defer_view_predicates(): class Root(morepath.App): pass class Sub(morepath.App): pass @Root.path(path='') class RootModel(object): pass @Root.json(model=RootModel) def root_model_default(self, request): return request.view(SubModel(), name='edit') @Sub.path(path='') class SubModel(object): pass @Sub.json(model=SubModel, name='edit') def submodel_edit(self, request): return {'hello': 'world'} @Root.mount(app=Sub, path='sub') def mount_sub(): return Sub() @Root.defer_links(model=SubModel) def defer_links_sub_model(app, obj): return app.child(Sub()) dectate.commit(Root, Sub) c = Client(Root()) response = c.get('/') assert response.json == {'hello': 'world'}
def test_extra_parameters_with_get_converters(): class app(morepath.App): pass class Model(object): def __init__(self, extra_parameters): self.extra_parameters = extra_parameters def get_converters(): return { 'a': int, 'b': type(u""), } @app.path(model=Model, path='/', get_converters=get_converters) def get_model(extra_parameters): return Model(extra_parameters) @app.view(model=Model) def default(self, request): return repr(sorted(self.extra_parameters.items())) @app.view(model=Model, name='link') def link(self, request): return request.link(self) c = Client(app()) response = c.get('/?a=1&b=B') assert response.body in \ (b"[(u'a', 1), (u'b', u'B')]", b"[('a', 1), ('b', 'B')]") response = c.get('/link?a=1&b=B') assert sorted(response.body[len('http://localhost/?'):].split(b"&")) == [ b'a=1', b'b=B' ] c.get('/?a=broken&b=B', status=400)
def test_json_obj_load(): class app(morepath.App): pass class Collection(object): def __init__(self): self.items = [] def add(self, item): self.items.append(item) collection = Collection() @app.path(path='/', model=Collection) def get_collection(): return collection @app.json(model=Collection, request_method='POST') def default(self, request): self.add(request.body_obj) return 'done' class Item(object): def __init__(self, value): self.value = value @app.load_json() def load_json(json, request): return Item(json['x']) c = Client(app()) c.post_json('/', {'x': 'foo'}) assert len(collection.items) == 1 assert isinstance(collection.items[0], Item) assert collection.items[0].value == 'foo'
def test_defer_link_acquisition_blocking(): class root(morepath.App): pass class sub(morepath.App): pass @root.path(path='model/{id}') class Model(object): def __init__(self, id): self.id = id @root.view(model=Model) def model_default(self, request): return "Hello" @sub.path(path='') class SubModel(object): pass @sub.view(model=SubModel) def sub_model_default(self, request): try: return request.link(Model('foo')) except LinkError: return "link error" @root.mount(app=sub, path='sub') def mount_sub(): return sub() # no defer_links_to_parent c = Client(root()) response = c.get('/sub') assert response.body == b'link error'
def test_abbr_nested(): class app(morepath.App): pass class Model(object): pass @app.path(path="/", model=Model) def get_model(): return Model() with app.view(model=Model) as view: @view() def default(self, request): return "Default" with view(name="extra") as view: @view() def get(self, request): return "Get" @view(request_method="POST") def post(self, request): return "Post" c = Client(app()) response = c.get("/") assert response.body == b"Default" response = c.get("/extra") assert response.body == b"Get" response = c.post("/extra") assert response.body == b"Post"
def test_mount_named_child_link_name_defaults_to_path(): class app(morepath.App): pass class mounted(morepath.App): pass @mounted.path(path='models/{id}') class Model(object): def __init__(self, id): self.id = id @app.path(path='') class Root(object): pass @app.view(model=Root) def app_root_default(self, request): return request.link(Model('one'), app=request.app.child(mounted)) @app.view(model=Root, name='extra') def app_root_default2(self, request): return request.link(Model('one'), app=request.app.child('subapp')) @app.mount(path='subapp', app=mounted) def get_context(): return mounted() dectate.commit(app, mounted) c = Client(app()) response = c.get('/') assert response.body == b'http://localhost/subapp/models/one' response = c.get('/extra') assert response.body == b'http://localhost/subapp/models/one'
def test_url_parameter_explicit_converter_get_converters(): class app(morepath.App): pass class Model(object): def __init__(self, id): self.id = id def get_converters(): return dict(id=Converter(int)) @app.path(model=Model, path='/', get_converters=get_converters) def get_model(id): return Model(id) @app.view(model=Model) def default(self, request): return "View: %s (%s)" % (self.id, type(self.id)) @app.view(model=Model, name='link') def link(self, request): return request.link(self) c = Client(app()) response = c.get('/?id=1') assert response.body in \ (b"View: 1 (<type 'int'>)", b"View: 1 (<class 'int'>)") response = c.get('/link?id=1') assert response.body == b'http://localhost/?id=1' response = c.get('/?id=broken', status=400) response = c.get('/') assert response.body in \ (b"View: None (<type 'NoneType'>)", b"View: None (<class 'NoneType'>)")
def test_class_link_with_subclass(): class App(morepath.App): pass class Model(object): pass class Sub(Model): pass @App.path(model=Model, path='/foo/{x}') def get_model(x): return Model() @App.view(model=Model) def link(self, request): return request.class_link(Sub, variables={'x': 'X'}) dectate.commit(App) c = Client(App()) response = c.get('/foo/3') assert response.body == b"http://localhost/foo/X"
def test_error_when_path_variable_is_none(): class App(morepath.App): pass class Model(object): def __init__(self, id): self.store_id = id @App.path(model=Model, path='models/{id}', variables=lambda m: {'id': None}) def get_model(id): return Model(id) @App.view(model=Model) def default(self, request): return request.link(self) dectate.commit(App) c = Client(App()) with pytest.raises(LinkError): c.get('/models/1')
def test_path_explicit_variables_app_arg(): class App(morepath.App): pass class Model(object): def __init__(self, id): self.store_id = id def my_variables(app, m): assert isinstance(app, App) return {'id': m.store_id} @App.path(model=Model, path='models/{id}', variables=my_variables) def get_model(id): return Model(id) @App.view(model=Model) def default(self, request): return request.link(self) c = Client(App()) response = c.get('/models/1') assert response.body == b'http://localhost/models/1'
def test_deferred_loop(): class root(morepath.App): pass class alpha(morepath.App): pass @root.path(path='') class RootModel(object): pass # not actually exposed with path anywhere! class Model(object): pass @root.json(model=RootModel) def root_model_default(self, request): return request.link(Model()) @root.mount(app=alpha, path='alpha') def mount_alpha(): return alpha() # setup a loop: defer to parent and back to child! @alpha.defer_links(model=Model) def defer_links_parent(app, obj): return app.parent @root.defer_links(model=Model) def defer_links_alpha(app, obj): return app.child(alpha()) c = Client(root()) with pytest.raises(LinkError): c.get('/')
def test_view_after_applies_to_some_exceptions(status_code, exception_class): class App(morepath.App): pass class Root(object): pass @App.path(model=Root, path='') def get_root(): return Root() @App.view(model=Root) def view(self, request): @request.after def set_header(response): response.headers.add('Foo', 'FOO') raise exception_class() dectate.commit(App) c = Client(App()) response = c.get('/', status=status_code) assert response.headers.get('Foo') == 'FOO'
def test_marshmallow_schema_class(): class User(object): def __init__(self, name, email): self.name = name self.email = email class UserSchema(Schema): name = fields.Str(required=True) email = fields.Email(required=True) class App(MarshmallowApp): pass user = User('Somebody', '*****@*****.**') @App.path(model=User, path='/') def get_user(): return user @App.json(model=User, request_method='PUT', load=loader(UserSchema)) def user_put(self, request, obj): for key, value in obj.items(): setattr(self, key, value) return "done" c = Client(App()) r = c.put_json('/', { 'name': "Somebody else", "email": "*****@*****.**" }) assert user.name == 'Somebody else' assert user.email == '*****@*****.**' r = c.put_json('/', {'name': 'Another'}, status=422) assert r.json == {'email': ['Missing data for required field.']}
def test_reset_unconsumed_path(): class TestApp(TransactionApp): attempts = 0 @TestApp.path('/foo/bar') class Foo(object): pass @TestApp.view(model=Foo) def view_foo(self, request): TestApp.attempts += 1 # on the first attempt raise a conflict error if TestApp.attempts == 1: raise Conflict return 'ok' # if the unconsumed path is reset wrongly, it'll accidentally pick # up this model instead of Foo @TestApp.path('/bar/foo') class Bar(object): pass @TestApp.view(model=Bar) def view_bar(self, request): return 'error' @TestApp.setting(section='transaction', name='attempts') def get_retry_attempts(): return 2 client = Client(TestApp()) response = client.get('/foo/bar') assert response.text == 'ok' assert TestApp.attempts == 2
def test_mount_directive_with_link_and_absorb(): class app1(morepath.App): pass @app1.path(path="") class Model1(object): pass class app2(morepath.App): pass class Model2(object): def __init__(self, absorb): self.absorb = absorb @app2.path(model=Model2, path='', absorb=True) def get_model(absorb): return Model2(absorb) @app2.view(model=Model2) def default(self, request): return "A:%s L:%s" % (self.absorb, request.link(self)) @app1.mount(path="foo", app=app2) def get_mount(): return app2() dectate.commit(app1, app2) c = Client(app1()) response = c.get('/foo') assert response.body == b'A: L:http://localhost/foo' response = c.get('/foo/bla') assert response.body == b'A:bla L:http://localhost/foo/bla'
def test_access_app_through_request(): class root(morepath.App): pass class sub(morepath.App): def __init__(self, name): self.name = name @root.path(path='') class RootModel(object): pass @root.view(model=RootModel) def root_model_default(self, request): child = request.app.child(sub, mount_name='foo') return request.link(SubModel('foo'), app=child) class SubModel(object): def __init__(self, name): self.name = name @sub.path(path='', model=SubModel) def get_sub_model(request): return SubModel(request.app.name) @root.mount(app=sub, path='{mount_name}', variables=lambda a: {'mount_name': a.name}) def mount_sub(mount_name): return sub(name=mount_name) dectate.commit(root, sub) c = Client(root()) response = c.get('/') assert response.body == b'http://localhost/foo'
def test_inject_webassets(tempdir): client = Client(spawn_test_app(tempdir)) assert '<head></head>' in client.get('/').text with pytest.raises(KeyError): assert '<head></head>' in client.get('?bundle=inexistant').text # the version of these assets stays the same because it's basically the # md5 hash of the javascript files included injected_html = ( '<script type="text/javascript" ' 'src="/assets/common.bundle.js?ddc71aa3"></script></body>') assert injected_html in client.get('?bundle=common').text injected_html = ( '<link rel="stylesheet" type="text/css" ' 'href="/assets/theme.bundle.css?32fda411"></head>') assert injected_html in client.get('?bundle=theme').text page = client.get('/alljs').text assert page.find('common.bundle.js') < page.find('extra.bundle.js')
def test_absorb_class_path_with_variables(): class App(morepath.App): pass class Root(object): pass class Model(object): def __init__(self, id, absorb): self.id = id self.absorb = absorb @App.path(model=Root, path='') def get_root(): return Root() @App.path(model=Model, path='{id}', absorb=True) def get_model(id, absorb): return Model(id, absorb) @App.view(model=Model) def default(self, request): return "I:%s A:%s" % (self.id, self.absorb) @App.view(model=Root) def default_root(self, request): return request.class_link(Model, variables=dict(id='foo', absorb='a/b')) dectate.commit(App) c = Client(App()) # link to a/b absorb response = c.get('/') assert response.body == b'http://localhost/foo/a/b'
def test_view_after_doesnt_apply_to_exception(): class App(morepath.App): pass class Root(object): pass @App.path(model=Root, path='') def get_root(): return Root() @App.view(model=Root) def view(self, request): @request.after def set_header(response): response.headers.add('Foo', 'FOO') raise HTTPNotFound() dectate.commit(App) c = Client(App()) response = c.get('/', status=404) assert response.headers.get('Foo') is None
def test_defer_view_acquisition_blocking(): class root(morepath.App): pass class sub(morepath.App): pass @root.path(path='model/{id}') class Model(object): def __init__(self, id): self.id = id @root.json(model=Model) def model_default(self, request): return {"Hello": "World"} @sub.path(path='') class SubModel(object): pass @sub.json(model=SubModel) def sub_model_default(self, request): return request.view(Model('foo')) is None @root.mount(app=sub, path='sub') def mount_sub(): return sub() # no defer_links_to_parent dectate.commit(root, sub) c = Client(root()) response = c.get('/sub') assert response.json is True
def test_defer_view_acquisition(): class root(morepath.App): pass class sub(morepath.App): pass @root.path(path='model/{id}') class Model(object): def __init__(self, id): self.id = id @root.json(model=Model) def model_default(self, request): return {"Hello": "World"} @sub.path(path='') class SubModel(object): pass @sub.json(model=SubModel) def sub_model_default(self, request): return request.view(Model('foo')) @root.mount(app=sub, path='sub') def mount_sub(obj, app): return app.child(sub()) @sub.defer_links(model=Model) def get_parent(app, obj): return app.parent c = Client(root()) response = c.get('/sub') assert response.json == {"Hello": "World"}
def test_reset_unconsumed_path(): class TestApp(TransactionApp): attempts = 0 @TestApp.path("/foo/bar") class Foo: pass @TestApp.view(model=Foo) def view_foo(self, request): TestApp.attempts += 1 # on the first attempt raise a conflict error if TestApp.attempts == 1: raise Conflict return "ok" # if the unconsumed path is reset wrongly, it'll accidentally pick # up this model instead of Foo @TestApp.path("/bar/foo") class Bar: pass @TestApp.view(model=Bar) def view_bar(self, request): return "error" @TestApp.setting(section="transaction", name="attempts") def get_retry_attempts(): return 2 client = Client(TestApp()) response = client.get("/foo/bar") assert response.text == "ok" assert TestApp.attempts == 2
def test_delete_todo(): c = Client(App()) response = c.delete("/todos/2") todo_list = { "todos": [ { "@id": "http://localhost/todos/0", "title": "Code", "completed": True }, { "@id": "http://localhost/todos/1", "title": "Test", "completed": False }, { "@id": "http://localhost/todos/3", "title": "Release", "completed": False }, ] } assert response.json == todo_list
def test_injector_does_not_fail_for_401_responses_with_no_content_type(): bower = bowerstatic.Bower() components = bower.components( 'components', os.path.join(os.path.dirname(__file__), 'bower_components')) def wsgi(environ, start_response): # Can not use 401 here as webtest only accepts 200 or 3xx, which is ok # as we want to test the behaviour if no content type is given start_response('302', [('Content-Type', None)]) include = components.includer(environ) with pytest.raises(bowerstatic.Error): include('jquery/nonexistent.js') return [b'<html><head></head><body>Hello!</body></html>'] injector = bower.injector(wsgi) c = Client(injector) # webtest checks, in contracy to pyramid, the headers and breaks if one of # them is not a string. with mock.patch('webtest.lint.check_headers'): c.get('/')
def test_no_permission(): class app(morepath.App): pass class Model(object): def __init__(self, id): self.id = id class Permission(object): pass @app.path( model=Model, path="{id}", variables=lambda model: {"id": model.id} ) def get_model(id): return Model(id) @app.view(model=Model, permission=Permission) def default(self, request): return "Model: %s" % self.id c = Client(app()) c.get("/foo", status=403)
def test_local_external_dependencies(): bower = bowerstatic.Bower() components = bower.components('components', os.path.join( os.path.dirname(__file__), 'bower_components')) local = bower.local_components('local', components) path = os.path.join( os.path.dirname(__file__), 'local_component') local.component(path, version='2.0') local.resource('local_component/local.js', dependencies=[ 'jquery']) def wsgi(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=UTF-8')]) include = local.includer(environ) include('local_component/local.js') return [b'<html><head></head><body>Hello!</body></html>'] wrapped = bower.wrap(wsgi) c = Client(wrapped) response = c.get('/') assert response.body == ( b'<html><head>' b'<script type="text/javascript" ' b'src="/bowerstatic/components/jquery/2.1.1/dist/jquery.js">' b'</script>\n' b'<script type="text/javascript" ' b'src="/bowerstatic/local/local_component/2.0/local.js"></script>' b'</head><body>Hello!</body></html>')
def test_POST_functionality_allows_POST_with_GET_operation_name(): wsgi = graphql_wsgi(TestSchema) c = Client(wsgi) response = c.post( '/?operationName=helloWorld', { 'query': b''' query helloYou { test(who: "You"), ...shared } query helloWorld { test(who: "World"), ...shared } query helloDolly { test(who: "Dolly"), ...shared } fragment shared on Root { shared: test(who: "Everyone") } ''' }) assert response.json == { 'data': { 'test': 'Hello World', 'shared': 'Hello Everyone' } }
def test_injector_endpoint_depends_on_main_missing(): bower = bowerstatic.Bower() components = bower.components( 'components', os.path.join(os.path.dirname(__file__), 'bower_components')) def wsgi(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=UTF-8')]) include = components.includer(environ) include('depends_on_missing_main') return [b'<html><head></head><body>Hello!</body></html>'] injector = bower.injector(wsgi) c = Client(injector) response = c.get('/') # without a main, it should just include nothing assert response.body == ( b'<html><head><script type="text/javascript" ' b'src="/bowerstatic/components/depends_on_missing_main/' b'2.1.1/resource.js"></script></head><body>Hello!</body></html>')