Coverage for app/backend/src/tests/fixtures/api/requests.py: 100%
72 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-09 14:50 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-09 14:50 +0000
1from contextlib import contextmanager
2from datetime import date, timedelta
3from typing import cast
5import grpc
7from couchers.constants import HOST_REQUEST_MIN_LENGTH_UTF16
8from couchers.proto import messages_pb2, requests_pb2, requests_pb2_grpc
9from couchers.servicers.requests import Requests
10from couchers.utils import date_to_api, today
11from tests.fixtures.misc import Moderator
12from tests.fixtures.sessions import FakeChannel
15def _pad_request_text_to_valid_length(text: str) -> str:
16 # Request lengths are measured in utf-16 code units to match the frontend.
17 while len(text.encode("utf-16-le")) // 2 < HOST_REQUEST_MIN_LENGTH_UTF16:
18 text += " padding"
19 return text
22# Neutral default text of valid length
23REQUEST_TEXT_DEFAULT = _pad_request_text_to_valid_length("Dummy request text.")
26@contextmanager
27def _requests_session(token: str):
28 channel = FakeChannel(token)
29 requests_pb2_grpc.add_RequestsServicer_to_server(Requests(), cast(grpc.Server, channel))
30 yield requests_pb2_grpc.RequestsStub(cast(grpc.Channel, channel))
33def create_host_request(
34 *,
35 token: str,
36 host_user_id: int,
37 # Strings allow testing malformed dates.
38 from_date: date | str | None = None,
39 to_date: date | str | None = None,
40 text: str | None = REQUEST_TEXT_DEFAULT,
41 pad_text_to_valid_length: bool = False,
42 public_trip_id: int | None = None,
43 approve_by: Moderator | None = None,
44) -> int:
45 if text is not None and pad_text_to_valid_length:
46 text = _pad_request_text_to_valid_length(text)
47 if from_date is None:
48 # Two days later is in the future no matter the host's timezone.
49 from_date = today() + timedelta(days=2)
50 if to_date is None:
51 to_date = (date.fromisoformat(from_date) if isinstance(from_date, str) else from_date) + timedelta(days=1)
53 with _requests_session(token) as session:
54 res: requests_pb2.CreateHostRequestRes = session.CreateHostRequest(
55 requests_pb2.CreateHostRequestReq(
56 host_user_id=host_user_id,
57 from_date=from_date if isinstance(from_date, str) else date_to_api(from_date),
58 to_date=to_date if isinstance(to_date, str) else date_to_api(to_date),
59 text=text,
60 public_trip_id=public_trip_id,
61 )
62 )
64 if approve_by is not None:
65 approve_by.approve_host_request(res.host_request_id)
67 return res.host_request_id
70def get_host_request(*, token: str, host_request_id: int) -> requests_pb2.HostRequest:
71 with _requests_session(token) as session:
72 host_request: requests_pb2.HostRequest = session.GetHostRequest(
73 requests_pb2.GetHostRequestReq(host_request_id=host_request_id)
74 )
75 return host_request
78def respond_host_request(
79 *,
80 token: str,
81 host_request_id: int,
82 status: messages_pb2.HostRequestStatus.ValueType,
83 text: str | None = None,
84) -> None:
85 with _requests_session(token) as session:
86 session.RespondHostRequest(
87 requests_pb2.RespondHostRequestReq(host_request_id=host_request_id, status=status, text=text)
88 )
91def set_host_request_archive_status(
92 *, token: str, host_request_id: int, is_archived: bool
93) -> requests_pb2.SetHostRequestArchiveStatusRes:
94 with _requests_session(token) as session:
95 res: requests_pb2.SetHostRequestArchiveStatusRes = session.SetHostRequestArchiveStatus(
96 requests_pb2.SetHostRequestArchiveStatusReq(host_request_id=host_request_id, is_archived=is_archived)
97 )
98 return res
101def list_host_requests(
102 *,
103 token: str,
104 number: int | None = None,
105 only_active: bool = False,
106 only_sent: bool = False,
107 only_received: bool = False,
108 only_archived: bool | None = None,
109 status_in: list[messages_pb2.HostRequestStatus.ValueType] | None = None,
110 sort_by: requests_pb2.HostRequestSortBy.ValueType | None = None,
111 page_token: str | None = None,
112) -> requests_pb2.ListHostRequestsRes:
113 with _requests_session(token) as session:
114 res: requests_pb2.ListHostRequestsRes = session.ListHostRequests(
115 requests_pb2.ListHostRequestsReq(
116 number=number,
117 only_active=only_active,
118 only_sent=only_sent,
119 only_received=only_received,
120 only_archived=only_archived,
121 status_in=status_in,
122 sort_by=sort_by,
123 page_token=page_token,
124 )
125 )
126 return res
129def list_stays(
130 *,
131 token: str,
132 role: requests_pb2.StayRole.ValueType,
133 page_size: int | None = None,
134 page_token: str | None = None,
135) -> requests_pb2.ListStaysRes:
136 with _requests_session(token) as session:
137 res: requests_pb2.ListStaysRes = session.ListStays(
138 requests_pb2.ListStaysReq(role=role, page_size=page_size, page_token=page_token)
139 )
140 return res
143def get_host_request_messages(
144 *, token: str, host_request_id: int, last_message_id: int | None = None, number: int | None = None
145) -> requests_pb2.GetHostRequestMessagesRes:
146 with _requests_session(token) as session:
147 res: requests_pb2.GetHostRequestMessagesRes = session.GetHostRequestMessages(
148 requests_pb2.GetHostRequestMessagesReq(
149 host_request_id=host_request_id, last_message_id=last_message_id, number=number
150 )
151 )
152 return res
155def send_host_request_message(*, token: str, host_request_id: int, text: str = "Dummy message.") -> None:
156 with _requests_session(token) as session:
157 session.SendHostRequestMessage(
158 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text=text)
159 )
162def get_host_request_updates(
163 *,
164 token: str,
165 newest_message_id: int,
166 number: int | None = None,
167 only_sent: bool = False,
168 only_received: bool = False,
169) -> requests_pb2.GetHostRequestUpdatesRes:
170 with _requests_session(token) as session:
171 res: requests_pb2.GetHostRequestUpdatesRes = session.GetHostRequestUpdates(
172 requests_pb2.GetHostRequestUpdatesReq(
173 newest_message_id=newest_message_id,
174 number=number,
175 only_sent=only_sent,
176 only_received=only_received,
177 )
178 )
179 return res
182def mark_last_seen_host_request(*, token: str, host_request_id: int, last_seen_message_id: int) -> None:
183 with _requests_session(token) as session:
184 session.MarkLastSeenHostRequest(
185 requests_pb2.MarkLastSeenHostRequestReq(
186 host_request_id=host_request_id, last_seen_message_id=last_seen_message_id
187 )
188 )
191def get_response_rate(*, token: str, user_id: int) -> requests_pb2.GetResponseRateRes:
192 with _requests_session(token) as session:
193 res: requests_pb2.GetResponseRateRes = session.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user_id))
194 return res
197def send_host_request_feedback(
198 *,
199 token: str,
200 host_request_id: int,
201 host_request_quality: requests_pb2.HostRequestQuality.ValueType = requests_pb2.HOST_REQUEST_QUALITY_UNSPECIFIED,
202 decline_reason: str | None = None,
203) -> None:
204 with _requests_session(token) as session:
205 session.SendHostRequestFeedback(
206 requests_pb2.SendHostRequestFeedbackReq(
207 host_request_id=host_request_id,
208 host_request_quality=host_request_quality,
209 decline_reason=decline_reason,
210 )
211 )