|
| 1 | +from datetime import timedelta |
| 2 | + |
| 3 | +import pytest |
| 4 | +from google.protobuf import empty_pb2 |
| 5 | + |
| 6 | +from couchers.constants import HOST_REQUEST_MIN_LENGTH_UTF16 |
| 7 | +from couchers.proto import conversations_pb2, dashboard_pb2, discussions_pb2, events_pb2, requests_pb2 |
| 8 | +from couchers.utils import today |
| 9 | +from tests.fixtures.db import generate_user |
| 10 | +from tests.fixtures.sessions import ( |
| 11 | + account_session, |
| 12 | + dashboard_session, |
| 13 | + discussions_session, |
| 14 | + events_session, |
| 15 | + requests_session, |
| 16 | +) |
| 17 | + |
| 18 | + |
| 19 | +@pytest.fixture(autouse=True) |
| 20 | +def _(testconfig): |
| 21 | + pass |
| 22 | + |
| 23 | + |
| 24 | +UPCOMING_STATUSES = [ |
| 25 | + conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, |
| 26 | + conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED, |
| 27 | +] |
| 28 | + |
| 29 | + |
| 30 | +def valid_request_text(text: str = "Test request") -> str: |
| 31 | + """Pads a request text to a valid length (measured in utf-16 code units, matching the frontend).""" |
| 32 | + utf16_length = len(text.encode("utf-16-le")) // 2 |
| 33 | + if utf16_length >= HOST_REQUEST_MIN_LENGTH_UTF16: |
| 34 | + return text |
| 35 | + return text + ("_" * (HOST_REQUEST_MIN_LENGTH_UTF16 - utf16_length)) |
| 36 | + |
| 37 | + |
| 38 | +def _setup_accepted_host_request(token_surfer, host_user_id, moderator): |
| 39 | + from_date = today() + timedelta(days=2) |
| 40 | + to_date = today() + timedelta(days=3) |
| 41 | + with requests_session(token_surfer) as api: |
| 42 | + host_request_id = api.CreateHostRequest( |
| 43 | + requests_pb2.CreateHostRequestReq( |
| 44 | + host_user_id=host_user_id, |
| 45 | + from_date=from_date.isoformat(), |
| 46 | + to_date=to_date.isoformat(), |
| 47 | + text=valid_request_text(), |
| 48 | + ) |
| 49 | + ).host_request_id |
| 50 | + moderator.approve_host_request(host_request_id) |
| 51 | + return host_request_id |
| 52 | + |
| 53 | + |
| 54 | +def test_GetDashboardV2_matches_individual_rpcs(db, moderator): |
| 55 | + user1, token1 = generate_user() |
| 56 | + user2, token2 = generate_user() |
| 57 | + |
| 58 | + host_request_id = _setup_accepted_host_request(token1, user2.id, moderator) |
| 59 | + with requests_session(token2) as api: |
| 60 | + api.RespondHostRequest( |
| 61 | + requests_pb2.RespondHostRequestReq( |
| 62 | + host_request_id=host_request_id, |
| 63 | + status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, |
| 64 | + text="Sure, come on over!", |
| 65 | + ) |
| 66 | + ) |
| 67 | + |
| 68 | + # the dashboard response must be identical to fanning out to the individual RPCs with the |
| 69 | + # same parameters the web frontend uses |
| 70 | + with requests_session(token1) as api: |
| 71 | + surfing = api.ListHostRequests( |
| 72 | + requests_pb2.ListHostRequestsReq( |
| 73 | + only_sent=True, |
| 74 | + only_active=True, |
| 75 | + status_in=UPCOMING_STATUSES, |
| 76 | + sort_by=requests_pb2.HOST_REQUEST_SORT_BY_FROM_DATE, |
| 77 | + ) |
| 78 | + ) |
| 79 | + hosting = api.ListHostRequests( |
| 80 | + requests_pb2.ListHostRequestsReq( |
| 81 | + only_received=True, |
| 82 | + only_active=True, |
| 83 | + status_in=UPCOMING_STATUSES, |
| 84 | + sort_by=requests_pb2.HOST_REQUEST_SORT_BY_FROM_DATE, |
| 85 | + ) |
| 86 | + ) |
| 87 | + with events_session(token1) as api: |
| 88 | + my_events = api.ListMyEvents(events_pb2.ListMyEventsReq(page_size=3)) |
| 89 | + community_events = api.ListMyEvents( |
| 90 | + events_pb2.ListMyEventsReq(page_size=3, my_communities=True, my_communities_exclude_global=True) |
| 91 | + ) |
| 92 | + with discussions_session(token1) as api: |
| 93 | + discussions = api.ListMyCommunitiesDiscussions(discussions_pb2.ListMyCommunitiesDiscussionsReq(page_size=3)) |
| 94 | + with account_session(token1) as api: |
| 95 | + reminders = api.GetReminders(empty_pb2.Empty()) |
| 96 | + |
| 97 | + with dashboard_session(token1) as api: |
| 98 | + res = api.GetDashboardV2(dashboard_pb2.GetDashboardV2Req()) |
| 99 | + |
| 100 | + assert res.reminders == reminders |
| 101 | + assert res.surfing == surfing |
| 102 | + assert res.hosting == hosting |
| 103 | + assert res.my_events == my_events |
| 104 | + assert res.community_events == community_events |
| 105 | + assert res.discussions == discussions |
| 106 | + |
| 107 | + # the surfer sees their upcoming trip under surfing, nothing under hosting |
| 108 | + assert len(res.surfing.host_requests) == 1 |
| 109 | + assert res.surfing.host_requests[0].host_request_id == host_request_id |
| 110 | + assert res.surfing.host_requests[0].status == conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED |
| 111 | + assert len(res.hosting.host_requests) == 0 |
| 112 | + |
| 113 | + |
| 114 | +def test_GetDashboardV2_buckets_by_role(db, moderator): |
| 115 | + user1, token1 = generate_user() |
| 116 | + user2, token2 = generate_user() |
| 117 | + |
| 118 | + host_request_id = _setup_accepted_host_request(token1, user2.id, moderator) |
| 119 | + with requests_session(token2) as api: |
| 120 | + api.RespondHostRequest( |
| 121 | + requests_pb2.RespondHostRequestReq( |
| 122 | + host_request_id=host_request_id, |
| 123 | + status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, |
| 124 | + text="Sure, come on over!", |
| 125 | + ) |
| 126 | + ) |
| 127 | + |
| 128 | + # the host sees the upcoming stay under hosting, nothing under surfing |
| 129 | + with dashboard_session(token2) as api: |
| 130 | + res = api.GetDashboardV2(dashboard_pb2.GetDashboardV2Req()) |
| 131 | + assert len(res.hosting.host_requests) == 1 |
| 132 | + assert res.hosting.host_requests[0].host_request_id == host_request_id |
| 133 | + assert len(res.surfing.host_requests) == 0 |
| 134 | + |
| 135 | + |
| 136 | +def test_GetDashboardV2_empty(db): |
| 137 | + user, token = generate_user() |
| 138 | + with dashboard_session(token) as api: |
| 139 | + res = api.GetDashboardV2(dashboard_pb2.GetDashboardV2Req()) |
| 140 | + assert len(res.surfing.host_requests) == 0 |
| 141 | + assert len(res.hosting.host_requests) == 0 |
| 142 | + assert len(res.my_events.events) == 0 |
| 143 | + assert len(res.community_events.events) == 0 |
| 144 | + assert len(res.discussions.discussions) == 0 |
| 145 | + assert len(res.reminders.reminders) == 0 |
0 commit comments