async def test_create_comment(self): comment = {**INIT_DATA.get("comment", [])[0]} async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.post(API_ROOT, data=json.dumps(comment)) expected = { "success": False, "comment": {}, "detail": "Comment owner doesn't exist", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected await Person.create(**INIT_DATA.get("person", [])[0]) async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.post(API_ROOT, data=json.dumps(comment)) actual = response.json() comment["user_id"] = comment.pop("user") expected = { "success": True, "comment": { "id": 1, **{ k if k not in ("user", "top_parent", "parent") else f"{k}_id": v for k, v in comment.items() }, "edited": actual["comment"]["edited"], }, "detail": "Comment successfully created", } assert response.status_code == status.HTTP_201_CREATED assert response.json() == expected
async def test_get_comments(self): async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT) expected = {"detail": "Not Found", "success": False, "comments": []} assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected # Insert new Comment comment_inserted = {**INIT_DATA.get("comment", [])[0]} await self.insert_comments([comment_inserted], [INIT_DATA.get("person", [])[0]]) async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT) actual = response.json() expected = { "next": None, "previous": None, "success": True, "comments": [{ "id": 1, "user_id": 1, "added": comment_inserted["added"], "edited": actual["comments"][0]["edited"], "votes": actual["comments"][0]["votes"], "nb_children": actual["comments"][0]["nb_children"], "content": comment_inserted["content"], "top_parent_id": comment_inserted["top_parent"], "parent_id": comment_inserted["parent"], "owner_fullname": actual["comments"][0]["owner_fullname"], }], } assert response.status_code == status.HTTP_200_OK assert expected == actual
async def test_add_owner_fullname(self): await API_functools.insert_default_data(table="person", quantity=2) data = list( map( lambda cmt: { **{ k: v for k, v in cmt.items() if k not in ("user", "parent", "top_parent") }, "user_id": cmt["user"], "parent_id": cmt["parent"], "top_parent_id": cmt["top_parent"], }, INIT_DATA.get("comment", [])[:2], )) actual = await API_functools.add_owner_fullname(data) expected = list( map( lambda cmt: { **cmt[1], "owner_fullname": actual[cmt[0]]["owner_fullname"], }, enumerate(data), )) assert actual == expected
async def test_get_children(self): # insert data await API_functools.insert_default_data( data={ "person": INIT_DATA.get("person", [])[:20], "comment": INIT_DATA.get("comment", [])[:20], }) comment = await Comment.filter(id=1).first() expected_children_IDs = list( filter( lambda c: c is not None, map( lambda tpl: tpl[0] if tpl[1]["parent"] == comment.id else None, enumerate(INIT_DATA.get("comment", [])[:20], start=1), ), )) expected_deep_children_IDs = list( filter( lambda c: c is not None, map( lambda tpl: tpl[0] if tpl[1]["top_parent"] == comment.id else None, enumerate(INIT_DATA.get("comment", [])[:20], start=1), ), )) actual_children_IDs = tuple(map(lambda c: c.id, await comment.children)) actual_json_children_IDs = tuple( map(lambda c: c["id"], await comment.json_children(["id"]))) assert len(actual_children_IDs) and len( actual_json_children_IDs) == len(expected_children_IDs) actual_children_IDs and actual_json_children_IDs == expected_children_IDs # test deep children actual_children_IDs = tuple(map(lambda c: c.id, await comment.children)) actual_json_children_IDs = tuple( map(lambda c: c["id"], await comment.json_children(["id"], deep=True))) assert len(actual_children_IDs) and len( actual_json_children_IDs) == len(expected_deep_children_IDs) (actual_children_IDs and actual_json_children_IDs) == expected_deep_children_IDs
async def test_patch_comment(self): comment_ID = 1 comment_to_update = {**INIT_DATA.get("comment", [])[0]} comment_content = { "content": INIT_DATA.get("comment", [])[1]["content"] } # Comment doesn't exist async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.patch(f"{API_ROOT}{comment_ID}", data=json.dumps(comment_content)) expected = { "success": False, "comment": {}, "detail": f"Comment with ID {comment_ID} doesn't exist.", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected # Insert new Comment await self.insert_comments([comment_to_update], [INIT_DATA.get("person", [])[0]]) # patch comment content async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.patch(f"{API_ROOT}{comment_ID}", data=json.dumps(comment_content)) comment_to_update["user_id"] = comment_to_update.pop("user") comment_to_update["top_parent_id"] = comment_to_update.pop( "top_parent", None) comment_to_update["parent_id"] = comment_to_update.pop("parent", None) comment_to_update["id"] = 1 actual = response.json() assert response.status_code == status.HTTP_202_ACCEPTED assert actual == { "success": True, "comment": { **comment_to_update, "edited": actual["comment"]["edited"], "content": comment_content["content"], }, "detail": "Comment successfully patched", }
async def test_delete_comment(self): # Comment doesn't exist comment_ID = 1 async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.delete(f"{API_ROOT}{comment_ID}") expected = { "success": False, "comment": {}, "detail": f"Comment with ID {comment_ID} doesn't exist", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected # Insert new Comment comment_to_delete = {**INIT_DATA.get("comment", [])[0]} await self.insert_comments([comment_to_delete], [INIT_DATA.get("person", [])[0]]) assert await Comment.all().count() == 1 async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.delete(f"{API_ROOT}{comment_ID}") comment_to_delete["user_id"] = comment_to_delete.pop("user", 1) actual = response.json() expected = { "success": True, "comment": { **{ k if k not in ("user", "top_parent", "parent") else f"{k}_id": v for k, v in comment_to_delete.items() }, "edited": actual["comment"]["edited"], "id": comment_ID, }, "detail": f"Comment {comment_ID} deleted successfully тнР", } assert response.status_code == status.HTTP_202_ACCEPTED assert actual == expected assert await Comment.filter(id=comment_ID).first() is None
async def test_instance_of(self): obj = await Person.create(**INIT_DATA.get("person", [])[0]) elements = { "Hello World": str, 1: int, obj: Person, (1, 2, 3, 4): tuple, } for el, instance in elements.items(): assert API_functools.instance_of(el, instance) is True assert API_functools.instance_of("Hello", int) is False
async def test__str__repr__(self): user = await Person.create(**INIT_DATA.get("person", [])[0]) comment = await Comment.create(user=user, content=lorem) expected_repr = "Class({!r})[{!r}]".format( comment.__class__.__name__, comment.content[:10], ) expected_str = "{!s}({!s})".format(comment.__class__.__name__, comment.content[:10]) assert comment.__repr__() == expected_repr assert comment.__str__() == expected_str
async def test_insert_default_data(self): nb_users_inserted = 4 await API_functools.insert_default_data( table="person", data=[*INIT_DATA.get("person", [])[:nb_users_inserted]], ) with pytest.raises(ValueError): await API_functools.insert_default_data( table="person", data=None, ) assert await Person.all().count() == nb_users_inserted
async def test_get_comments_only_parents(self): comments = INIT_DATA.get("comment", [])[:20] # insert data await API_functools.insert_default_data( data={ "person": INIT_DATA.get("person", [])[:20], "comment": comments, }) async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(f"{API_ROOT}?parents=1") actual = response.json() expected = { "next": None, "previous": None, "success": True, "comments": [{ "id": actual["comments"][pk - 1]["id"], **{ k if k not in ("user", "top_parent", "parent") else f"{k}_id": v for k, v in cmt.items() }, "edited": actual["comments"][pk - 1]["edited"], "votes": actual["comments"][pk - 1]["votes"], "nb_children": actual["comments"][pk - 1]["nb_children"], "owner_fullname": actual["comments"][pk - 1]["owner_fullname"], } for pk, cmt in enumerate( filter(lambda c: c["parent"] is None, comments), start=1)], } assert response.status_code == status.HTTP_200_OK assert actual == expected
async def test__insert_default_data(self): # Insert a Person user_to_create = INIT_DATA.get("person", [])[0] user_created = await API_functools._insert_default_data( "person", user_to_create) assert API_functools.instance_of(user_created, Person) is True # Insert a Comment comment_to_create = { **INIT_DATA.get("comment", [])[0], "user": user_created.id, } comment_created = await API_functools._insert_default_data( "comment", comment_to_create) assert API_functools.instance_of(comment_created, Comment) is True # Insert a Vote vote_to_create = { "user": user_created.id, "comment": comment_created.id, } vote_created = await API_functools._insert_default_data( "vote", vote_to_create) assert API_functools.instance_of(vote_created, Vote) is True
async def test_tortoise_to_dict(self): actual = API_functools.tortoise_to_dict( await Person(**INIT_DATA.get("person", [])[0])) actual["date_of_birth"] = jsonable_encoder(actual["date_of_birth"]) assert actual == { "avatar": avatar, "company": "Edgetag", "country_of_birth": "Egypt", "date_of_birth": "1978-04-15", "email": "*****@*****.**", "first_name": "Shalom", "gender": "Male", "id": None, "is_admin": True, "job": "Compensation Analyst", "last_name": "Handes", }
async def test_get_comments_with_limit_offset(self): limit = 4 offset = 0 comments = [*INIT_DATA.get("comment", [])[:limit + 4]] users = INIT_DATA.get("person", [])[:limit + 4] await self.insert_comments(comments, users) assert await Comment.all().count() == len(comments) # Scene 1 get first data, previous=Null async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={ "limit": limit, "offset": offset }) actual = response.json() expected = { "next": f"{API_ROOT}?limit={limit}&offset={limit}", "previous": None, "success": True, "comments": [{ "id": n, "added": comment["added"], "edited": actual["comments"][n - 1]["edited"], "content": comment["content"], "votes": actual["comments"][n - 1]["votes"], "nb_children": actual["comments"][n - 1]["nb_children"], "user_id": comment["user"], "top_parent_id": comment["top_parent"], "parent_id": comment["parent"], "owner_fullname": actual["comments"][n - 1]["owner_fullname"], } for n, comment in enumerate(comments[:limit], start=1)], } assert response.status_code == status.HTTP_200_OK assert actual == expected # Scene 2 get last data, next=Null async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={ "limit": limit, "offset": limit }) actual = response.json() expected = { "next": None, "previous": f"{API_ROOT}?limit={limit}&offset={offset}", "success": True, "comments": [{ "id": n + limit + 1, "added": comment["added"], "edited": actual["comments"][n]["edited"], "content": comment["content"], "votes": actual["comments"][n]["votes"], "nb_children": actual["comments"][n]["nb_children"], "user_id": comment["user"], "top_parent_id": comment["top_parent"], "parent_id": comment["parent"], "owner_fullname": actual["comments"][n]["owner_fullname"], } for n, comment in enumerate(comments[limit:], start=0)], } assert response.status_code == status.HTTP_200_OK assert actual == expected limit = 0 offset = -1 # Test bad limit and offset values async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={ "limit": limit, "offset": limit }) expected = { "success": False, "comments": [], "detail": "Invalid values: offset(>=0) or limit(>0)", } assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == expected
async def test_put_comment(self): comment_ID = 1 comment_to_update = {**INIT_DATA.get("comment", [])[0]} comment_new_data = { "content": INIT_DATA.get("comment", [])[1]["content"], "user": INIT_DATA.get("comment", [])[1]["user"], } # test owner doesn't exist async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.put( f"{API_ROOT}{comment_ID}", data=json.dumps(comment_new_data), ) expected = { "success": False, "comment": {}, "detail": "Comment owner doesn't exist.", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected await API_functools.insert_default_data("person", quantity=2) # test comment doesn't exist async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.put( f"{API_ROOT}{comment_ID}", data=json.dumps(comment_new_data), ) expected = { "success": False, "comment": {}, "detail": f"Comment with ID {comment_ID} doesn't exist.", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected # Insert new Comment await self.insert_comments([comment_to_update]) # Get first comment async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.put( f"{API_ROOT}{comment_ID}", data=json.dumps(comment_new_data), ) comment_to_update.pop("user", None) comment_to_update["top_parent_id"] = comment_to_update.pop( "top_parent", None) comment_to_update["parent_id"] = comment_to_update.pop("parent", None) comment_new_data["user_id"] = comment_new_data.pop("user", 2) actual = response.json() expected = { "success": True, "comment": { **comment_to_update, **comment_new_data, "id": 1, "edited": actual["comment"]["edited"], }, "detail": "Comment successfully updated", } assert response.status_code == status.HTTP_202_ACCEPTED assert actual == expected
async def test_get_comment_by_user(self): # Inserted 4 comment with ID 1 as user owner owner_ID = 1 comments = tuple( map( lambda cm: { **cm, "user": owner_ID }, [*INIT_DATA.get("comment", [])[:4]], )) await self.insert_comments( comments, INIT_DATA.get("person", [])[:2], ) # owner doesn't exist async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(f"{API_ROOT}user/3") expected = { "success": False, "comments": [], "detail": "Comment owner doesn't exist", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected # Not Found async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(f"{API_ROOT}user/2") expected = { "success": False, "comments": [], "detail": "Not Found", } assert response.status_code == status.HTTP_404_NOT_FOUND assert response.json() == expected async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(f"{API_ROOT}user/{owner_ID}") actual = response.json() expected_comments = [{ **{ k if k not in ("user", "top_parent", "parent") else f"{k}_id": v for k, v in cm.items() }, "id": pk, "edited": actual["comments"][pk - 1]["edited"], "votes": actual["comments"][pk - 1]["votes"], "nb_children": actual["comments"][pk - 1]["nb_children"], "owner_fullname": actual["comments"][pk - 1]["owner_fullname"], } for pk, cm in enumerate(comments, start=1)] expected = { "next": None, "previous": None, "success": True, "comments": expected_comments, } assert response.status_code == status.HTTP_200_OK assert len(actual["comments"]) == 4 assert actual == expected
async def test_get_comment_by_ID(self): comment_ID = 1 comment = {**INIT_DATA.get("comment", [])[0]} # Not found async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(f"{API_ROOT}{comment_ID}") expected = {"success": False, "comment": {}, "detail": "Not Found"} assert response.status_code == 404 assert response.json() == expected # Insert new Comment await self.insert_comments([comment], [INIT_DATA.get("person", [])[0]]) expected_comment = await Comment.get(pk=comment_ID) async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(f"{API_ROOT}{comment_ID}") actual = response.json() comment["user_id"] = comment.pop("user", 1) expected = { "success": True, "comment": { **{ k if k not in ("user", "top_parent", "parent") else f"{k}_id": v for k, v in comment.items() }, "id": expected_comment.id, "edited": expected_comment.edited.isoformat(), "votes": actual["comment"]["votes"], "nb_children": actual["comment"]["nb_children"], "owner_fullname": actual["comment"]["owner_fullname"], }, "detail": "Successful operation", } assert response.status_code == 200 assert actual == expected # insert some comments data comments = INIT_DATA.get("comment", [])[1:20] await self.insert_comments(comments, INIT_DATA.get("person", [])[1:20]) # Test Get comment children async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get( f"{API_ROOT}{expected_comment.id}?children=true") actual = response.json() expected_children = await expected_comment.json_children() expected.pop("comment", None) expected.pop("detail", None) expected["previous"] = None expected["next"] = None expected["comments"] = expected_children # Test Get comment children bad sort attribute async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get( f"{API_ROOT}{expected_comment.id}?children=true&sort=invalid:asc" ) actual = response.json() expected_children = await expected_comment.json_children() expected.pop("comment", None) expected.pop("detail", None) expected["previous"] = None expected["next"] = None expected["comments"] = expected_children assert response.status_code == status.HTTP_400_BAD_REQUEST assert actual == { "success": False, "comments": [], "detail": invalid_sort_detail }
async def test_comments_sorted_by_attribute(self): # sort by user id ascending order content_asc = "content:asc" # sort by date added descending order added_desc = "added:desc" data_nbr = 4 comments = [*INIT_DATA.get("comment", [])[:data_nbr]] users = INIT_DATA.get("person", [])[:data_nbr] await self.insert_comments(comments, users) assert await Comment.all().count() == data_nbr # Test order by content ASC async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={"sort": content_asc}) actual = response.json() comments = sorted( comments, key=lambda u: u[content_asc.split(":")[0]], ) expected = { "next": None, "previous": None, "success": True, "comments": [{ "id": actual["comments"][n]["id"], "added": c["added"], "edited": actual["comments"][n]["edited"], "content": c["content"], "votes": actual["comments"][n]["votes"], "nb_children": actual["comments"][n]["nb_children"], "user_id": c["user"], "top_parent_id": c["top_parent"], "parent_id": c["parent"], "owner_fullname": actual["comments"][n]["owner_fullname"], } for n, c in enumerate(comments, start=0)], } assert response.status_code == status.HTTP_200_OK assert actual == expected # Test order by added DESC async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={"sort": added_desc}) actual = response.json() comments = sorted(comments, key=lambda u: u[added_desc.split(":")[0]], reverse=True) expected = { "next": None, "previous": None, "success": True, "comments": [{ "id": actual["comments"][n]["id"], "added": c["added"], "edited": actual["comments"][n]["edited"], "content": c["content"], "votes": actual["comments"][n]["votes"], "nb_children": actual["comments"][n]["nb_children"], "user_id": c["user"], "top_parent_id": c["top_parent"], "parent_id": c["parent"], "owner_fullname": actual["comments"][n]["owner_fullname"], } for n, c in enumerate(comments, start=0)], } assert response.status_code == status.HTTP_200_OK assert actual == expected # Test bad order by order_by = "undefined:asc" async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={"sort": order_by}) expected = { "success": False, "comments": [], "detail": invalid_sort_detail, } assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == expected
async def test_users_sorted_by_attribute(self): # sort by first_name ascending order asc = "first_name:asc" # sort by first_name descending order desc = "first_name:desc" users = INIT_DATA.get("person", [])[:4] with futures.ProcessPoolExecutor() as executor: for user in users: executor.map(await API_functools._insert_default_data( "person", user)) assert await Person.all().count() == len(users) # Test order by first_name ASC async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={"sort": asc}) expected = { "next": None, "previous": None, "success": True, "users": sorted( [{ "id": n, **user } for n, user in enumerate(users, start=1)], key=lambda u: u[asc.split(":")[0]], ), } assert response.status_code == status.HTTP_200_OK assert response.json() == expected # Test order by first_name DESC async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={"sort": desc}) expected = { "next": None, "previous": None, "success": True, "users": sorted( [{ "id": n, **user } for n, user in enumerate(users, start=1)], key=lambda u: u[desc.split(":")[0]], reverse=True, ), } assert response.status_code == status.HTTP_200_OK assert response.json() == expected # Test bad order by order_by = "undefined:asc" async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={"sort": order_by}) detail = "Invalid sort parameters. it must match \ attribute:order. ex: id:asc or id:desc" expected = { "success": False, "users": [], "detail": detail, } assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == expected
async def test_get_users_with_limit_offset(self): limit = 5 offset = 0 users = INIT_DATA.get("person", [])[:10] # Insert data with futures.ProcessPoolExecutor() as executor: for user in users: executor.map(await API_functools._insert_default_data( "person", user)) assert await Person.all().count() == len(users) # Scene 1 get first data, previous=Null async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={ "limit": limit, "offset": offset }) expected = { "next": f"{API_ROOT}?limit={limit}&offset={limit}", "previous": None, "success": True, "users": [{ "id": n, **user } for n, user in enumerate(users[:limit], start=1)], } assert response.status_code == status.HTTP_200_OK assert response.json() == expected # Scene 2 get last data, next=Null async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={ "limit": limit, "offset": limit }) expected = { "next": None, "previous": f"{API_ROOT}?limit={limit}&offset={offset}", "success": True, "users": [{ "id": n, **user } for n, user in enumerate(users[limit:], start=limit + 1)], } assert response.status_code == status.HTTP_200_OK assert response.json() == expected limit = 0 offset = -1 # Test bad limit and offset values async with AsyncClient(app=app, base_url=BASE_URL) as ac: response = await ac.get(API_ROOT, params={ "limit": limit, "offset": limit }) expected = { "success": False, "users": [], "detail": "Invalid values: offset(>=0) or limit(>0)", } assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == expected