def test_apps_session_cookies_expire(): # Given that I have an app with a cookie store that immediately expires session cookies cookie_store = CookieStore(b"secret", cookie_ttl=0) def set_username(username: str, session: Session) -> None: session["username"] = username def get_username(session: Session) -> Optional[str]: return session.get("username") app = App( components=[ SessionComponent(cookie_store), ], middleware=[ SessionMiddleware(cookie_store), ResponseRendererMiddleware(), ], routes=[ Route("/set-username/{username}", set_username), Route("/get-username", get_username), ], ) # And a client for that app client = testing.TestClient(app) # When I make a request to a handler that stores session data response = client.get(app.reverse_uri("set_username", username="******")) # Then I should get back a successful response assert response.status_code == 200 # And the response should contain my session cookie cookie = cookies.SimpleCookie() for data in response.headers.get_all("set-cookie"): cookie.load(data.replace("SameSite=Strict", "")) assert "__sess__" in cookie # When I make another request with that same cookie session_cookie = cookie.output(attrs=[], header="") response = client.get(app.reverse_uri("get_username"), headers={ "cookie": session_cookie, }) # Then I should get back nothing assert response.json() is None
def test_openapi_can_render_fields_with_different_request_and_response_names(): # Given that I have a schema that has different names based on whether it's in the request or response @schema class A: x: int = field(request_name="X", response_name="Y") def index(a: A) -> A: pass # And an app app = App(routes=[Route("/", index)]) # When I generate a document document = generate_openapi_document( app, Metadata("example", "an example", "0.0.0"), []) # Then the schema should mark that field as writeOnly response_schema = document["components"]["schemas"][ "tests.openapi.test_openapi.A"] assert response_schema["properties"] == { "X": { "type": "integer", "format": "int64", "writeOnly": True, }, "Y": { "type": "integer", "format": "int64", "readOnly": True, }, }
def test_openapi_can_render_request_only_fields(): # Given that I have a schema that has request-only fields @schema class A: x: int = field(request_only=True) def index(a: A) -> A: pass # And an app app = App(routes=[Route("/", index)]) # When I generate a document document = generate_openapi_document( app, Metadata("example", "an example", "0.0.0"), []) # Then the schema should mark that field as writeOnly response_schema = document["components"]["schemas"][ "tests.openapi.test_openapi.A"] assert response_schema["properties"] == { "x": { "type": "integer", "format": "int64", "writeOnly": True, }, }
def test_middleware_white_listing(app_settings, testing_token): def test_handler(jwt_identity: JWTIdentity): if jwt_identity is None: return "No user token present" return jwt_identity.id routes = [Route("/whitelisted", method="GET", handler=test_handler)] components = [ SettingsComponent({ **app_settings, "JWT_AUTH_WHITELIST": ["test_handler"] }), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/whitelisted", headers={"Authorization": f"Bearer {testing_token}"}) unauthenticated = client.get("/whitelisted") assert 200 == response.status_code assert "1234567890" in response.data assert 200 == unauthenticated.status_code assert "No user token present" in unauthenticated.data
def get_botx_wsgi_api( messages: List[APIMessage], requests: List[APIRequest], errors: Dict[Type[BotXMethod], Tuple[int, Any]], ) -> App: """Generate BotX API mock. Arguments: messages: list of message that were sent from bot and should be extended. requests: all requests that were sent from bot. errors: errors to be generated by mocked API. Returns: Generated BotX API mock for using with httpx. """ return App( components=[ SettingsComponent( Settings(messages=messages, requests=requests, errors=errors), ), ], routes=list(_create_molten_routes()), middleware=[error_middleware], parsers=[JSONParser()], )
def test_apps_can_be_injected_into_singleton_components(): # Given that I have a singleton component that requests the app class AClass: # noqa def __init__(self, app): self.app = app class AComponent: is_cacheable = True is_singleton = True def can_handle_parameter(self, parameter): return parameter.annotation is AClass def resolve(self, app: BaseApp): return AClass(app) app = App(components=[AComponent()]) # When I resolve that component def test(a_class: AClass): # Then its app property should be the app instance assert a_class.app is app resolver = app.injector.get_resolver() resolver.resolve(test)()
def setup_app(): get_schema = OpenAPIHandler( metadata=Metadata( title="Pet Store", description=__doc__, version="0.0.0", ), security_schemes=[HTTPSecurityScheme("Bearer", "bearer")], default_security_scheme="Bearer", ) get_schema = annotate(no_auth=True)(get_schema) get_docs = annotate(no_auth=True)(OpenAPIUIHandler()) return App( components=[ DatabaseComponent(), categories.CategoryManagerComponent(), tags.TagManagerComponent(), pets.PetManagerComponent(), ], middleware=[ ResponseRendererMiddleware(), auth_middleware, ], routes=[ Include("/v1/categories", categories.routes), Include("/v1/pets", pets.routes), Include("/v1/tags", tags.routes), Route("/_docs", get_docs), Route("/_schema", get_schema), ], )
def test_middleware_token_validation_raises_error_on_token_exp(app_settings): def test_handler(jwt_identity: JWTIdentity): if jwt_identity is None: return "No user token present" return jwt_identity.id jwt = JWT(key="keepthissafe", alg="HS256") iat = dt.datetime.now() + dt.timedelta(seconds=-10) exp = iat + dt.timedelta(seconds=5) payload = {"sub": "1234567890", "name": "John Doe", "iat": iat, "exp": exp} token = jwt.encode(payload) routes = [Route("/auth-required", method="GET", handler=test_handler)] components = [ SettingsComponent(app_settings), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/auth-required", headers={"Authorization": f"Bearer {token}"}) assert 401 == response.status_code content = response.json() assert "error_message" in content assert content.get("status") == 401
def test_openapi_can_render_api_key_security_schemes_correctly(): # Given that I have an APIKeySecurityScheme security_scheme = APIKeySecurityScheme( name="api-key", param_name="x-api-key", in_="header", ) # When I generate a document with that security scheme document = generate_openapi_document( App(), Metadata( "example", "an example", "0.0.0", ), security_schemes=[security_scheme], default_security_scheme="api-key", ) # Then I should get back a valid, non-ambiguous, OpenAPI document assert document["components"] == { "schemas": {}, "securitySchemes": { "api-key": { "name": "x-api-key", "in": "header", "type": "apiKey", }, }, }
def setup_app(): setup_logging() cookie_store = CookieStore(**settings.strict_get("sessions")) get_schema = OpenAPIHandler( Metadata( title="Chat", description="A simple chat app.", version="0.0.0", ), ) get_docs = OpenAPIUIHandler() app = App( components=[ AccountManagerComponent(), ChatHandlerFactoryComponent(), ChatroomListenerComponent(), ChatroomRegistryComponent(), CurrentAccountComponent(), PasswordHasherComponent(), RedisComponent(), SQLAlchemyEngineComponent(), SQLAlchemySessionComponent(), SessionComponent(cookie_store), SettingsComponent(settings), TemplatesComponent(path_to("templates")), ], middleware=[ RequestIdMiddleware(), SessionMiddleware(cookie_store), ResponseRendererMiddleware(), WebsocketsMiddleware(), SQLAlchemyMiddleware(), ], routes=[ Route("/_schema", get_schema), Route("/_docs", get_docs), Route("/", index), Route("/login", login), Route("/register", register), Include("/v1", [ Include("/accounts", accounts.routes, namespace="accounts"), Include("/chat", chat.routes, namespace="chat"), Include("/sessions", sessions.routes, namespace="sessions"), ], namespace="v1"), ], ) decorated_app = WhiteNoise(app, **settings.strict_get("whitenoise")) return decorated_app, app
def test_empty_app_can_return_openapi_document(): # Given that I have an empty app app = App(routes=[ Route("/schema.json", OpenAPIHandler( Metadata( title="empty application", description="an application that doesn't do anything", version="0.1.0", contact=Contact(name="Jim Gordon", ), )), name="schema"), ]) # When I visit its schema uri response = testing.TestClient(app).get("/schema.json") # Then I should get back a successful response assert response.status_code == 200 assert response.json() == { "openapi": "3.0.1", "info": { "title": "empty application", "description": "an application that doesn't do anything", "version": "0.1.0", "contact": { "name": "Jim Gordon", }, }, "paths": { "/schema.json": { "get": { "tags": [], "operationId": "schema", "summary": "Generates an OpenAPI v3 document.", "description": "", "deprecated": False, "parameters": [], "responses": { "200": { "description": "A successful response.", "content": {}, }, }, } } }, "components": { "schemas": {}, "securitySchemes": {}, }, }
def create_app(_components=None, _middleware=None, _routes=None): app = App( components=_components or components, middleware=_middleware or middleware, routes=_routes or routes, parsers=[ JSONParser(), URLEncodingParser(), MultiPartParser(), ], renderers=[JSONRenderer()] ) setup_db(app) return app
def test_app_can_render_mail_templates(): mail = Mail( user="******", password="******", port=587, use_tls=True, suppress_send=True, ) mail.send = MagicMock(return_value=None) def template_handler(mail_templates: MailTemplates) -> Response: mail.send_message( subject="Test email", html=mail_templates.render("test_template.html", name="Molten"), recipients=["*****@*****.**"], ) return Response(HTTP_204, content="") app = App( components=[MailTemplatesComponent("./tests/mail_templates")], routes=[Route("/", template_handler, name="index")], ) client = testing.TestClient(app) # Given that a handler will use templating # When constructing and email response = client.get(app.reverse_uri("index")) # Then I should get back a successfull response assert response.status_code == 204 # and the handler should have called the Mail object # with the string value of the rendered template mail_msg = mail.send.call_args[0][0] assert "<th>Hey there Molten</th>" in mail_msg.html
def test_middleware_raises_401_error(app_settings): def test_handler(): return "Handler called" routes = [Route("/auth-required", method="GET", handler=test_handler)] components = [ SettingsComponent(app_settings), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/auth-required") assert 401 == response.status_code
def test_claims_required_attaches_values(app_settings): @claims_required({"admin": True}) def test_handler(): return "Handler called" routes = [Route("/claims", method="GET", handler=test_handler)] components = [SettingsComponent(app_settings)] middleware = [ResponseRendererMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/claims") assert 200 == response.status_code assert "admin" in test_handler.claims assert test_handler.claims.get("admin") is True assert "Handler called" in response.data
def test_openapi_can_render_lists_of_x(fields, expected): # Given that I have a schema that has a list of something in it A = type("A", (object, ), fields) A.__annotations__ = fields A = schema(A) def index() -> A: pass # And an app app = App(routes=[Route("/", index)]) # When I generate a document document = generate_openapi_document( app, Metadata("example", "an example", "0.0.0"), []) # Then the return schema should have an array of that thing response_schema = document["components"]["schemas"][ "tests.openapi.test_openapi.A"] assert response_schema["properties"] == expected
def test_openapi_can_render_documents_with_method_handlers(): # Given that I have a resource class @schema class User: username: str class Users: def get_users(self) -> User: pass # And an app that uses that an instance of that resource users = Users() app = App(routes=[Route("/users", users.get_users)]) # When I generate a document document = generate_openapi_document( app, Metadata("example", "an example", "0.0.0"), []) # Then I should get back a valid document assert document
def test_JWT_claims_options_raises_error(app_settings, testing_token): def test_handler(jwt_identity: JWTIdentity): if jwt_identity is None: return "No user token present" return jwt_identity.id jwt = JWT(key=app_settings.get("JWT_SECRET_KEY"), alg="HS256") mod_token = jwt.encode({ **jwt.decode(testing_token), **{ "iss": "https://molten.com" } }) routes = [Route("/claim_options", method="GET", handler=test_handler)] components = [ SettingsComponent({ **app_settings, "JWT_CLAIMS_OPTIONS": { "iss": { "essential": True, "values": ["https://example.com", "https://example.org"], } }, }), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) missing_claim_response = client.get( "/claim_options", headers={"Authorization": f"Bearer {testing_token}"}) wrong_claim_value_response = client.get( "/claim_options", headers={"Authorization": f"Bearer {mod_token}"}) assert 401 == missing_claim_response.status_code assert 401 == wrong_claim_value_response.status_code
def test_claims_required_raises_error(app_settings, testing_token): @claims_required({"admin": True}) def test_handler(): return "Handler called" routes = [Route("/claims", method="GET", handler=test_handler)] components = [ SettingsComponent(app_settings), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/claims", headers={"Authorization": f"Bearer {testing_token}"}) assert 403 == response.status_code
def test_middleware_anonymous_user_support(app_settings): @allow_anonymous def test_handler(): return "Handler called" routes = [Route("/auth-maybe", method="GET", handler=test_handler)] components = [ SettingsComponent(app_settings), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/auth-maybe") assert 200 == response.status_code assert "Handler called" in response.data
def create_app(middleware=None, components=None, settings=None): if settings is None: settings = Settings({ 'database_engine_dsn': os.environ['SQLALCHEMY_URI'], 'identity_server': os.environ['IDENTITY_SERVER'], 'secret_key': os.environ['SECRET_KEY'], }) if middleware is None: middleware = [ ResponseRendererMiddleware(), SQLAlchemyMiddleware(), auth_middleware, ] if components is None: components = [ SettingsComponent(settings), SQLAlchemyEngineComponent(), SQLAlchemySessionComponent(), RequestSessionComponent(), AuthProviderComponent(), ManagerComponent(ChoreInstanceManager), ManagerComponent(ChoreDefinitionManager), UserProviderComponent(), ] app = App( routes=[ Route('/login', login, method='POST', name='login'), Include( '/api', routes, namespace='api', ) ], middleware=middleware, components=components, ) return app
def test_ws_middleware_validates_origin(): # Given that I have an app instance whose ws middleware validates the incoming origin app = App( middleware=[ ResponseRendererMiddleware(), WebsocketsMiddleware(re.compile("example.com")), ], routes=[Route("/echo", echo)], ) # And a ws client for that app client = WebsocketsTestClient(app) # When I try to connect to its echo endopoint with an invalid origin # Then an error should occur with pytest.raises(ValueError): client.connect("/echo") # When I try to connect to its echo endopoint with a valid origin with client.connect("/echo", headers={"origin": "example.com"}) as sock: # Then my connection should succeed assert sock
def test_identity_extract_jwt_from_cookie(app_settings): def test_auth(jwt: JWT): cookie_name = "molten_auth_cookie" cookie_value = jwt.encode({"sub": 123456, "name": "spiderman"}) auth_response = Response(HTTP_200) auth_response.set_cookie(Cookie(cookie_name, cookie_value)) return auth_response def test_cookie(jwt_identity: JWTIdentity): if jwt_identity is None: return "Didn't work" return f"Hello {jwt_identity.name} your sub id is {jwt_identity.sub}" routes = [ Route("/auth", method="POST", handler=test_auth), Route("/cookie", method="GET", handler=test_cookie), ] components = [ SettingsComponent({ **app_settings, **{ "JWT_AUTH_COOKIE": "molten_auth_cookie" } }), JWTComponent(), JWTIdentityComponent(), ] app = App(routes=routes, components=components) client = testing.TestClient(app) auth_response = client.post("/auth") cookie_value = auth_response.headers.get_all("set-cookie")[0] assert "molten_auth_cookie" in cookie_value cookie_response = client.get("/cookie", headers={"cookie": cookie_value}) assert "123456" in cookie_response.data assert "spiderman" in cookie_response.data
def test_middleware_token_validation_passes(app_settings, testing_token): def test_handler(jwt_identity: JWTIdentity): if jwt_identity is None: return "No user token present" return jwt_identity.id routes = [Route("/auth-required", method="GET", handler=test_handler)] components = [ SettingsComponent(app_settings), JWTComponent(), JWTIdentityComponent(), ] middleware = [ResponseRendererMiddleware(), JWTAuthMiddleware()] app = App(routes=routes, components=components, middleware=middleware) client = testing.TestClient(app) response = client.get("/auth-required", headers={"Authorization": f"Bearer {testing_token}"}) assert 200 == response.status_code assert "1234567890" in response.data
def setup_app(): setup_logging() get_docs = OpenAPIUIHandler() get_schema = OpenAPIHandler( metadata=Metadata( title="Pets", description="", version="0.0.0", ), ) app = App( components=[ ManagerComponent(PetManager), SQLAlchemyEngineComponent(), SQLAlchemySessionComponent(), SettingsComponent(settings), TemplatesComponent(path_to("templates")), ], middleware=[ RequestIdMiddleware(), ResponseRendererMiddleware(), SQLAlchemyMiddleware(), ], routes=[ Route("/_docs", get_docs), Route("/_schema", get_schema), Route("/", index), Include("/v1/pets", pets.routes, namespace="pets"), ], ) decorated_app = WhiteNoise(app, **settings.strict_get("whitenoise")) return decorated_app, app
def test_missing_auth_cookie(app_settings): def test_cookie(jwt_identity: JWTIdentity): if jwt_identity is None: return "Didn't work" return f"Hello {jwt_identity.name} your sub id is {jwt_identity.sub}" routes = [Route("/cookie", method="GET", handler=test_cookie)] components = [ SettingsComponent({ **app_settings, **{ "JWT_AUTH_COOKIE": "molten_auth_cookie" } }), JWTComponent(), JWTIdentityComponent(), ] app = App(routes=routes, components=components) client = testing.TestClient(app) cookie_response = client.get("/cookie") assert "Didn't work" in cookie_response.data
from molten import App, Route def hello(name: str, age: int) -> str: return f"Hello {age} year old named {name}!" app = App(routes=[Route("/hello/{name}/{age}", hello)])
from molten import App, JSONRenderer, QueryParam, ResponseRendererMiddleware, Route from molten.contrib.sessions import CookieStore, Session, SessionComponent, SessionMiddleware cookie_store = CookieStore(b"ubersecret") def set_username(username: QueryParam, session: Session) -> str: session["username"] = username return username def get_username(session: Session) -> Optional[str]: return session.get("username") app = App( components=[ SessionComponent(cookie_store), ], middleware=[ SessionMiddleware(cookie_store), ResponseRendererMiddleware([ JSONRenderer(), ]), ], routes=[ Route("/get-username", get_username), Route("/set-username", set_username), ], )
"MAIL_PASSWORD": "******", "MAIL_PORT": 587, "MAIL_USE_TLS": True, "MAIL_DEFAULT_SENDER": "*****@*****.**", } ) def send_message(params: QueryParams, mail: Mail): """Emails an email address provided in the query string""" addresses = params.get_all("email") if not addresses: return Response( HTTP_400, content="Provide emails in the query params to send a welcome message", ) msg = Message( subject="Welcome to Molten!", body="Welcome to Molten! Glad to have you here.", recipients=addresses, ) mail.send(msg) return Response(HTTP_204, content="") routes = [Route("/", send_message, "POST")] components = [SettingsComponent(settings), MailComponent()] app = App(routes=routes, components=components)
title="Emeeting API", description="An API for managing your room meetings.", version="0.0.1", )) get_docs = OpenAPIUIHandler() """ Add middlewares """ middlewares = [prometheus_middleware, ResponseRendererMiddleware()] """ Include or add routes """ routes = [ Route("/", get_docs), Route("/schema", get_schema), Route("/metrics", expose_metrics), Include("/v1/rooms", routes=room.routes), Include("/v1/meetings", routes=meeting.routes), ] """ Start application """ app = App(routes=routes, middleware=middlewares) app = CORS(app, headers="*", methods="*", origin="*", maxage="86400") log.info("Start application successfully.")