class SQLAlchemySequenceTestCase(BaseTestCase): def setUp(self): super(SQLAlchemySequenceTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app) self.sa = SQLAlchemy(self.app, session_options={"autoflush": False}) def test_sequence_primary_key(self): sa = self.sa user_id_seq = sa.Sequence('user_id_seq') class User(sa.Model): id = sa.Column(sa.Integer, user_id_seq, primary_key=True) username = sa.Column(sa.String, unique=True) sa.create_all() class UserResource(ModelResource): class Schema: username = fields.String() class Meta: model = User include_id = True self.api.add_resource(UserResource) response = self.client.post('/user', data={"username": "******"}) self.assert200(response) self.assertJSONEqual({"$id": 1, "username": "******"}, response.json)
def test_api_register_resource(self): class BookResource(ModelResource): class Meta: name = "book" model = "book" manager = MemoryManager api = Api(self.app) api.add_resource(BookResource) response = self.client.get("/schema") self.assertEqual( { "$schema": "http://json-schema.org/draft-04/hyper-schema#", "properties": { "book": { "$ref": "/book/schema#" } }, }, response.json, ) response = self.client.get("/book/schema") self.assert200(response)
class SQLAlchemyInspectionTestCase(BaseTestCase): def setUp(self): super(SQLAlchemyInspectionTestCase, self).setUp() self.app.config["SQLALCHEMY_ENGINE"] = "sqlite://" self.api = Api(self.app) self.sa = sa = SQLAlchemy(self.app, session_options={"autoflush": False}) def test_inspection_auto_id_attribute_type(self): sa = self.sa class User(sa.Model): username = sa.Column(sa.String, primary_key=True) first_name = sa.Column(sa.String) last_name = sa.Column(sa.String) sa.create_all() class UserResource(ModelResource): class Schema: username = fields.String() class Meta: model = User include_id = True self.api.add_resource(UserResource) self.assertEqual(User.username, UserResource.manager.id_column) self.assertEqual("username", UserResource.manager.id_field.attribute) self.assertIsInstance(UserResource.manager.id_field, fields.String) response = self.client.post("/user", data={"username": "******", "first_name": "Foo"}) self.assert200(response) self.assertJSONEqual({"$id": "foo", "first_name": "Foo", "last_name": None, "username": "******"}, response.json)
def test_api_blueprint(self): api_bp = Blueprint("potion_blueprint", __name__.split(".")[0]) api = Api(api_bp) api.add_resource(self.SampleResource) # Register Blueprint self.app.register_blueprint(api_bp) response = self.client.get("/samples")
def test_api_blueprint(self): api_bp = Blueprint("potion_blueprint", __name__.split(".")[0]) api = Api(api_bp) api.add_resource(self.SampleResource) # Register Blueprint self.app.register_blueprint(api_bp) self.client.get("/samples")
class ErrorMessagesTestCase(BaseTestCase): def setUp(self): super(ErrorMessagesTestCase, self).setUp() self.api = Api(self.app, prefix='/prefix') class ErrorResource(Resource): @Route.GET def forbidden(self): raise Forbidden() @Route.GET def python_exception(self): raise ValueError() @Route.GET def duplicate_key(self): raise DuplicateKey() class Meta: name = 'error' self.api.add_resource(ErrorResource) def test_werkzeug_exception(self): response = self.client.get('/prefix/error/forbidden') self.assert403(response) self.assertEqual({ "message": "You don't have the permission to access the requested resource. " "It is either read-protected or not readable by the server.", "status": 403 }, response.json) def test_potion_exception(self): response = self.client.get('/prefix/error/duplicate-key') self.assertStatus(response, 409) self.assertEqual({ "message": "Conflict", "status": 409 }, response.json) def test_not_found_exception(self): response = self.client.get('/prefix/error/missing') self.assert404(response) self.assertEqual({ "message": "The requested URL was not found on the server. If you entered " "the URL manually please check your spelling and try again.", "status": 404 }, response.json) def test_exception_outside_api(self): response = self.client.get('/missing') self.assert404(response) @unittest.SkipTest def test_python_exception(self): response = self.client.get('/prefix/error/python-exception') self.assert500(response) self.assertEqual({}, response.json)
def test_api_blueprint_w_prefix(self): api_bp = Blueprint("potion_blueprint", __name__.split(".")[0]) api = Api(api_bp, prefix="/api/v1") api.add_resource(self.SampleResource) # Register Blueprint self.app.register_blueprint(api_bp) response = self.client.get("/api/v1/samples") self.assert200(response) response = self.client.get("/api/v1/samples/schema") self.assertEqual('^\\/api\\/v1\\/samples\\/[^/]+$', response.json['properties']['$uri']['pattern'])
def init_app(app): """ Configuring the Flask app's extensions """ # initialize Flask extensions app.db = init_db(app) # setup Flask-Potion routes v1_api = Api(app) v1_api.add_resource(BetaResource) v1_api.add_resource(AlphaResource) return app
def test_route_decorator(self): def unauthorize(fn): @wraps(fn) def wrapper(*args, **kwargs): raise Unauthorized() return wrapper def denormalize(fn): @wraps(fn) def wrapper(*args, **kwargs): return 'not ' + fn(*args, **kwargs) return wrapper class FooResource(Resource): @Route.GET def no_decorator(self): return 'normal' @Route.GET def simple_decorator(self): return 'normal' @Route.GET def unauthorize_decorator(self): return 'normal' class Meta: name = 'foo' title = 'Foo bar' route_decorators = { 'readSimpleDecorator': denormalize, 'readUnauthorizeDecorator': unauthorize } self.assertEqual('normal', FooResource().no_decorator()) self.assertEqual('normal', FooResource().simple_decorator()) self.assertEqual('normal', FooResource().unauthorize_decorator()) api = Api(self.app) api.add_resource(FooResource) response = self.client.get("/foo/no-decorator") self.assertEqual('normal', response.json) response = self.client.get("/foo/simple-decorator") self.assertEqual('not normal', response.json) response = self.client.get("/foo/unauthorize-decorator") self.assert401(response)
def test_route_decorator(self): def unauthorize(fn): @wraps(fn) def wrapper(*args, **kwargs): raise Unauthorized() return wrapper def denormalize(fn): @wraps(fn) def wrapper(*args, **kwargs): return 'not ' + fn(*args, **kwargs) return wrapper class FooResource(Resource): @Route.GET def no_decorator(self): return 'normal' @Route.GET def simple_decorator(self): return 'normal' @Route.GET def unauthorize_decorator(self): return 'normal' class Meta: name = 'foo' title = 'Foo bar' route_decorators = { 'readSimpleDecorator': denormalize, 'readUnauthorizeDecorator': unauthorize, } self.assertEqual('normal', FooResource().no_decorator()) self.assertEqual('normal', FooResource().simple_decorator()) self.assertEqual('normal', FooResource().unauthorize_decorator()) api = Api(self.app) api.add_resource(FooResource) response = self.client.get("/foo/no-decorator") self.assertEqual('normal', response.json) response = self.client.get("/foo/simple-decorator") self.assertEqual('not normal', response.json) response = self.client.get("/foo/unauthorize-decorator") self.assert401(response)
def test_api_prefix(self): api = Api(self.app, prefix='/api/v1') class BookResource(ModelResource): class Meta: name = "book" model = "book" manager = MemoryManager @Route.GET def genres(self): return ['fiction', 'non-fiction'] @ItemRoute.GET def rating(self): return 4.5 api.add_resource(BookResource) response = self.client.get("/schema") self.assert404(response) response = self.client.get("/api/v1/schema") self.assertEqual( { "$schema": "http://json-schema.org/draft-04/hyper-schema#", "properties": { "book": { "$ref": "/api/v1/book/schema#" } }, }, response.json, ) response = self.client.get("/api/v1/book/schema") self.assert200(response) self.assertEqual( { "/api/v1/book", "/api/v1/book/schema", "/api/v1/book/genres", "/api/v1/book/{id}", "/api/v1/book/{id}/rating", }, {link_['href'] for link_ in response.json['links']}, )
def test_route_success_code(self): class FooResource(Resource): @Route.GET(success_code=201) def foo(self): return 'foo' class Meta: name = 'foo' api = Api(self.app) api.add_resource(FooResource) response = self.client.get("/foo/foo") self.assertEqual(201, response.status_code) self.assertEqual('foo', response.json)
def initialize_app(flask_app): configure_app(flask_app) api = Api(app) blueprint = Blueprint('api', __name__, url_prefix='/api') api.init_app(blueprint) flask_app.register_blueprint(blueprint) api.add_resource(CampaignResource) api.add_resource(Resource) # Swagger(app) db.init_app(flask_app)
def test_api_blueprint_w_prefix(self): api_bp = Blueprint("potion_blueprint", __name__.split(".")[0]) api = Api(api_bp, prefix="/api/v1") api.add_resource(self.SampleResource) # Register Blueprint self.app.register_blueprint(api_bp) response = self.client.get("/api/v1/samples") self.assert200(response) response = self.client.get("/api/v1/samples/schema") self.assertEqual( '^\\/api\\/v1\\/samples\\/[^/]+$', response.json['properties']['$uri']['pattern'], )
class SQLAlchemyInspectionTestCase(BaseTestCase): def setUp(self): super(SQLAlchemyInspectionTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app) self.sa = SQLAlchemy(self.app, session_options={"autoflush": False}) def test_inspection_auto_id_attribute_type(self): sa = self.sa class User(sa.Model): username = sa.Column(sa.String, primary_key=True) first_name = sa.Column(sa.String) last_name = sa.Column(sa.String) sa.create_all() class UserResource(ModelResource): class Schema: username = fields.String() class Meta: model = User include_id = True self.api.add_resource(UserResource) self.assertEqual(User.username, UserResource.manager.id_column) self.assertEqual('username', UserResource.manager.id_field.attribute) self.assertIsInstance(UserResource.manager.id_field, fields.String) response = self.client.post('/user', data={ "username": "******", "first_name": "Foo" }) self.assert200(response) self.assertJSONEqual( { "$id": "foo", "first_name": "Foo", "last_name": None, "username": "******" }, response.json, )
def run(): """ Main entry point """ app = Flask(__name__, static_path='') app.config['DATABASE'] = 'sqlite://' # pylint: disable=no-member if not Position.table_exists(): Position.create_table() if not Search.table_exists(): Search.create_table() app.config["POTION_DEFAULT_PER_PAGE"] = 10000000 app.config["POTION_MAX_PER_PAGE"] = 10000000 api = Api(app, default_manager=PeeweeManager) api.add_resource(PositionResource) api.add_resource(SearchResource) app.run(debug=True, host="127.0.0.1", port=int(CONFIG['main'].get("port", 8000)))
class ResourceTestCase(BaseTestCase): def setUp(self): super(ResourceTestCase, self).setUp() self.api = Api(self.app) def test_resource(self): class FooResource(Resource): class Schema: name = fields.String() class Meta: name = 'foo' self.api.add_resource(FooResource) #self.assertEqual(['create', 'update', 'schema'], list(FooResource.routes.())) data, code, headers = FooResource().described_by() self.assertEqual({"name": {"type": "string"}}, data["properties"])
class ResourceTestCase(BaseTestCase): def setUp(self): super(ResourceTestCase, self).setUp() self.api = Api(self.app) def test_resource(self): class FooResource(Resource): class Schema: name = fields.String() class Meta: name = "foo" self.api.add_resource(FooResource) # self.assertEqual(['create', 'update', 'schema'], list(FooResource.routes.())) data, code, headers = FooResource().described_by() self.assertEqual({"name": {"type": "string"}}, data["properties"])
def test_schema_decoration(self): def is_teapot(fn): @wraps(fn) def wrapper(*args, **kwargs): return '', 418, {} return wrapper api = Api(self.app, decorators=[is_teapot]) class FooResource(Resource): class Meta: name = 'foo' api.add_resource(FooResource) response = self.client.get("/schema") self.assertEqual(response.status_code, 418) response = self.client.get("/foo/schema") self.assertEqual(response.status_code, 418)
def test_api_register_resource(self): class BookResource(ModelResource): class Meta: name = "book" model = "book" manager = MemoryManager api = Api(self.app) api.add_resource(BookResource) response = self.client.get("/schema") self.assertEqual({ "$schema": "http://json-schema.org/draft-04/hyper-schema#", "properties": { "book": {"$ref": "/book/schema#"} } }, response.json) response = self.client.get("/book/schema") self.assert200(response)
def test_api_prefix(self): api = Api(self.app, prefix='/api/v1') class BookResource(ModelResource): class Meta: name = "book" model = "book" manager = MemoryManager @Route.GET def genres(self): return ['fiction', 'non-fiction'] @ItemRoute.GET def rating(self): return 4.5 api.add_resource(BookResource) response = self.client.get("/schema") self.assert404(response) response = self.client.get("/api/v1/schema") self.assertEqual({ "$schema": "http://json-schema.org/draft-04/hyper-schema#", "properties": { "book": {"$ref": "/api/v1/book/schema#"} } }, response.json) response = self.client.get("/api/v1/book/schema") self.assert200(response) self.assertEqual({ "/api/v1/book", "/api/v1/book/schema", "/api/v1/book/genres", "/api/v1/book/{id}", "/api/v1/book/{id}/rating" }, {l['href'] for l in response.json['links']})
def test_schema_decoration_disable(self): def is_teapot(fn): @wraps(fn) def wrapper(*args, **kwargs): return '', 418, {} return wrapper self.app.config['POTION_DECORATE_SCHEMA_ENDPOINTS'] = False api = Api(self.app, decorators=[is_teapot]) class FooResource(Resource): class Meta: name = 'foo' api.add_resource(FooResource) response = self.client.get("/schema") self.assert200(response) response = self.client.get("/foo/schema") self.assert200(response)
class SQLAlchemySequenceTestCase(BaseTestCase): def setUp(self): super(SQLAlchemySequenceTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app) self.sa = sa = SQLAlchemy(self.app, session_options={"autoflush": False}) def test_sequence_primary_key(self): sa = self.sa user_id_seq = sa.Sequence('user_id_seq') class User(sa.Model): id = sa.Column(sa.Integer, user_id_seq, primary_key=True) username = sa.Column(sa.String, unique=True) sa.create_all() class UserResource(ModelResource): class Schema: username = fields.String() class Meta: model = User include_id = True self.api.add_resource(UserResource) response = self.client.post('/user', data={"username": "******"}) self.assert200(response) self.assertJSONEqual({ "$id": 1, "username": "******" }, response.json)
class Schema: article = fields.ToOne('article') author = fields.ToOne('user') class Meta: model = Comment read_only_fields = ['author'] permissions = { 'create': 'anybody', 'update': 'user:author', 'delete': ['update:article', 'admin'] } for resource in (UserResource, ArticleResource, CommentResource): api.add_resource(resource) @signals.before_create.connect_via(ANY) def before_create_article_comment(sender, item): if issubclass(sender, (ArticleResource, CommentResource)): item.author_id = current_user.id db.create_all() if __name__ == '__main__': # Add some example users db.session.add(User(username='******', is_editor=True)) db.session.add(User(username='******', is_editor=True)) db.session.add(User(username='******', is_admin=True)) db.session.add(User(username='******'))
class FilterTestCase(BaseTestCase): def setUp(self): super(FilterTestCase, self).setUp() app = self.app app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' app.config['TESTING'] = True self.api = Api(self.app) self.sa = sa = SQLAlchemy(app) class User(sa.Model): id = sa.Column(sa.Integer, primary_key=True) first_name = sa.Column(sa.String(60), nullable=False) last_name = sa.Column(sa.String(60), nullable=False) gender = sa.Column(sa.String(1)) age = sa.Column(sa.Integer) is_staff = sa.Column(sa.Boolean, default=None) class Thing(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) belongs_to_id = sa.Column(sa.Integer, sa.ForeignKey(User.id)) belongs_to = sa.relationship(User, backref=backref('things', lazy='dynamic')) date_time = sa.Column(sa.DateTime) date = sa.Column(sa.Date) sa.create_all() class UserResource(ModelResource): class Schema: gender = fields.String(enum=['f', 'm'], nullable=True) class Meta: model = User include_id = True class ThingResource(ModelResource): class Schema: belongs_to = fields.ToOne('user', nullable=True) class Meta: model = Thing filters = { '$uri': { None: filters.EqualFilter, 'eq': filters.EqualFilter, 'ne': filters.NotEqualFilter, 'in': filters.InFilter }, '*': True } class AllowUserResource(ModelResource): class Meta: model = User name = 'allow-user' filters = { 'first_name': ['eq'], 'is_staff': True } class UseToManyResource(ModelResource): class Schema: things = fields.ToMany('thing') class Meta: name = 'user-to-many' model = User self.api.add_resource(UserResource) self.api.add_resource(ThingResource) self.api.add_resource(UseToManyResource) self.api.add_resource(AllowUserResource) def post_sample_set_a(self): for user in [ {'first_name': 'John', 'last_name': 'Doe', 'age': 32, 'is_staff': True, 'gender': 'm'}, {'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25, 'is_staff': False, 'gender': 'm'}, {'first_name': 'Jane', 'last_name': 'Roe', 'age': 18, 'is_staff': False, 'gender': 'f'}, {'first_name': 'Joe', 'last_name': 'Bloggs', 'age': 21, 'is_staff': True, 'gender': 'm'}, {'first_name': 'Sue', 'last_name': 'Watts', 'age': 25, 'is_staff': True} ]: response = self.client.post('/user', data=user) self.assert200(response) def test_equality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": "Doe"}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": 25}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25}, {'first_name': 'Sue', 'last_name': 'Watts', 'age': 25}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'is_staff']) response = self.client.get('/user?where={"last_name": "Doe", "age": 25}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inequality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$ne": "Watts"}, "age": {"$ne": 32}}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gt": 25}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gte": 25}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Sue', 'last_name': 'Watts'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lte": 21}}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": 21.0}}') self.assert400(response) response = self.client.get('/user?where={"age": {"$lt": null}}') self.assert400(response) response = self.client.get('/user?where={"first_name": {"$gt": "Jo"}}') self.assert400(response) def test_in(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$in": ["Bloggs", "Watts"]}}') self.assertEqualWithout([ {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'Sue', 'last_name': 'Watts'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"last_name": {"$in": []}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_startswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$startswith": "Jo"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$startswith": "J%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_istartswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$istartswith": "jo"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_iendswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$iendswith": "Oe"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Jane', 'last_name': 'Roe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_contains(self): self.post_sample_set_a() response = self.client.get('/user') user_ids = [user['$id'] for user in response.json] for thing in [ {'name': 'A', 'belongs_to': user_ids[0]}, {'name': 'B', 'belongs_to': user_ids[2]}, {'name': 'C', 'belongs_to': user_ids[1]}, {'name': 'D', 'belongs_to': user_ids[4]}, {'name': 'E', 'belongs_to': user_ids[3]}, {'name': 'F', 'belongs_to': None} ]: response = self.client.post('/thing', data=thing) self.assert200(response) response = self.client.get('/user-to-many?where={"things": {"$contains": {"$ref": "/thing/1"}}}') self.assertEqualWithout([ { "things": [{"$ref": "/thing/1"}], "first_name": "John", "last_name": "Doe" } ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_text_search(self): self.post_sample_set_a() response = self.client.get('/user?search=sbc+dedf&rank=1') def test_sort(self): self.post_sample_set_a() response = self.client.get('/user?sort={"last_name": true, "first_name": false}') self.assert200(response) self.assertEqualWithout([ {'first_name': 'Sue', 'last_name': 'Watts'}, {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?sort={"age": false, "first_name": false}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Sue', 'last_name': 'Watts'}, {'first_name': 'John', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_sort_relationship(self): self.post_sample_set_a() response = self.client.get('/user') user_ids = [user['$id'] for user in response.json] for thing in [ {'name': 'A', 'belongs_to': user_ids[0]}, {'name': 'B', 'belongs_to': user_ids[2]}, {'name': 'C', 'belongs_to': user_ids[1]}, {'name': 'D', 'belongs_to': user_ids[4]}, {'name': 'E', 'belongs_to': user_ids[3]}, {'name': 'F', 'belongs_to': None} ]: response = self.client.post('/thing', data=thing) self.assert200(response) thinggetter = lambda thing: thing['belongs_to']['$ref'] if thing['belongs_to'] else '' response = self.client.get('/thing?sort={"belongs_to": false}') self.assertEqual(sorted(response.json, key=thinggetter), response.json) response = self.client.get('/thing?sort={"belongs_to": true}') self.assertEqual(list(reversed(sorted(response.json, key=thinggetter))), response.json) response = self.client.get('/thing?sort={"name": false, "belongs_to": false}') self.assertEqual(sorted(response.json, key=lambda thing: thing['name']), response.json) def test_sort_relationship_none(self): for thing in [ {'name': 'A', 'belongs_to': None}, {'name': 'B', 'belongs_to': None}, {'name': 'C', 'belongs_to': None} ]: response = self.client.post('/thing', data=thing) self.assert200(response) response = self.client.get('/thing?sort={"belongs_to": false}') self.assertEqual(3, len(response.json)) def test_filter_and_sort_uri(self): for thing in [ {"name": "A thing"}, {"name": "B thing"} ]: response = self.client.post('/thing', data=thing) self.assert200(response) response1 = self.client.get('/thing?where={"$uri": "/thing/1"}') response2 = self.client.get('/thing?where={"$uri": {"$eq": "/thing/1"}}') response3 = self.client.get('/thing?where={"$uri": {"$ne": "/thing/2"}}') response4 = self.client.get('/thing?where={"$uri": {"$in": ["/thing/1"]}}') for response in [response1, response2, response3, response4]: self.assert200(response1) self.assertEqualWithout([{'$uri': u'/thing/1', 'name': 'A thing'}], response.json, without=['date', 'date_time', 'belongs_to']) response_multi = self.client.get('/thing?where={"$uri": {"$in": ["/thing/1", "/thing/2"]}}') self.assert200(response_multi) self.assertEqualWithout([{'$uri': '/thing/1', 'name': 'A thing'}, {'$uri': '/thing/2', 'name': 'B thing'}], response_multi.json, without=['date', 'date_time', 'belongs_to']) response_sort = self.client.get('/thing?sort={"$uri": false}') self.assert200(response_sort) self.assertEqualWithout([{'$uri': '/thing/1', 'name': 'A thing'}, {'$uri': '/thing/2', 'name': 'B thing'}], response_sort.json, without=['date', 'date_time', 'belongs_to']) def test_sort_filter_date(self): for thing in [ {'name': 'A', 'date_time': {'$date': 1446561100000}}, {'name': 'B', 'date_time': {'$date': 1000000000000}}, {'name': 'C', 'date_time': {'$date': 1446561110000}}, {'name': 'D', 'date_time': {'$date': 1446561120000}}, {'name': 'E', 'date_time': {'$date': 1446561130000}} ]: response = self.client.post('/thing', data=thing) self.assert200(response) response = self.client.get('/thing?sort={"date_time": false}') self.assertEqual(sorted(response.json, key=lambda thing: thing['date_time']['$date']), response.json) response = self.client.get('/thing?where={"date_time": {"$eq": {"$date": 1000000000000}}}') self.assertEqualWithout([ {'name': 'B', 'date_time': {'$date': 1000000000000}}, ], response.json, without=['$uri', 'date', 'belongs_to']) response = self.client.get('/thing?where={"date_time": {"$gt": {"$date": 1000000000000}}}') self.assertEqualWithout([ {'name': 'A', 'date_time': {'$date': 1446561100000}}, {'name': 'C', 'date_time': {'$date': 1446561110000}}, {'name': 'D', 'date_time': {'$date': 1446561120000}}, {'name': 'E', 'date_time': {'$date': 1446561130000}} ], response.json, without=['$uri', 'date', 'belongs_to']) response = self.client.get('/thing?where={"date_time": {"$lt": {"$date": 1000000000000}}}') self.assertEqualWithout([], response.json, without=['$uri', 'date', 'belongs_to']) response = self.client.get('/thing?where={"date_time": {"$between": [{"$date": 1446561110000}, {"$date": 1446561120000}]}}') self.assertEqualWithout([ {'name': 'C', 'date_time': {'$date': 1446561110000}}, {'name': 'D', 'date_time': {'$date': 1446561120000}}, ], response.json, without=['$uri', 'date', 'belongs_to']) def test_sort_and_where(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$startswith": "Jo"}}&sort={"first_name": false}') self.assertEqualWithout([ {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inherited_filters(self): self.assertEqual({ 'string': { 'eq': filters.EqualFilter, }, 'email': { None: filters.EqualFilter, 'eq': filters.EqualFilter, 'ne': filters.NotEqualFilter, 'in': filters.InFilter, 'contains': filters.StringContainsFilter, 'icontains': filters.StringIContainsFilter, 'endswith': filters.EndsWithFilter, 'iendswith': filters.IEndsWithFilter, 'startswith': filters.StartsWithFilter, 'istartswith': filters.IStartsWithFilter, }, 'uri': { 'eq': filters.EqualFilter, 'ne': filters.NotEqualFilter, 'endswith': filters.EndsWithFilter }, 'date_string': { None: filters.EqualFilter, 'eq': filters.EqualFilter, 'ne': filters.NotEqualFilter, 'in': filters.InFilter, 'lt': filters.LessThanFilter, 'lte': filters.LessThanEqualFilter, 'gt': filters.GreaterThanFilter, 'gte': filters.GreaterThanEqualFilter, 'between': filters.DateBetweenFilter, } }, filters_for_fields({ 'string': fields.String(), # inherit from String 'email': fields.Email(), 'uri': fields.Uri(), # no filter defined for Raw 'raw': fields.Raw({}), # inherits from String, but there is a filter for DateString 'date_string': fields.DateString() }, filter_names=FILTER_NAMES, filters_by_type=FILTERS_BY_TYPE, filters_expression={ 'string': ['eq'], 'email': True, 'uri': ['eq', 'ne', 'endswith'], '*': True })) @unittest.SkipTest def test_sort_pages(self): pass @unittest.SkipTest def test_disallowed_where_filters(self): pass @unittest.SkipTest def test_schema(self): pass
def test_multiple_blueprints(self): # Create Blueprints api_bp1 = Blueprint("potion1", __name__.split(".")[0]) api_bp2 = Blueprint("potion2", __name__.split(".")[0], url_prefix="/api") # Create Api objects, add resources, and register blueprints with app api1 = Api(api_bp1, prefix="/api/v1") api2 = Api(api_bp2, prefix="/v2") api1.add_resource(self.SampleResource) with self.assertRaises(RuntimeError): api2.add_resource(self.SampleResource) api2.add_resource(self.SampleResource2) self.app.register_blueprint(api_bp1) self.app.register_blueprint(api_bp2) # Test both endpoints response = self.client.get("/api/v1/samples") self.assert200(response) response = self.client.get("/api/v2/samples") self.assert200(response) response = self.client.get("/api/v1/schema") self.assert200(response) self.assertEqual( '/api/v1/samples/schema#', response.json['properties']['samples']['$ref'] ) response = self.client.get("/api/v2/schema") self.assert200(response) self.assertEqual( '/api/v2/samples/schema#', response.json['properties']['samples']['$ref'] ) response = self.client.get("/api/v1/samples/schema") self.assertEqual( '^\\/api\\/v1\\/samples\\/[^/]+$', response.json['properties']['$uri']['pattern'], ) response = self.client.get("/api/v2/samples/schema") self.assertEqual( '^\\/api\\/v2\\/samples\\/[^/]+$', response.json['properties']['$uri']['pattern'], ) # Test that we have two prefix'd schemas response = self.client.get("/api/v1/schema") self.assert200(response) v1_schema = json.loads(response.data) response = self.client.get("/api/v2/schema") self.assert200(response) v2_schema = json.loads(response.data) assert v1_schema != v2_schema assert v1_schema["properties"]["samples"] != v2_schema["properties"]["samples"] # Test that endpoints are linked to same resource response = self.client.post('/api/v1/samples', data={"name": "to_v1"}) self.assert200(response) response = self.client.post('/api/v2/samples', data={"name": "to_v2"}) self.assert200(response) response = self.client.get("/api/v1/samples/1") assert response.json['$uri'] == "/api/v1/samples/1" self.assert200(response) response = self.client.get("/api/v2/samples/1") assert response.json['$uri'] == "/api/v2/samples/1" self.assert200(response)
class PrincipalTestCase(BaseTestCase): def create_app(self): app = super(PrincipalTestCase, self).create_app() app.test_client_class = AuthorizedApiClient self.principal = Principal(app) self.sa = sa = SQLAlchemy(app) class User(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String()) class BookStore(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String()) owner_id = sa.Column(sa.Integer, sa.ForeignKey(User.id)) owner = sa.relationship(User, backref=backref('stores', lazy='dynamic')) class Book(sa.Model): id = sa.Column(sa.Integer, primary_key=True) title = sa.Column(sa.String(), nullable=False) author_id = sa.Column(sa.Integer, sa.ForeignKey(User.id)) author = sa.relationship(User, backref=backref('books', lazy='dynamic')) class BookSigning(sa.Model): id = sa.Column(sa.Integer, primary_key=True) book_id = sa.Column(sa.Integer, sa.ForeignKey(Book.id), nullable=False) store_id = sa.Column(sa.Integer, sa.ForeignKey(BookStore.id), nullable=False) book = sa.relationship(Book) store = sa.relationship(BookStore) sa.create_all() for model in (BookStore, User, Book, BookSigning): setattr(self, model.__tablename__.upper(), model) return app def setUp(self): super(PrincipalTestCase, self).setUp() self.mock_user = None @identity_loaded.connect_via(self.app) def on_identity_loaded(sender, identity): identity.provides.add(UserNeed(identity.id)) for role in self.mock_user.get('roles', []): identity.provides.add(RoleNeed(role)) for need in self.mock_user.get('needs', []): identity.provides.add(need) def authenticate(fn): @wraps(fn) def wrapper(*args, **kwargs): auth = request.authorization if not auth: raise Unauthorized() if auth.password == 'password': identity_changed.send(current_app._get_current_object(), identity=Identity(self.mock_user['id'])) else: raise Unauthorized() return fn(*args, **kwargs) return wrapper self.api = Api(self.app, decorators=[authenticate]) def test_role(self): with self.assertRaises(RuntimeError): manager = principals(MemoryManager) def test_role(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'create': 'author' } self.api.add_resource(BookResource) response = self.client.post('/book', data={'title': 'Foo'}, auth=False) self.assert401(response) self.mock_user = {'id': 1} response = self.client.post('/book', data={'title': 'Foo'}) self.assert403(response) self.mock_user = {'id': 1, 'roles': ['author']} response = self.client.post('/book', data={'title': 'Foo'}) self.assert200(response) self.assertEqual({'title': 'Foo', '$uri': '/book/1'}, response.json) self.assert200(self.client.patch('/book/1', data={'title': 'Foo I'})) self.mock_user = {'id': 1} self.assert403(self.client.patch('/book/1', data={'title': 'Bar'})) self.assert403(self.client.delete('/book/1')) # self.user = {'id': 1, 'roles': ['author']} # self.assert200(self.client.delete('/book/1')) # response = self.client.post('/book', data={'title': 'Foo'}) # # self.assert200(response) def test_access_forbidden_to_resource_collection(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': 'author', 'create': 'author', } self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['author']} response = self.client.post('/book', data={'title': 'Foo'}) self.assert200(response) self.assertEqual({'title': 'Foo', '$uri': '/book/1'}, response.json) self.assert200(self.client.get('/book')) self.mock_user = {'id': 1} self.assert403(self.client.get('/book')) def test_inherit_role_to_one_field(self): class BookStoreResource(PrincipalResource): class Meta: model = self.BOOK_STORE permissions = { 'create': 'admin', 'update': ['admin'] } class BookSigningResource(PrincipalResource): class Schema: book = fields.ToOne('book') store = fields.ToOne('book_store') class Meta: model = self.BOOK_SIGNING permissions = { 'create': 'update:store' } class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'create': 'yes' } self.api.add_resource(BookStoreResource) self.api.add_resource(BookSigningResource) self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200(self.client.post('/book_store', data={ 'name': 'Foo Books' })) self.assert200(self.client.post('/book', data={ 'title': 'Bar' })) self.mock_user = {'id': 2} response = self.client.post('/book_signing', data={ 'book': {'$ref': '/book/1'}, 'store': {'$ref': '/book_store/1'} }) self.assert403(response) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200(self.client.post('/book_signing', data={ 'book': {'$ref': '/book/1'}, 'store': {'$ref': '/book_store/1'} })) def test_user_need(self): class BookStoreResource(PrincipalResource): class Schema: owner = fields.ToOne('user') class Meta: model = self.BOOK_STORE permissions = { 'create': 'admin', 'update': ['admin', 'user:owner'] } class UserResource(PrincipalResource): class Meta: model = self.USER permissions = { 'create': 'admin' } self.api.add_resource(BookStoreResource) self.api.add_resource(UserResource) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200(self.client.post('/user', data={'name': 'Admin'})) for i, store in enumerate([ { 'name': 'Books & More', 'owner': { 'name': 'Mr. Moore' } }, { 'name': 'Foo Books', 'owner': { 'name': 'Foo' } } ]): response = self.client.post('/user', data=store['owner']) owner = {'$ref': response.json['$uri']} response = self.client.post('/book_store', data={ 'name': store['name'], 'owner': owner }) self.assertEqual({'$uri': '/book_store/{}'.format(i + 1), 'name': store['name'], 'owner': owner}, response.json) response = self.client.patch('/book_store/1', data={'name': 'books & moore'}) self.assert200(response) self.mock_user = {'id': 3} response = self.client.patch('/book_store/1', data={'name': 'Books & Foore'}) self.assert403(response) self.mock_user = {'id': 2} response = self.client.patch('/book_store/1', data={'name': 'Books & Moore'}) self.assert200(response) self.assertEqual({ '$uri': '/book_store/1', 'name': 'Books & Moore', 'owner': {'$ref': '/user/2'} }, response.json) response = self.client.patch('/book_store/2', data={'name': 'Moore Books'}) self.assert403(response) def test_item_need_update(self): class BookStoreResource(PrincipalResource): class Meta: model = self.BOOK_STORE permissions = { 'create': 'admin', 'update': 'update' } self.api.add_resource(BookStoreResource) self.mock_user = {'id': 1, 'roles': ['admin']} # response = self.client.post('/book_store', data=[ # {'name': 'Bar Books'}, # {'name': 'Foomazon'} # ]) response = self.client.post('/book_store', data={'name': 'Bar Books'}) self.assert200(response) response = self.client.post('/book_store', data={'name': 'Foomazon'}) self.assert200(response) self.mock_user = {'id': 1, 'needs': [ItemNeed('update', 2, 'book_store')]} self.assert403(self.client.patch('/book_store/1', data={'name': 'Foo'})) response = self.client.patch('/book_store/2', data={'name': 'Foo'}) self.assert200(response) self.assertEqual({'$uri': '/book_store/2', 'name': 'Foo'}, response.json) # TODO DELETE def test_yes_no(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': 'yes', 'create': 'admin', 'update': 'no' } self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200(self.client.post('/book', data={'title': 'Foo'})) self.assert403(self.client.patch('/book/1', data={'title': 'Bar'})) self.assert200(self.client.get('/book/1')) self.assert200(self.client.get('/book')) def test_item_need_read(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': ['owns-copy', 'admin'], 'create': 'admin', 'owns-copy': 'owns-copy' } self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} # TODO Bulk inserts # response = self.client.post('/book', data=[ # {'title': 'GoT Vol. {}'.format(i + 1)} for i in range(20) # ]) for i in range(20): self.client.post('/book', data={'title': 'GoT Vol. {}'.format(i + 1)}) self.assertEqual(20, len(self.client.get('/book').json)) self.mock_user = {'id': 2, 'needs': [ItemNeed('owns-copy', i, 'book') for i in (1, 4, 6, 8, 11, 15, 19)]} self.assertEqual(7, len(self.client.get('/book').json)) self.mock_user = {'id': 3, 'needs': [ItemNeed('owns-copy', i, 'book') for i in (2, 7, 19)]} self.assertEqual([ {'$uri': '/book/2', 'title': 'GoT Vol. 2'}, {'$uri': '/book/7', 'title': 'GoT Vol. 7'}, {'$uri': '/book/19', 'title': 'GoT Vol. 19'} ], self.client.get('/book').json) self.assert404(self.client.get('/book/15')) self.assert200(self.client.get('/book/2')) self.assert200(self.client.get('/book/7')) self.assert404(self.client.get('/book/1')) self.assert404(self.client.get('/book/99')) self.mock_user = {'id': 4} self.assertEqual([], self.client.get('/book').json) def test_relationship(self): "should require update permission on parent resource for updating, read permissions on both" class BookResource(PrincipalResource): class Schema: author = fields.ToOne('user', nullable=True) class Meta: model = self.BOOK permissions = { 'read': ['owns-copy', 'update', 'admin'], 'create': 'writer', 'update': 'user:author', 'owns-copy': 'owns-copy' } class UserResource(PrincipalResource): books = Relation(BookResource) class Meta: model = self.USER permissions = { 'create': 'admin' } self.api.add_resource(UserResource) self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} for user in [ {'name': 'Admin'}, {'name': 'Author 1'}, {'name': 'Author 2'} ]: response = self.client.post('/user', data=user) self.assert200(response) response = self.client.post('/book', data={ 'title': 'Foo' }) self.assert403(response) self.mock_user = {'id': 2, 'roles': ['writer']} response = self.client.post('/book', data={ 'author': {'$ref': '/user/2'}, 'title': 'Bar' }) self.assert200(response) self.mock_user = {'id': 3, 'roles': ['writer']} response = self.client.post('/book', data={'title': 'Spying: Novel'}) self.assert200(response) response = self.client.post('/book', data={'title': 'Spied: The Sequel'}) self.assert200(response) response = self.client.post('/book', data={'title': 'Spy: The Prequel'}) self.assert200(response) self.assertJSONEqual({'$uri': '/book/4', 'author': None, 'title': 'Spy: The Prequel'}, response.json) self.mock_user = {'id': 1, 'roles': ['admin']} self.client.post('/user/3/books', data={'$ref': '/book/2'}) self.client.post('/user/3/books', data={'$ref': '/book/3'}) self.client.post('/user/3/books', data={'$ref': '/book/4'}) self.mock_user = {'id': 3, 'roles': ['writer']} self.assert200(response) response = self.client.get('/user/3/books') self.assert200(response) self.assertEqual(3, len(response.json)) # read -> update -> user:author self.mock_user = {'id': 4, 'needs': [ItemNeed('owns-copy', 3, 'book')]} response = self.client.get('/user/3/books') self.assertEqual(1, len(response.json)) # read -> owns-copy self.assert200(self.client.get('/book/3')) self.assert404(self.client.get('/book/2')) self.mock_user = {'id': 5} response = self.client.get('/user/3/books') self.assertEqual(0, len(response.json)) self.assert404(self.client.get('/book/2')) @unittest.SkipTest def test_item_route(self): "should require read permission on parent resource plus any additional permissions" pass def test_permission_circular(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': 'create', 'create': 'read', 'update': 'create', 'delete': 'update' } self.api.add_resource(BookResource) with self.assertRaises(RuntimeError): BookResource.manager._needs
'create': super_admin_only, 'update': super_admin_only, 'delete': 'no', } class Schema: id = fields.String(min_length=3, max_length=3) @signals.before_create.connect_via(GatewayResource) @signals.before_create.connect_via(UserResource) @signals.before_create.connect_via(VoucherResource) @signals.before_create.connect_via(CategoryResource) @signals.before_create.connect_via(ProductResource) def set_scope(sender, item): if current_user.has_role('network-admin') or current_user.has_role( 'gateway-admin'): item.network_id = current_user.network_id if current_user.has_role('gateway-admin'): item.gateway_id = current_user.gateway_id api.add_resource(UserResource) api.add_resource(VoucherResource) api.add_resource(GatewayResource) api.add_resource(NetworkResource) api.add_resource(CategoryResource) api.add_resource(ProductResource) api.add_resource(CurrencyResource)
class SQLAlchemyTestCase(BaseTestCase): def setUp(self): super(SQLAlchemyTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app, default_manager=SQLAlchemyManager) self.sa = sa = SQLAlchemy(self.app, session_options={"autoflush": False}) class Type(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False, unique=True) version = sa.Column(sa.Integer(), nullable=True) class Machine(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) wattage = sa.Column(sa.Float) type_id = sa.Column(sa.Integer, sa.ForeignKey(Type.id)) type = sa.relationship(Type, backref=backref('machines', lazy='dynamic', uselist=True)) sa.create_all() class MachineResource(ModelResource): class Meta: model = Machine include_id = True include_type = True class Schema: type = fields.ToOne('type') class TypeResource(ModelResource): class Meta: model = Type include_id = True include_type = True class Schema: machines = fields.ToMany('machine') self.MachineResource = MachineResource self.TypeResource = TypeResource self.api.add_resource(MachineResource) self.api.add_resource(TypeResource) def tearDown(self): self.sa.drop_all() def test_field_discovery(self): self.assertEqual(set(self.MachineResource.schema.fields.keys()), {'$id', '$type', 'name', 'type', 'wattage'}) self.assertEqual(set(self.TypeResource.schema.fields.keys()), {'$id', '$type', 'name', 'version', 'machines'}) self.assertEqual(self.MachineResource.meta.name, 'machine') self.assertEqual(self.TypeResource.meta.name, 'type') def test_create_no_json(self): response = self.client.post('/machine', data='invalid') self.assert400(response) def test_create_json_string(self): response = self.client.post('/machine', data='invalid', force_json=True) self.assert400(response) def test_conflict(self): response = self.client.post('/type', data={"name": "foo"}) self.assert200(response) response = self.client.post('/type', data={"name": "foo"}) self.assertStatus(response, 409) def test_create(self): response = self.client.post('/type', data={}) self.assert400(response) self.assertEqual({ "errors": [ { "message": "'name' is a required property", "path": [], "validationOf": { "required": [ "name" ] } } ], "message": "Bad Request", "status": 400 }, response.json) response = self.client.post('/type', data={"name": "x-ray"}) self.assertJSONEqual({'$id': 1, '$type': 'type', 'machines': [], "name": "x-ray", 'version': None}, response.json) response = self.client.post('/machine', data={"name": "Irradiator I", "type": 1}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'machine', 'type': {"$ref": "/type/1"}, "wattage": None, "name": "Irradiator I"}, response.json) response = self.client.post('/machine', data={"name": "Sol IV", "type": 1, "wattage": 1.23e45}) self.assert200(response) self.assertJSONEqual({'$id': 2, '$type': 'machine', 'type': {"$ref": "/type/1"}, "wattage": 1.23e45, "name": "Sol IV"}, response.json) response = self.client.get('/type/1') self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'type', 'machines': [ {'$ref': '/machine/1'}, {'$ref': '/machine/2'} ], "name": "x-ray", 'version': None }, response.json) def test_get(self): type_ = lambda i: {"$id": i, "$type": "type", "name": "Type-{}".format(i), "machines": [], 'version': None} for i in range(1, 10): response = self.client.post('/type', data={"name": "Type-{}".format(i), "machines": []}) self.assert200(response) self.assertJSONEqual(type_(i), response.json) response = self.client.get('/type/{}'.format(i)) self.assert200(response) self.assertJSONEqual(type_(i), response.json) response = self.client.get('/type') self.assert200(response) self.assertJSONEqual([type_(i) for i in range(1, i + 1)], response.json) response = self.client.get('/type/{}'.format(i + 1)) self.assert404(response) self.assertJSONEqual({ 'item': {'$id': i + 1, '$type': 'type'}, 'message': 'Not Found', 'status': 404 }, response.json) @unittest.SkipTest def test_pagination(self): pass # TODO def test_update(self): response = self.client.post('/type', data={"name": "T1"}) self.assert200(response) response = self.client.post('/type', data={"name": "T2"}) self.assert200(response) response = self.client.post('/machine', data={"name": "Robot", "type": 1}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'machine', 'type': {"$ref": "/type/1"}, "wattage": None, "name": "Robot"}, response.json) response = self.client.patch('/machine/1', data={}) self.assert200(response) response = self.client.patch('/machine/1', data={"wattage": 10000}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'machine', 'type': {"$ref": "/type/1"}, "wattage": 10000, "name": "Robot"}, response.json) response = self.client.patch('/machine/1', data={"type": {"$ref": "/type/2"}}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'machine', 'type': {"$ref": "/type/2"}, "wattage": 10000, "name": "Robot"}, response.json) response = self.client.patch('/type/1', data={"version": 1}) self.assertJSONEqual({'$id': 1, '$type': 'type', 'name': 'T1', 'version': 1, 'machines': []}, response.json) response = self.client.patch('/type/1', data={"version": None}) self.assertJSONEqual({'$id': 1, '$type': 'type', 'name': 'T1', 'machines': [], 'version': None}, response.json) response = self.client.patch('/machine/1', data={"type": None}) self.assert400(response) self.assertJSONEqual({ 'errors': [ { "message": "None is not valid under any of the given schemas", "path": [ "type" ], "validationOf": { "anyOf": [ { "additionalProperties": False, "properties": { "$ref": { "pattern": "^\\/type\\/[^/]+$", "type": "string" } }, "type": "object" }, { "type": "integer" } ] } } ], 'message': 'Bad Request', 'status': 400 }, response.json) response = self.client.patch('/machine/1', data={"name": "Foo"}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'machine', 'type': {"$ref": "/type/2"}, "wattage": 10000, "name": "Foo"}, response.json) def test_delete(self): response = self.client.delete('/type/1') self.assert404(response) response = self.client.post('/type', data={"name": "Foo", "machines": []}) self.assert200(response) response = self.client.delete('/type/1') self.assertStatus(response, 204) response = self.client.delete('/type/1') self.assert404(response)
class FieldsTestCase(BaseTestCase): def setUp(self): super(FieldsTestCase, self).setUp() app = self.app app.config['MONGODB_DB'] = 'potion-test-db' app.config['TESTING'] = True self.api = Api(self.app, default_manager=MongoEngineManager) self.me = MongoEngine(app) def test_object_id_field(self): class Model(self.me.Document): meta = {'collection': 'model'} an_id = ObjectIdField() class Resource(ModelResource): class Meta: model = Model self.api.add_resource(Resource) response = self.client.get('/model/schema') self.assertEqual(response.json['properties']['an_id'], {'type': 'string'}) self.assertRaises(InvalidId, self.client.post, '/model', data={'an_id': "abc"}) hex = 'adfb48a6763c5741b92f6ade' object_id = ObjectId('adfb48a6763c5741b92f6ade') response = self.client.post('/model', data={'an_id': hex}) self.assertEqual(object_id, ObjectId(response.json['an_id'])) def test_map_field(self): class ReferenceModel(EmbeddedDocument): id = ObjectIdField() meta = {'collection': 'reference-model'} class Model(self.me.Document): meta = {'collection': 'model'} float_mapping = MapField(FloatField()) string_mapping = MapField(StringField()) object_id_mapping = MapField(ObjectIdField()) reference_mapping = MapField(EmbeddedDocumentField(ReferenceModel)) class Resource(ModelResource): class Meta: model = Model self.api.add_resource(Resource) response = self.client.get('/model/schema') self.assertEqual( response.json['properties']['float_mapping'] ['additionalProperties'], {'type': 'number'}) self.assertEqual( response.json['properties']['float_mapping']['default'], {}) self.assertEqual( response.json['properties']['string_mapping'] ['additionalProperties'], {'type': 'string'}) self.assertEqual( response.json['properties']['string_mapping']['default'], {}) self.assertEqual( response.json['properties']['reference_mapping'] ['additionalProperties'], { 'additionalProperties': False, 'type': 'object', 'properties': { 'id': { 'type': 'string' } } }) self.assertEqual( response.json['properties']['reference_mapping']['default'], {}) ref_model = dict(id='adfb48a6763c5741b92f6ade') response = self.client.post("/model", data={ 'reference_mapping': { "1": ref_model }, 'object_id_mapping': { "a": ref_model["id"] } }) self.assertEqualWithout(response.json, { 'reference_mapping': { '1': { 'id': 'adfb48a6763c5741b92f6ade' } }, '$uri': '/model/561e6a807f551ce7d5df1003', 'float_mapping': {}, 'object_id_mapping': { 'a': 'adfb48a6763c5741b92f6ade' }, 'string_mapping': {} }, without=["$uri"]) def tearDown(self): self.me.connection.drop_database('potion-test-db')
# database from being destroyed after each request. pass app = Flask(__name__) app.debug = True app.config['DATABASE'] = 'sqlite://' db = DB(app) class Book(db.Model): title = CharField(null=True, unique=True) year_published = IntegerField() class BookResource(ModelResource): class Meta: name = 'book' model = Book class Schema: year_published = fields.Integer(minimum=1400) api = Api(app, default_manager=PeeweeManager) api.add_resource(BookResource) if __name__ == '__main__': app.run()
class FilterTestCase(BaseTestCase): def setUp(self): super(FilterTestCase, self).setUp() app = self.app app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' app.config['TESTING'] = True self.api = Api(self.app) self.sa = sa = SQLAlchemy(app) class User(sa.Model): id = sa.Column(sa.Integer, primary_key=True) first_name = sa.Column(sa.String(60), nullable=False) last_name = sa.Column(sa.String(60), nullable=False) gender = sa.Column(sa.String(1)) age = sa.Column(sa.Integer) is_staff = sa.Column(sa.Boolean, default=None) class Thing(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) belongs_to_id = sa.Column(sa.Integer, sa.ForeignKey(User.id)) belongs_to = sa.relationship(User, backref=backref('things', lazy='dynamic')) date_time = sa.Column(sa.DateTime) date = sa.Column(sa.Date) sa.create_all() class UserResource(ModelResource): class Schema: gender = fields.String(enum=['f', 'm'], nullable=True) class Meta: model = User include_id = True class ThingResource(ModelResource): class Schema: belongs_to = fields.ToOne('user', nullable=True) class Meta: model = Thing class AllowUserResource(ModelResource): class Meta: model = User name = 'allow-user' filters = {'first_name': ['eq'], 'is_staff': True} class UseToManyResource(ModelResource): class Schema: things = fields.ToMany('thing') class Meta: name = 'user-to-many' model = User self.api.add_resource(UserResource) self.api.add_resource(ThingResource) self.api.add_resource(UseToManyResource) self.api.add_resource(AllowUserResource) def post_sample_set_a(self): for user in [{ 'first_name': 'John', 'last_name': 'Doe', 'age': 32, 'is_staff': True, 'gender': 'm' }, { 'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25, 'is_staff': False, 'gender': 'm' }, { 'first_name': 'Jane', 'last_name': 'Roe', 'age': 18, 'is_staff': False, 'gender': 'f' }, { 'first_name': 'Joe', 'last_name': 'Bloggs', 'age': 21, 'is_staff': True, 'gender': 'm' }, { 'first_name': 'Sue', 'last_name': 'Watts', 'age': 25, 'is_staff': True }]: response = self.client.post('/user', data=user) self.assert200(response) def test_equality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": "Doe"}') self.assertEqualWithout([ { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, ], response.json, without=[ '$uri', '$uri', '$id', '$type', 'gender', 'age', 'is_staff' ]) response = self.client.get('/user?where={"age": 25}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25 }, { 'first_name': 'Sue', 'last_name': 'Watts', 'age': 25 }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'is_staff']) response = self.client.get( '/user?where={"last_name": "Doe", "age": 25}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inequality(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$ne": "Watts"}, "age": {"$ne": 32}}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gt": 25}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gte": 25}}') self.assertEqualWithout( [ { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Sue', 'last_name': 'Watts' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lte": 21}}') self.assertEqualWithout( [{ 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": 21.0}}') self.assert400(response) response = self.client.get('/user?where={"age": {"$lt": null}}') self.assert400(response) response = self.client.get('/user?where={"first_name": {"$gt": "Jo"}}') self.assert400(response) def test_in(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$in": ["Bloggs", "Watts"]}}') self.assertEqualWithout( [{ 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'Sue', 'last_name': 'Watts' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"last_name": {"$in": []}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_startswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$startswith": "Jo"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$startswith": "J%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_istartswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$istartswith": "jo"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_iendswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$iendswith": "Oe"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Jane', 'last_name': 'Roe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_contains(self): self.post_sample_set_a() response = self.client.get('/user') user_ids = [user['$id'] for user in response.json] for thing in [{ 'name': 'A', 'belongs_to': user_ids[0] }, { 'name': 'B', 'belongs_to': user_ids[2] }, { 'name': 'C', 'belongs_to': user_ids[1] }, { 'name': 'D', 'belongs_to': user_ids[4] }, { 'name': 'E', 'belongs_to': user_ids[3] }, { 'name': 'F', 'belongs_to': None }]: response = self.client.post('/thing', data=thing) self.assert200(response) response = self.client.get( '/user-to-many?where={"things": {"$contains": {"$ref": "/thing/1"}}}' ) self.assertEqualWithout( [{ "things": [{ "$ref": "/thing/1" }], "first_name": "John", "last_name": "Doe" }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_text_search(self): self.post_sample_set_a() response = self.client.get('/user?search=sbc+dedf&rank=1') def test_sort(self): self.post_sample_set_a() response = self.client.get( '/user?sort={"last_name": true, "first_name": false}') self.assert200(response) self.assertEqualWithout( [{ 'first_name': 'Sue', 'last_name': 'Watts' }, { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?sort={"age": false, "first_name": false}') self.assertEqualWithout( [ { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Sue', 'last_name': 'Watts' }, { 'first_name': 'John', 'last_name': 'Doe' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_sort_relationship(self): self.post_sample_set_a() response = self.client.get('/user') user_ids = [user['$id'] for user in response.json] for thing in [{ 'name': 'A', 'belongs_to': user_ids[0] }, { 'name': 'B', 'belongs_to': user_ids[2] }, { 'name': 'C', 'belongs_to': user_ids[1] }, { 'name': 'D', 'belongs_to': user_ids[4] }, { 'name': 'E', 'belongs_to': user_ids[3] }, { 'name': 'F', 'belongs_to': None }]: response = self.client.post('/thing', data=thing) self.assert200(response) thinggetter = lambda thing: thing['belongs_to']['$ref'] if thing[ 'belongs_to'] else '' response = self.client.get('/thing?sort={"belongs_to": false}') self.assertEqual(sorted(response.json, key=thinggetter), response.json) response = self.client.get('/thing?sort={"belongs_to": true}') self.assertEqual( list(reversed(sorted(response.json, key=thinggetter))), response.json) response = self.client.get( '/thing?sort={"name": false, "belongs_to": false}') self.assertEqual( sorted(response.json, key=lambda thing: thing['name']), response.json) def test_sort_relationship_none(self): for thing in [{ 'name': 'A', 'belongs_to': None }, { 'name': 'B', 'belongs_to': None }, { 'name': 'C', 'belongs_to': None }]: response = self.client.post('/thing', data=thing) self.assert200(response) response = self.client.get('/thing?sort={"belongs_to": false}') self.assertEqual(3, len(response.json)) def test_sort_filter_date(self): for thing in [{ 'name': 'A', 'date_time': { '$date': 1446561100000 } }, { 'name': 'B', 'date_time': { '$date': 1000000000000 } }, { 'name': 'C', 'date_time': { '$date': 1446561110000 } }, { 'name': 'D', 'date_time': { '$date': 1446561120000 } }, { 'name': 'E', 'date_time': { '$date': 1446561130000 } }]: response = self.client.post('/thing', data=thing) self.assert200(response) response = self.client.get('/thing?sort={"date_time": false}') self.assertEqual( sorted(response.json, key=lambda thing: thing['date_time']['$date']), response.json) response = self.client.get( '/thing?where={"date_time": {"$eq": {"$date": 1000000000000}}}') self.assertEqualWithout([ { 'name': 'B', 'date_time': { '$date': 1000000000000 } }, ], response.json, without=['$uri', 'date', 'belongs_to']) response = self.client.get( '/thing?where={"date_time": {"$gt": {"$date": 1000000000000}}}') self.assertEqualWithout([{ 'name': 'A', 'date_time': { '$date': 1446561100000 } }, { 'name': 'C', 'date_time': { '$date': 1446561110000 } }, { 'name': 'D', 'date_time': { '$date': 1446561120000 } }, { 'name': 'E', 'date_time': { '$date': 1446561130000 } }], response.json, without=['$uri', 'date', 'belongs_to']) response = self.client.get( '/thing?where={"date_time": {"$lt": {"$date": 1000000000000}}}') self.assertEqualWithout([], response.json, without=['$uri', 'date', 'belongs_to']) response = self.client.get( '/thing?where={"date_time": {"$between": [{"$date": 1446561110000}, {"$date": 1446561120000}]}}' ) self.assertEqualWithout([ { 'name': 'C', 'date_time': { '$date': 1446561110000 } }, { 'name': 'D', 'date_time': { '$date': 1446561120000 } }, ], response.json, without=['$uri', 'date', 'belongs_to']) def test_sort_and_where(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$startswith": "Jo"}}&sort={"first_name": false}' ) self.assertEqualWithout( [{ 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_sort_pages(self): pass @unittest.SkipTest def test_disallowed_where_filters(self): pass @unittest.SkipTest def test_schema(self): pass
class PeeweeTestCase(BaseTestCase): def setUp(self): super(PeeweeTestCase, self).setUp() self.app.config['DATABASE'] = 'sqlite://' self.db = db = PeeweeTestDB(self.app) self.api = Api(self.app) class Type(db.Model): name = pw.CharField(max_length=60, null=False, unique=True) class Machine(db.Model): name = pw.CharField(max_length=60, null=False) wattage = pw.FloatField(null=True) type = pw.ForeignKeyField(Type, related_name='machines') self.db.database.connect() self.db.database.create_tables([Type, Machine]) class MachineResource(ModelResource): class Meta: model = Machine include_id = True include_type = True manager = PeeweeManager class Schema: type = fields.ToOne('type') class TypeResource(ModelResource): class Meta: model = Type include_id = True include_type = True manager = PeeweeManager class Schema: machines = fields.ToMany(MachineResource) self.MachineResource = MachineResource self.TypeResource = TypeResource self.api.add_resource(MachineResource) self.api.add_resource(TypeResource) def tearDown(self): self.db.database.close() def test_field_discovery(self): self.assertEqual( set(self.MachineResource.schema.fields.keys()), {'$id', '$type', 'name', 'type', 'wattage'}) self.assertEqual( set(self.TypeResource.schema.fields.keys()), {'$id', '$type', 'name', 'machines'}) self.assertEqual(self.MachineResource.meta.name, 'machine') self.assertEqual(self.TypeResource.meta.name, 'type') def test_create_no_json(self): response = self.client.post('/machine', data='invalid') self.assert400(response) def test_create_json_string(self): response = self.client.post( '/machine', data='invalid', force_json=True) self.assert400(response) def test_conflict(self): response = self.client.post('/type', data={'name': 'foo'}) self.assert200(response) response = self.client.post('/type', data={'name': 'foo'}) self.assertStatus(response, 409) def test_create(self): response = self.client.post('/type', data={}) self.assert400(response) self.assertEqual({ 'errors': [ { 'message': "'name' is a required property", 'path': [], 'validationOf': { 'required': [ 'name' ] } } ], 'message': 'Bad Request', 'status': 400 }, response.json) response = self.client.post('/type', data={'name': 'x-ray'}) self.assertJSONEqual({ '$id': 1, '$type': 'type', 'machines': [], 'name': 'x-ray'}, response.json) response = self.client.post( '/machine', data={'name': 'Irradiator I', 'type': 1}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'machine', 'type': {'$ref': '/type/1'}, 'wattage': None, 'name': 'Irradiator I'}, response.json) response = self.client.post( '/machine', data={'name': 'Sol IV', 'type': 1, 'wattage': 1.23e45}) self.assert200(response) self.assertJSONEqual({ '$id': 2, '$type': 'machine', 'type': {'$ref': '/type/1'}, 'wattage': 1.23e45, 'name': 'Sol IV'}, response.json) response = self.client.get('/type/1') self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'type', 'machines': [ {'$ref': '/machine/1'}, {'$ref': '/machine/2'}], 'name': 'x-ray'}, response.json) def test_get(self): def type_(i): return { '$id': i, '$type': 'type', 'name': 'Type-{}'.format(i), 'machines': []} for i in range(1, 10): response = self.client.post( '/type', data={'name': 'Type-{}'.format(i), 'machines': []}) self.assert200(response) self.assertJSONEqual(type_(i), response.json) response = self.client.get('/type/{}'.format(i)) self.assert200(response) self.assertJSONEqual(type_(i), response.json) response = self.client.get('/type') self.assert200(response) self.assertJSONEqual( [type_(i) for i in range(1, i + 1)], response.json) response = self.client.get('/type/{}'.format(i + 1)) self.assert404(response) self.assertJSONEqual({ 'item': {'$id': i + 1, '$type': 'type'}, 'message': 'Not Found', 'status': 404}, response.json) @unittest.SkipTest def test_pagination(self): pass # TODO def test_update(self): response = self.client.post('/type', data={'name': 'T1'}) self.assert200(response) response = self.client.post('/type', data={'name': 'T2'}) self.assert200(response) response = self.client.post( '/machine', data={'name': 'Robot', 'type': 1}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'machine', 'type': {'$ref': '/type/1'}, 'wattage': None, 'name': 'Robot'}, response.json) response = self.client.patch('/machine/1', data={}) self.assert200(response) response = self.client.patch('/machine/1', data={'wattage': 10000}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'machine', 'type': {'$ref': '/type/1'}, 'wattage': 10000, 'name': 'Robot'}, response.json) response = self.client.patch( '/machine/1', data={'type': {'$ref': '/type/2'}}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'machine', 'type': {'$ref': '/type/2'}, 'wattage': 10000, 'name': 'Robot'}, response.json) response = self.client.patch('/machine/1', data={'type': None}) self.assert400(response) self.assertJSONEqual({ 'errors': [{ 'message': 'None is not valid under any of the given schemas', 'path': [ 'type'], 'validationOf': { 'anyOf': [{ 'additionalProperties': False, 'properties': { '$ref': { 'format': 'uri', 'pattern': '^\\/type\\/[^/]+$', 'type': 'string'}}, 'type': 'object'}, { 'type': 'integer'}]}}], 'message': 'Bad Request', 'status': 400}, response.json) response = self.client.patch('/machine/1', data={'name': 'Foo'}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'machine', 'type': {'$ref': '/type/2'}, 'wattage': 10000, 'name': 'Foo'}, response.json) def test_delete(self): response = self.client.delete('/type/1') self.assert404(response) response = self.client.post( '/type', data={'name': 'Foo', 'machines': []}) self.assert200(response) response = self.client.delete('/type/1') self.assertStatus(response, 204) response = self.client.delete('/type/1') self.assert404(response)
class SQLAlchemySortTestCase(BaseTestCase): def setUp(self): super(SQLAlchemySortTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app) self.sa = sa = SQLAlchemy( self.app, session_options={"autoflush": False}) class Type(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) class Machine(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) type_id = sa.Column(sa.Integer, sa.ForeignKey(Type.id)) type = sa.relationship(Type, foreign_keys=[type_id]) sa.create_all() class MachineResource(ModelResource): class Meta: model = Machine class Schema: type = fields.ToOne('type') class TypeResource(ModelResource): class Meta: model = Type sort_attribute = ('name', True) self.MachineResource = MachineResource self.TypeResource = TypeResource self.api.add_resource(MachineResource) self.api.add_resource(TypeResource) def test_default_sorting_with_desc(self): self.client.post('/type', data={"name": "aaa"}) self.client.post('/type', data={"name": "ccc"}) self.client.post('/type', data={"name": "bbb"}) response = self.client.get('/type') self.assert200(response) self.assertJSONEqual( [{'$uri': '/type/2', 'name': 'ccc'}, {'$uri': '/type/3', 'name': 'bbb'}, {'$uri': '/type/1', 'name': 'aaa'}], response.json) def test_sort_by_related_field(self): response = self.client.post('/type', data={"name": "aaa"}) self.assert200(response) aaa_uri = response.json["$uri"] response = self.client.post('/type', data={"name": "bbb"}) self.assert200(response) bbb_uri = response.json["$uri"] self.client.post( '/machine', data={"name": "foo", "type": {"$ref": aaa_uri}}) self.assert200(response) self.client.post( '/machine', data={"name": "bar", "type": {"$ref": bbb_uri}}) self.assert200(response) response = self.client.get('/machine?sort={"type": true}') self.assert200(response) type_uris = [entry['type']['$ref'] for entry in response.json] self.assertTrue(type_uris, [bbb_uri, aaa_uri]) response = self.client.get('/machine?sort={"type": false}') self.assert200(response) type_uris = [entry['type']['$ref'] for entry in response.json] self.assertTrue(type_uris, [bbb_uri, aaa_uri])
title = db.Column(db.String(), nullable=False) year_published = db.Column(db.Integer) author = db.relationship(Author, backref=backref('books', lazy='dynamic')) db.create_all() class BookResource(ModelResource): class Meta: model = Book class Schema: author = fields.ToOne('author') class AuthorResource(ModelResource): books = Relation('book') class Meta: model = Author natural_key = ('first_name', 'last_name') api = Api(app) api.add_resource(BookResource) api.add_resource(AuthorResource) if __name__ == '__main__': app.run()
class QueryOptionsSQLAlchemyTestCase(BaseTestCase): def setUp(self): super(QueryOptionsSQLAlchemyTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app, default_manager=SQLAlchemyManager) self.sa = sa = SQLAlchemy(self.app, session_options={"autoflush": False}) class Type(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False, unique=True) version = sa.Column(sa.Integer(), nullable=True) machines = sa.relationship('Machine', back_populates='type') class Machine(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) wattage = sa.Column(sa.Float) type_id = sa.Column(sa.Integer, sa.ForeignKey(Type.id)) type = sa.relationship(Type, back_populates='machines') sa.create_all() class MachineResource(ModelResource): class Meta: model = Machine include_type = True class Schema: type = fields.ToOne('type') class TypeResource(ModelResource): class Meta: model = Type include_type = True query_options = [joinedload(Type.machines)] class Schema: machines = fields.ToMany('machine') self.MachineResource = MachineResource self.TypeResource = TypeResource self.api.add_resource(MachineResource) self.api.add_resource(TypeResource) def tearDown(self): self.sa.drop_all() def test_get(self): response = self.client.post('/type', data={"name": "aaa"}) self.assert200(response) aaa_uri = response.json["$uri"] response = self.client.post('/machine', data={ "name": "foo", "type": { "$ref": aaa_uri } }) self.assert200(response) machine_uri = response.json['$uri'] with DBQueryCounter(self.sa.session) as counter: response = self.client.get(aaa_uri) self.assert200(response) self.assertJSONEqual( response.json, { '$type': 'type', '$uri': aaa_uri, 'machines': [{ '$ref': machine_uri }], 'name': 'aaa', 'version': None, }, ) counter.assert_count(1)
class QueryOptionsSQLAlchemyTestCase(BaseTestCase): def setUp(self): super(QueryOptionsSQLAlchemyTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app, default_manager=SQLAlchemyManager) self.sa = sa = SQLAlchemy(self.app, session_options={"autoflush": False}) class Type(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False, unique=True) version = sa.Column(sa.Integer(), nullable=True) machines = sa.relationship('Machine', back_populates='type') class Machine(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) wattage = sa.Column(sa.Float) type_id = sa.Column(sa.Integer, sa.ForeignKey(Type.id)) type = sa.relationship(Type, back_populates='machines') sa.create_all() class MachineResource(ModelResource): class Meta: model = Machine include_type = True class Schema: type = fields.ToOne('type') class TypeResource(ModelResource): class Meta: model = Type include_type = True query_options = [joinedload(Type.machines)] class Schema: machines = fields.ToMany('machine') self.MachineResource = MachineResource self.TypeResource = TypeResource self.api.add_resource(MachineResource) self.api.add_resource(TypeResource) def tearDown(self): self.sa.drop_all() def test_get(self): response = self.client.post('/type', data={"name": "aaa"}) self.assert200(response) aaa_uri = response.json["$uri"] response = self.client.post( '/machine', data={"name": "foo", "type": {"$ref": aaa_uri}}) self.assert200(response) machine_uri = response.json['$uri'] with DBQueryCounter(self.sa.session) as counter: response = self.client.get(aaa_uri) self.assert200(response) self.assertJSONEqual( response.json, {'$type': 'type', '$uri': aaa_uri, 'machines': [{'$ref': machine_uri}], 'name': 'aaa', 'version': None, }) counter.assert_count(1)
class RelationTestCase(BaseTestCase): def setUp(self): super(RelationTestCase, self).setUp() self.api = Api(self.app) def test_pagination(self): class Person(ModelResource): class Schema: name = fields.String() class Meta: name = "person" model = name manager = MemoryManager self.api.add_resource(Person) response = self.client.get('/person') self.assert200(response) self.assertEqual('0', response.headers.get('X-Total-Count')) self.assertEqual('</person?page=1&per_page=20>; rel="self",' '</person?page=1&per_page=20>; rel="last"', response.headers['Link']) for i in range(1, 51): response = self.client.post('/person', data={"name": str(i)}) self.assert200(response) response = self.client.get('/person') self.assert200(response) self.assertJSONEqual([{"$uri": "/person/{}".format(i), "name": str(i)} for i in range(1, 21)], response.json) response = self.client.get('/person?page=3') self.assert200(response) self.assertEqual('50', response.headers.get('X-Total-Count')) self.assertEqual('</person?page=3&per_page=20>; rel="self",' '</person?page=1&per_page=20>; rel="first",' '</person?page=2&per_page=20>; rel="prev",' '</person?page=3&per_page=20>; rel="last"', response.headers['Link']) self.assertJSONEqual([{"$uri": "/person/{}".format(i), "name": str(i)} for i in range(41, 51)], response.json) def test_where_to_one(self): class Person(ModelResource): class Schema: name = fields.String() mother = fields.ToOne('person', nullable=True) class Meta: name = "person" model = name manager = MemoryManager self.api.add_resource(Person) response = self.client.post('/person', data={ 'name': 'Anna' }) # No. Bad self.assert200(response) self.assertJSONEqual({'$uri': '/person/1', 'mother': None, 'name': 'Anna'}, response.json) self.client.post('/person', data={ 'name': 'Betty', 'mother': {"$ref": "/person/1"} }) self.client.post('/person', data={ 'name': 'Bob', 'mother': {"$ref": "/person/1"} }) self.client.post('/person', data={ 'name': 'Foo', 'mother': {"$ref": "/person/2"} }) self.client.post('/person', data={ 'name': 'Clare', 'mother': {"$ref": "/person/2"} }) response = self.client.get('/person?where={"mother": null}') self.assertJSONEqual([ {'$uri': '/person/1', 'mother': None, 'name': 'Anna'} ], response.json) response = self.client.get('/person?where={"mother": {"$ref": "/person/1"}}') self.assertJSONEqual([ {'$uri': '/person/2', 'mother': {'$ref': '/person/1'}, 'name': 'Betty'}, {'$uri': '/person/3', 'mother': {'$ref': '/person/1'}, 'name': 'Bob'} ], response.json) response = self.client.get('/person?where={"mother": {"$ref": "/person/2"}, "name": {"$startswith": "C"}}') self.assertJSONEqual([ {'$uri': '/person/5', 'mother': {'$ref': '/person/2'}, 'name': 'Clare'} ], response.json)
class PeeeeFilterTestCase(BaseTestCase): def setUp(self): super(PeeeeFilterTestCase, self).setUp() app = self.app app.config['DATABASE'] = 'sqlite://' self.db = db = PeeweeTestDB(self.app) self.api = Api(self.app, default_manager=PeeweeManager) app.debug = True class User(db.Model): id = IntegerField(primary_key=True) first_name = CharField(max_length=60, null=False) last_name = CharField(max_length=60, null=False) gender = CharField(max_length=1, null=True) age = IntegerField() is_staff = BooleanField(default=None) db.database.connect() db.database.create_tables([User]) class UserResource(ModelResource): class Schema: gender = fields.String(enum=['f', 'm'], nullable=True) class Meta: model = User class AllowUserResource(ModelResource): class Meta: model = User name = 'allow-user' allowed_filters = { 'first_name': ['$eq'], 'is_staff': '*' } self.api.add_resource(UserResource) self.api.add_resource(AllowUserResource) def post_sample_set_a(self): for user in [ {'first_name': 'John', 'last_name': 'Doe', 'age': 32, 'is_staff': True, 'gender': 'm'}, {'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25, 'is_staff': False, 'gender': 'm'}, {'first_name': 'Jane', 'last_name': 'Roe', 'age': 18, 'is_staff': False, 'gender': 'f'}, {'first_name': 'Joe', 'last_name': 'Bloggs', 'age': 21, 'is_staff': True, 'gender': 'm'}, {'first_name': 'Sue', 'last_name': 'Watts', 'age': 25, 'is_staff': True} ]: response = self.client.post('/user', data=user) self.assert200(response) def test_equality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": "Doe"}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": 25}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25}, {'first_name': 'Sue', 'last_name': 'Watts', 'age': 25}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'is_staff']) response = self.client.get('/user?where={"last_name": "Doe", "age": 25}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inequality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$ne": "Watts"}, "age": {"$ne": 32}}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gt": 25}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gte": 25}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Sue', 'last_name': 'Watts'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lte": 21}}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": 21.0}}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": null}}') self.assert400(response) response = self.client.get('/user?where={"first_name": {"$gt": "Jo"}}') self.assert400(response) def test_in(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$in": ["Bloggs", "Watts"]}}') self.assertEqualWithout([ {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'Sue', 'last_name': 'Watts'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"last_name": {"$in": []}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_startswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$startswith": "Jo"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$startswith": "J%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_istartswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$istartswith": "jo"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_iendswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$iendswith": "Oe"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Jane', 'last_name': 'Roe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_text_search(self): self.post_sample_set_a() response = self.client.get('/user?search=sbc+dedf&rank=1') def test_sort(self): self.post_sample_set_a() response = self.client.get('/user?sort={"last_name": true, "first_name": false}') self.assert200(response) self.assertEqualWithout([ {'first_name': 'Sue', 'last_name': 'Watts'}, {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?sort={"age": false, "first_name": false}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Sue', 'last_name': 'Watts'}, {'first_name': 'John', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_sort_and_where(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$startswith": "Jo"}}&sort={"first_name": false}') self.assertEqualWithout([ {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_sort_pages(self): pass @unittest.SkipTest def test_disallowed_where_filters(self): pass @unittest.SkipTest def test_schema(self): pass
# coding: utf-8 from ..models import Call from flask_potion import Api, ModelResource, fields from flask_potion.routes import ItemRoute api = Api() class CallResource(ModelResource): class Meta: model = Call ''' @ItemRoute.GET('/calling') def greeting(self, call) -> fields.String(): return "Hello, {}!".format(call.id) ''' api.add_resource(CallResource)
class SQLAlchemyRelationTestCase(BaseTestCase): def setUp(self): super(SQLAlchemyRelationTestCase, self).setUp() self.app.config['SQLALCHEMY_ENGINE'] = 'sqlite://' self.api = Api(self.app) self.sa = sa = SQLAlchemy(self.app, session_options={"autoflush": False}) group_members = sa.Table('group_members', sa.Column('group_id', sa.Integer(), sa.ForeignKey('group.id')), sa.Column('user_id', sa.Integer(), sa.ForeignKey('user.id'))) class User(sa.Model): id = sa.Column(sa.Integer, primary_key=True) parent_id = sa.Column(sa.Integer, sa.ForeignKey(id)) name = sa.Column(sa.String(60), nullable=False) parent = sa.relationship('User', remote_side=[id], backref=backref('children', lazy='dynamic')) class Group(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String(60), nullable=False) members = sa.relationship('User', secondary=group_members, backref=backref('memberships', lazy='dynamic')) sa.create_all() class UserResource(ModelResource): class Meta: model = User include_id = True include_type = True children = Relation('self') class GroupResource(ModelResource): class Meta: model = Group include_id = True include_type = True members = Relation('user') self.api.add_resource(UserResource) self.api.add_resource(GroupResource) def test_relationship_secondary(self): response = self.client.post('/group', data={"name": "Foo"}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'group', "name": "Foo"}, response.json) response = self.client.post('/user', data={"name": "Bar"}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'user', "name": "Bar"}, response.json) response = self.client.get('/group/1/members') self.assert200(response) self.assertJSONEqual([], response.json) response = self.client.post('/group/1/members', data={"$ref": "/user/1"}) self.assert200(response) self.assertJSONEqual({"$ref": "/user/1"}, response.json) response = self.client.get('/group/1/members') self.assert200(response) self.assertJSONEqual([{"$ref": "/user/1"}], response.json) def test_relationship_secondary_delete_missing(self): response = self.client.post('/group', data={"name": "Foo"}) response = self.client.post('/user', data={"name": "Bar"}) response = self.client.delete('/group/1/members/1') self.assertStatus(response, 204) def test_relationship_post(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) self.assertJSONEqual({'$id': 1, '$type': 'user', "name": "Foo"}, response.json) response = self.client.post('/user', data={"name": "Bar"}) self.assert200(response) self.assertJSONEqual({'$id': 2, '$type': 'user', "name": "Bar"}, response.json) response = self.client.post('/user/1/children', data={"$ref": "/user/2"}) self.assert200(response) self.assertJSONEqual({"$ref": "/user/2"}, response.json) def test_relationship_get(self): self.test_relationship_post() response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual([{"$ref": "/user/2"}], response.json) def test_relationship_delete(self): self.test_relationship_post() response = self.client.delete('/user/1/children/2') self.assertStatus(response, 204) response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual([], response.json) def test_relationship_delete_missing(self): self.test_relationship_post() response = self.client.delete('/user/1/children/2') self.assertStatus(response, 204) response = self.client.delete('/user/1/children/2') self.assertStatus(response, 204) response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual([], response.json) def test_relationship_pagination(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) for i in range(2, 50): response = self.client.post('/user', data={"name": str(i)}) self.assert200(response) response = self.client.post('/user/1/children', data={"$ref": "/user/{}".format(response.json['$id'])}) self.assert200(response) response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual([{"$ref": "/user/{}".format(i)} for i in range(2, 22)], response.json) response = self.client.get('/user/1/children?page=3') self.assert200(response) self.assertJSONEqual([{"$ref": "/user/{}".format(i)} for i in range(42, 50)], response.json) self.assertEqual('48', response.headers['X-Total-Count']) self.assertEqual('</user/1/children?page=3&per_page=20>; rel="self",' '</user/1/children?page=1&per_page=20>; rel="first",' '</user/1/children?page=2&per_page=20>; rel="prev",' '</user/1/children?page=3&per_page=20>; rel="last"', response.headers['Link'])
class FilterTestCase(BaseTestCase): def setUp(self): super(FilterTestCase, self).setUp() app = self.app app.config['MONGODB_DB'] = 'potion-test-db' app.config['TESTING'] = True self.api = Api(self.app, default_manager=MongoEngineManager) self.me = me = MongoEngine(app) class User(me.Document): meta = { "collection": "user" } first_name = StringField(max_length=60, null=False) last_name = StringField(max_length=60, null=False) gender = StringField(max_length=1) age = IntField() is_staff = BooleanField(default=None) class UserResource(ModelResource): class Schema: gender = fields.String(enum=['f', 'm'], nullable=True) class Meta: model = User class AllowUserResource(ModelResource): class Meta: model = User name = 'allow-user' allowed_filters = { 'first_name': ['$eq'], 'is_staff': '*' } self.api.add_resource(UserResource) self.api.add_resource(AllowUserResource) def post_sample_set_a(self): for user in [ {'first_name': 'John', 'last_name': 'Doe', 'age': 32, 'is_staff': True, 'gender': 'm'}, {'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25, 'is_staff': False, 'gender': 'm'}, {'first_name': 'Jane', 'last_name': 'Roe', 'age': 18, 'is_staff': False, 'gender': 'f'}, {'first_name': 'Joe', 'last_name': 'Bloggs', 'age': 21, 'is_staff': True, 'gender': 'm'}, {'first_name': 'Sue', 'last_name': 'Watts', 'age': 25, 'is_staff': True} ]: response = self.client.post('/user', data=user) self.assert200(response) def test_equality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": "Doe"}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": 25}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25}, {'first_name': 'Sue', 'last_name': 'Watts', 'age': 25}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'is_staff']) response = self.client.get('/user?where={"last_name": "Doe", "age": 25}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inequality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$ne": "Watts"}, "age": {"$ne": 32}}') self.assertEqualWithout([ {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gt": 25}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gte": 25}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Sue', 'last_name': 'Watts'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lte": 21}}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": 21.0}}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": null}}') self.assert400(response) response = self.client.get('/user?where={"first_name": {"$gt": "Jo"}}') self.assert400(response) def test_in(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": {"$in": ["Bloggs", "Watts"]}}') self.assertEqualWithout([ {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'Sue', 'last_name': 'Watts'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"last_name": {"$in": []}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_startswith(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$startswith": "Jo"}}') self.assertEqualWithout([ {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"first_name": {"$startswith": "J%e"}}') self.assertEqualWithout([], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_text_search(self): self.post_sample_set_a() response = self.client.get('/user?search=sbc+dedf&rank=1') def test_sort(self): self.post_sample_set_a() response = self.client.get('/user?sort={"last_name": true, "first_name": false}') self.assert200(response) self.assertEqualWithout([ {'first_name': 'Sue', 'last_name': 'Watts'}, {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?sort={"age": false, "first_name": false}') self.assertEqualWithout([ {'first_name': 'Jane', 'last_name': 'Roe'}, {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'Jonnie', 'last_name': 'Doe'}, {'first_name': 'Sue', 'last_name': 'Watts'}, {'first_name': 'John', 'last_name': 'Doe'}, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_sort_and_where(self): self.post_sample_set_a() response = self.client.get('/user?where={"first_name": {"$startswith": "Jo"}}&sort={"first_name": false}') self.assertEqualWithout([ {'first_name': 'Joe', 'last_name': 'Bloggs'}, {'first_name': 'John', 'last_name': 'Doe'}, {'first_name': 'Jonnie', 'last_name': 'Doe'} ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_sort_pages(self): pass @unittest.SkipTest def test_disallowed_where_filters(self): pass @unittest.SkipTest def test_schema(self): pass def tearDown(self): self.me.connection.drop_database('potion-test-db')
def test_route_disabling(self): class FooResource(Resource): @Route.GET def foo(self): return 'foo' @Route.GET def baz(self): return 'baz' @baz.POST def baz(self, value): return 'baz: {}'.format(value) baz.request_schema = fields.String() class Meta: name = 'foo' exclude_routes = ('readBaz', ) class BarResource(FooResource): class Meta: name = 'bar' class BazResource(BarResource): class Meta: name = 'baz' exclude_routes = ('readFoo', ) api = Api(self.app) api.add_resource(FooResource) api.add_resource(BarResource) api.add_resource(BazResource) self.assertEqual( { 'describedBy': Resource.described_by, 'readFoo': FooResource.foo, 'createBaz': FooResource.baz, }, FooResource.routes, ) self.assertEqual( { 'describedBy': Resource.described_by, 'readFoo': FooResource.foo, 'createBaz': FooResource.baz, }, BarResource.routes, ) self.assertIsNone(BazResource.routes.get('readFoo', None)) self.assertIsNotNone(BazResource.routes.get('readBaz', None)) self.assertIsNotNone(BazResource.routes.get('createBaz', None)) response = self.client.get("/foo/foo") self.assertEqual('foo', response.json) response = self.client.get("/foo/baz") self.assert405(response) response = self.client.get("/bar/foo") self.assert200(response) self.assertEqual('foo', response.json) response = self.client.get("/bar/baz") self.assert405(response) response = self.client.post("/bar/baz", data='xyz', force_json=True) self.assert200(response) self.assertEqual('baz: xyz', response.json) response = self.client.get("/baz/foo") self.assert404(response) response = self.client.get("/baz/baz") self.assertEqual('baz', response.json) response = self.client.post("/baz/baz", data='123', force_json=True) self.assert200(response) self.assertEqual('baz: 123', response.json)
class MongoEngineSignalTestCase(BaseTestCase): def setUp(self): super(MongoEngineSignalTestCase, self).setUp() self.app.config['MONGODB_DB'] = 'potion-test-db' self.api = Api(self.app, default_manager=MongoEngineManager) self.me = me = MongoEngine(self.app) class User(me.Document): name = StringField(max_length=60, null=False) gender = StringField(max_length=1, null=True) children = ListField(ReferenceField("User")) def __eq__(self, other): return self.name == other.name def __repr__(self): return 'User({})'.format(self.name) class Group(me.Document): name = StringField(max_length=60, null=False) class GroupMembership(me.Document): user = ReferenceField(User) group = ReferenceField(Group) class UserResource(ModelResource): class Meta: model = User children = Relation('self') class GroupResource(ModelResource): class Meta: model = Group members = Relation(UserResource) self.User = User self.Group = Group self.UserResource = UserResource self.GroupResource = GroupResource self.api.add_resource(UserResource) self.api.add_resource(GroupResource) def tearDown(self): self.me.connection.drop_database('potion-test-db') @contextmanager def assertSignals(self, expected_events, sender=ANY): events = [] def receiver_(signal, sender, **kwargs): events.append((signal, sender, kwargs)) receivers = { signal: partial(receiver_, signal) for signal in [ signals.before_create, signals.after_create, signals. before_update, signals.after_update, signals.before_delete, signals.after_delete, signals.before_add_to_relation, signals. after_add_to_relation, signals.before_remove_from_relation, signals.after_remove_from_relation ] } for signal, receiver in receivers.items(): signal.connect(receiver, sender=sender, weak=False) try: yield None except: for signal, receiver in receivers.items(): signal.disconnect(receiver) raise else: for signal, receiver in receivers.items(): signal.disconnect(receiver) self.assertEqual(events, expected_events) def test_create_signal(self): with self.assertSignals([(signals.before_create, self.UserResource, { 'item': self.User(name="Foo") }), (signals.after_create, self.UserResource, { 'item': self.User(name="Foo") })]): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) self.assertJSONEqual( { '$uri': response.json["$uri"], "name": "Foo", "gender": None }, response.json) def test_update_signal(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) with self.assertSignals([(signals.before_update, self.UserResource, { 'changes': { 'gender': 'M', 'name': 'Bar' }, 'item': self.User(name="Bar") }), (signals.after_update, self.UserResource, { 'changes': { 'gender': 'M', 'name': 'Bar' }, 'item': self.User(name="Bar") })]): uri = response.json["$uri"] response = self.client.patch(uri, data={ "name": "Bar", "gender": "M" }) self.assert200(response) self.assertJSONEqual({ '$uri': uri, "name": "Bar", "gender": "M" }, response.json) def test_delete_signal(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) with self.assertSignals([(signals.before_delete, self.UserResource, { 'item': self.User(name="Foo") }), (signals.after_delete, self.UserResource, { 'item': self.User(name="Foo") })]): response = self.client.delete(response.json["$uri"]) self.assertStatus(response, 204) def test_relation_signal(self): response = self.client.post('/user', data={"name": "Foo"}) user1_uri = response.json["$uri"] self.assert200(response) with self.assertSignals([ (signals.before_create, self.UserResource, { 'item': self.User(name="Bar") }), (signals.after_create, self.UserResource, { 'item': self.User(name="Bar") }), (signals.before_add_to_relation, self.UserResource, { 'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar") }), (signals.after_add_to_relation, self.UserResource, { 'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar") }), (signals.before_remove_from_relation, self.UserResource, { 'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar") }), (signals.after_remove_from_relation, self.UserResource, { 'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar") }) ]): response = self.client.post('/user', data={"name": "Bar"}) user2_uri = response.json["$uri"] user2_id = user2_uri.split("/")[-1] self.assert200(response) response = self.client.post('{}/children'.format(user1_uri), data={"$ref": user2_uri}) self.assert200(response) response = self.client.delete('{}/children/{}'.format( user1_uri, user2_id)) self.assertStatus(response, 204)
class FilterTestCase(BaseTestCase): def setUp(self): super(FilterTestCase, self).setUp() app = self.app app.config['MONGODB_DB'] = 'potion-test-db' app.config['TESTING'] = True self.api = Api(self.app, default_manager=MongoEngineManager) self.me = me = MongoEngine(app) class User(me.Document): meta = {"collection": "user"} first_name = StringField(max_length=60, null=False) last_name = StringField(max_length=60, null=False) gender = StringField(max_length=1) age = IntField() is_staff = BooleanField(default=None) class UserResource(ModelResource): class Schema: gender = fields.String(enum=['f', 'm'], nullable=True) class Meta: model = User class AllowUserResource(ModelResource): class Meta: model = User name = 'allow-user' allowed_filters = {'first_name': ['$eq'], 'is_staff': '*'} self.api.add_resource(UserResource) self.api.add_resource(AllowUserResource) def post_sample_set_a(self): for user in [{ 'first_name': 'John', 'last_name': 'Doe', 'age': 32, 'is_staff': True, 'gender': 'm' }, { 'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25, 'is_staff': False, 'gender': 'm' }, { 'first_name': 'Jane', 'last_name': 'Roe', 'age': 18, 'is_staff': False, 'gender': 'f' }, { 'first_name': 'Joe', 'last_name': 'Bloggs', 'age': 21, 'is_staff': True, 'gender': 'm' }, { 'first_name': 'Sue', 'last_name': 'Watts', 'age': 25, 'is_staff': True }]: response = self.client.post('/user', data=user) self.assert200(response) def test_equality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": "Doe"}') self.assertEqualWithout([ { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, ], response.json, without=[ '$uri', '$uri', '$id', '$type', 'gender', 'age', 'is_staff' ]) response = self.client.get('/user?where={"age": 25}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25 }, { 'first_name': 'Sue', 'last_name': 'Watts', 'age': 25 }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'is_staff']) response = self.client.get( '/user?where={"last_name": "Doe", "age": 25}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inequality(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$ne": "Watts"}, "age": {"$ne": 32}}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gt": 25}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gte": 25}}') self.assertEqualWithout( [ { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Sue', 'last_name': 'Watts' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lte": 21}}') self.assertEqualWithout( [{ 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": 21.0}}') self.assertEqualWithout( [{ 'first_name': 'Jane', 'last_name': 'Roe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": null}}') self.assert400(response) response = self.client.get('/user?where={"first_name": {"$gt": "Jo"}}') self.assert400(response) def test_in(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$in": ["Bloggs", "Watts"]}}') self.assertEqualWithout( [{ 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'Sue', 'last_name': 'Watts' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"last_name": {"$in": []}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_startswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$startswith": "Jo"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$startswith": "J%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_text_search(self): self.post_sample_set_a() response = self.client.get('/user?search=sbc+dedf&rank=1') def test_sort(self): self.post_sample_set_a() response = self.client.get( '/user?sort={"last_name": true, "first_name": false}') self.assert200(response) self.assertEqualWithout( [{ 'first_name': 'Sue', 'last_name': 'Watts' }, { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?sort={"age": false, "first_name": false}') self.assertEqualWithout( [ { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Sue', 'last_name': 'Watts' }, { 'first_name': 'John', 'last_name': 'Doe' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_sort_and_where(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$startswith": "Jo"}}&sort={"first_name": false}' ) self.assertEqualWithout( [{ 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_sort_pages(self): pass @unittest.SkipTest def test_disallowed_where_filters(self): pass @unittest.SkipTest def test_schema(self): pass def tearDown(self): self.me.connection.drop_database('potion-test-db')
class NaturalKeyTestCase(BaseTestCase): def setUp(self): super(NaturalKeyTestCase, self).setUp() self.api = Api(self.app, prefix='/api') def test_simple_key(self): class Foo(ModelResource): class Meta: key_converters = [RefKey()] model = 'foo' manager = MemoryManager class Schema: inception = fields.ToOne('foo') self.api.add_resource(Foo) foo_field = fields.ToOne(Foo) self.assertJSONEqual(FOO_REFERENCE, foo_field.response) self.assertJSONEqual(FOO_REFERENCE, foo_field.request) def test_multiple_keys(self): with self.assertRaises(RuntimeError) as cx: class Bar(ModelResource): class Meta: key_converters = (RefKey(), PropertyKey('name')) model = 'bar' natural_key = 'alias' manager = MemoryManager class Schema: name = fields.String() alias = fields.String() self.api.add_resource(Bar) self.assertEqual('Multiple keys of type string defined for bar', cx.exception.args[0]) def test_property_key(self): class Foo(ModelResource): class Schema: name = fields.String() class Meta: natural_key = 'name' manager = MemoryManager model = 'foo' self.api.add_resource(Foo) foo_field = fields.ToOne(Foo) self.assertJSONEqual(FOO_REFERENCE, foo_field.response) self.assertJSONEqual( { "anyOf": [FOO_REFERENCE, { "type": "integer" }, { "type": "string" }] }, foo_field.request) response = self.client.post('/api/foo', data={"name": "Jane"}) self.assert200(response) response = self.client.post('/api/foo', data={"name": "John"}) self.assert200(response) self.assertEqual({'id': 2, 'name': 'John'}, foo_field.convert(2)) self.assertEqual({'id': 1, 'name': 'Jane'}, foo_field.convert('Jane')) with self.assertRaises(ValidationError): foo_field.convert(['John']) with self.assertRaises(ItemNotFound) as cx: foo_field.convert('Joanne') self.assertEqual( { "message": "Not Found", "status": 404, "item": { "$type": "foo", "$where": { "name": "Joanne" } } }, cx.exception.as_dict()) def test_properties_key(self): class Foo(ModelResource): class Schema: first_name = fields.String() last_name = fields.String() class Meta: natural_key = ['first_name', 'last_name'] manager = MemoryManager model = 'foo' name = 'foo' self.api.add_resource(Foo) foo_field = fields.ToOne(Foo, nullable=True) self.assertJSONEqual(FOO_REFERENCE_NULLABLE, foo_field.response) self.assertJSONEqual( { "anyOf": [ FOO_REFERENCE, { "type": "integer" }, { "type": "array", "items": [{ "type": "string" }, { "type": "string" }], "additionalItems": False }, { "type": "null" } ] }, foo_field.request) response = self.client.post('/api/foo', data={ "first_name": "Jane", "last_name": "Doe" }) self.assert200(response) response = self.client.post('/api/foo', data={ "first_name": "John", "last_name": "Doe" }) self.assert200(response) self.assertEqual({ 'first_name': 'Jane', 'id': 1, 'last_name': 'Doe' }, foo_field.convert(1)) self.assertEqual({ 'first_name': 'John', 'id': 2, 'last_name': 'Doe' }, foo_field.convert(['John', 'Doe'])) self.assertEqual({ 'first_name': 'John', 'id': 2, 'last_name': 'Doe' }, foo_field.convert({"$ref": "/api/foo/2"})) with self.assertRaises(ItemNotFound) as cx: foo_field.convert(['John', 'Joe']) self.assertEqual( { "message": "Not Found", "status": 404, "item": { "$type": "foo", "$where": { "first_name": "John", "last_name": "Joe" } } }, cx.exception.as_dict()) with self.assertRaises(ValidationError): foo_field.convert(['John', None])
class PeeweeSignalTestCase(BaseTestCase): def setUp(self): super(PeeweeSignalTestCase, self).setUp() app = self.app app.config['DATABASE'] = 'sqlite://' self.db = db = PeeweeTestDB(self.app) self.api = Api(self.app, default_manager=PeeweeManager) class User(db.Model): name = CharField(max_length=60) gender = CharField(max_length=1, null=True) parent = ForeignKeyField('self', null=True, related_name='children') def __eq__(self, other): return self.name == other.name def __repr__(self): return 'User({})'.format(self.name) class Group(db.Model): name = CharField(max_length=60) class GroupMembership(db.Model): user = ForeignKeyField(User) group = ForeignKeyField(Group) db.database.connect() db.database.create_tables([User, Group, GroupMembership]) class UserResource(ModelResource): class Meta: model = User children = Relation('self') class GroupResource(ModelResource): class Meta: model = Group members = Relation(UserResource) self.User = User self.Group = Group self.UserResource = UserResource self.GroupResource = GroupResource self.api.add_resource(UserResource) self.api.add_resource(GroupResource) @contextmanager def assertSignals(self, expected_events, sender=ANY): events = [] def receiver_(signal, sender, **kwargs): events.append((signal, sender, kwargs)) receivers = { signal: partial(receiver_, signal) for signal in [ signals.before_create, signals.after_create, signals.before_update, signals.after_update, signals.before_delete, signals.after_delete, signals.before_add_to_relation, signals.after_add_to_relation, signals.before_remove_from_relation, signals.after_remove_from_relation ] } for signal, receiver in receivers.items(): signal.connect(receiver, sender=sender, weak=False) try: yield None except: for signal, receiver in receivers.items(): signal.disconnect(receiver) raise else: for signal, receiver in receivers.items(): signal.disconnect(receiver) self.assertEqual(events, expected_events) def test_create_signal(self): with self.assertSignals([ (signals.before_create, self.UserResource, {'item': self.User(name="Foo")}), (signals.after_create, self.UserResource, {'item': self.User(name="Foo")}) ]): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) self.assertJSONEqual({'$uri': '/user/1', "name": "Foo", "gender": None}, response.json) def test_update_signal(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) with self.assertSignals([ (signals.before_update, self.UserResource, {'changes': {'gender': 'M', 'name': 'Bar'}, 'item': self.User(name="Bar")}), (signals.after_update, self.UserResource, {'changes': {'gender': 'M', 'name': 'Bar'}, 'item': self.User(name="Bar")}) ]): response = self.client.patch('/user/1', data={"name": "Bar", "gender": "M"}) self.assert200(response) self.assertJSONEqual({'$uri': '/user/1', "name": "Bar", "gender": "M"}, response.json) def test_delete_signal(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) with self.assertSignals([ (signals.before_delete, self.UserResource, {'item': self.User(name="Foo")}), (signals.after_delete, self.UserResource, {'item': self.User(name="Foo")}) ]): response = self.client.delete('/user/1') self.assertStatus(response, 204) def test_relation_signal(self): response = self.client.post('/user', data={"name": "Foo"}) self.assert200(response) with self.assertSignals([ (signals.before_create, self.UserResource, {'item': self.User(name="Bar")}), (signals.after_create, self.UserResource, {'item': self.User(name="Bar")}), (signals.before_add_to_relation, self.UserResource, {'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar")}), (signals.after_add_to_relation, self.UserResource, {'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar")}), (signals.before_remove_from_relation, self.UserResource, {'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar")}), (signals.after_remove_from_relation, self.UserResource, {'item': self.User(name="Foo"), 'attribute': 'children', 'child': self.User(name="Bar")}) ]): response = self.client.post('/user', data={"name": "Bar"}) self.assert200(response) response = self.client.post('/user/1/children', data={"$ref": "/user/2"}) self.assert200(response) response = self.client.delete('/user/1/children/2') self.assertStatus(response, 204)
class Schema: article = fields.ToOne('article') author = fields.ToOne('user') class Meta: model = Comment read_only_fields = ['author'] permissions = { 'create': 'anybody', 'update': 'user:author', 'delete': ['update:article', 'admin'] } for resource in (UserResource, ArticleResource, CommentResource): api.add_resource(resource) @signals.before_create.connect_via(ANY) def before_create_article_comment(sender, item): if issubclass(sender, (ArticleResource, CommentResource)): item.author_id = current_user.id db.create_all() if __name__ == '__main__': # Add some example users db.session.add(User(username='******', is_editor=True)) db.session.add(User(username='******', is_editor=True)) db.session.add(User(username='******', is_admin=True))
class PrincipalTestCase(BaseTestCase): def create_app(self): app = super(PrincipalTestCase, self).create_app() app.test_client_class = AuthorizedApiClient self.principal = Principal(app) self.sa = sa = SQLAlchemy(app) class User(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String()) class BookStore(sa.Model): id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String()) owner_id = sa.Column(sa.Integer, sa.ForeignKey(User.id)) owner = sa.relationship(User, backref=backref('stores', lazy='dynamic')) class Book(sa.Model): id = sa.Column(sa.Integer, primary_key=True) title = sa.Column(sa.String(), nullable=False) author_id = sa.Column(sa.Integer, sa.ForeignKey(User.id)) author = sa.relationship(User, backref=backref('books', lazy='dynamic')) class BookSigning(sa.Model): id = sa.Column(sa.Integer, primary_key=True) book_id = sa.Column(sa.Integer, sa.ForeignKey(Book.id), nullable=False) store_id = sa.Column(sa.Integer, sa.ForeignKey(BookStore.id), nullable=False) book = sa.relationship(Book) store = sa.relationship(BookStore) sa.create_all() for model in (BookStore, User, Book, BookSigning): setattr(self, model.__tablename__.upper(), model) return app def setUp(self): super(PrincipalTestCase, self).setUp() self.mock_user = None @identity_loaded.connect_via(self.app) def on_identity_loaded(sender, identity): identity.provides.add(UserNeed(identity.id)) for role in self.mock_user.get('roles', []): identity.provides.add(RoleNeed(role)) for need in self.mock_user.get('needs', []): identity.provides.add(need) def authenticate(fn): @wraps(fn) def wrapper(*args, **kwargs): auth = request.authorization if not auth: raise Unauthorized() if auth.password == 'password': identity_changed.send(current_app._get_current_object(), identity=Identity( self.mock_user['id'])) else: raise Unauthorized() return fn(*args, **kwargs) return wrapper self.api = Api(self.app, decorators=[authenticate]) def test_role(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = {'create': 'author'} self.api.add_resource(BookResource) response = self.client.post('/book', data={'title': 'Foo'}, auth=False) self.assert401(response) self.mock_user = {'id': 1} response = self.client.post('/book', data={'title': 'Foo'}) self.assert403(response) self.mock_user = {'id': 1, 'roles': ['author']} response = self.client.post('/book', data={'title': 'Foo'}) self.assert200(response) self.assertEqual({'title': 'Foo', '$uri': '/book/1'}, response.json) self.assert200(self.client.patch('/book/1', data={'title': 'Foo I'})) self.mock_user = {'id': 1} self.assert403(self.client.patch('/book/1', data={'title': 'Bar'})) self.assert403(self.client.delete('/book/1')) # self.user = {'id': 1, 'roles': ['author']} # self.assert200(self.client.delete('/book/1')) # response = self.client.post('/book', data={'title': 'Foo'}) # # self.assert200(response) def test_access_forbidden_to_resource_collection(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': 'author', 'create': 'author', } self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['author']} response = self.client.post('/book', data={'title': 'Foo'}) self.assert200(response) self.assertEqual({'title': 'Foo', '$uri': '/book/1'}, response.json) self.assert200(self.client.get('/book')) self.mock_user = {'id': 1} self.assert403(self.client.get('/book')) def test_inherit_role_to_one_field(self): class BookStoreResource(PrincipalResource): class Meta: model = self.BOOK_STORE permissions = {'create': 'admin', 'update': ['admin']} class BookSigningResource(PrincipalResource): class Schema: book = fields.ToOne('book') store = fields.ToOne('book_store') class Meta: model = self.BOOK_SIGNING permissions = {'create': 'update:store'} class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = {'create': 'yes'} self.api.add_resource(BookStoreResource) self.api.add_resource(BookSigningResource) self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200( self.client.post('/book_store', data={'name': 'Foo Books'})) self.assert200(self.client.post('/book', data={'title': 'Bar'})) self.mock_user = {'id': 2} response = self.client.post('/book_signing', data={ 'book': { '$ref': '/book/1' }, 'store': { '$ref': '/book_store/1' } }) self.assert403(response) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200( self.client.post('/book_signing', data={ 'book': { '$ref': '/book/1' }, 'store': { '$ref': '/book_store/1' } })) def test_user_need(self): class BookStoreResource(PrincipalResource): class Schema: owner = fields.ToOne('user') class Meta: model = self.BOOK_STORE permissions = { 'create': 'admin', 'update': ['admin', 'user:owner'] } class UserResource(PrincipalResource): class Meta: model = self.USER permissions = {'create': 'admin'} self.api.add_resource(BookStoreResource) self.api.add_resource(UserResource) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200(self.client.post('/user', data={'name': 'Admin'})) for i, store in enumerate([{ 'name': 'Books & More', 'owner': { 'name': 'Mr. Moore' } }, { 'name': 'Foo Books', 'owner': { 'name': 'Foo' } }]): response = self.client.post('/user', data=store['owner']) owner = {'$ref': response.json['$uri']} response = self.client.post('/book_store', data={ 'name': store['name'], 'owner': owner }) self.assertEqual( { '$uri': '/book_store/{}'.format(i + 1), 'name': store['name'], 'owner': owner }, response.json) response = self.client.patch('/book_store/1', data={'name': 'books & moore'}) self.assert200(response) self.mock_user = {'id': 3} response = self.client.patch('/book_store/1', data={'name': 'Books & Foore'}) self.assert403(response) self.mock_user = {'id': 2} response = self.client.patch('/book_store/1', data={'name': 'Books & Moore'}) self.assert200(response) self.assertEqual( { '$uri': '/book_store/1', 'name': 'Books & Moore', 'owner': { '$ref': '/user/2' } }, response.json) response = self.client.patch('/book_store/2', data={'name': 'Moore Books'}) self.assert403(response) def test_item_need_update(self): class BookStoreResource(PrincipalResource): class Meta: model = self.BOOK_STORE permissions = {'create': 'admin', 'update': 'update'} self.api.add_resource(BookStoreResource) self.mock_user = {'id': 1, 'roles': ['admin']} # response = self.client.post('/book_store', data=[ # {'name': 'Bar Books'}, # {'name': 'Foomazon'} # ]) response = self.client.post('/book_store', data={'name': 'Bar Books'}) self.assert200(response) response = self.client.post('/book_store', data={'name': 'Foomazon'}) self.assert200(response) self.mock_user = { 'id': 1, 'needs': [ItemNeed('update', 2, 'book_store')] } self.assert403(self.client.patch('/book_store/1', data={'name': 'Foo'})) response = self.client.patch('/book_store/2', data={'name': 'Foo'}) self.assert200(response) self.assertEqual({ '$uri': '/book_store/2', 'name': 'Foo' }, response.json) # TODO DELETE def test_yes_no(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': 'yes', 'create': 'admin', 'update': 'no' } self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} self.assert200(self.client.post('/book', data={'title': 'Foo'})) self.assert403(self.client.patch('/book/1', data={'title': 'Bar'})) self.assert200(self.client.get('/book/1')) self.assert200(self.client.get('/book')) def test_item_need_read(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': ['owns-copy', 'admin'], 'create': 'admin', 'owns-copy': 'owns-copy' } self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} # TODO Bulk inserts # response = self.client.post('/book', data=[ # {'title': 'GoT Vol. {}'.format(i + 1)} for i in range(20) # ]) for i in range(20): self.client.post('/book', data={'title': 'GoT Vol. {}'.format(i + 1)}) self.assertEqual(20, len(self.client.get('/book').json)) self.mock_user = { 'id': 2, 'needs': [ ItemNeed('owns-copy', i, 'book') for i in (1, 4, 6, 8, 11, 15, 19) ] } self.assertEqual(7, len(self.client.get('/book').json)) self.mock_user = { 'id': 3, 'needs': [ItemNeed('owns-copy', i, 'book') for i in (2, 7, 19)] } self.assertEqual([{ '$uri': '/book/2', 'title': 'GoT Vol. 2' }, { '$uri': '/book/7', 'title': 'GoT Vol. 7' }, { '$uri': '/book/19', 'title': 'GoT Vol. 19' }], self.client.get('/book').json) self.assert404(self.client.get('/book/15')) self.assert200(self.client.get('/book/2')) self.assert200(self.client.get('/book/7')) self.assert404(self.client.get('/book/1')) self.assert404(self.client.get('/book/99')) self.mock_user = {'id': 4} self.assertEqual([], self.client.get('/book').json) def test_relationship(self): "should require update permission on parent resource for updating, read permissions on both" class BookResource(PrincipalResource): class Schema: author = fields.ToOne('user', nullable=True) class Meta: model = self.BOOK permissions = { 'read': ['owns-copy', 'update', 'admin'], 'create': 'writer', 'update': 'user:author', 'owns-copy': 'owns-copy' } class UserResource(PrincipalResource): books = Relation(BookResource) class Meta: model = self.USER permissions = {'create': 'admin'} self.api.add_resource(UserResource) self.api.add_resource(BookResource) self.mock_user = {'id': 1, 'roles': ['admin']} for user in [{ 'name': 'Admin' }, { 'name': 'Author 1' }, { 'name': 'Author 2' }]: response = self.client.post('/user', data=user) self.assert200(response) response = self.client.post('/book', data={'title': 'Foo'}) self.assert403(response) self.mock_user = {'id': 2, 'roles': ['writer']} response = self.client.post('/book', data={ 'author': { '$ref': '/user/2' }, 'title': 'Bar' }) self.assert200(response) self.mock_user = {'id': 3, 'roles': ['writer']} response = self.client.post('/book', data={'title': 'Spying: Novel'}) self.assert200(response) response = self.client.post('/book', data={'title': 'Spied: The Sequel'}) self.assert200(response) response = self.client.post('/book', data={'title': 'Spy: The Prequel'}) self.assert200(response) self.assertJSONEqual( { '$uri': '/book/4', 'author': None, 'title': 'Spy: The Prequel' }, response.json) self.mock_user = {'id': 1, 'roles': ['admin']} self.client.post('/user/3/books', data={'$ref': '/book/2'}) self.client.post('/user/3/books', data={'$ref': '/book/3'}) self.client.post('/user/3/books', data={'$ref': '/book/4'}) self.mock_user = {'id': 3, 'roles': ['writer']} self.assert200(response) response = self.client.get('/user/3/books') self.assert200(response) self.assertEqual(3, len(response.json)) # read -> update -> user:author self.mock_user = {'id': 4, 'needs': [ItemNeed('owns-copy', 3, 'book')]} response = self.client.get('/user/3/books') self.assertEqual(1, len(response.json)) # read -> owns-copy self.assert200(self.client.get('/book/3')) self.assert404(self.client.get('/book/2')) self.mock_user = {'id': 5} response = self.client.get('/user/3/books') self.assertEqual(0, len(response.json)) self.assert404(self.client.get('/book/2')) @unittest.SkipTest def test_item_route(self): "should require read permission on parent resource plus any additional permissions" pass def test_permission_circular(self): class BookResource(PrincipalResource): class Meta: model = self.BOOK permissions = { 'read': 'create', 'create': 'read', 'update': 'create', 'delete': 'update' } self.api.add_resource(BookResource) with self.assertRaises(RuntimeError): BookResource.manager._needs
from flask_sqlalchemy import SQLAlchemy, Model from sqlalchemy import Column, DateTime, BigInteger from flask_potion import Api, fields from flask_cors import CORS from datetime import datetime, date class TimedModel(Model): id = Column(BigInteger, primary_key=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) def __repr__(self): return "<{} #{}>".format(self.__class__.__name__, self.id) app = Flask(__name__) app.config.from_object('config') db = SQLAlchemy(app, model_class=TimedModel) CORS(app, expose_headers=['X-Total-Count', 'Link', 'Date']) from app.resources import VideoResource, ViewResource, OverrideManger API = Api(app, default_manager=OverrideManger) API.add_resource(ViewResource) API.add_resource(VideoResource)
from mongoengine import StringField, IntField from flask_potion import Api, ModelResource, fields from flask.ext.potion.contrib.mongoengine.manager import MongoEngineManager app = Flask(__name__) app.debug = True app.config['MONGODB_DB'] = 'potion-example' me = MongoEngine(app) class Book(me.Document): title = StringField(null=False, unique=True) year_published = IntField(null=True) class BookResource(ModelResource): class Meta: name = 'book' model = Book class Schema: year_published = fields.Integer(minimum=1400) api = Api(app, default_manager=MongoEngineManager) api.add_resource(BookResource) if __name__ == '__main__': app.run()
class NaturalKeyTestCase(BaseTestCase): def setUp(self): super(NaturalKeyTestCase, self).setUp() self.api = Api(self.app, prefix='/api') def test_simple_key(self): class Foo(ModelResource): class Meta: key_converters = [ RefKey() ] model = 'foo' manager = MemoryManager class Schema: inception = fields.ToOne('foo') self.api.add_resource(Foo) foo_field = fields.ToOne(Foo) self.assertJSONEqual(FOO_REFERENCE, foo_field.response) self.assertJSONEqual(FOO_REFERENCE, foo_field.request) def test_multiple_keys(self): with self.assertRaises(RuntimeError) as cx: class Bar(ModelResource): class Meta: key_converters = ( RefKey(), PropertyKey('name') ) model = 'bar' natural_key = 'alias' manager = MemoryManager class Schema: name = fields.String() alias = fields.String() self.api.add_resource(Bar) self.assertEqual('Multiple keys of type string defined for bar', cx.exception.args[0]) def test_property_key(self): class Foo(ModelResource): class Schema: name = fields.String() class Meta: natural_key = 'name' manager = MemoryManager model = 'foo' self.api.add_resource(Foo) foo_field = fields.ToOne(Foo) self.assertJSONEqual(FOO_REFERENCE, foo_field.response) self.assertJSONEqual({ "anyOf": [ FOO_REFERENCE, { "type": "integer" }, { "type": "string" } ] }, foo_field.request) response = self.client.post('/api/foo', data={ "name": "Jane" }) self.assert200(response) response = self.client.post('/api/foo', data={ "name": "John" }) self.assert200(response) self.assertEqual( {'id': 2, 'name': 'John'}, foo_field.convert(2) ) self.assertEqual( {'id': 1, 'name': 'Jane'}, foo_field.convert('Jane') ) with self.assertRaises(ValidationError): foo_field.convert(['John']) with self.assertRaises(ItemNotFound) as cx: foo_field.convert('Joanne') self.assertEqual({ "message": "Not Found", "status": 404, "item": { "$type": "foo", "$where": { "name": "Joanne" } } }, cx.exception.as_dict()) def test_properties_key(self): class Foo(ModelResource): class Schema: first_name = fields.String() last_name = fields.String() class Meta: natural_key = ['first_name', 'last_name'] manager = MemoryManager model = 'foo' name = 'foo' self.api.add_resource(Foo) foo_field = fields.ToOne(Foo, nullable=True) self.assertJSONEqual(FOO_REFERENCE_NULLABLE, foo_field.response) self.assertJSONEqual({ "anyOf": [ FOO_REFERENCE, { "type": "integer" }, { "type": "array", "items": [{"type": "string"}, {"type": "string"}], "additionalItems": False }, { "type": "null" } ] }, foo_field.request) response = self.client.post('/api/foo', data={ "first_name": "Jane", "last_name": "Doe" }) self.assert200(response) response = self.client.post('/api/foo', data={ "first_name": "John", "last_name": "Doe" }) self.assert200(response) self.assertEqual( {'first_name': 'Jane', 'id': 1, 'last_name': 'Doe'}, foo_field.convert(1) ) self.assertEqual( {'first_name': 'John', 'id': 2, 'last_name': 'Doe'}, foo_field.convert(['John', 'Doe']) ) self.assertEqual( {'first_name': 'John', 'id': 2, 'last_name': 'Doe'}, foo_field.convert({"$ref": "/api/foo/2"}) ) with self.assertRaises(ItemNotFound) as cx: foo_field.convert(['John', 'Joe']) self.assertEqual({ "message": "Not Found", "status": 404, "item": { "$type": "foo", "$where": { "first_name": "John", "last_name": "Joe" } } }, cx.exception.as_dict()) with self.assertRaises(ValidationError): foo_field.convert(['John', None])
class PeeweeRelationTestCase(BaseTestCase): def setUp(self): super(PeeweeRelationTestCase, self).setUp() self.app.config['DATABASE'] = 'sqlite://' self.db = db = PeeweeTestDB(self.app) self.api = Api(self.app) class User(db.Model): parent = pw.ForeignKeyField('self', related_name='children', null=True) name = pw.CharField(max_length=60, null=False) class Group(db.Model): name = pw.CharField(max_length=60, null=False) members = ManyToManyField(User, related_name='memberships') db.database.connect() db.database.create_tables([ User, Group, Group.members.get_through_model()]) self.User = User self.Group = Group class UserResource(ModelResource): class Meta: model = User include_id = True include_type = True manager = PeeweeManager children = Relation('self') class GroupResource(ModelResource): class Meta: model = Group include_id = True include_type = True manager = PeeweeManager members = Relation('user') self.api.add_resource(UserResource) self.api.add_resource(GroupResource) def tearDown(self): self.db.database.drop_tables([ self.Group.members.get_through_model(), self.Group, self.User]) if not self.db.database.is_closed(): self.db.database.close() def test_relationship_secondary(self): response = self.client.post('/group', data={'name': 'Foo'}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'group', 'name': 'Foo'}, response.json) response = self.client.post('/user', data={'name': 'Bar'}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'user', 'name': 'Bar'}, response.json) response = self.client.get('/group/1/members') self.assert200(response) self.assertJSONEqual([], response.json) response = self.client.post( '/group/1/members', data={'$ref': '/user/1'}) self.assert200(response) self.assertJSONEqual({'$ref': '/user/1'}, response.json) response = self.client.get('/group/1/members') self.assert200(response) self.assertJSONEqual([{'$ref': '/user/1'}], response.json) def test_relationship_secondary_delete_missing(self): response = self.client.post('/group', data={"name": "Foo"}) response = self.client.post('/user', data={"name": "Bar"}) response = self.client.delete('/group/1/members/1') self.assertStatus(response, 204) def test_relationship_post(self): response = self.client.post('/user', data={'name': 'Foo'}) self.assert200(response) self.assertJSONEqual({ '$id': 1, '$type': 'user', 'name': 'Foo'}, response.json) response = self.client.post('/user', data={'name': 'Bar'}) self.assert200(response) self.assertJSONEqual({ '$id': 2, '$type': 'user', 'name': 'Bar'}, response.json) response = self.client.post( '/user/1/children', data={'$ref': '/user/2'}) self.assert200(response) self.assertJSONEqual({'$ref': '/user/2'}, response.json) def test_relationship_get(self): self.test_relationship_post() response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual([{'$ref': '/user/2'}], response.json) def test_relationship_delete(self): self.test_relationship_post() response = self.client.delete('/user/1/children/2') self.assertStatus(response, 204) response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual([], response.json) def test_relationship_pagination(self): response = self.client.post('/user', data={'name': 'Foo'}) self.assert200(response) for i in range(2, 50): response = self.client.post('/user', data={'name': str(i)}) self.assert200(response) response = self.client.post( '/user/1/children', data={'$ref': '/user/{}'.format(response.json['$id'])}) self.assert200(response) response = self.client.get('/user/1/children') self.assert200(response) self.assertJSONEqual( [{'$ref': '/user/{}'.format(i)} for i in range(2, 22)], response.json) response = self.client.get('/user/1/children?page=3') self.assert200(response) self.assertJSONEqual( [{'$ref': '/user/{}'.format(i)} for i in range(42, 50)], response.json)
def test_multiple_blueprints(self): # Create Blueprints api_bp1 = Blueprint("potion1", __name__.split(".")[0]) api_bp2 = Blueprint("potion2", __name__.split(".")[0], url_prefix="/api") # Create Api objects, add resources, and register blueprints with app api1 = Api(api_bp1, prefix="/api/v1") api2 = Api(api_bp2, prefix="/v2") api1.add_resource(self.SampleResource) with self.assertRaises(RuntimeError): api2.add_resource(self.SampleResource) api2.add_resource(self.SampleResource2) self.app.register_blueprint(api_bp1) self.app.register_blueprint(api_bp2) # Test both endpoints response = self.client.get("/api/v1/samples") self.assert200(response) response = self.client.get("/api/v2/samples") self.assert200(response) response = self.client.get("/api/v1/schema") self.assert200(response) self.assertEqual('/api/v1/samples/schema#', response.json['properties']['samples']['$ref']) response = self.client.get("/api/v2/schema") self.assert200(response) self.assertEqual('/api/v2/samples/schema#', response.json['properties']['samples']['$ref']) response = self.client.get("/api/v1/samples/schema") self.assertEqual('^\\/api\\/v1\\/samples\\/[^/]+$', response.json['properties']['$uri']['pattern']) response = self.client.get("/api/v2/samples/schema") self.assertEqual('^\\/api\\/v2\\/samples\\/[^/]+$', response.json['properties']['$uri']['pattern']) # Test that we have two prefix'd schemas response = self.client.get("/api/v1/schema") self.assert200(response) v1_schema = json.loads(response.data) response = self.client.get("/api/v2/schema") self.assert200(response) v2_schema = json.loads(response.data) assert v1_schema != v2_schema assert v1_schema["properties"]["samples"] != v2_schema["properties"]["samples"] # Test that endpoints are linked to same resource response = self.client.post('/api/v1/samples', data={ "name": "to_v1" }) self.assert200(response) response = self.client.post('/api/v2/samples', data={ "name": "to_v2" }) self.assert200(response) response = self.client.get("/api/v1/samples/1") assert response.json['$uri'] == "/api/v1/samples/1" self.assert200(response) response = self.client.get("/api/v2/samples/1") assert response.json['$uri'] == "/api/v2/samples/1" self.assert200(response)
class RelationTestCase(BaseTestCase): def setUp(self): super(RelationTestCase, self).setUp() self.api = Api(self.app) def test_pagination(self): class Person(ModelResource): class Schema: name = fields.String() class Meta: name = "person" model = name manager = MemoryManager self.api.add_resource(Person) response = self.client.get('/person') self.assert200(response) self.assertEqual('0', response.headers.get('X-Total-Count')) self.assertEqual( '</person?page=1&per_page=20>; rel="self",' '</person?page=1&per_page=20>; rel="last"', response.headers['Link']) for i in range(1, 51): response = self.client.post('/person', data={"name": str(i)}) self.assert200(response) response = self.client.get('/person') self.assert200(response) self.assertJSONEqual([{ "$uri": "/person/{}".format(i), "name": str(i) } for i in range(1, 21)], response.json) response = self.client.get('/person?page=3') self.assert200(response) self.assertEqual('50', response.headers.get('X-Total-Count')) self.assertEqual( '</person?page=3&per_page=20>; rel="self",' '</person?page=1&per_page=20>; rel="first",' '</person?page=2&per_page=20>; rel="prev",' '</person?page=3&per_page=20>; rel="last"', response.headers['Link']) self.assertJSONEqual([{ "$uri": "/person/{}".format(i), "name": str(i) } for i in range(41, 51)], response.json) def test_where_to_one(self): class Person(ModelResource): class Schema: name = fields.String() mother = fields.ToOne('person', nullable=True) class Meta: name = "person" model = name manager = MemoryManager self.api.add_resource(Person) response = self.client.post('/person', data={'name': 'Anna'}) # No. Bad self.assert200(response) self.assertJSONEqual( { '$uri': '/person/1', 'mother': None, 'name': 'Anna' }, response.json) self.client.post('/person', data={ 'name': 'Betty', 'mother': { "$ref": "/person/1" } }) self.client.post('/person', data={ 'name': 'Bob', 'mother': { "$ref": "/person/1" } }) self.client.post('/person', data={ 'name': 'Foo', 'mother': { "$ref": "/person/2" } }) self.client.post('/person', data={ 'name': 'Clare', 'mother': { "$ref": "/person/2" } }) response = self.client.get('/person?where={"mother": null}') self.assertJSONEqual([{ '$uri': '/person/1', 'mother': None, 'name': 'Anna' }], response.json) response = self.client.get( '/person?where={"mother": {"$ref": "/person/1"}}') self.assertJSONEqual([{ '$uri': '/person/2', 'mother': { '$ref': '/person/1' }, 'name': 'Betty' }, { '$uri': '/person/3', 'mother': { '$ref': '/person/1' }, 'name': 'Bob' }], response.json) response = self.client.get( '/person?where={"mother": {"$ref": "/person/2"}, "name": {"$startswith": "C"}}' ) self.assertJSONEqual([{ '$uri': '/person/5', 'mother': { '$ref': '/person/2' }, 'name': 'Clare' }], response.json)
class ModelResourceTestCase(BaseTestCase): def setUp(self): super(ModelResourceTestCase, self).setUp() self.api = Api(self.app, default_manager=MemoryManager) def test_schema_io(self): class FooResource(ModelResource): class Schema: name = fields.String() secret = fields.String(io="c") slug = fields.String(io="cr") class Meta: name = "foo" self.api.add_resource(FooResource) response = self.client.post("/foo", data={ "name": "Foo", "secret": "mystery", "slug": "foo" }) self.assert200(response) self.assertEqual({ "$uri": "/foo/1", "name": "Foo", "slug": "foo" }, response.json) self.assertEqual({ "id": 1, "name": "Foo", "slug": "foo", "secret": "mystery" }, FooResource.manager.items[1]) response = self.client.patch("/foo/1", data={ "name": "Bar", "secret": "123456" }) self.assert400(response) response = self.client.patch("/foo/1", data={ "name": "Bar" }) self.assert200(response) self.assertEqual({ "$uri": "/foo/1", "name": "Bar", "slug": "foo" }, response.json) self.assertEqual({ "id": 1, "name": "Bar", "slug": "foo", "secret": "mystery" }, FooResource.manager.items[1]) def test_inline_schema(self): class FooResource(ModelResource): class Meta: name = "foo" class BarResource(ModelResource): class Meta: name = "bar" self.api.add_resource(FooResource) self.api.add_resource(BarResource) foo = fields.Inline(FooResource) foo.bind(BarResource) self.assertEqual({'$ref': '/foo/schema'}, foo.response) def test_schema_io_create_flag(self): class FooResource(ModelResource): class Schema: name = fields.String() slug = fields.String(io="cr") class Meta: name = "foo" self.api.add_resource(FooResource) data, code, headers = FooResource().described_by() [create_link] = [ link for link in data['links'] if link['rel'] == 'create'] [update_link] = [ link for link in data['links'] if link['rel'] == 'update'] self.assertEqual({'$ref': '#'}, create_link['schema']) self.assertEqual({ "type": "object", "additionalProperties": False, "properties": { "name": { "type": "string" } } }, update_link["schema"]) self.assertEqual( ["$uri", "name", "slug"], sorted(data["properties"].keys()))
class PeeeeFilterTestCase(BaseTestCase): def setUp(self): super(PeeeeFilterTestCase, self).setUp() app = self.app app.config['DATABASE'] = 'sqlite://' self.db = db = PeeweeTestDB(self.app) self.api = Api(self.app, default_manager=PeeweeManager) app.debug = True class User(db.Model): id = IntegerField(primary_key=True) first_name = CharField(max_length=60, null=False) last_name = CharField(max_length=60, null=False) gender = CharField(max_length=1, null=True) age = IntegerField() is_staff = BooleanField(default=None) db.database.connect() db.database.create_tables([User]) class UserResource(ModelResource): class Schema: gender = fields.String(enum=['f', 'm'], nullable=True) class Meta: model = User class AllowUserResource(ModelResource): class Meta: model = User name = 'allow-user' allowed_filters = {'first_name': ['$eq'], 'is_staff': '*'} self.api.add_resource(UserResource) self.api.add_resource(AllowUserResource) def post_sample_set_a(self): for user in [{ 'first_name': 'John', 'last_name': 'Doe', 'age': 32, 'is_staff': True, 'gender': 'm' }, { 'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25, 'is_staff': False, 'gender': 'm' }, { 'first_name': 'Jane', 'last_name': 'Roe', 'age': 18, 'is_staff': False, 'gender': 'f' }, { 'first_name': 'Joe', 'last_name': 'Bloggs', 'age': 21, 'is_staff': True, 'gender': 'm' }, { 'first_name': 'Sue', 'last_name': 'Watts', 'age': 25, 'is_staff': True }]: response = self.client.post('/user', data=user) self.assert200(response) def test_equality(self): self.post_sample_set_a() response = self.client.get('/user?where={"last_name": "Doe"}') self.assertEqualWithout([ { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, ], response.json, without=[ '$uri', '$uri', '$id', '$type', 'gender', 'age', 'is_staff' ]) response = self.client.get('/user?where={"age": 25}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe', 'age': 25 }, { 'first_name': 'Sue', 'last_name': 'Watts', 'age': 25 }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'is_staff']) response = self.client.get( '/user?where={"last_name": "Doe", "age": 25}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_inequality(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$ne": "Watts"}, "age": {"$ne": 32}}') self.assertEqualWithout( [ { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gt": 25}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$gte": 25}}') self.assertEqualWithout( [ { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Sue', 'last_name': 'Watts' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lte": 21}}') self.assertEqualWithout( [{ 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": 21.0}}') self.assertEqualWithout( [{ 'first_name': 'Jane', 'last_name': 'Roe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"age": {"$lt": null}}') self.assert400(response) response = self.client.get('/user?where={"first_name": {"$gt": "Jo"}}') self.assert400(response) def test_in(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$in": ["Bloggs", "Watts"]}}') self.assertEqualWithout( [{ 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'Sue', 'last_name': 'Watts' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get('/user?where={"last_name": {"$in": []}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_startswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$startswith": "Jo"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$startswith": "J%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_istartswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$istartswith": "jo"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_iendswith(self): self.post_sample_set_a() response = self.client.get( '/user?where={"last_name": {"$iendswith": "Oe"}}') self.assertEqualWithout( [{ 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Jane', 'last_name': 'Roe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?where={"first_name": {"$istartswith": "j%e"}}') self.assertEqualWithout( [], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_text_search(self): self.post_sample_set_a() response = self.client.get('/user?search=sbc+dedf&rank=1') def test_sort(self): self.post_sample_set_a() response = self.client.get( '/user?sort={"last_name": true, "first_name": false}') self.assert200(response) self.assertEqualWithout( [{ 'first_name': 'Sue', 'last_name': 'Watts' }, { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) response = self.client.get( '/user?sort={"age": false, "first_name": false}') self.assertEqualWithout( [ { 'first_name': 'Jane', 'last_name': 'Roe' }, { 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }, { 'first_name': 'Sue', 'last_name': 'Watts' }, { 'first_name': 'John', 'last_name': 'Doe' }, ], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) def test_sort_and_where(self): self.post_sample_set_a() response = self.client.get( '/user?where={"first_name": {"$startswith": "Jo"}}&sort={"first_name": false}' ) self.assertEqualWithout( [{ 'first_name': 'Joe', 'last_name': 'Bloggs' }, { 'first_name': 'John', 'last_name': 'Doe' }, { 'first_name': 'Jonnie', 'last_name': 'Doe' }], response.json, without=['$uri', '$id', '$type', 'gender', 'age', 'is_staff']) @unittest.SkipTest def test_sort_pages(self): pass @unittest.SkipTest def test_disallowed_where_filters(self): pass @unittest.SkipTest def test_schema(self): pass