Coverage for src/tests/test_requests.py: 100%

530 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-04-16 15:13 +0000

1from datetime import timedelta 

2 

3import grpc 

4import pytest 

5from sqlalchemy.sql import select 

6 

7from couchers import errors 

8from couchers.db import session_scope 

9from couchers.materialized_views import refresh_materialized_view 

10from couchers.models import Message, MessageType 

11from couchers.templates.v2 import v2date 

12from couchers.utils import now, today 

13from proto import api_pb2, conversations_pb2, requests_pb2 

14from tests.test_fixtures import ( # noqa 

15 api_session, 

16 db, 

17 email_fields, 

18 generate_user, 

19 mock_notification_email, 

20 push_collector, 

21 requests_session, 

22 testconfig, 

23) 

24 

25 

26@pytest.fixture(autouse=True) 

27def _(testconfig): 

28 pass 

29 

30 

31def test_create_request(db): 

32 user1, token1 = generate_user() 

33 user2, token2 = generate_user() 

34 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

35 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

36 today_minus_2 = (today() - timedelta(days=2)).isoformat() 

37 today_minus_3 = (today() - timedelta(days=3)).isoformat() 

38 with requests_session(token1) as api: 

39 with pytest.raises(grpc.RpcError) as e: 

40 api.CreateHostRequest( 

41 requests_pb2.CreateHostRequestReq( 

42 host_user_id=user1.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

43 ) 

44 ) 

45 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

46 assert e.value.details() == errors.CANT_REQUEST_SELF 

47 

48 with pytest.raises(grpc.RpcError) as e: 

49 api.CreateHostRequest( 

50 requests_pb2.CreateHostRequestReq( 

51 host_user_id=999, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

52 ) 

53 ) 

54 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

55 assert e.value.details() == errors.USER_NOT_FOUND 

56 

57 with pytest.raises(grpc.RpcError) as e: 

58 api.CreateHostRequest( 

59 requests_pb2.CreateHostRequestReq( 

60 host_user_id=user2.id, from_date=today_plus_3, to_date=today_plus_2, text="Test request" 

61 ) 

62 ) 

63 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

64 assert e.value.details() == errors.DATE_FROM_AFTER_TO 

65 

66 with pytest.raises(grpc.RpcError) as e: 

67 api.CreateHostRequest( 

68 requests_pb2.CreateHostRequestReq( 

69 host_user_id=user2.id, from_date=today_minus_3, to_date=today_plus_2, text="Test request" 

70 ) 

71 ) 

72 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

73 assert e.value.details() == errors.DATE_FROM_BEFORE_TODAY 

74 

75 with pytest.raises(grpc.RpcError) as e: 

76 api.CreateHostRequest( 

77 requests_pb2.CreateHostRequestReq( 

78 host_user_id=user2.id, from_date=today_plus_2, to_date=today_minus_2, text="Test request" 

79 ) 

80 ) 

81 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

82 assert e.value.details() == errors.DATE_FROM_AFTER_TO 

83 

84 with pytest.raises(grpc.RpcError) as e: 

85 api.CreateHostRequest( 

86 requests_pb2.CreateHostRequestReq( 

87 host_user_id=user2.id, from_date="2020-00-06", to_date=today_minus_2, text="Test request" 

88 ) 

89 ) 

90 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

91 assert e.value.details() == errors.INVALID_DATE 

92 

93 res = api.CreateHostRequest( 

94 requests_pb2.CreateHostRequestReq( 

95 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

96 ) 

97 ) 

98 assert ( 

99 api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_sent=True)) 

100 .host_requests[0] 

101 .latest_message.text.text 

102 == "Test request" 

103 ) 

104 

105 today_ = today() 

106 today_plus_one_year = today_ + timedelta(days=365) 

107 today_plus_one_year_plus_2 = (today_plus_one_year + timedelta(days=2)).isoformat() 

108 today_plus_one_year_plus_3 = (today_plus_one_year + timedelta(days=3)).isoformat() 

109 with pytest.raises(grpc.RpcError) as e: 

110 api.CreateHostRequest( 

111 requests_pb2.CreateHostRequestReq( 

112 host_user_id=user2.id, 

113 from_date=today_plus_one_year_plus_2, 

114 to_date=today_plus_one_year_plus_3, 

115 text="Test from date after one year", 

116 ) 

117 ) 

118 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

119 assert e.value.details() == errors.DATE_FROM_AFTER_ONE_YEAR 

120 

121 with pytest.raises(grpc.RpcError) as e: 

122 api.CreateHostRequest( 

123 requests_pb2.CreateHostRequestReq( 

124 host_user_id=user2.id, 

125 from_date=today_plus_2, 

126 to_date=today_plus_one_year_plus_3, 

127 text="Test to date one year after from date", 

128 ) 

129 ) 

130 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

131 assert e.value.details() == errors.DATE_TO_AFTER_ONE_YEAR 

132 

133 

134def test_create_request_incomplete_profile(db): 

135 user1, token1 = generate_user(complete_profile=False) 

136 user2, _ = generate_user() 

137 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

138 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

139 with requests_session(token1) as api: 

140 with pytest.raises(grpc.RpcError) as e: 

141 api.CreateHostRequest( 

142 requests_pb2.CreateHostRequestReq( 

143 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

144 ) 

145 ) 

146 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

147 assert e.value.details() == errors.INCOMPLETE_PROFILE_SEND_REQUEST 

148 

149 

150def add_message(db, text, author_id, conversation_id): 

151 with session_scope() as session: 

152 message = Message( 

153 conversation_id=conversation_id, author_id=author_id, text=text, message_type=MessageType.text 

154 ) 

155 

156 session.add(message) 

157 

158 

159def test_GetHostRequest(db): 

160 user1, token1 = generate_user() 

161 user2, token2 = generate_user() 

162 user3, token3 = generate_user() 

163 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

164 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

165 with requests_session(token1) as api: 

166 host_request_id = api.CreateHostRequest( 

167 requests_pb2.CreateHostRequestReq( 

168 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

169 ) 

170 ).host_request_id 

171 

172 with pytest.raises(grpc.RpcError) as e: 

173 api.GetHostRequest(requests_pb2.GetHostRequestReq(host_request_id=999)) 

174 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

175 assert e.value.details() == errors.HOST_REQUEST_NOT_FOUND 

176 

177 api.SendHostRequestMessage( 

178 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 1") 

179 ) 

180 

181 res = api.GetHostRequest(requests_pb2.GetHostRequestReq(host_request_id=host_request_id)) 

182 assert res.latest_message.text.text == "Test message 1" 

183 

184 

185def test_ListHostRequests(db): 

186 user1, token1 = generate_user() 

187 user2, token2 = generate_user() 

188 user3, token3 = generate_user() 

189 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

190 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

191 with requests_session(token1) as api: 

192 host_request_1 = api.CreateHostRequest( 

193 requests_pb2.CreateHostRequestReq( 

194 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

195 ) 

196 ).host_request_id 

197 

198 host_request_2 = api.CreateHostRequest( 

199 requests_pb2.CreateHostRequestReq( 

200 host_user_id=user3.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 2" 

201 ) 

202 ).host_request_id 

203 

204 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_sent=True)) 

205 assert res.no_more 

206 assert len(res.host_requests) == 2 

207 

208 with requests_session(token2) as api: 

209 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

210 assert res.no_more 

211 assert len(res.host_requests) == 1 

212 assert res.host_requests[0].latest_message.text.text == "Test request 1" 

213 assert res.host_requests[0].surfer_user_id == user1.id 

214 assert res.host_requests[0].host_user_id == user2.id 

215 assert res.host_requests[0].status == conversations_pb2.HOST_REQUEST_STATUS_PENDING 

216 

217 add_message(db, "Test request 1 message 1", user2.id, host_request_1) 

218 add_message(db, "Test request 1 message 2", user2.id, host_request_1) 

219 add_message(db, "Test request 1 message 3", user2.id, host_request_1) 

220 

221 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

222 assert res.host_requests[0].latest_message.text.text == "Test request 1 message 3" 

223 

224 api.CreateHostRequest( 

225 requests_pb2.CreateHostRequestReq( 

226 host_user_id=user1.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 3" 

227 ) 

228 ) 

229 

230 add_message(db, "Test request 2 message 1", user1.id, host_request_2) 

231 add_message(db, "Test request 2 message 2", user3.id, host_request_2) 

232 

233 with requests_session(token3) as api: 

234 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

235 assert res.no_more 

236 assert len(res.host_requests) == 1 

237 assert res.host_requests[0].latest_message.text.text == "Test request 2 message 2" 

238 

239 with requests_session(token1) as api: 

240 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

241 assert len(res.host_requests) == 1 

242 

243 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq()) 

244 assert len(res.host_requests) == 3 

245 

246 

247def test_ListHostRequests_pagination_regression(db): 

248 """ 

249 ListHostRequests was skipping a request when getting multiple pages 

250 """ 

251 user1, token1 = generate_user() 

252 user2, token2 = generate_user() 

253 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

254 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

255 with requests_session(token1) as api: 

256 host_request_1 = api.CreateHostRequest( 

257 requests_pb2.CreateHostRequestReq( 

258 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

259 ) 

260 ).host_request_id 

261 

262 host_request_2 = api.CreateHostRequest( 

263 requests_pb2.CreateHostRequestReq( 

264 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 2" 

265 ) 

266 ).host_request_id 

267 

268 host_request_3 = api.CreateHostRequest( 

269 requests_pb2.CreateHostRequestReq( 

270 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 3" 

271 ) 

272 ).host_request_id 

273 

274 with requests_session(token2) as api: 

275 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

276 assert res.no_more 

277 assert len(res.host_requests) == 3 

278 assert res.host_requests[0].latest_message.text.text == "Test request 3" 

279 assert res.host_requests[1].latest_message.text.text == "Test request 2" 

280 assert res.host_requests[2].latest_message.text.text == "Test request 1" 

281 

282 with requests_session(token2) as api: 

283 api.RespondHostRequest( 

284 requests_pb2.RespondHostRequestReq( 

285 host_request_id=host_request_2, 

286 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

287 text="Accepting host request 2", 

288 ) 

289 ) 

290 api.RespondHostRequest( 

291 requests_pb2.RespondHostRequestReq( 

292 host_request_id=host_request_1, 

293 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

294 text="Accepting host request 1", 

295 ) 

296 ) 

297 api.RespondHostRequest( 

298 requests_pb2.RespondHostRequestReq( 

299 host_request_id=host_request_3, 

300 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

301 text="Accepting host request 3", 

302 ) 

303 ) 

304 

305 with requests_session(token2) as api: 

306 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

307 assert res.no_more 

308 assert len(res.host_requests) == 3 

309 assert res.host_requests[0].latest_message.text.text == "Accepting host request 3" 

310 assert res.host_requests[1].latest_message.text.text == "Accepting host request 1" 

311 assert res.host_requests[2].latest_message.text.text == "Accepting host request 2" 

312 

313 with requests_session(token2) as api: 

314 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True, number=1)) 

315 assert not res.no_more 

316 assert len(res.host_requests) == 1 

317 assert res.host_requests[0].latest_message.text.text == "Accepting host request 3" 

318 res = api.ListHostRequests( 

319 requests_pb2.ListHostRequestsReq(only_received=True, number=1, last_request_id=res.last_request_id) 

320 ) 

321 assert not res.no_more 

322 assert len(res.host_requests) == 1 

323 assert res.host_requests[0].latest_message.text.text == "Accepting host request 1" 

324 res = api.ListHostRequests( 

325 requests_pb2.ListHostRequestsReq(only_received=True, number=1, last_request_id=res.last_request_id) 

326 ) 

327 assert res.no_more 

328 assert len(res.host_requests) == 1 

329 assert res.host_requests[0].latest_message.text.text == "Accepting host request 2" 

330 

331 

332def test_ListHostRequests_active_filter(db): 

333 user1, token1 = generate_user() 

334 user2, token2 = generate_user() 

335 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

336 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

337 

338 with requests_session(token1) as api: 

339 request_id = api.CreateHostRequest( 

340 requests_pb2.CreateHostRequestReq( 

341 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

342 ) 

343 ).host_request_id 

344 api.RespondHostRequest( 

345 requests_pb2.RespondHostRequestReq( 

346 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

347 ) 

348 ) 

349 

350 with requests_session(token2) as api: 

351 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_received=True)) 

352 assert len(res.host_requests) == 1 

353 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_active=True)) 

354 assert len(res.host_requests) == 0 

355 

356 

357def test_RespondHostRequests(db): 

358 user1, token1 = generate_user() 

359 user2, token2 = generate_user() 

360 user3, token3 = generate_user() 

361 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

362 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

363 

364 with requests_session(token1) as api: 

365 request_id = api.CreateHostRequest( 

366 requests_pb2.CreateHostRequestReq( 

367 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

368 ) 

369 ).host_request_id 

370 

371 # another user can't access 

372 with requests_session(token3) as api: 

373 with pytest.raises(grpc.RpcError) as e: 

374 api.RespondHostRequest( 

375 requests_pb2.RespondHostRequestReq( 

376 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

377 ) 

378 ) 

379 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

380 assert e.value.details() == errors.HOST_REQUEST_NOT_FOUND 

381 

382 with requests_session(token1) as api: 

383 with pytest.raises(grpc.RpcError) as e: 

384 api.RespondHostRequest( 

385 requests_pb2.RespondHostRequestReq( 

386 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

387 ) 

388 ) 

389 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

390 assert e.value.details() == errors.NOT_THE_HOST 

391 

392 with requests_session(token2) as api: 

393 # non existing id 

394 with pytest.raises(grpc.RpcError) as e: 

395 api.RespondHostRequest( 

396 requests_pb2.RespondHostRequestReq( 

397 host_request_id=9999, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

398 ) 

399 ) 

400 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

401 

402 # host can't confirm or cancel (host should accept/reject) 

403 with pytest.raises(grpc.RpcError) as e: 

404 api.RespondHostRequest( 

405 requests_pb2.RespondHostRequestReq( 

406 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

407 ) 

408 ) 

409 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

410 assert e.value.details() == errors.INVALID_HOST_REQUEST_STATUS 

411 with pytest.raises(grpc.RpcError) as e: 

412 api.RespondHostRequest( 

413 requests_pb2.RespondHostRequestReq( 

414 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

415 ) 

416 ) 

417 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

418 assert e.value.details() == errors.INVALID_HOST_REQUEST_STATUS 

419 

420 api.RespondHostRequest( 

421 requests_pb2.RespondHostRequestReq( 

422 host_request_id=request_id, 

423 status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED, 

424 text="Test rejection message", 

425 ) 

426 ) 

427 res = api.GetHostRequestMessages(requests_pb2.GetHostRequestMessagesReq(host_request_id=request_id)) 

428 assert res.messages[0].text.text == "Test rejection message" 

429 assert res.messages[1].WhichOneof("content") == "host_request_status_changed" 

430 assert res.messages[1].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

431 # should be able to move from rejected -> accepted 

432 api.RespondHostRequest( 

433 requests_pb2.RespondHostRequestReq( 

434 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

435 ) 

436 ) 

437 

438 with requests_session(token1) as api: 

439 # can't make pending 

440 with pytest.raises(grpc.RpcError) as e: 

441 api.RespondHostRequest( 

442 requests_pb2.RespondHostRequestReq( 

443 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_PENDING 

444 ) 

445 ) 

446 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

447 assert e.value.details() == errors.INVALID_HOST_REQUEST_STATUS 

448 

449 # can confirm then cancel 

450 api.RespondHostRequest( 

451 requests_pb2.RespondHostRequestReq( 

452 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

453 ) 

454 ) 

455 

456 api.RespondHostRequest( 

457 requests_pb2.RespondHostRequestReq( 

458 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

459 ) 

460 ) 

461 

462 # can't confirm after having cancelled 

463 with pytest.raises(grpc.RpcError) as e: 

464 api.RespondHostRequest( 

465 requests_pb2.RespondHostRequestReq( 

466 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

467 ) 

468 ) 

469 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

470 assert e.value.details() == errors.INVALID_HOST_REQUEST_STATUS 

471 

472 # at this point there should be 7 messages 

473 # 2 for creation, 2 for the status change with message, 3 for the other status changed 

474 with requests_session(token1) as api: 

475 res = api.GetHostRequestMessages(requests_pb2.GetHostRequestMessagesReq(host_request_id=request_id)) 

476 assert len(res.messages) == 7 

477 assert res.messages[0].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

478 assert res.messages[1].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

479 assert res.messages[2].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

480 assert res.messages[4].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

481 assert res.messages[6].WhichOneof("content") == "chat_created" 

482 

483 

484def test_get_host_request_messages(db): 

485 user1, token1 = generate_user() 

486 user2, token2 = generate_user() 

487 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

488 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

489 with requests_session(token1) as api: 

490 res = api.CreateHostRequest( 

491 requests_pb2.CreateHostRequestReq( 

492 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

493 ) 

494 ) 

495 conversation_id = res.host_request_id 

496 

497 add_message(db, "Test request 1 message 1", user1.id, conversation_id) 

498 add_message(db, "Test request 1 message 2", user1.id, conversation_id) 

499 add_message(db, "Test request 1 message 3", user1.id, conversation_id) 

500 

501 with requests_session(token2) as api: 

502 api.RespondHostRequest( 

503 requests_pb2.RespondHostRequestReq( 

504 host_request_id=conversation_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

505 ) 

506 ) 

507 

508 add_message(db, "Test request 1 message 4", user2.id, conversation_id) 

509 add_message(db, "Test request 1 message 5", user2.id, conversation_id) 

510 

511 api.RespondHostRequest( 

512 requests_pb2.RespondHostRequestReq( 

513 host_request_id=conversation_id, status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

514 ) 

515 ) 

516 

517 with requests_session(token1) as api: 

518 res = api.GetHostRequestMessages(requests_pb2.GetHostRequestMessagesReq(host_request_id=conversation_id)) 

519 # 9 including initial message 

520 assert len(res.messages) == 9 

521 assert res.no_more 

522 

523 res = api.GetHostRequestMessages( 

524 requests_pb2.GetHostRequestMessagesReq(host_request_id=conversation_id, number=3) 

525 ) 

526 assert not res.no_more 

527 assert len(res.messages) == 3 

528 assert res.messages[0].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

529 assert res.messages[0].WhichOneof("content") == "host_request_status_changed" 

530 assert res.messages[1].text.text == "Test request 1 message 5" 

531 assert res.messages[2].text.text == "Test request 1 message 4" 

532 

533 res = api.GetHostRequestMessages( 

534 requests_pb2.GetHostRequestMessagesReq( 

535 host_request_id=conversation_id, last_message_id=res.messages[2].message_id, number=6 

536 ) 

537 ) 

538 assert res.no_more 

539 assert len(res.messages) == 6 

540 assert res.messages[0].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

541 assert res.messages[0].WhichOneof("content") == "host_request_status_changed" 

542 assert res.messages[1].text.text == "Test request 1 message 3" 

543 assert res.messages[2].text.text == "Test request 1 message 2" 

544 assert res.messages[3].text.text == "Test request 1 message 1" 

545 assert res.messages[4].text.text == "Test request 1" 

546 assert res.messages[5].WhichOneof("content") == "chat_created" 

547 

548 

549def test_SendHostRequestMessage(db): 

550 user1, token1 = generate_user() 

551 user2, token2 = generate_user() 

552 user3, token3 = generate_user() 

553 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

554 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

555 with requests_session(token1) as api: 

556 host_request_id = api.CreateHostRequest( 

557 requests_pb2.CreateHostRequestReq( 

558 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request 1" 

559 ) 

560 ).host_request_id 

561 

562 with pytest.raises(grpc.RpcError) as e: 

563 api.SendHostRequestMessage( 

564 requests_pb2.SendHostRequestMessageReq(host_request_id=999, text="Test message 1") 

565 ) 

566 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

567 

568 with pytest.raises(grpc.RpcError) as e: 

569 api.SendHostRequestMessage(requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="")) 

570 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

571 assert e.value.details() == errors.INVALID_MESSAGE 

572 

573 api.SendHostRequestMessage( 

574 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 1") 

575 ) 

576 res = api.GetHostRequestMessages(requests_pb2.GetHostRequestMessagesReq(host_request_id=host_request_id)) 

577 assert res.messages[0].text.text == "Test message 1" 

578 assert res.messages[0].author_user_id == user1.id 

579 

580 with requests_session(token3) as api: 

581 # other user can't send 

582 with pytest.raises(grpc.RpcError) as e: 

583 api.SendHostRequestMessage( 

584 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 2") 

585 ) 

586 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

587 assert e.value.details() == errors.HOST_REQUEST_NOT_FOUND 

588 

589 with requests_session(token2) as api: 

590 api.SendHostRequestMessage( 

591 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 2") 

592 ) 

593 res = api.GetHostRequestMessages(requests_pb2.GetHostRequestMessagesReq(host_request_id=host_request_id)) 

594 # including 2 for creation control message and message 

595 assert len(res.messages) == 4 

596 assert res.messages[0].text.text == "Test message 2" 

597 assert res.messages[0].author_user_id == user2.id 

598 

599 # can't send messages to a rejected, confirmed or cancelled request, but can for accepted 

600 api.RespondHostRequest( 

601 requests_pb2.RespondHostRequestReq( 

602 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

603 ) 

604 ) 

605 with pytest.raises(grpc.RpcError) as e: 

606 api.SendHostRequestMessage( 

607 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 3") 

608 ) 

609 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

610 assert e.value.details() == errors.HOST_REQUEST_CLOSED 

611 

612 api.RespondHostRequest( 

613 requests_pb2.RespondHostRequestReq( 

614 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

615 ) 

616 ) 

617 

618 with requests_session(token1) as api: 

619 api.RespondHostRequest( 

620 requests_pb2.RespondHostRequestReq( 

621 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

622 ) 

623 ) 

624 api.SendHostRequestMessage( 

625 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 3") 

626 ) 

627 

628 api.RespondHostRequest( 

629 requests_pb2.RespondHostRequestReq( 

630 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

631 ) 

632 ) 

633 with pytest.raises(grpc.RpcError) as e: 

634 api.SendHostRequestMessage( 

635 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 3") 

636 ) 

637 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

638 assert e.value.details() == errors.HOST_REQUEST_CLOSED 

639 

640 

641def test_get_updates(db): 

642 user1, token1 = generate_user() 

643 user2, token2 = generate_user() 

644 user3, token3 = generate_user() 

645 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

646 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

647 with requests_session(token1) as api: 

648 host_request_id = api.CreateHostRequest( 

649 requests_pb2.CreateHostRequestReq( 

650 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test message 0" 

651 ) 

652 ).host_request_id 

653 

654 api.SendHostRequestMessage( 

655 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 1") 

656 ) 

657 api.SendHostRequestMessage( 

658 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 2") 

659 ) 

660 api.RespondHostRequest( 

661 requests_pb2.RespondHostRequestReq( 

662 host_request_id=host_request_id, 

663 status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED, 

664 text="Test message 3", 

665 ) 

666 ) 

667 

668 api.CreateHostRequest( 

669 requests_pb2.CreateHostRequestReq( 

670 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test message 4" 

671 ) 

672 ) 

673 

674 res = api.GetHostRequestMessages(requests_pb2.GetHostRequestMessagesReq(host_request_id=host_request_id)) 

675 assert len(res.messages) == 6 

676 assert res.messages[0].text.text == "Test message 3" 

677 assert res.messages[1].host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

678 assert res.messages[2].text.text == "Test message 2" 

679 assert res.messages[3].text.text == "Test message 1" 

680 assert res.messages[4].text.text == "Test message 0" 

681 message_id_3 = res.messages[0].message_id 

682 message_id_cancel = res.messages[1].message_id 

683 message_id_2 = res.messages[2].message_id 

684 message_id_1 = res.messages[3].message_id 

685 message_id_0 = res.messages[4].message_id 

686 

687 with pytest.raises(grpc.RpcError) as e: 

688 api.GetHostRequestUpdates(requests_pb2.GetHostRequestUpdatesReq(newest_message_id=0)) 

689 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

690 

691 res = api.GetHostRequestUpdates(requests_pb2.GetHostRequestUpdatesReq(newest_message_id=message_id_1)) 

692 assert res.no_more 

693 assert len(res.updates) == 5 

694 assert res.updates[0].message.text.text == "Test message 2" 

695 assert ( 

696 res.updates[1].message.host_request_status_changed.status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

697 ) 

698 assert res.updates[1].status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

699 assert res.updates[2].message.text.text == "Test message 3" 

700 assert res.updates[3].message.WhichOneof("content") == "chat_created" 

701 assert res.updates[3].status == conversations_pb2.HOST_REQUEST_STATUS_PENDING 

702 assert res.updates[4].message.text.text == "Test message 4" 

703 

704 res = api.GetHostRequestUpdates(requests_pb2.GetHostRequestUpdatesReq(newest_message_id=message_id_1, number=1)) 

705 assert not res.no_more 

706 assert len(res.updates) == 1 

707 assert res.updates[0].message.text.text == "Test message 2" 

708 assert res.updates[0].status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

709 

710 with requests_session(token3) as api: 

711 # other user can't access 

712 res = api.GetHostRequestUpdates(requests_pb2.GetHostRequestUpdatesReq(newest_message_id=message_id_1)) 

713 assert len(res.updates) == 0 

714 

715 

716def test_mark_last_seen(db): 

717 user1, token1 = generate_user() 

718 user2, token2 = generate_user() 

719 user3, token3 = generate_user() 

720 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

721 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

722 with requests_session(token1) as api: 

723 host_request_id = api.CreateHostRequest( 

724 requests_pb2.CreateHostRequestReq( 

725 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test message 0" 

726 ) 

727 ).host_request_id 

728 

729 host_request_id_2 = api.CreateHostRequest( 

730 requests_pb2.CreateHostRequestReq( 

731 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test message 0a" 

732 ) 

733 ).host_request_id 

734 

735 api.SendHostRequestMessage( 

736 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 1") 

737 ) 

738 api.SendHostRequestMessage( 

739 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id, text="Test message 2") 

740 ) 

741 api.RespondHostRequest( 

742 requests_pb2.RespondHostRequestReq( 

743 host_request_id=host_request_id, 

744 status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED, 

745 text="Test message 3", 

746 ) 

747 ) 

748 

749 # test Ping unseen host request count, should be automarked after sending 

750 with api_session(token1) as api: 

751 assert api.Ping(api_pb2.PingReq()).unseen_received_host_request_count == 0 

752 assert api.Ping(api_pb2.PingReq()).unseen_sent_host_request_count == 0 

753 

754 with api_session(token2) as api: 

755 assert api.Ping(api_pb2.PingReq()).unseen_received_host_request_count == 2 

756 assert api.Ping(api_pb2.PingReq()).unseen_sent_host_request_count == 0 

757 

758 with requests_session(token2) as api: 

759 assert api.ListHostRequests(requests_pb2.ListHostRequestsReq()).host_requests[0].last_seen_message_id == 0 

760 

761 api.MarkLastSeenHostRequest( 

762 requests_pb2.MarkLastSeenHostRequestReq(host_request_id=host_request_id, last_seen_message_id=3) 

763 ) 

764 

765 assert api.ListHostRequests(requests_pb2.ListHostRequestsReq()).host_requests[0].last_seen_message_id == 3 

766 

767 with pytest.raises(grpc.RpcError) as e: 

768 api.MarkLastSeenHostRequest( 

769 requests_pb2.MarkLastSeenHostRequestReq(host_request_id=host_request_id, last_seen_message_id=1) 

770 ) 

771 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

772 assert e.value.details() == errors.CANT_UNSEE_MESSAGES 

773 

774 # this will be used to test sent request notifications 

775 host_request_id_3 = api.CreateHostRequest( 

776 requests_pb2.CreateHostRequestReq( 

777 host_user_id=user1.id, from_date=today_plus_2, to_date=today_plus_3, text="Another test request" 

778 ) 

779 ).host_request_id 

780 

781 # this should make id_2 all read 

782 api.SendHostRequestMessage( 

783 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id_2, text="Test") 

784 ) 

785 

786 with api_session(token2) as api: 

787 assert api.Ping(api_pb2.PingReq()).unseen_received_host_request_count == 1 

788 assert api.Ping(api_pb2.PingReq()).unseen_sent_host_request_count == 0 

789 

790 # make sure sent and received count for unseen notifications 

791 with requests_session(token1) as api: 

792 api.SendHostRequestMessage( 

793 requests_pb2.SendHostRequestMessageReq(host_request_id=host_request_id_3, text="Test message") 

794 ) 

795 

796 with api_session(token2) as api: 

797 assert api.Ping(api_pb2.PingReq()).unseen_received_host_request_count == 1 

798 assert api.Ping(api_pb2.PingReq()).unseen_sent_host_request_count == 1 

799 

800 

801def test_response_rate(db): 

802 user1, token1 = generate_user() 

803 user2, token2 = generate_user() 

804 user3, token3 = generate_user(delete_user=True) 

805 

806 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

807 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

808 

809 with session_scope() as session: 

810 refresh_materialized_view(session, "user_response_rates") 

811 

812 with requests_session(token1) as api: 

813 # deleted: not found 

814 with pytest.raises(grpc.RpcError) as e: 

815 api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user3.id)) 

816 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

817 assert e.value.details() == errors.USER_NOT_FOUND 

818 

819 # no requests: insufficient 

820 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

821 assert res.HasField("insufficient_data") 

822 

823 # send a request and back date it by 36 hours 

824 host_request_1 = api.CreateHostRequest( 

825 requests_pb2.CreateHostRequestReq( 

826 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

827 ) 

828 ).host_request_id 

829 with session_scope() as session: 

830 session.execute( 

831 select(Message) 

832 .where(Message.conversation_id == host_request_1) 

833 .where(Message.message_type == MessageType.chat_created) 

834 ).scalar_one().time = now() - timedelta(hours=36) 

835 refresh_materialized_view(session, "user_response_rates") 

836 

837 # still insufficient 

838 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

839 assert res.HasField("insufficient_data") 

840 

841 # send a request and back date it by 35 hours 

842 host_request_2 = api.CreateHostRequest( 

843 requests_pb2.CreateHostRequestReq( 

844 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

845 ) 

846 ).host_request_id 

847 with session_scope() as session: 

848 session.execute( 

849 select(Message) 

850 .where(Message.conversation_id == host_request_2) 

851 .where(Message.message_type == MessageType.chat_created) 

852 ).scalar_one().time = now() - timedelta(hours=35) 

853 refresh_materialized_view(session, "user_response_rates") 

854 

855 # still insufficient 

856 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

857 assert res.HasField("insufficient_data") 

858 

859 # send a request and back date it by 34 hours 

860 host_request_3 = api.CreateHostRequest( 

861 requests_pb2.CreateHostRequestReq( 

862 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

863 ) 

864 ).host_request_id 

865 with session_scope() as session: 

866 session.execute( 

867 select(Message) 

868 .where(Message.conversation_id == host_request_3) 

869 .where(Message.message_type == MessageType.chat_created) 

870 ).scalar_one().time = now() - timedelta(hours=34) 

871 refresh_materialized_view(session, "user_response_rates") 

872 

873 # now low 

874 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

875 assert res.HasField("low") 

876 

877 with requests_session(token2) as api: 

878 # accept a host req 

879 api.RespondHostRequest( 

880 requests_pb2.RespondHostRequestReq( 

881 host_request_id=host_request_2, 

882 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

883 text="Accepting host request", 

884 ) 

885 ) 

886 

887 with session_scope() as session: 

888 refresh_materialized_view(session, "user_response_rates") 

889 

890 with requests_session(token1) as api: 

891 # now some w p33 = 35h 

892 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

893 assert res.HasField("some") 

894 assert res.some.response_time_p33.ToTimedelta() == timedelta(hours=35) 

895 

896 with requests_session(token2) as api: 

897 # accept another host req 

898 api.RespondHostRequest( 

899 requests_pb2.RespondHostRequestReq( 

900 host_request_id=host_request_3, 

901 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

902 text="Accepting host request", 

903 ) 

904 ) 

905 

906 with session_scope() as session: 

907 refresh_materialized_view(session, "user_response_rates") 

908 

909 with requests_session(token1) as api: 

910 # now most w p33 = 34h, p66 = 35h 

911 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

912 assert res.HasField("most") 

913 assert res.most.response_time_p33.ToTimedelta() == timedelta(hours=34) 

914 assert res.most.response_time_p66.ToTimedelta() == timedelta(hours=35) 

915 

916 with requests_session(token2) as api: 

917 # accept last host req 

918 api.RespondHostRequest( 

919 requests_pb2.RespondHostRequestReq( 

920 host_request_id=host_request_1, 

921 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

922 text="Accepting host request", 

923 ) 

924 ) 

925 

926 with session_scope() as session: 

927 refresh_materialized_view(session, "user_response_rates") 

928 

929 with requests_session(token1) as api: 

930 # now all w p33 = 34h, p66 = 35h 

931 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

932 assert res.HasField("almost_all") 

933 assert res.almost_all.response_time_p33.ToTimedelta() == timedelta(hours=34) 

934 assert res.almost_all.response_time_p66.ToTimedelta() == timedelta(hours=35) 

935 

936 # send a request and back date it by 2 hours 

937 host_request_4 = api.CreateHostRequest( 

938 requests_pb2.CreateHostRequestReq( 

939 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

940 ) 

941 ).host_request_id 

942 with session_scope() as session: 

943 session.execute( 

944 select(Message) 

945 .where(Message.conversation_id == host_request_4) 

946 .where(Message.message_type == MessageType.chat_created) 

947 ).scalar_one().time = now() - timedelta(hours=2) 

948 refresh_materialized_view(session, "user_response_rates") 

949 

950 # send a request and back date it by 4 hours 

951 host_request_5 = api.CreateHostRequest( 

952 requests_pb2.CreateHostRequestReq( 

953 host_user_id=user2.id, from_date=today_plus_2, to_date=today_plus_3, text="Test request" 

954 ) 

955 ).host_request_id 

956 with session_scope() as session: 

957 session.execute( 

958 select(Message) 

959 .where(Message.conversation_id == host_request_5) 

960 .where(Message.message_type == MessageType.chat_created) 

961 ).scalar_one().time = now() - timedelta(hours=4) 

962 refresh_materialized_view(session, "user_response_rates") 

963 

964 # now some w p33 = 35h 

965 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

966 assert res.HasField("some") 

967 assert res.some.response_time_p33.ToTimedelta() == timedelta(hours=35) 

968 

969 with requests_session(token2) as api: 

970 # accept host req 

971 api.RespondHostRequest( 

972 requests_pb2.RespondHostRequestReq( 

973 host_request_id=host_request_5, 

974 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

975 text="Accepting host request", 

976 ) 

977 ) 

978 

979 with session_scope() as session: 

980 refresh_materialized_view(session, "user_response_rates") 

981 

982 with requests_session(token1) as api: 

983 # now most w p33 = 34h, p66 = 36h 

984 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

985 assert res.HasField("most") 

986 assert res.most.response_time_p33.ToTimedelta() == timedelta(hours=34) 

987 assert res.most.response_time_p66.ToTimedelta() == timedelta(hours=36) 

988 

989 with requests_session(token2) as api: 

990 # accept host req 

991 api.RespondHostRequest( 

992 requests_pb2.RespondHostRequestReq( 

993 host_request_id=host_request_4, 

994 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

995 text="Accepting host request", 

996 ) 

997 ) 

998 

999 with session_scope() as session: 

1000 refresh_materialized_view(session, "user_response_rates") 

1001 

1002 with requests_session(token1) as api: 

1003 # now most w p33 = 4h, p66 = 35h 

1004 res = api.GetResponseRate(requests_pb2.GetResponseRateReq(user_id=user2.id)) 

1005 assert res.HasField("almost_all") 

1006 assert res.almost_all.response_time_p33.ToTimedelta() == timedelta(hours=4) 

1007 assert res.almost_all.response_time_p66.ToTimedelta() == timedelta(hours=35) 

1008 

1009 

1010def test_request_notifications(db, push_collector): 

1011 host, host_token = generate_user(complete_profile=True) 

1012 surfer, surfer_token = generate_user(complete_profile=True) 

1013 

1014 today_plus_2 = (today() + timedelta(days=2)).isoformat() 

1015 today_plus_3 = (today() + timedelta(days=3)).isoformat() 

1016 

1017 with requests_session(surfer_token) as api: 

1018 with mock_notification_email() as mock: 

1019 hr_id = api.CreateHostRequest( 

1020 requests_pb2.CreateHostRequestReq( 

1021 host_user_id=host.id, 

1022 from_date=today_plus_2, 

1023 to_date=today_plus_3, 

1024 text="can i stay plz", 

1025 ) 

1026 ).host_request_id 

1027 

1028 mock.assert_called_once() 

1029 e = email_fields(mock) 

1030 assert e.recipient == host.email 

1031 assert "host request" in e.subject.lower() 

1032 assert host.name in e.plain 

1033 assert host.name in e.html 

1034 assert surfer.name in e.plain 

1035 assert surfer.name in e.html 

1036 assert v2date(today_plus_2, host) in e.plain 

1037 assert v2date(today_plus_2, host) in e.html 

1038 assert v2date(today_plus_3, host) in e.plain 

1039 assert v2date(today_plus_3, host) in e.html 

1040 assert "http://localhost:5001/img/thumbnail/" not in e.plain 

1041 assert "http://localhost:5001/img/thumbnail/" in e.html 

1042 assert f"http://localhost:3000/messages/request/{hr_id}" in e.plain 

1043 assert f"http://localhost:3000/messages/request/{hr_id}" in e.html 

1044 

1045 push_collector.assert_user_has_single_matching( 

1046 host.id, 

1047 title=f"{surfer.name} sent you a host request", 

1048 ) 

1049 

1050 with requests_session(host_token) as api: 

1051 with mock_notification_email() as mock: 

1052 api.RespondHostRequest( 

1053 requests_pb2.RespondHostRequestReq( 

1054 host_request_id=hr_id, 

1055 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

1056 text="Accepting host request", 

1057 ) 

1058 ) 

1059 

1060 e = email_fields(mock) 

1061 assert e.recipient == surfer.email 

1062 assert "host request" in e.subject.lower() 

1063 assert host.name in e.plain 

1064 assert host.name in e.html 

1065 assert surfer.name in e.plain 

1066 assert surfer.name in e.html 

1067 assert v2date(today_plus_2, surfer) in e.plain 

1068 assert v2date(today_plus_2, surfer) in e.html 

1069 assert v2date(today_plus_3, surfer) in e.plain 

1070 assert v2date(today_plus_3, surfer) in e.html 

1071 assert "http://localhost:5001/img/thumbnail/" not in e.plain 

1072 assert "http://localhost:5001/img/thumbnail/" in e.html 

1073 assert f"http://localhost:3000/messages/request/{hr_id}" in e.plain 

1074 assert f"http://localhost:3000/messages/request/{hr_id}" in e.html 

1075 

1076 push_collector.assert_user_has_single_matching( 

1077 surfer.id, 

1078 title=f"{host.name} accepted your host request", 

1079 )