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

547 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-07-02 02:47 +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 # 9 including initial message 

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

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, 

536 last_message_id=res.messages[2].message_id, 

537 number=6, 

538 ) 

539 ) 

540 assert res.no_more 

541 assert len(res.messages) == 6 

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

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

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

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

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

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

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

549 

550 

551def test_SendHostRequestMessage(db): 

552 user1, token1 = generate_user() 

553 user2, token2 = generate_user() 

554 user3, token3 = generate_user() 

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

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

557 with requests_session(token1) as api: 

558 host_request_id = api.CreateHostRequest( 

559 requests_pb2.CreateHostRequestReq( 

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

561 ) 

562 ).host_request_id 

563 

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

565 api.SendHostRequestMessage( 

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

567 ) 

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

569 

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

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

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

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

574 

575 api.SendHostRequestMessage( 

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

577 ) 

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

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

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

581 

582 with requests_session(token3) as api: 

583 # other user can't send 

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

585 api.SendHostRequestMessage( 

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

587 ) 

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

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

590 

591 with requests_session(token2) as api: 

592 api.SendHostRequestMessage( 

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

594 ) 

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

596 # including 2 for creation control message and message 

597 assert len(res.messages) == 4 

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

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

600 

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

602 api.RespondHostRequest( 

603 requests_pb2.RespondHostRequestReq( 

604 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

605 ) 

606 ) 

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

608 api.SendHostRequestMessage( 

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

610 ) 

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

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

613 

614 api.RespondHostRequest( 

615 requests_pb2.RespondHostRequestReq( 

616 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

617 ) 

618 ) 

619 

620 with requests_session(token1) as api: 

621 api.RespondHostRequest( 

622 requests_pb2.RespondHostRequestReq( 

623 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

624 ) 

625 ) 

626 api.SendHostRequestMessage( 

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

628 ) 

629 

630 api.RespondHostRequest( 

631 requests_pb2.RespondHostRequestReq( 

632 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

633 ) 

634 ) 

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

636 api.SendHostRequestMessage( 

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

638 ) 

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

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

641 

642 

643def test_get_updates(db): 

644 user1, token1 = generate_user() 

645 user2, token2 = generate_user() 

646 user3, token3 = generate_user() 

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

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

649 with requests_session(token1) as api: 

650 host_request_id = api.CreateHostRequest( 

651 requests_pb2.CreateHostRequestReq( 

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

653 ) 

654 ).host_request_id 

655 

656 api.SendHostRequestMessage( 

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

658 ) 

659 api.SendHostRequestMessage( 

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

661 ) 

662 api.RespondHostRequest( 

663 requests_pb2.RespondHostRequestReq( 

664 host_request_id=host_request_id, 

665 status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED, 

666 text="Test message 3", 

667 ) 

668 ) 

669 

670 api.CreateHostRequest( 

671 requests_pb2.CreateHostRequestReq( 

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

673 ) 

674 ) 

675 

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

677 assert len(res.messages) == 6 

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

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

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

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

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

683 message_id_3 = res.messages[0].message_id 

684 message_id_cancel = res.messages[1].message_id 

685 message_id_2 = res.messages[2].message_id 

686 message_id_1 = res.messages[3].message_id 

687 message_id_0 = res.messages[4].message_id 

688 

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

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

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

692 

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

694 assert res.no_more 

695 assert len(res.updates) == 5 

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

697 assert ( 

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

699 ) 

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

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

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

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

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

705 

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

707 assert not res.no_more 

708 assert len(res.updates) == 1 

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

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

711 

712 with requests_session(token3) as api: 

713 # other user can't access 

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

715 assert len(res.updates) == 0 

716 

717 

718def test_archive_host_request(db): 

719 user1, token1 = generate_user() 

720 user2, token2 = generate_user() 

721 

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

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

724 

725 with requests_session(token1) as api: 

726 host_request_id = api.CreateHostRequest( 

727 requests_pb2.CreateHostRequestReq( 

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

729 ) 

730 ).host_request_id 

731 

732 api.SendHostRequestMessage( 

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

734 ) 

735 api.SendHostRequestMessage( 

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

737 ) 

738 # happy path archiving host request 

739 with requests_session(token1) as api: 

740 api.RespondHostRequest( 

741 requests_pb2.RespondHostRequestReq( 

742 host_request_id=host_request_id, 

743 status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED, 

744 text="Test message 3", 

745 ) 

746 ) 

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

748 assert len(res.host_requests) == 1 

749 assert res.host_requests[0].status == conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

750 api.SetHostRequestArchiveStatus( 

751 requests_pb2.SetHostRequestArchiveStatusReq(host_request_id=host_request_id, is_archived=True) 

752 ) 

753 res = api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_archived=True)) 

754 assert len(res.host_requests) == 1 

755 

756 

757def test_mark_last_seen(db): 

758 user1, token1 = generate_user() 

759 user2, token2 = generate_user() 

760 user3, token3 = generate_user() 

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

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

763 with requests_session(token1) as api: 

764 host_request_id = api.CreateHostRequest( 

765 requests_pb2.CreateHostRequestReq( 

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

767 ) 

768 ).host_request_id 

769 

770 host_request_id_2 = api.CreateHostRequest( 

771 requests_pb2.CreateHostRequestReq( 

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

773 ) 

774 ).host_request_id 

775 

776 api.SendHostRequestMessage( 

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

778 ) 

779 api.SendHostRequestMessage( 

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

781 ) 

782 api.RespondHostRequest( 

783 requests_pb2.RespondHostRequestReq( 

784 host_request_id=host_request_id, 

785 status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED, 

786 text="Test message 3", 

787 ) 

788 ) 

789 

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

791 with api_session(token1) as api: 

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

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

794 

795 with api_session(token2) as api: 

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

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

798 

799 with requests_session(token2) as api: 

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

801 

802 api.MarkLastSeenHostRequest( 

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

804 ) 

805 

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

807 

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

809 api.MarkLastSeenHostRequest( 

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

811 ) 

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

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

814 

815 # this will be used to test sent request notifications 

816 host_request_id_3 = api.CreateHostRequest( 

817 requests_pb2.CreateHostRequestReq( 

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

819 ) 

820 ).host_request_id 

821 

822 # this should make id_2 all read 

823 api.SendHostRequestMessage( 

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

825 ) 

826 

827 with api_session(token2) as api: 

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

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

830 

831 # make sure sent and received count for unseen notifications 

832 with requests_session(token1) as api: 

833 api.SendHostRequestMessage( 

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

835 ) 

836 

837 with api_session(token2) as api: 

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

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

840 

841 

842def test_response_rate(db): 

843 user1, token1 = generate_user() 

844 user2, token2 = generate_user() 

845 user3, token3 = generate_user(delete_user=True) 

846 

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

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

849 

850 with session_scope() as session: 

851 refresh_materialized_view(session, "user_response_rates") 

852 

853 with requests_session(token1) as api: 

854 # deleted: not found 

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

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

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

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

859 

860 # no requests: insufficient 

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

862 assert res.HasField("insufficient_data") 

863 

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

865 host_request_1 = api.CreateHostRequest( 

866 requests_pb2.CreateHostRequestReq( 

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

868 ) 

869 ).host_request_id 

870 with session_scope() as session: 

871 session.execute( 

872 select(Message) 

873 .where(Message.conversation_id == host_request_1) 

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

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

876 refresh_materialized_view(session, "user_response_rates") 

877 

878 # still insufficient 

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

880 assert res.HasField("insufficient_data") 

881 

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

883 host_request_2 = api.CreateHostRequest( 

884 requests_pb2.CreateHostRequestReq( 

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

886 ) 

887 ).host_request_id 

888 with session_scope() as session: 

889 session.execute( 

890 select(Message) 

891 .where(Message.conversation_id == host_request_2) 

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

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

894 refresh_materialized_view(session, "user_response_rates") 

895 

896 # still insufficient 

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

898 assert res.HasField("insufficient_data") 

899 

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

901 host_request_3 = api.CreateHostRequest( 

902 requests_pb2.CreateHostRequestReq( 

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

904 ) 

905 ).host_request_id 

906 with session_scope() as session: 

907 session.execute( 

908 select(Message) 

909 .where(Message.conversation_id == host_request_3) 

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

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

912 refresh_materialized_view(session, "user_response_rates") 

913 

914 # now low 

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

916 assert res.HasField("low") 

917 

918 with requests_session(token2) as api: 

919 # accept a host req 

920 api.RespondHostRequest( 

921 requests_pb2.RespondHostRequestReq( 

922 host_request_id=host_request_2, 

923 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

924 text="Accepting host request", 

925 ) 

926 ) 

927 

928 with session_scope() as session: 

929 refresh_materialized_view(session, "user_response_rates") 

930 

931 with requests_session(token1) as api: 

932 # now some w p33 = 35h 

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

934 assert res.HasField("some") 

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

936 

937 with requests_session(token2) as api: 

938 # accept another host req 

939 api.RespondHostRequest( 

940 requests_pb2.RespondHostRequestReq( 

941 host_request_id=host_request_3, 

942 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

943 text="Accepting host request", 

944 ) 

945 ) 

946 

947 with session_scope() as session: 

948 refresh_materialized_view(session, "user_response_rates") 

949 

950 with requests_session(token1) as api: 

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

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

953 assert res.HasField("most") 

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

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

956 

957 with requests_session(token2) as api: 

958 # accept last host req 

959 api.RespondHostRequest( 

960 requests_pb2.RespondHostRequestReq( 

961 host_request_id=host_request_1, 

962 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

963 text="Accepting host request", 

964 ) 

965 ) 

966 

967 with session_scope() as session: 

968 refresh_materialized_view(session, "user_response_rates") 

969 

970 with requests_session(token1) as api: 

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

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

973 assert res.HasField("almost_all") 

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

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

976 

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

978 host_request_4 = api.CreateHostRequest( 

979 requests_pb2.CreateHostRequestReq( 

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

981 ) 

982 ).host_request_id 

983 with session_scope() as session: 

984 session.execute( 

985 select(Message) 

986 .where(Message.conversation_id == host_request_4) 

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

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

989 refresh_materialized_view(session, "user_response_rates") 

990 

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

992 host_request_5 = api.CreateHostRequest( 

993 requests_pb2.CreateHostRequestReq( 

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

995 ) 

996 ).host_request_id 

997 with session_scope() as session: 

998 session.execute( 

999 select(Message) 

1000 .where(Message.conversation_id == host_request_5) 

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

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

1003 refresh_materialized_view(session, "user_response_rates") 

1004 

1005 # now some w p33 = 35h 

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

1007 assert res.HasField("some") 

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

1009 

1010 with requests_session(token2) as api: 

1011 # accept host req 

1012 api.RespondHostRequest( 

1013 requests_pb2.RespondHostRequestReq( 

1014 host_request_id=host_request_5, 

1015 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

1016 text="Accepting host request", 

1017 ) 

1018 ) 

1019 

1020 with session_scope() as session: 

1021 refresh_materialized_view(session, "user_response_rates") 

1022 

1023 with requests_session(token1) as api: 

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

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

1026 assert res.HasField("most") 

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

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

1029 

1030 with requests_session(token2) as api: 

1031 # accept host req 

1032 api.RespondHostRequest( 

1033 requests_pb2.RespondHostRequestReq( 

1034 host_request_id=host_request_4, 

1035 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

1036 text="Accepting host request", 

1037 ) 

1038 ) 

1039 

1040 with session_scope() as session: 

1041 refresh_materialized_view(session, "user_response_rates") 

1042 

1043 with requests_session(token1) as api: 

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

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

1046 assert res.HasField("almost_all") 

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

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

1049 

1050 

1051def test_request_notifications(db, push_collector): 

1052 host, host_token = generate_user(complete_profile=True) 

1053 surfer, surfer_token = generate_user(complete_profile=True) 

1054 

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

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

1057 

1058 with requests_session(surfer_token) as api: 

1059 with mock_notification_email() as mock: 

1060 hr_id = api.CreateHostRequest( 

1061 requests_pb2.CreateHostRequestReq( 

1062 host_user_id=host.id, 

1063 from_date=today_plus_2, 

1064 to_date=today_plus_3, 

1065 text="can i stay plz", 

1066 ) 

1067 ).host_request_id 

1068 

1069 mock.assert_called_once() 

1070 e = email_fields(mock) 

1071 assert e.recipient == host.email 

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

1073 assert host.name in e.plain 

1074 assert host.name in e.html 

1075 assert surfer.name in e.plain 

1076 assert surfer.name in e.html 

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

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

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

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

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

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

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

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

1085 

1086 push_collector.assert_user_has_single_matching( 

1087 host.id, 

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

1089 ) 

1090 

1091 with requests_session(host_token) as api: 

1092 with mock_notification_email() as mock: 

1093 api.RespondHostRequest( 

1094 requests_pb2.RespondHostRequestReq( 

1095 host_request_id=hr_id, 

1096 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

1097 text="Accepting host request", 

1098 ) 

1099 ) 

1100 

1101 e = email_fields(mock) 

1102 assert e.recipient == surfer.email 

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

1104 assert host.name in e.plain 

1105 assert host.name in e.html 

1106 assert surfer.name in e.plain 

1107 assert surfer.name in e.html 

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

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

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

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

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

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

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

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

1116 

1117 push_collector.assert_user_has_single_matching( 

1118 surfer.id, 

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

1120 )