async def test_create_user_as_supervisor(users, supervisor1_client): new_user = get_fake_user() new_user.pop("id") # Valid res = await supervisor1_client.post("/users", json=new_user) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) all_users = await User.query.gino.all() assert len(all_users) == len(users) + 1 assert profile_created_from_origin(new_user, all_users[-1].to_dict()) # Valid new_user = get_fake_user() new_user.pop("id") res = await supervisor1_client.post("/users", json=new_user) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) all_users = await User.query.gino.all() assert len(all_users) == len(users) + 2 assert profile_created_from_origin(new_user, all_users[-1].to_dict()) # Create an existing user res = await supervisor1_client.post("/users", json=new_user) assert res.status == 400
async def test_create_visitor_without_token(client, visitors): new_visitor = get_fake_visitor() new_visitor.pop("id") # Missing token res = await client.post("/visitors", json=new_visitor) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) all_visitors = await Visitor.query.gino.all() assert len(all_visitors) == len(visitors) + 1 assert profile_created_from_origin(new_visitor, all_visitors[-1].to_dict()) # Valid new_user = get_fake_visitor() new_user.pop("id") res = await client.post("/visitors", json=new_user) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) all_users = await Visitor.query.gino.all() assert len(all_users) == len(visitors) + 2 assert profile_created_from_origin(new_user, all_users[-1].to_dict()) # Create an existing user res = await client.post("/visitors", json=new_user) assert res.status == 400
async def test_get_flagged_chats_of_online_visitors(supervisor1_client): # Create some visitors visitors = [] chats = [] for _ in range(30): new_visitor = get_fake_visitor() new_visitor.pop("id") res = await supervisor1_client.post("/visitors", json=new_visitor) assert res.status == 200 body = await res.json() visitors.append(body["data"]) chat = await Chat.get_or_create(visitor_id=body["data"]["id"]) chats.append(chat) # Flag some chats index = 7 for visitor in visitors[7:26]: chat = await Chat.get_or_create(visitor_id=visitor["id"]) sleep(0.001) updated_chat = await Chat.modify( {"id": chat["id"]}, {"severity_level": DEFAULT_SEVERITY_LEVEL_OF_CHAT + 1}) chats[index] = updated_chat index += 1 # Get the first 15 flagged chats online_visitors = [visitor["id"] for visitor in visitors] flagged_chats = await get_flagged_chats_of_online_visitors( Visitor, Chat, in_values=online_visitors) assert len(flagged_chats) == 15 for expected, visitor in zip(reversed(visitors[11:26]), flagged_chats): # room = flag_chat["room"] # visitor = flag_chat["visitor"] # Compare chat = await Chat.get(visitor_id=visitor["id"]) # assert profile_created_from_origin(room, chat) # assert profile_created_from_origin(expected, visitor) assert profile_created_from_origin({**chat, **expected}, visitor) # Unflag some chats for chat in chats[11:25]: await Chat.modify({"id": chat["id"]}, {"severity_level": DEFAULT_SEVERITY_LEVEL_OF_CHAT}) # Get the remained flagged chats flagged_chats = await get_flagged_chats_of_online_visitors( Visitor, Chat, in_values=online_visitors) assert len(flagged_chats) == 5 for expected, visitor in zip(reversed(visitors[7:11] + visitors[25:26]), flagged_chats): # room = flag_chat["room"] # visitor = flag_chat["user"] # Compare chat = await Chat.get(visitor_id=visitor["id"]) # assert profile_created_from_origin(room, chat) # assert profile_created_from_origin(expected, visitor) assert profile_created_from_origin({**chat, **expected}, visitor)
async def test_get_chat_messages_as_supervisor(supervisor1_client, visitors, users): visitor_id = visitors[-1]["id"] # Create some dummy chat messages chat = await Chat.add(visitor_id=visitor_id) messages = [] for sequence_num in range(1, 25): content = {"value": fake.sentence(nb_words=10)} sender = users[-6]["id"] if randint(0, 1) else None chat_msg = { "chat_id": chat["id"], "sequence_num": sequence_num, "content": content, "sender": sender, } await ChatMessage.add(**chat_msg) chat_msg["sender"] = users[-6] if sender else None messages.append(chat_msg) # Try getting the chat messages res = await supervisor1_client.get( "/visitors/{}/messages".format(visitor_id)) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 15 # The limit for expected, actual in zip(messages[9:], body["data"]): assert profile_created_from_origin(expected, actual, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], actual["sender"]) # Ensure that getting the next messages work too prev_page_link = get_prev_page_link(body) res = await supervisor1_client.get(prev_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 9 for expected, actual in zip(messages[:9], body["data"]): assert profile_created_from_origin(expected, actual, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], actual["sender"]) # Ensure that getting the next messages are empty prev_page_link = get_prev_page_link(body) res = await supervisor1_client.get(prev_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert not body["data"] assert isinstance(body["links"], dict) assert not body["links"]
async def test_get_visitor_bookmark_of_staff(supervisor1_client, users): # Create some visitors visitors = [] for _ in range(32): new_visitor = get_fake_visitor() new_visitor.pop("id") res = await supervisor1_client.post("/visitors", json=new_visitor) assert res.status == 200 body = await res.json() visitors.append(body["data"]) # Bookmark some visitors for visitor in visitors: res = await supervisor1_client.patch( "/visitors/{}/bookmark".format(visitor["id"]), json={"is_bookmarked": True} ) assert res.status == 200 visitors = visitors[::-1] # Get the bookmarked visitors res = await supervisor1_client.get("/visitors/bookmarked") body = await res.json() assert res.status == 200 assert "data" in body assert isinstance(body["data"], list) assert "links" in body and "next" in body["links"] assert len(body["data"]) == 15 for expected, actual in zip(visitors[:15], body["data"]): assert profile_created_from_origin(expected, actual) # Next page next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) body = await res.json() assert res.status == 200 assert "data" in body assert isinstance(body["data"], list) assert "links" in body and "next" in body["links"] assert len(body["data"]) == 15 for expected, actual in zip(visitors[15:30], body["data"]): assert profile_created_from_origin(expected, actual) # Last page next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) body = await res.json() assert res.status == 200 assert "data" in body assert isinstance(body["data"], list) assert "links" in body and "next" in body["links"] assert len(body["data"]) == 2 for expected, actual in zip(visitors[30:], body["data"]): assert profile_created_from_origin(expected, actual)
async def test_get_all_agents(users, supervisor1_client): res = await supervisor1_client.get("/users?role_id={}".format( ROLES.inverse["agent"])) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert all(user["role_id"] == ROLES.inverse["agent"] for user in body["data"]) for expected, actual in zip(users[-6:-4], body["data"][-2:]): profile_created_from_origin(expected, actual)
async def test_get_many_visitors(supervisor1_client): # Create some visitors visitors = [] for _ in range(33): new_visitor = get_fake_visitor() new_visitor.pop("id") res = await supervisor1_client.post("/visitors", json=new_visitor) assert res.status == 200 body = await res.json() visitors.append(body["data"]) visitors = visitors[::-1] # Get the visitor (sorted by created order) res = await supervisor1_client.get("/visitors") assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 15 assert "links" in body and "next" in body["links"] for expected, actual in zip(visitors[:15], body["data"]): assert profile_created_from_origin(expected, actual) # Get the next page of visitors next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 15 assert "links" in body and "next" in body["links"] for expected, actual in zip(visitors[15:30], body["data"]): assert profile_created_from_origin(expected, actual) # Get the last page of visitors next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 10 # = 3 (created just now) + 7 (in fixtures) assert "links" in body and "next" in body["links"] for expected, actual in zip(visitors[30:], body["data"]): assert profile_created_from_origin(expected, actual)
async def test_update_one_user_as_supervisor(users, supervisor1_client): new_changes = { "full_name": "this name surely doesnt exist", "password": "******", } # With id res = await supervisor1_client.patch("/users/{}".format(users[0]["id"]), json=new_changes) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) updated_user = await get_one(User, internal_id=1) updated_user = updated_user.to_dict() ## Assert the new password has been updated assert profile_created_from_origin( { **body["data"], "password": hash_password(new_changes["password"]) }, updated_user, ) # User doesnt exist res = await supervisor1_client.patch("/users/{}".format("9" * 32), json=new_changes) assert res.status == 404 # Update to a weak password new_changes = {"password": "******"} res = await supervisor1_client.patch("/users/{}".format(users[1]["id"]), json=new_changes) assert res.status == 400
async def test_update_anonymous_as_self(visitors, anonymous1_client): new_changes = { "name": "this name surely doesnt exist", "password": "******", } # With id res = await anonymous1_client.patch("/visitors/{}".format( visitors[-4]["id"]), json=new_changes) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) updated_user = await get_one(Visitor, id=visitors[-4]["id"]) updated_user = updated_user.to_dict() ## Assert the new password has been updated assert profile_created_from_origin( { **body["data"], "password": hash_password(new_changes["password"]) }, updated_user, ignore={"updated_at"}, )
async def test_get_one_anonymous(visitor1_client, visitors): res = await visitor1_client.get("/visitors/{}".format(visitors[-3]["id"])) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) assert profile_created_from_origin(visitors[-3], body["data"])
async def test_update_user_as_admin(users, admin1_client): new_changes = { "full_name": "this name surely doesnt exist", "password": "******", } res = await admin1_client.patch("/users/{}".format(users[5]["id"]), json=new_changes) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) updated_user = await get_one(User, internal_id=6) updated_user = updated_user.to_dict() ## Assert the new password has been updated assert profile_created_from_origin( { **body["data"], "password": hash_password(new_changes["password"]) }, updated_user, ) # Admin can update supervisor res = await admin1_client.patch("/users/{}".format(users[-3]["id"]), json=new_changes) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) updated_user = await get_one(User, id=users[-3]["id"]) updated_user = updated_user.to_dict() ## Assert the new password has been updated assert profile_created_from_origin( { **body["data"], "password": hash_password(new_changes["password"]) }, updated_user, )
async def test_update_visitor_bookmark(supervisor1_client, visitors, users): visitor_id = visitors[4]["id"] res = await supervisor1_client.patch("/visitors/{}/bookmark".format(visitor_id)) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) assert profile_created_from_origin( {"staff_id": users[-4]["id"], "visitor_id": visitor_id, "is_bookmarked": False}, body["data"], )
async def test_login_visitor(client, visitors): for user in visitors[:-4] + visitors[-2:]: res = await client.post( "/visitor/login", json={ "email": user["email"], "password": user["password"] }, ) assert res.status == 200 body = await res.json() assert isinstance(body, dict) assert "access_token" in body and "refresh_token" not in body assert "user" in body assert "access_token" in res.cookies assert "refresh_token" in res.cookies assert profile_created_from_origin(body["user"], user, ignore={"is_anonymous", "disabled"}) assert not body["user"]["is_anonymous"] assert not body["user"]["disabled"] # Login with wrong password user = visitors[-1] res = await client.post("/visitor/login", json={ "email": user["email"], "password": "******" }) assert res.status == 401 # Login with weak password user = visitors[-1] res = await client.post("/visitor/login", json={ "email": user["email"], "password": "******" }) assert res.status == 401 # Login with missing password user = visitors[-1] res = await client.post("/visitor/login", json={"email": user["email"]}) assert res.status == 400 # Login with missing email user = visitors[-1] res = await client.post("/visitor/login", json={"password": user["password"]}) assert res.status == 400
async def test_get_one_visitor(visitor1_client, visitors): res = await visitor1_client.get("/visitors/{}".format(visitors[2]["id"])) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) assert profile_created_from_origin(visitors[2], body["data"]) # User doesnt exist res = await visitor1_client.get("/visitors/{}".format("9" * 32)) assert res.status == 404 res = await visitor1_client.get("/visitors/true") assert res.status == 404
async def test_visitor_send_first_msg(sio_client_visitor, server_path, token_visitor_1, visitors): # Get the visitor info visitor = await Visitor.get(id=visitors[-1]["id"]) await sio_client_visitor.connect( server_path, headers={"Authorization": token_visitor_1}) chat = await get_one(Chat, visitor_id=visitor["id"]) assert chat is not None assert await cache.exists(chat.id) # Get the queue room org = (await Organisation.query.gino.all())[0] queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id) unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats is None # Get the chat room chat_room = await Chat.get(visitor_id=visitor["id"]) # Send the first message new_content = {"value": "This is the first message"} await sio_client_visitor.call("visitor_first_msg", new_content, timeout=1) # Ensure the cache has the sent message unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats == [{ "user": visitor, "room": chat_room, "contents": [new_content] }] # Check if the message has been updated to backend messages = await ChatMessage.get(chat_id=chat_room["id"]) assert len(messages) == 1 assert profile_created_from_origin( { "sequence_num": 1, "chat_id": chat_room["id"], "type_id": 1, "content": new_content, "sender": None, }, messages[0], ) await sio_client_visitor.disconnect()
async def test_login_user(client, users): for user in users[-4:-1]: res = await client.post("/login", json={ "email": user["email"], "password": user["password"] }) assert res.status == 200 body = await res.json() assert isinstance(body, dict) assert "access_token" in body and "refresh_token" not in body assert "user" in body assert "access_token" in res.cookies assert "refresh_token" in res.cookies assert profile_created_from_origin(user, body["user"]) # Login with wrong password user = users[-1] res = await client.post("/login", json={ "email": user["email"], "password": "******" }) assert res.status == 401 # Login with weak password user = users[-1] res = await client.post("/login", json={ "email": user["email"], "password": "******" }) assert res.status == 401 # Login with missing password user = users[-1] res = await client.post("/login", json={"email": user["email"]}) assert res.status == 400 # Login with missing email user = users[-1] res = await client.post("/login", json={"password": user["password"]}) assert res.status == 400
async def test_login_anonymous(client): """Anonymous login means creating a new accoun""" res = await client.post("/anonymous/login", json={"name": "George"}) assert res.status == 200 body = await res.json() assert isinstance(body, dict) assert "access_token" in body and "refresh_token" not in body assert "user" in body assert "access_token" in res.cookies assert "refresh_token" in res.cookies assert profile_created_from_origin( body["user"], { "name": "George", "is_anonymous": True, "email": None, "disabled": False }, ignore={"id"}, )
async def test_get_users_with_after_id(users, supervisor1_client): # Use after_id in query parameter. res = await supervisor1_client.get("/users?after_id={}".format( users[2]["id"])) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 8 # Check if all profiles match from id 4 to 19 assert all( profile_created_from_origin(origin, created) for origin, created in zip(users[3:20], body["data"])) # Invalid after_id res = await supervisor1_client.get("/users?after_id=2") assert res.status == 404 res = await supervisor1_client.get("/users?after_id=") assert res.status == 400
async def test_update_visitor_bookmark_existing(supervisor1_client, visitors, users): visitor_id = visitors[4]["id"] # A bookmark will be auto created on GET/UPDATE res = await supervisor1_client.get( "/visitors/{}/bookmark".format(visitors[2]["id"]) ) assert res.status == 200 res = await supervisor1_client.patch( "/visitors/{}/bookmark".format(visitor_id), json={"is_bookmarked": True} ) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], dict) assert profile_created_from_origin( {"staff_id": users[-4]["id"], "visitor_id": visitor_id, "is_bookmarked": True}, body["data"], )
async def test_get_visitors_most_recent(users, supervisor1_client): # Create a lot more visitors to test visitors = [get_fake_visitor() for _ in range(32)] for visitor in visitors: _visitor = deepcopy(visitor) # Anonymous users don't have passwords if "password" in _visitor: _visitor["password"] = hash_password(_visitor["password"]) await Visitor(**_visitor).create() # Create some dummy chat messages created_at = 1 staff = users[-5] for visitor in visitors[::-1]: chat = await Chat.add(visitor_id=visitor["id"]) for sequence_num in range(3): content = {"content": fake.sentence(nb_words=10)} chat_msg = { "chat_id": chat["id"], "sequence_num": sequence_num, "content": content, "sender": None, "created_at": created_at, } created_at += 1 await ChatMessage.add(**chat_msg) # Let a staff send a message, as staffs can only fetch visitors # that chatted with the staffs from his org await ChatMessage.add( **{ "chat_id": chat["id"], "sequence_num": sequence_num + 1, "content": { "content": fake.sentence(nb_words=10) }, "sender": staff["id"], "created_at": created_at, }) # Get the most recent visitors that chatted with the staffs from org res = await supervisor1_client.get("/visitors/most_recent") assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 15 assert "links" in body and "next" in body["links"] for expected, actual in zip(visitors, body["data"]): assert profile_created_from_origin(expected, actual) # Ensure that the next links work as well next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 15 assert "links" in body and "next" in body["links"] for expected, actual in zip(visitors[15:], body["data"]): assert profile_created_from_origin(expected, actual) # Last page next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) assert res.status == 200 assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 2 assert "links" in body and "next" in body["links"] for expected, actual in zip(visitors[30:], body["data"]): assert profile_created_from_origin(expected, actual)
async def test_visitor_send_msg_before_a_staff_join( sio_client_visitor, server_path, token_visitor_1, sio_client_agent1, token_agent_1, visitors, ): # Get the visitor info visitor = await Visitor.get(id=visitors[-1]["id"]) await sio_client_visitor.connect( server_path, headers={"Authorization": token_visitor_1}) # Get the queue room org = (await Organisation.query.gino.all())[0] queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id) unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats is None # Get the chat room chat_room = await Chat.get(visitor_id=visitor["id"]) # Send the first message new_content = {"value": "This is the first message"} await sio_client_visitor.call("visitor_first_msg", new_content) # A staff connects and receive the message await sio_client_agent1.connect(server_path, headers={"Authorization": token_agent_1}) await sio_client_agent1.sleep(1) # Assert no errors are raised when the staff connects excs = await cache.get("exceptions", []) assert not excs # Visitor sends another message (chat is still unclaimed) second_content = {"value": "Second message"} await sio_client_visitor.call("visitor_msg_unclaimed", second_content) # Check if the message has been updated to backend messages = await ChatMessage.get(chat_id=chat_room["id"]) assert len(messages) == 2 expected_msgs = [ { "sequence_num": 1, "chat_id": chat_room["id"], "type_id": 1, "content": new_content, "sender": None, }, { "sequence_num": 2, "chat_id": chat_room["id"], "type_id": 1, "content": second_content, "sender": None, }, ] for expected, message in zip(expected_msgs, messages): assert profile_created_from_origin(expected, message) # Ensure that the chat in queue room is also updated unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats == [{ "user": visitor, "room": chat_room, "contents": [new_content, second_content] }] # Assert no errors are raised when the visitor sends the 2nd msg excs = await cache.get("exceptions", []) assert not excs await sio_client_visitor.disconnect() await sio_client_agent1.disconnect()
async def test_visitor_second_session( sio_client_visitor, server_path, token_visitor_1, sio_client_agent1, token_agent_1, visitors, users, ): # Get the visitor info visitor = await Visitor.get(id=visitors[-1]["id"]) agent = await User.get(id=users[-6]["id"]) # Get the queue room org = (await Organisation.query.gino.all())[0] queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id) unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats is None # A staff connects first await sio_client_agent1.connect(server_path, headers={"Authorization": token_agent_1}) await sio_client_agent1.sleep(1) # Then the visitor connects await sio_client_visitor.connect( server_path, headers={"Authorization": token_visitor_1}) # Get the chat room chat_room = await Chat.get(visitor_id=visitor["id"]) # Send the first message new_content = {"value": "This is the first message"} await sio_client_visitor.call("visitor_first_msg", new_content) # Staff claim the chat await sio_client_agent1.call("staff_join", {"room": chat_room["id"]}, timeout=1) # Staff sends a message staff_first_content = {"value": "I am an agent."} await sio_client_agent1.call("staff_msg", { "room": chat_room["id"], "content": staff_first_content }) # Visitor sends back a message visitor_third_content = {"value": "Hello stranger."} await sio_client_visitor.call("visitor_msg", visitor_third_content, timeout=1) # Agent leaves the chat await sio_client_agent1.call("staff_leave_room", {"room": chat_room["id"]}) # Visitor disconnects to connect again, in a new session await sio_client_visitor.disconnect() # The room has been cleared from cache after visitor disconnects assert not await cache.exists(chat_room["id"]) await sio_client_visitor.connect( server_path, headers={"Authorization": token_visitor_1}) # Send a new message on the new session another_content = {"value": "First message in new session"} await sio_client_visitor.call("visitor_first_msg", another_content) messages = await ChatMessage.get(chat_id=chat_room["id"]) assert len(messages) == 6 expected_msgs = [ { "sequence_num": 1, "chat_id": chat_room["id"], "type_id": 1, "content": new_content, "sender": None, }, { "sequence_num": 2, "type_id": 0, "content": { "value": "join room" }, "sender": agent, "chat_id": chat_room["id"], }, { "sequence_num": 3, "chat_id": chat_room["id"], "type_id": 1, "content": staff_first_content, "sender": agent, }, { "sequence_num": 4, "chat_id": chat_room["id"], "type_id": 1, "content": visitor_third_content, "sender": None, }, { "sequence_num": 5, "type_id": 0, "content": { "value": "leave room" }, "sender": agent, "chat_id": chat_room["id"], }, { "sequence_num": 6, "chat_id": chat_room["id"], "type_id": 1, "content": another_content, "sender": None, }, ] for expected, message in zip(expected_msgs, messages): assert profile_created_from_origin(expected, message, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], message["sender"]) await sio_client_visitor.disconnect() await sio_client_agent1.disconnect()
async def test_get_all_users(supervisor1_client, users): res = await supervisor1_client.get("/users") assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 11 # Default offset for User is 11 assert all( profile_created_from_origin(origin, created) for origin, created in zip(users, body["data"])) # GET request will have its body ignored. res = await supervisor1_client.get("/users", json={"id": 3}) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 11 # Default offset for User is 11 # Get one user by id res = await supervisor1_client.get("/users?id={}".format(users[2]["id"])) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 1 assert profile_created_from_origin(users[2], body["data"][0]) ## LIMIT ## # No users res = await supervisor1_client.get("/users?limit=0") assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert not body["data"] # 10 users res = await supervisor1_client.get("/users?limit=10") assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 10 assert all( profile_created_from_origin(origin, created) for origin, created in zip(users[:10], body["data"])) # Get the next 10 users next_page_link = body["links"]["next"] # Strip the host, as it is a testing host next_page_link = "/" + "/".join(next_page_link.split("/")[3:]) res = await supervisor1_client.get(next_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert len(body["data"]) == 1 assert all( profile_created_from_origin(origin, created) for origin, created in zip(users[10:11], body["data"])) # -1 users res = await supervisor1_client.get("/users?limit=-1") assert res.status == 400
async def test_get_unread_visitors_for_staff(supervisor1_client): # Create some visitors visitors = [] for _ in range(30): new_visitor = get_fake_visitor() new_visitor.pop("id") res = await supervisor1_client.post("/visitors", json=new_visitor) assert res.status == 200 body = await res.json() visitors.append(body["data"]) # Create some dummy chat messages created_at = 1 chat_messages = {} chats = [] for visitor in visitors: chat = await Chat.add(visitor_id=visitor["id"]) chats.append(chat) for sequence_num in range(4): content = {"content": fake.sentence(nb_words=10)} chat_msg = { "chat_id": chat["id"], "sequence_num": sequence_num, "content": content, "sender": None, "created_at": created_at, } created_at += 1 created_msg = await ChatMessage.add(**chat_msg) chat_messages.setdefault(visitor["id"], []).append(created_msg) # Mark some visitors as read for visitor in visitors[12:17] + visitors[22:26]: res = await supervisor1_client.patch( "/visitors/{}/last_seen".format(visitor["id"]), json={"last_seen_msg_id": chat_messages[visitor["id"]][-1]["id"]}, ) assert res.status == 200 # Mark some visitors as partially read for visitor in visitors[5:10]: res = await supervisor1_client.patch( "/visitors/{}/last_seen".format(visitor["id"]), json={"last_seen_msg_id": chat_messages[visitor["id"]][2]["id"]}, ) assert res.status == 200 # Get the first unread visitors res = await supervisor1_client.get("/visitors/unread") assert res.status == 200 body = await res.json() assert "data" in body assert "links" not in body assert isinstance(body["data"], list) assert len(body["data"]) == 15 for expected_visitor, expected_chat, item in zip( reversed(visitors[:12] + visitors[17:22] + visitors[26:]), reversed(chats[:12] + chats[17:22] + chats[26:]), body["data"], ): actual_visitor = item["user"] actual_chat = item["room"] assert profile_created_from_origin(expected_visitor, actual_visitor) assert profile_created_from_origin(expected_chat, actual_chat) # Mark some visitors as fully read for visitor in visitors[2:8] + visitors[26:29]: res = await supervisor1_client.patch( "/visitors/{}/last_seen".format(visitor["id"]), json={"last_seen_msg_id": chat_messages[visitor["id"]][3]["id"]}, ) assert res.status == 200 # Get the second unread visitors res = await supervisor1_client.get("/visitors/unread") assert res.status == 200 body = await res.json() assert "data" in body assert "links" not in body assert isinstance(body["data"], list) assert len(body["data"]) == 12 for expected_visitor, expected_chat, item in zip( reversed(visitors[:2] + visitors[8:12] + visitors[17:22] + visitors[29:]), reversed(chats[:2] + chats[8:12] + chats[17:22] + chats[29:]), body["data"], ): actual_visitor = item["user"] actual_chat = item["room"] assert profile_created_from_origin(expected_visitor, actual_visitor) assert profile_created_from_origin(expected_chat, actual_chat) # Mark all visitors as read for visitor in visitors: res = await supervisor1_client.patch( "/visitors/{}/last_seen".format(visitor["id"]), json={"last_seen_msg_id": chat_messages[visitor["id"]][-1]["id"]}, ) assert res.status == 200 # Get the last unread visitors res = await supervisor1_client.get("/visitors/unread") assert res.status == 200 body = await res.json() assert "data" in body assert "links" not in body assert isinstance(body["data"], list) assert not body["data"]
async def test_staff_claim_a_visitor( sio_client_visitor, server_path, token_visitor_1, sio_client_agent1, token_agent_1, visitors, users, ): # Get the visitor info visitor = await Visitor.get(id=visitors[-1]["id"]) agent = await User.get(id=users[-6]["id"]) # Get the queue room org = (await Organisation.query.gino.all())[0] queue_room = "{}{}".format(UNCLAIMED_CHATS_PREFIX, org.id) unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats is None # A staff connects first await sio_client_agent1.connect(server_path, headers={"Authorization": token_agent_1}) await sio_client_agent1.sleep(1) # Assert no errors are raised when the staff connects excs = await cache.get("exceptions", []) assert not excs # Then the visitor connects await sio_client_visitor.connect( server_path, headers={"Authorization": token_visitor_1}) # Get the chat room chat_room = await Chat.get(visitor_id=visitor["id"]) # Send the first message new_content = {"value": "This is the first message"} await sio_client_visitor.call("visitor_first_msg", new_content) # There are no staffs assigned yet cache_chat_room = await cache.get(chat_room["id"]) assert cache_chat_room["staff"] is None # Staff claim the chat await sio_client_agent1.call("staff_join", {"room": chat_room["id"]}, timeout=1) # Assert no errors are raised when the staff claims the chat excs = await cache.get("exceptions", []) assert not excs # Ensure that the chat in queue room is also updated unclaimed_chats = await cache.get(queue_room) assert unclaimed_chats == [] # Staff sends a message staff_first_content = {"value": "I am an agent."} await sio_client_agent1.call("staff_msg", { "room": chat_room["id"], "content": staff_first_content }) # Visitor sends back a message visitor_third_content = {"value": "Hello stranger."} await sio_client_visitor.call("visitor_msg", visitor_third_content, timeout=1) # Agent leaves the chat await sio_client_agent1.call("staff_leave_room", {"room": chat_room["id"]}) messages = await ChatMessage.get(chat_id=chat_room["id"]) assert len(messages) == 5 expected_msgs = [ { "sequence_num": 1, "chat_id": chat_room["id"], "type_id": 1, "content": new_content, "sender": None, }, { "sequence_num": 2, "type_id": 0, "content": { "value": "join room" }, "sender": agent, "chat_id": chat_room["id"], }, { "sequence_num": 3, "chat_id": chat_room["id"], "type_id": 1, "content": staff_first_content, "sender": agent, }, { "sequence_num": 4, "chat_id": chat_room["id"], "type_id": 1, "content": visitor_third_content, "sender": None, }, { "sequence_num": 5, "type_id": 0, "content": { "value": "leave room" }, "sender": agent, "chat_id": chat_room["id"], }, ] for expected, message in zip(expected_msgs, messages): assert profile_created_from_origin(expected, message, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], message["sender"]) await sio_client_visitor.disconnect() await sio_client_agent1.disconnect()
async def test_get_messages_unread_from_top(supervisor1_client, visitors, users): visitor_id = visitors[-1]["id"] # Create some dummy chat messages chat = await Chat.add(visitor_id=visitor_id) messages = [] for sequence_num in range(1, 37): content = {"value": fake.sentence(nb_words=10)} sender = users[-6]["id"] if randint(0, 1) else None chat_msg = { "chat_id": chat["id"], "sequence_num": sequence_num, "content": content, "sender": sender, } created_msg = await ChatMessage.add(**chat_msg) created_msg["sender"] = users[-6] if sender else None messages.append(created_msg) # When the chat has no unread, starts from top res = await supervisor1_client.get( "/visitors/{}/messages?starts_from_unread=true".format(visitor_id)) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert "links" in body and "next" in body["links"] and "prev" in body[ "links"] assert len(body["data"]) == 15 for expected, actual in zip(messages[:15], body["data"]): assert profile_created_from_origin(expected, actual, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], actual["sender"]) next_page_link = get_next_page_link(body) prev_page_link = get_prev_page_link(body) # Get the prev pages until no more res = await supervisor1_client.get(prev_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert ("links" in body and "next" not in body["links"] and "prev" not in body["links"]) assert not body["data"] # Get the next messages from unread til most recent res = await supervisor1_client.get(next_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert "links" in body and "next" in body["links"] and "prev" in body[ "links"] assert len(body["data"]) == 15 for expected, actual in zip(messages[15:30], body["data"]): assert profile_created_from_origin(expected, actual, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], actual["sender"]) # Get the next messages until end next_page_link = get_next_page_link(body) res = await supervisor1_client.get(next_page_link) assert res.status == 200 body = await res.json() assert "data" in body assert isinstance(body["data"], list) assert "links" in body and "next" in body["links"] and "prev" in body[ "links"] assert len(body["data"]) == 6 for expected, actual in zip(messages[30:], body["data"]): assert profile_created_from_origin(expected, actual, ignore={"sender"}) assert profile_created_from_origin(expected["sender"], actual["sender"])