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

507 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-10-15 13:03 +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.models import Message, MessageType 

10from couchers.templates.v2 import v2date 

11from couchers.utils import now, today 

12from proto import api_pb2, conversations_pb2, requests_pb2 

13from tests.test_fixtures import ( # noqa 

14 api_session, 

15 db, 

16 email_fields, 

17 generate_user, 

18 mock_notification_email, 

19 push_collector, 

20 requests_session, 

21 testconfig, 

22) 

23 

24 

25@pytest.fixture(autouse=True) 

26def _(testconfig): 

27 pass 

28 

29 

30def test_create_request(db): 

31 user1, token1 = generate_user() 

32 user2, token2 = generate_user() 

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

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

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

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

37 with requests_session(token1) as api: 

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

39 api.CreateHostRequest( 

40 requests_pb2.CreateHostRequestReq( 

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

42 ) 

43 ) 

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

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

46 

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

48 api.CreateHostRequest( 

49 requests_pb2.CreateHostRequestReq( 

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

51 ) 

52 ) 

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

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

55 

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

57 api.CreateHostRequest( 

58 requests_pb2.CreateHostRequestReq( 

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

60 ) 

61 ) 

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

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

64 

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

66 api.CreateHostRequest( 

67 requests_pb2.CreateHostRequestReq( 

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

69 ) 

70 ) 

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

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

73 

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

75 api.CreateHostRequest( 

76 requests_pb2.CreateHostRequestReq( 

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

78 ) 

79 ) 

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

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

82 

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

84 api.CreateHostRequest( 

85 requests_pb2.CreateHostRequestReq( 

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

87 ) 

88 ) 

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

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

91 

92 res = api.CreateHostRequest( 

93 requests_pb2.CreateHostRequestReq( 

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

95 ) 

96 ) 

97 assert ( 

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

99 .host_requests[0] 

100 .latest_message.text.text 

101 == "Test request" 

102 ) 

103 

104 today_ = today() 

105 today_plus_one_year = today_ + timedelta(days=365) 

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

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

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

109 api.CreateHostRequest( 

110 requests_pb2.CreateHostRequestReq( 

111 host_user_id=user2.id, 

112 from_date=today_plus_one_year_plus_2, 

113 to_date=today_plus_one_year_plus_3, 

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

115 ) 

116 ) 

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

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

119 

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

121 api.CreateHostRequest( 

122 requests_pb2.CreateHostRequestReq( 

123 host_user_id=user2.id, 

124 from_date=today_plus_2, 

125 to_date=today_plus_one_year_plus_3, 

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

127 ) 

128 ) 

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

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

131 

132 

133def test_create_request_incomplete_profile(db): 

134 user1, token1 = generate_user(complete_profile=False) 

135 user2, _ = generate_user() 

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

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

138 with requests_session(token1) as api: 

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

140 api.CreateHostRequest( 

141 requests_pb2.CreateHostRequestReq( 

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

143 ) 

144 ) 

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

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

147 

148 

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

150 with session_scope() as session: 

151 message = Message( 

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

153 ) 

154 

155 session.add(message) 

156 

157 

158def test_GetHostRequest(db): 

159 user1, token1 = generate_user() 

160 user2, token2 = generate_user() 

161 user3, token3 = generate_user() 

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

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

164 with requests_session(token1) as api: 

165 host_request_id = api.CreateHostRequest( 

166 requests_pb2.CreateHostRequestReq( 

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

168 ) 

169 ).host_request_id 

170 

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

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

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

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

175 

176 api.SendHostRequestMessage( 

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

178 ) 

179 

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

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

182 

183 

184def test_ListHostRequests(db): 

185 user1, token1 = generate_user() 

186 user2, token2 = generate_user() 

187 user3, token3 = generate_user() 

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

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

190 with requests_session(token1) as api: 

191 host_request_1 = api.CreateHostRequest( 

192 requests_pb2.CreateHostRequestReq( 

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

194 ) 

195 ).host_request_id 

196 

197 host_request_2 = api.CreateHostRequest( 

198 requests_pb2.CreateHostRequestReq( 

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

200 ) 

201 ).host_request_id 

202 

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

204 assert res.no_more 

205 assert len(res.host_requests) == 2 

206 

207 with requests_session(token2) as api: 

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

209 assert res.no_more 

210 assert len(res.host_requests) == 1 

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

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

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

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

215 

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

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

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

219 

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

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

222 

223 api.CreateHostRequest( 

224 requests_pb2.CreateHostRequestReq( 

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

226 ) 

227 ) 

228 

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

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

231 

232 with requests_session(token3) as api: 

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

234 assert res.no_more 

235 assert len(res.host_requests) == 1 

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

237 

238 with requests_session(token1) as api: 

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

240 assert len(res.host_requests) == 1 

241 

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

243 assert len(res.host_requests) == 3 

244 

245 

246def test_ListHostRequests_pagination_regression(db): 

247 """ 

248 ListHostRequests was skipping a request when getting multiple pages 

249 """ 

250 user1, token1 = generate_user() 

251 user2, token2 = generate_user() 

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

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

254 with requests_session(token1) as api: 

255 host_request_1 = api.CreateHostRequest( 

256 requests_pb2.CreateHostRequestReq( 

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

258 ) 

259 ).host_request_id 

260 

261 host_request_2 = api.CreateHostRequest( 

262 requests_pb2.CreateHostRequestReq( 

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

264 ) 

265 ).host_request_id 

266 

267 host_request_3 = api.CreateHostRequest( 

268 requests_pb2.CreateHostRequestReq( 

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

270 ) 

271 ).host_request_id 

272 

273 with requests_session(token2) as api: 

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

275 assert res.no_more 

276 assert len(res.host_requests) == 3 

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

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

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

280 

281 with requests_session(token2) as api: 

282 api.RespondHostRequest( 

283 requests_pb2.RespondHostRequestReq( 

284 host_request_id=host_request_2, 

285 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

286 text="Accepting host request 2", 

287 ) 

288 ) 

289 api.RespondHostRequest( 

290 requests_pb2.RespondHostRequestReq( 

291 host_request_id=host_request_1, 

292 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

293 text="Accepting host request 1", 

294 ) 

295 ) 

296 api.RespondHostRequest( 

297 requests_pb2.RespondHostRequestReq( 

298 host_request_id=host_request_3, 

299 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

300 text="Accepting host request 3", 

301 ) 

302 ) 

303 

304 with requests_session(token2) as api: 

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

306 assert res.no_more 

307 assert len(res.host_requests) == 3 

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

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

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

311 

312 with requests_session(token2) as api: 

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

314 assert not res.no_more 

315 assert len(res.host_requests) == 1 

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

317 res = api.ListHostRequests( 

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

319 ) 

320 assert not res.no_more 

321 assert len(res.host_requests) == 1 

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

323 res = api.ListHostRequests( 

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

325 ) 

326 assert res.no_more 

327 assert len(res.host_requests) == 1 

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

329 

330 

331def test_ListHostRequests_active_filter(db): 

332 user1, token1 = generate_user() 

333 user2, token2 = generate_user() 

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

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

336 

337 with requests_session(token1) as api: 

338 request_id = api.CreateHostRequest( 

339 requests_pb2.CreateHostRequestReq( 

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

341 ) 

342 ).host_request_id 

343 api.RespondHostRequest( 

344 requests_pb2.RespondHostRequestReq( 

345 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

346 ) 

347 ) 

348 

349 with requests_session(token2) as api: 

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

351 assert len(res.host_requests) == 1 

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

353 assert len(res.host_requests) == 0 

354 

355 

356def test_RespondHostRequests(db): 

357 user1, token1 = generate_user() 

358 user2, token2 = generate_user() 

359 user3, token3 = generate_user() 

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

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

362 

363 with requests_session(token1) as api: 

364 request_id = api.CreateHostRequest( 

365 requests_pb2.CreateHostRequestReq( 

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

367 ) 

368 ).host_request_id 

369 

370 # another user can't access 

371 with requests_session(token3) as api: 

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

373 api.RespondHostRequest( 

374 requests_pb2.RespondHostRequestReq( 

375 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

376 ) 

377 ) 

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

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

380 

381 with requests_session(token1) as api: 

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

383 api.RespondHostRequest( 

384 requests_pb2.RespondHostRequestReq( 

385 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

386 ) 

387 ) 

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

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

390 

391 with requests_session(token2) as api: 

392 # non existing id 

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

394 api.RespondHostRequest( 

395 requests_pb2.RespondHostRequestReq( 

396 host_request_id=9999, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

397 ) 

398 ) 

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

400 

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

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

403 api.RespondHostRequest( 

404 requests_pb2.RespondHostRequestReq( 

405 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

406 ) 

407 ) 

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

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

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

411 api.RespondHostRequest( 

412 requests_pb2.RespondHostRequestReq( 

413 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

414 ) 

415 ) 

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

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

418 

419 api.RespondHostRequest( 

420 requests_pb2.RespondHostRequestReq( 

421 host_request_id=request_id, 

422 status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED, 

423 text="Test rejection message", 

424 ) 

425 ) 

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

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

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

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

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

431 api.RespondHostRequest( 

432 requests_pb2.RespondHostRequestReq( 

433 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

434 ) 

435 ) 

436 

437 with requests_session(token1) as api: 

438 # can't make pending 

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

440 api.RespondHostRequest( 

441 requests_pb2.RespondHostRequestReq( 

442 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_PENDING 

443 ) 

444 ) 

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

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

447 

448 # can confirm then cancel 

449 api.RespondHostRequest( 

450 requests_pb2.RespondHostRequestReq( 

451 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

452 ) 

453 ) 

454 

455 api.RespondHostRequest( 

456 requests_pb2.RespondHostRequestReq( 

457 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

458 ) 

459 ) 

460 

461 # can't confirm after having cancelled 

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

463 api.RespondHostRequest( 

464 requests_pb2.RespondHostRequestReq( 

465 host_request_id=request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

466 ) 

467 ) 

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

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

470 

471 # at this point there should be 7 messages 

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

473 with requests_session(token1) as api: 

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

475 assert len(res.messages) == 7 

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

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

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

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

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

481 

482 

483def test_get_host_request_messages(db): 

484 user1, token1 = generate_user() 

485 user2, token2 = generate_user() 

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

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

488 with requests_session(token1) as api: 

489 res = api.CreateHostRequest( 

490 requests_pb2.CreateHostRequestReq( 

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

492 ) 

493 ) 

494 conversation_id = res.host_request_id 

495 

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

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

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

499 

500 with requests_session(token2) as api: 

501 api.RespondHostRequest( 

502 requests_pb2.RespondHostRequestReq( 

503 host_request_id=conversation_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

504 ) 

505 ) 

506 

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

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

509 

510 api.RespondHostRequest( 

511 requests_pb2.RespondHostRequestReq( 

512 host_request_id=conversation_id, status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

513 ) 

514 ) 

515 

516 with requests_session(token1) as api: 

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

518 # 9 including initial message 

519 assert len(res.messages) == 9 

520 assert res.no_more 

521 

522 res = api.GetHostRequestMessages( 

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

524 ) 

525 assert not res.no_more 

526 assert len(res.messages) == 3 

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

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

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

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

531 

532 res = api.GetHostRequestMessages( 

533 requests_pb2.GetHostRequestMessagesReq( 

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

535 ) 

536 ) 

537 assert res.no_more 

538 assert len(res.messages) == 6 

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

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

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

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

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

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

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

546 

547 

548def test_SendHostRequestMessage(db): 

549 user1, token1 = generate_user() 

550 user2, token2 = generate_user() 

551 user3, token3 = generate_user() 

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

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

554 with requests_session(token1) as api: 

555 host_request_id = api.CreateHostRequest( 

556 requests_pb2.CreateHostRequestReq( 

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

558 ) 

559 ).host_request_id 

560 

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

562 api.SendHostRequestMessage( 

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

564 ) 

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

566 

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

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

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

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

571 

572 api.SendHostRequestMessage( 

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

574 ) 

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

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

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

578 

579 with requests_session(token3) as api: 

580 # other user can't send 

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

582 api.SendHostRequestMessage( 

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

584 ) 

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

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

587 

588 with requests_session(token2) as api: 

589 api.SendHostRequestMessage( 

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

591 ) 

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

593 # including 2 for creation control message and message 

594 assert len(res.messages) == 4 

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

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

597 

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

599 api.RespondHostRequest( 

600 requests_pb2.RespondHostRequestReq( 

601 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_REJECTED 

602 ) 

603 ) 

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

605 api.SendHostRequestMessage( 

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

607 ) 

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

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

610 

611 api.RespondHostRequest( 

612 requests_pb2.RespondHostRequestReq( 

613 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

614 ) 

615 ) 

616 

617 with requests_session(token1) as api: 

618 api.RespondHostRequest( 

619 requests_pb2.RespondHostRequestReq( 

620 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

621 ) 

622 ) 

623 api.SendHostRequestMessage( 

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

625 ) 

626 

627 api.RespondHostRequest( 

628 requests_pb2.RespondHostRequestReq( 

629 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED 

630 ) 

631 ) 

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

633 api.SendHostRequestMessage( 

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

635 ) 

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

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

638 

639 

640def test_get_updates(db): 

641 user1, token1 = generate_user() 

642 user2, token2 = generate_user() 

643 user3, token3 = generate_user() 

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

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

646 with requests_session(token1) as api: 

647 host_request_id = api.CreateHostRequest( 

648 requests_pb2.CreateHostRequestReq( 

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

650 ) 

651 ).host_request_id 

652 

653 api.SendHostRequestMessage( 

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

655 ) 

656 api.SendHostRequestMessage( 

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

658 ) 

659 api.RespondHostRequest( 

660 requests_pb2.RespondHostRequestReq( 

661 host_request_id=host_request_id, 

662 status=conversations_pb2.HOST_REQUEST_STATUS_CANCELLED, 

663 text="Test message 3", 

664 ) 

665 ) 

666 

667 api.CreateHostRequest( 

668 requests_pb2.CreateHostRequestReq( 

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

670 ) 

671 ) 

672 

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

674 assert len(res.messages) == 6 

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

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

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

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

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

680 message_id_3 = res.messages[0].message_id 

681 message_id_cancel = res.messages[1].message_id 

682 message_id_2 = res.messages[2].message_id 

683 message_id_1 = res.messages[3].message_id 

684 message_id_0 = res.messages[4].message_id 

685 

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

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

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

689 

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

691 assert res.no_more 

692 assert len(res.updates) == 5 

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

694 assert ( 

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

696 ) 

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

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

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

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

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

702 

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

704 assert not res.no_more 

705 assert len(res.updates) == 1 

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

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

708 

709 with requests_session(token3) as api: 

710 # other user can't access 

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

712 assert len(res.updates) == 0 

713 

714 

715def test_mark_last_seen(db): 

716 user1, token1 = generate_user() 

717 user2, token2 = generate_user() 

718 user3, token3 = generate_user() 

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

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

721 with requests_session(token1) as api: 

722 host_request_id = api.CreateHostRequest( 

723 requests_pb2.CreateHostRequestReq( 

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

725 ) 

726 ).host_request_id 

727 

728 host_request_id_2 = api.CreateHostRequest( 

729 requests_pb2.CreateHostRequestReq( 

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

731 ) 

732 ).host_request_id 

733 

734 api.SendHostRequestMessage( 

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

736 ) 

737 api.SendHostRequestMessage( 

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

739 ) 

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 

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

749 with api_session(token1) as api: 

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

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

752 

753 with api_session(token2) as api: 

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

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

756 

757 with requests_session(token2) as api: 

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

759 

760 api.MarkLastSeenHostRequest( 

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

762 ) 

763 

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

765 

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

767 api.MarkLastSeenHostRequest( 

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

769 ) 

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

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

772 

773 # this will be used to test sent request notifications 

774 host_request_id_3 = api.CreateHostRequest( 

775 requests_pb2.CreateHostRequestReq( 

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

777 ) 

778 ).host_request_id 

779 

780 # this should make id_2 all read 

781 api.SendHostRequestMessage( 

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

783 ) 

784 

785 with api_session(token2) as api: 

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

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

788 

789 # make sure sent and received count for unseen notifications 

790 with requests_session(token1) as api: 

791 api.SendHostRequestMessage( 

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

793 ) 

794 

795 with api_session(token2) as api: 

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

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

798 

799 

800def test_response_rate(db): 

801 user1, token1 = generate_user() 

802 user2, token2 = generate_user() 

803 

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

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

806 

807 with requests_session(token1) as api: 

808 # no requests: insufficient 

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

810 assert res.HasField("insufficient_data") 

811 

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

813 host_request_1 = api.CreateHostRequest( 

814 requests_pb2.CreateHostRequestReq( 

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

816 ) 

817 ).host_request_id 

818 with session_scope() as session: 

819 session.execute( 

820 select(Message) 

821 .where(Message.conversation_id == host_request_1) 

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

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

824 

825 # still insufficient 

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

827 assert res.HasField("insufficient_data") 

828 

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

830 host_request_2 = api.CreateHostRequest( 

831 requests_pb2.CreateHostRequestReq( 

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

833 ) 

834 ).host_request_id 

835 with session_scope() as session: 

836 session.execute( 

837 select(Message) 

838 .where(Message.conversation_id == host_request_2) 

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

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

841 

842 # still insufficient 

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

844 assert res.HasField("insufficient_data") 

845 

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

847 host_request_3 = api.CreateHostRequest( 

848 requests_pb2.CreateHostRequestReq( 

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

850 ) 

851 ).host_request_id 

852 with session_scope() as session: 

853 session.execute( 

854 select(Message) 

855 .where(Message.conversation_id == host_request_3) 

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

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

858 

859 # now low 

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

861 assert res.HasField("low") 

862 

863 with requests_session(token2) as api: 

864 # accept a host req 

865 api.RespondHostRequest( 

866 requests_pb2.RespondHostRequestReq( 

867 host_request_id=host_request_2, 

868 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

869 text="Accepting host request", 

870 ) 

871 ) 

872 

873 with requests_session(token1) as api: 

874 # now some w p33 = 35h 

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

876 assert res.HasField("some") 

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

878 

879 with requests_session(token2) as api: 

880 # accept another host req 

881 api.RespondHostRequest( 

882 requests_pb2.RespondHostRequestReq( 

883 host_request_id=host_request_3, 

884 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

885 text="Accepting host request", 

886 ) 

887 ) 

888 

889 with requests_session(token1) as api: 

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

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

892 assert res.HasField("most") 

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

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

895 

896 with requests_session(token2) as api: 

897 # accept last host req 

898 api.RespondHostRequest( 

899 requests_pb2.RespondHostRequestReq( 

900 host_request_id=host_request_1, 

901 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

902 text="Accepting host request", 

903 ) 

904 ) 

905 

906 with requests_session(token1) as api: 

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

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

909 assert res.HasField("almost_all") 

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

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

912 

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

914 host_request_4 = api.CreateHostRequest( 

915 requests_pb2.CreateHostRequestReq( 

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

917 ) 

918 ).host_request_id 

919 with session_scope() as session: 

920 session.execute( 

921 select(Message) 

922 .where(Message.conversation_id == host_request_4) 

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

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

925 

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

927 host_request_5 = api.CreateHostRequest( 

928 requests_pb2.CreateHostRequestReq( 

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

930 ) 

931 ).host_request_id 

932 with session_scope() as session: 

933 session.execute( 

934 select(Message) 

935 .where(Message.conversation_id == host_request_5) 

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

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

938 

939 # now some w p33 = 35h 

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

941 assert res.HasField("some") 

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

943 

944 with requests_session(token2) as api: 

945 # accept host req 

946 api.RespondHostRequest( 

947 requests_pb2.RespondHostRequestReq( 

948 host_request_id=host_request_5, 

949 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

950 text="Accepting host request", 

951 ) 

952 ) 

953 

954 with requests_session(token1) as api: 

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

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

957 assert res.HasField("most") 

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

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

960 

961 with requests_session(token2) as api: 

962 # accept host req 

963 api.RespondHostRequest( 

964 requests_pb2.RespondHostRequestReq( 

965 host_request_id=host_request_4, 

966 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

967 text="Accepting host request", 

968 ) 

969 ) 

970 

971 with requests_session(token1) as api: 

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

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

974 assert res.HasField("almost_all") 

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

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

977 

978 

979def test_request_notifications(db, push_collector): 

980 host, host_token = generate_user(complete_profile=True) 

981 surfer, surfer_token = generate_user(complete_profile=True) 

982 

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

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

985 

986 with requests_session(surfer_token) as api: 

987 with mock_notification_email() as mock: 

988 hr_id = api.CreateHostRequest( 

989 requests_pb2.CreateHostRequestReq( 

990 host_user_id=host.id, 

991 from_date=today_plus_2, 

992 to_date=today_plus_3, 

993 text="can i stay plz", 

994 ) 

995 ).host_request_id 

996 

997 mock.assert_called_once() 

998 e = email_fields(mock) 

999 assert e.recipient == host.email 

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

1001 assert host.name in e.plain 

1002 assert host.name in e.html 

1003 assert surfer.name in e.plain 

1004 assert surfer.name in e.html 

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

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

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

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

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

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

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

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

1013 

1014 push_collector.assert_user_has_single_matching( 

1015 host.id, 

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

1017 ) 

1018 

1019 with requests_session(host_token) as api: 

1020 with mock_notification_email() as mock: 

1021 api.RespondHostRequest( 

1022 requests_pb2.RespondHostRequestReq( 

1023 host_request_id=hr_id, 

1024 status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED, 

1025 text="Accepting host request", 

1026 ) 

1027 ) 

1028 

1029 e = email_fields(mock) 

1030 assert e.recipient == surfer.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, surfer) in e.plain 

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

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

1039 assert v2date(today_plus_3, surfer) 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 surfer.id, 

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

1048 )