def test_item_path(fconfig: Config, db: SQLAlchemy): """ Tests that the URL converter works for the item endpoints of the resources. The following test has set an URL converter of type int, and will allow only integers using the flask rules. """ DeviceDef, *_ = fconfig.RESOURCE_DEFINITIONS # type: Tuple[ResourceDef, ...] def cannot_find(id): assert id == 1 return Response(status=200) DeviceDef.VIEW.one = MagicMock(side_effect=cannot_find) app = Teal(config=fconfig, db=db) client = app.test_client() # type: Client with populated_db(db, app): # All ok, we expect an int and got an int client.get(res=DeviceDef.type, item=1) DeviceDef.VIEW.one.assert_called_once_with(1) # Conversion of 'int' works in here client.get(res=DeviceDef.type, item='1') assert DeviceDef.VIEW.one.call_count == 2 # Anything else fails and our function is directly not executed client.get(res=DeviceDef.type, item='foo', status=NotFound) assert DeviceDef.VIEW.one.call_count == 2
def test_post(fconfig: Config, db: SQLAlchemy): """ Tests posting resources, going through API (Marshmallow) and DB (SQLAlchemy) validation, and retrieving and returning a result. """ DeviceDef, ComponentDef, ComputerDef = fconfig.RESOURCE_DEFINITIONS # type: Tuple[ResourceDef] Computer = ComputerDef.MODEL Component = ComponentDef.MODEL PC = { 'id': 1, 'model': 'foo', 'components': [{'id': 2, 'type': 'Component'}, {'id': 3, 'type': 'Component'}] } def post(): pc = request.get_json() pc = Computer(**pc) db.session.add(pc) db.session.commit() return Response(status=201) def _one(id): pc = Computer.query.filter_by(id=id).first() return_pc = { 'id': pc.id, 'model': pc.model, 'type': pc.type, } # todo convert components to JSON return return_pc def one(id: int): return jsonify(_one(id)) def find(_): return jsonify([_one(1)]) ComputerDef.VIEW.post = MagicMock(side_effect=post) ComputerDef.VIEW.one = MagicMock(side_effect=one) ComputerDef.VIEW.find = MagicMock(side_effect=find) app = Teal(config=fconfig, db=db) client = app.test_client() # type: Client with populated_db(db, app): client.post(res=ComputerDef.type, data=PC) # Wrong data data, _ = client.post(res=ComputerDef.type, data={'id': 'foo'}, status=ValidationError) assert data == { 'code': 422, 'type': 'ValidationError', 'message': {'id': ['Not a valid integer.']} } # Get the first data data, _ = client.get(res=ComputerDef.type, item=1) assert data == {'id': 1, 'model': 'foo', 'type': 'Computer'} # Get all data data, _ = client.get(res=ComputerDef.type) assert data == [{'id': 1, 'model': 'foo', 'type': 'Computer'}]
def test_token_auth_view(db: SQLAlchemy): """ Ensures that an authorization endpoint correctly protects against wrong credentials (this case tokens), allowing the endpoint to only specific cases. """ class TestTokenAuth(TokenAuth): authenticate = MagicMock(side_effect=Unauthorized) class FooSchema(Schema): pass class FooView(View): get = MagicMock(side_effect=lambda id: jsonify({'did': 'it!'})) class Foo(db.Model): id = db.Column(db.Integer, primary_key=True) class FooDef(Resource): SCHEMA = FooSchema VIEW = FooView MODEL = Foo AUTH = True class TestConfig(Config): RESOURCE_DEFINITIONS = [FooDef] app = Teal(config=TestConfig(), Auth=TestTokenAuth, db=db) client = app.test_client() # No token # No auth header sent client.get(res=FooSchema.t, status=Unauthorized) assert TestTokenAuth.authenticate.call_count == 0 # Wrong format # System couldn't parse Auth header client.get(res=FooSchema.t, token='this is wrong', status=Unauthorized) assert TestTokenAuth.authenticate.call_count == 0 # Wrong credentials # System can parse credentials but they are incorrect client.get(res=FooSchema.t, token=b64encode(b'nok:').decode(), status=Unauthorized) # Authenticate method was hit assert TestTokenAuth.authenticate.call_count == 1 # OK # Our authenticate method now returns some dummy user instead of # raising Unauthorized TestTokenAuth.authenticate = MagicMock(return_value={'id': '1'}) data, _ = client.get(res=FooSchema.t, token=b64encode(b'ok:').decode()) TestTokenAuth.authenticate.assert_called_once_with('ok', '') # The endpoint was hit assert data == {'did': 'it!'} FooView.get.assert_called_once_with(id=None)
def client(app: Teal) -> Client: return app.test_client()