async def test_user_can_delete_own_comment(app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: created_comment_response = await authorized_client.post( app.url_path_for("comments:create-comment-for-article", slug=test_article.slug), json={"comment": { "body": "comment" }}, ) created_comment = CommentInResponse(**created_comment_response.json()) await authorized_client.delete( app.url_path_for( "comments:delete-comment-from-article", slug=test_article.slug, comment_id=str(created_comment.comment.id_), )) comments_for_article_response = await authorized_client.get( app.url_path_for("comments:get-comments-for-article", slug=test_article.slug)) comments = ListOfCommentsInResponse(**comments_for_article_response.json()) assert len(comments.comments) == 0
async def test_user_can_change_following_for_another_user( app: FastAPI, authorized_client: AsyncClient, pool: Pool, test_user: UserInDB, api_method: str, route_name: str, following: bool, ) -> None: async with pool.acquire() as conn: users_repo = UsersRepository(conn) user = await users_repo.create_user( username="******", email="*****@*****.**", password="******", ) if not following: profiles_repo = ProfilesRepository(conn) await profiles_repo.add_user_into_followers( target_user=user, requested_user=test_user) change_following_response = await authorized_client.request( api_method, app.url_path_for(route_name, username=user.username)) assert change_following_response.status_code == status.HTTP_200_OK response = await authorized_client.get( app.url_path_for("profiles:get-profile", username=user.username)) profile = ProfileInResponse(**response.json()) assert profile.profile.username == user.username assert profile.profile.following == following
async def test_user_can_change_favorite_state( app: FastAPI, authorized_client: AsyncClient, test_article: Article, test_user: UserInDB, pool: Pool, api_method: str, route_name: str, favorite_state: bool, ) -> None: if not favorite_state: async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) await articles_repo.add_article_into_favorites( article=test_article, user=test_user) await authorized_client.request( api_method, app.url_path_for(route_name, slug=test_article.slug)) response = await authorized_client.get( app.url_path_for("articles:get-article", slug=test_article.slug)) article = ArticleInResponse(**response.json()) assert article.article.favorited == favorite_state assert article.article.favorites_count == int(favorite_state)
def setup_frontend_services(app: FastAPI): """ Setup entrypoint for this app module. Used in core.application.init_app """ def _on_startup() -> None: def is_included(key) -> bool: return ( app.state.settings.CATALOG_DEV_FEATURES_ENABLED # FIXME: STILL UNDER DEVELOPMENT # - Parameter services # - Iterator # - Iterator consumer or not is_parameter_service(key) or not is_frontend_service(key) or not is_iterator_service(key) or not is_iterator_consumer_service(key)) catalog = [ _as_dict(metadata) for metadata in iter_service_docker_data() if is_included(metadata.key) ] app.state.frontend_services_catalog = catalog app.add_event_handler("startup", _on_startup)
def setup_mongo(app: FastAPI): """ Создаем инстанс Монги """ # app.client = ma.AsyncIOMotorClient(MONGO_HOST) app.mongo = {} for db in app.config['databases']: client = ma.AsyncIOMotorClient(db['address']) app.mongo[db['name']] = {} for collection in db['collections']: index_fields = collection.get('index_fields') if index_fields: if len(list(set(collection['index_fields']) - set(collection['fields']))) > 0: raise WrongCollectionFormat('"index_fields" got an extra fields not included in "fields"') db_instance = client[db['name']] collection_instance = db_instance[collection['name']] app.mongo[db['name']][collection['name']] = MongoInstance( BaseModel(db_instance, collection_instance), collection['fields'], index_fields, )
async def test_filtering_with_limit_and_offset(app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, pool: Pool) -> None: async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) for i in range(5, 10): await articles_repo.create_article( slug=f"slug-{i}", title="tmp", description="tmp", body="tmp", author=test_user, ) full_response = await authorized_client.get( app.url_path_for("articles:list-articles")) full_articles = ListOfArticlesInResponse(**full_response.json()) response = await authorized_client.get( app.url_path_for("articles:list-articles"), params={ "limit": 2, "offset": 3 }) articles_from_response = ListOfArticlesInResponse(**response.json()) assert full_articles.articles[3:] == articles_from_response.articles
def setup_mongo(app: FastAPI): app.client = ma.AsyncIOMotorClient(MONGO_HOST) app.db = app.client[MONGO_DB_NAME] app.mongo = { 'beer': Beer(app.db), 'wine': Wine(app.db), 'vodka': Vodka(app.db) }
def setup_fastAPI(fh, nginx_x_accel_redirect_base=None, apache_xsendfile=None): def wsgi_application(env, start_response): trans = Bunch( response=Response(), app=Bunch(config=Bunch( nginx_x_accel_redirect_base=nginx_x_accel_redirect_base, apache_xsendfile=apache_xsendfile))) trans.response.headers['content-length'] = len(CONTENT) trans.response.set_content_type('application/octet-stream') return send_file(start_response, trans, fh) app = FastAPI() app.mount('/test/send_file', WSGIMiddleware(wsgi_application)) return app
async def test_empty_feed_if_user_has_not_followings( app: FastAPI, authorized_client: AsyncClient, test_article: Article, test_user: UserInDB, pool: Pool, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) articles_repo = ArticlesRepository(connection) for i in range(5): user = await users_repo.create_user(username=f"user-{i}", email=f"user-{i}@email.com", password="******") for j in range(5): await articles_repo.create_article( slug=f"slug-{i}-{j}", title="tmp", description="tmp", body="tmp", author=user, tags=[f"tag-{i}-{j}"], ) response = await authorized_client.get( app.url_path_for("articles:get-user-feed-articles")) articles = ListOfArticlesInResponse(**response.json()) assert articles.articles == []
def _create_instance(settings: Settings) -> FastAPI: return FastAPI( debug=settings.WEB_APP_DEBUG, title=settings.WEB_APP_TITLE, description=settings.WEB_APP_DESCRIPTION, version=settings.WEB_APP_VERSION, )
async def test_user_can_not_modify_article_that_is_not_authored_by_him( app: FastAPI, authorized_client: AsyncClient, pool: Pool, api_method: str, route_name: str, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) user = await users_repo.create_user(username="******", email="*****@*****.**", password="******") articles_repo = ArticlesRepository(connection) await articles_repo.create_article( slug="test-slug", title="Test Slug", description="Slug for tests", body="Test " * 100, author=user, tags=["tests", "testing", "pytest"], ) response = await authorized_client.request( api_method, app.url_path_for(route_name, slug="test-slug"), json={"article": { "title": "Updated Title" }}, ) assert response.status_code == status.HTTP_403_FORBIDDEN
async def test_unregistered_user_will_receive_profile_without_following( app: FastAPI, client: AsyncClient, test_user: UserInDB) -> None: response = await client.get( app.url_path_for("profiles:get-profile", username=test_user.username)) profile = ProfileInResponse(**response.json()) assert profile.profile.username == test_user.username assert not profile.profile.following
async def test_user_can_not_change_following_state_to_the_same_twice( app: FastAPI, authorized_client: AsyncClient, pool: Pool, test_user: UserInDB, api_method: str, route_name: str, following: bool, ) -> None: async with pool.acquire() as conn: users_repo = UsersRepository(conn) user = await users_repo.create_user( username="******", email="*****@*****.**", password="******", ) if following: profiles_repo = ProfilesRepository(conn) await profiles_repo.add_user_into_followers( target_user=user, requested_user=test_user) response = await authorized_client.request( api_method, app.url_path_for(route_name, username=user.username)) assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_article_will_contain_only_attached_tags( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, pool: Pool) -> None: attached_tags = ["tag1", "tag3"] async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) await articles_repo.create_article( slug=f"test-slug", title="tmp", description="tmp", body="tmp", author=test_user, tags=attached_tags, ) for i in range(5): await articles_repo.create_article( slug=f"slug-{i}", title="tmp", description="tmp", body="tmp", author=test_user, tags=[f"tag-{i}"], ) response = await authorized_client.get( app.url_path_for("articles:get-article", slug="test-slug")) article = ArticleInResponse(**response.json()) assert len(article.article.tags) == len(attached_tags) assert set(article.article.tags) == set(attached_tags)
async def test_user_successful_login( app: FastAPI, client: AsyncClient, test_user: UserInDB ) -> None: login_json = {"user": {"email": "*****@*****.**", "password": "******"}} response = await client.post(app.url_path_for("auth:login"), json=login_json) assert response.status_code == HTTP_200_OK
async def test_user_can_update_article( app: FastAPI, authorized_client: AsyncClient, test_article: Article, update_field: str, update_value: str, extra_updates: dict, ) -> None: # type: ignore response = await authorized_client.put( app.url_path_for("articles:update-article", slug=test_article.slug), json={"article": { update_field: update_value }}, ) assert response.status_code == status.HTTP_200_OK article = ArticleInResponse(**response.json()).article article_as_dict = article.dict() assert article_as_dict[update_field] == update_value for extra_field, extra_value in extra_updates.items(): assert article_as_dict[extra_field] == extra_value exclude_fields = {update_field, *extra_updates.keys(), "updated_at"} assert article.dict(exclude=exclude_fields) == test_article.dict( exclude=exclude_fields)
async def test_user_can_retrieve_article_if_exists( app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: response = await authorized_client.get( app.url_path_for("articles:get-article", slug=test_article.slug)) article = ArticleInResponse(**response.json()) assert article.article == test_article
def override_fastapi_openapi_method(app: FastAPI): # pylint: disable=protected-access app._original_openapi = types.MethodType(copy_func(app.openapi), app) # type: ignore def _custom_openapi_method(self: FastAPI) -> Dict: """Overrides FastAPI.openapi member function returns OAS schema with vendor extensions """ # NOTE: see fastapi.applications.py:FastApi.openapi(self) implementation if not self.openapi_schema: self.openapi_schema = self._original_openapi() # type: ignore _patch_openapi_specs(self.openapi_schema) return self.openapi_schema app.openapi = types.MethodType(_custom_openapi_method, app)
async def test_unable_to_login_with_wrong_jwt_prefix(app: FastAPI, client: AsyncClient, token: str) -> None: response = await client.get( app.url_path_for("users:get-current-user"), headers={"Authorization": f"WrongPrefix {token}"}, ) assert response.status_code == HTTP_403_FORBIDDEN
async def test_unable_to_login_when_user_does_not_exist_any_more( app: FastAPI, client: AsyncClient, authorization_prefix: str) -> None: token = create_access_token_for_user( User(username="******", email="*****@*****.**"), "secret") response = await client.get( app.url_path_for("users:get-current-user"), headers={"Authorization": f"{authorization_prefix} {token}"}, ) assert response.status_code == HTTP_403_FORBIDDEN
async def test_user_receiving_feed_with_limit_and_offset( app: FastAPI, authorized_client: AsyncClient, test_article: Article, test_user: UserInDB, pool: Pool, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) profiles_repo = ProfilesRepository(connection) articles_repo = ArticlesRepository(connection) for i in range(5): user = await users_repo.create_user(username=f"user-{i}", email=f"user-{i}@email.com", password="******") if i == 2: await profiles_repo.add_user_into_followers( target_user=user, requested_user=test_user) for j in range(5): await articles_repo.create_article( slug=f"slug-{i}-{j}", title="tmp", description="tmp", body="tmp", author=user, tags=[f"tag-{i}-{j}"], ) full_response = await authorized_client.get( app.url_path_for("articles:get-user-feed-articles")) full_articles = ListOfArticlesInResponse(**full_response.json()) response = await authorized_client.get( app.url_path_for("articles:get-user-feed-articles"), params={ "limit": 2, "offset": 3 }, ) articles_from_response = ListOfArticlesInResponse(**response.json()) assert full_articles.articles[3:] == articles_from_response.articles
async def test_user_can_not_retrieve_not_existing_article( app: FastAPI, authorized_client: AsyncClient, test_article: Article, api_method: str, route_name: str, ) -> None: response = await authorized_client.request( api_method, app.url_path_for(route_name, slug="wrong-slug")) assert response.status_code == status.HTTP_404_NOT_FOUND
def setup_app(app: FastAPI): BASEDIR = os.path.dirname(os.path.realpath(__file__)) PHOTO_PATH = os.path.join(BASEDIR, 'photo/') app.photo_path = { 'beer': os.path.join(PHOTO_PATH, 'beer'), 'wine': os.path.join(PHOTO_PATH, 'wine'), 'vodka': os.path.join(PHOTO_PATH, 'vodka'), }
async def test_user_will_receive_error_for_not_existing_comment( app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: not_found_response = await authorized_client.delete( app.url_path_for( "comments:delete-comment-from-article", slug=test_article.slug, comment_id="1", )) assert not_found_response.status_code == status.HTTP_404_NOT_FOUND
async def test_user_can_not_change_following_state_for_him_self( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, api_method: str, route_name: str, ) -> None: response = await authorized_client.request( api_method, app.url_path_for(route_name, username=test_user.username)) assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_user_login_when_credential_part_does_not_match( app: FastAPI, client: AsyncClient, test_user: UserInDB, credentials_part: str, credentials_value: str, ) -> None: login_json = {"user": {"email": "*****@*****.**", "password": "******"}} login_json["user"][credentials_part] = credentials_value response = await client.post(app.url_path_for("auth:login"), json=login_json) assert response.status_code == HTTP_400_BAD_REQUEST
async def test_user_can_add_comment_for_article(app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: created_comment_response = await authorized_client.post( app.url_path_for("comments:create-comment-for-article", slug=test_article.slug), json={"comment": { "body": "comment" }}, ) created_comment = CommentInResponse(**created_comment_response.json()) comments_for_article_response = await authorized_client.get( app.url_path_for("comments:get-comments-for-article", slug=test_article.slug)) comments = ListOfCommentsInResponse(**comments_for_article_response.json()) assert created_comment.comment == comments.comments[0]
async def test_user_can_not_create_article_with_duplicated_slug( app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: article_data = { "title": "Test Slug", "body": "does not matter", "description": "¯\\_(ツ)_/¯", } response = await authorized_client.post( app.url_path_for("articles:create-article"), json={"article": article_data}) assert response.status_code == status.HTTP_400_BAD_REQUEST
def create_dynamic_router(schema: Schema, app: FastAPI, old_slug: str = None): router = APIRouter() route_get_entities(router=router, schema=schema) route_get_entity(router=router, schema=schema) route_create_entity(router=router, schema=schema) route_update_entity(router=router, schema=schema) route_delete_entity(router=router, schema=schema) router_routes = [(r.path, r.methods) for r in router.routes] routes_to_remove = [] for route in app.routes: if (route.path, route.methods) in router_routes: routes_to_remove.append(route) elif old_slug and (route.path.startswith(f'/entity/{old_slug}/') or route.path == f'/entity/{old_slug}'): routes_to_remove.append(route) for route in routes_to_remove: app.routes.remove(route) app.include_router(router, prefix='/entity') app.openapi_schema = None
async def test_list_of_tags_when_tags_exist( app: FastAPI, client: AsyncClient, pool: Pool ) -> None: tags = ["tag1", "tag2", "tag3", "tag4", "tag1"] async with pool.acquire() as conn: tags_repo = TagsRepository(conn) await tags_repo.create_tags_that_dont_exist(tags=tags) response = await client.get(app.url_path_for("tags:get-all")) tags_from_response = response.json()["tags"] assert len(tags_from_response) == len(set(tags)) assert all((tag in tags for tag in tags_from_response))