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

537 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-02 20:25 +0000

1from datetime import timedelta 

2from unittest.mock import patch 

3 

4import grpc 

5import pytest 

6from google.protobuf import empty_pb2 

7 

8from couchers import errors 

9from couchers.db import session_scope 

10from couchers.materialized_views import refresh_materialized_views_rapid 

11from couchers.models import ( 

12 Conversation, 

13 HostRequest, 

14 HostRequestStatus, 

15 Message, 

16 MessageType, 

17 Reference, 

18 ReferenceType, 

19 User, 

20) 

21from couchers.sql import couchers_select as select 

22from couchers.utils import create_coordinate, now, to_aware_datetime, today 

23from proto import conversations_pb2, references_pb2, requests_pb2 

24from tests.test_fixtures import ( # noqa 

25 account_session, 

26 db, 

27 email_fields, 

28 generate_user, 

29 make_user_block, 

30 mock_notification_email, 

31 push_collector, 

32 references_session, 

33 requests_session, 

34 testconfig, 

35) 

36 

37 

38@pytest.fixture(autouse=True) 

39def _(testconfig): 

40 pass 

41 

42 

43def create_host_request( 

44 session, 

45 surfer_user_id, 

46 host_user_id, 

47 host_request_age=timedelta(days=15), 

48 status=HostRequestStatus.confirmed, 

49 host_reason_didnt_meetup=None, 

50 surfer_reason_didnt_meetup=None, 

51): 

52 """ 

53 Create a host request that's `host_request_age` old 

54 """ 

55 from_date = today() - host_request_age - timedelta(days=2) 

56 to_date = today() - host_request_age 

57 fake_created = now() - host_request_age - timedelta(days=3) 

58 conversation = Conversation() 

59 session.add(conversation) 

60 session.flush() 

61 session.add( 

62 Message( 

63 time=fake_created + timedelta(seconds=1), 

64 conversation_id=conversation.id, 

65 author_id=surfer_user_id, 

66 message_type=MessageType.chat_created, 

67 ) 

68 ) 

69 message = Message( 

70 time=fake_created + timedelta(seconds=2), 

71 conversation_id=conversation.id, 

72 author_id=surfer_user_id, 

73 text="Hi, I'm requesting to be hosted.", 

74 message_type=MessageType.text, 

75 ) 

76 session.add(message) 

77 session.flush() 

78 host_request = HostRequest( 

79 conversation_id=conversation.id, 

80 surfer_user_id=surfer_user_id, 

81 host_user_id=host_user_id, 

82 from_date=from_date, 

83 to_date=to_date, 

84 status=status, 

85 surfer_last_seen_message_id=message.id, 

86 host_reason_didnt_meetup=host_reason_didnt_meetup, 

87 surfer_reason_didnt_meetup=surfer_reason_didnt_meetup, 

88 hosting_city="Test City", 

89 hosting_location=create_coordinate(0, 0), 

90 hosting_radius=10, 

91 ) 

92 session.add(host_request) 

93 session.commit() 

94 return host_request.conversation_id 

95 

96 

97def create_host_request_by_date( 

98 session, 

99 surfer_user_id, 

100 host_user_id, 

101 from_date, 

102 to_date, 

103 status, 

104 host_sent_request_reminders, 

105 last_sent_request_reminder_time, 

106): 

107 conversation = Conversation() 

108 session.add(conversation) 

109 session.flush() 

110 

111 session.add( 

112 Message( 

113 time=from_date + timedelta(seconds=1), 

114 conversation_id=conversation.id, 

115 author_id=surfer_user_id, 

116 message_type=MessageType.chat_created, 

117 ) 

118 ) 

119 

120 message = Message( 

121 time=from_date + timedelta(seconds=2), 

122 conversation_id=conversation.id, 

123 author_id=surfer_user_id, 

124 text="Hi, I'm requesting to be hosted.", 

125 message_type=MessageType.text, 

126 ) 

127 

128 host_request = HostRequest( 

129 conversation_id=conversation.id, 

130 surfer_user_id=surfer_user_id, 

131 host_user_id=host_user_id, 

132 from_date=from_date, 

133 to_date=to_date, 

134 status=status, 

135 host_sent_request_reminders=host_sent_request_reminders, 

136 last_sent_request_reminder_time=last_sent_request_reminder_time, 

137 hosting_city="Test City", 

138 hosting_location=create_coordinate(0, 0), 

139 hosting_radius=10, 

140 ) 

141 

142 session.add(host_request) 

143 session.commit() 

144 return host_request.conversation_id 

145 

146 

147def create_host_reference(session, from_user_id, to_user_id, reference_age, *, surfing=True, host_request_id=None): 

148 if host_request_id: 

149 actual_host_request_id = host_request_id 

150 else: 

151 if surfing: 

152 actual_host_request_id = host_request_id or create_host_request( 

153 session, from_user_id, to_user_id, reference_age + timedelta(days=1) 

154 ) 

155 else: 

156 actual_host_request_id = host_request_id or create_host_request( 

157 session, to_user_id, from_user_id, reference_age + timedelta(days=1) 

158 ) 

159 

160 host_request = session.execute( 

161 select(HostRequest).where(HostRequest.conversation_id == actual_host_request_id) 

162 ).scalar_one() 

163 

164 reference = Reference( 

165 time=now() - reference_age, 

166 from_user_id=from_user_id, 

167 host_request_id=host_request.conversation_id, 

168 text="Dummy reference", 

169 rating=0.5, 

170 was_appropriate=True, 

171 ) 

172 

173 if host_request.surfer_user_id == from_user_id: 

174 reference.reference_type = ReferenceType.surfed 

175 reference.to_user_id = host_request.host_user_id 

176 assert from_user_id == host_request.surfer_user_id 

177 else: 

178 reference.reference_type = ReferenceType.hosted 

179 reference.to_user_id = host_request.surfer_user_id 

180 assert from_user_id == host_request.host_user_id 

181 

182 session.add(reference) 

183 session.commit() 

184 return reference.id, actual_host_request_id 

185 

186 

187def create_friend_reference(session, from_user_id, to_user_id, reference_age): 

188 reference = Reference( 

189 time=now() - reference_age, 

190 from_user_id=from_user_id, 

191 to_user_id=to_user_id, 

192 reference_type=ReferenceType.friend, 

193 text="Test friend request", 

194 rating=0.4, 

195 was_appropriate=True, 

196 ) 

197 session.add(reference) 

198 session.commit() 

199 return reference.id 

200 

201 

202def test_ListPagination(db): 

203 user1, token1 = generate_user() 

204 user2, token2 = generate_user() 

205 user3, token3 = generate_user() 

206 user4, token4 = generate_user() 

207 user5, token5 = generate_user() 

208 user6, token6 = generate_user() 

209 user7, token7 = generate_user() 

210 user8, token8 = generate_user() 

211 user9, token9 = generate_user() 

212 

213 with session_scope() as session: 

214 # bidirectional references 

215 ref2, hr2 = create_host_reference(session, user2.id, user1.id, timedelta(days=16, seconds=110), surfing=True) 

216 ref2b, _ = create_host_reference( 

217 session, user1.id, user2.id, timedelta(days=16, seconds=100), host_request_id=hr2 

218 ) 

219 

220 ref3, _ = create_host_reference(session, user3.id, user1.id, timedelta(days=16, seconds=90), surfing=False) 

221 ref4, _ = create_host_reference(session, user4.id, user1.id, timedelta(days=16, seconds=80), surfing=True) 

222 ref4b = create_friend_reference(session, user1.id, user4.id, timedelta(days=16, seconds=70)) 

223 

224 ref5, hr5 = create_host_reference(session, user5.id, user1.id, timedelta(days=16, seconds=60), surfing=False) 

225 ref5b, _ = create_host_reference( 

226 session, user1.id, user5.id, timedelta(days=16, seconds=50), host_request_id=hr5 

227 ) 

228 

229 ref6, _ = create_host_reference(session, user6.id, user1.id, timedelta(days=16, seconds=40), surfing=True) 

230 

231 ref7 = create_friend_reference(session, user7.id, user1.id, timedelta(days=16, seconds=30)) 

232 

233 ref8, _ = create_host_reference(session, user8.id, user1.id, timedelta(days=16, seconds=20), surfing=False) 

234 ref9, _ = create_host_reference(session, user9.id, user1.id, timedelta(days=16, seconds=10), surfing=False) 

235 

236 # should be visible even under 2 weeks 

237 ref7b = create_friend_reference(session, user1.id, user7.id, timedelta(days=9)) 

238 

239 # hidden because it's less than 2 weeks 

240 ref6hidden, _ = create_host_reference(session, user6.id, user1.id, timedelta(days=5), surfing=False) 

241 

242 # visible because both were written 

243 ref8b, hr8 = create_host_reference(session, user8.id, user1.id, timedelta(days=3, seconds=20), surfing=False) 

244 ref8c, _ = create_host_reference( 

245 session, user1.id, user8.id, timedelta(days=3, seconds=10), host_request_id=hr8 

246 ) 

247 

248 # note that visibility tests don't really test real logic 

249 

250 # these check the right refs are in the right requests and appear in the right order (latest first) 

251 

252 with references_session(token2) as api: 

253 # written by user1 

254 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id, page_size=2)) 

255 assert [ref.reference_id for ref in res.references] == [ref8c, ref7b] 

256 

257 res = api.ListReferences( 

258 references_pb2.ListReferencesReq(from_user_id=user1.id, page_token=res.next_page_token, page_size=2) 

259 ) 

260 assert [ref.reference_id for ref in res.references] == [ref5b, ref4b] 

261 

262 res = api.ListReferences( 

263 references_pb2.ListReferencesReq(from_user_id=user1.id, page_token=res.next_page_token, page_size=2) 

264 ) 

265 assert [ref.reference_id for ref in res.references] == [ref2b] 

266 assert not res.next_page_token 

267 

268 # received by user1 

269 res = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id, page_size=5)) 

270 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8, ref7, ref6] 

271 

272 res = api.ListReferences( 

273 references_pb2.ListReferencesReq(to_user_id=user1.id, page_token=res.next_page_token, page_size=5) 

274 ) 

275 assert [ref.reference_id for ref in res.references] == [ref5, ref4, ref3, ref2] 

276 assert not res.next_page_token 

277 

278 # same thing but with filters 

279 res = api.ListReferences( 

280 references_pb2.ListReferencesReq( 

281 to_user_id=user1.id, 

282 reference_type_filter=[ 

283 references_pb2.REFERENCE_TYPE_HOSTED, 

284 references_pb2.REFERENCE_TYPE_SURFED, 

285 references_pb2.REFERENCE_TYPE_FRIEND, 

286 ], 

287 page_size=5, 

288 ) 

289 ) 

290 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8, ref7, ref6] 

291 

292 res = api.ListReferences( 

293 references_pb2.ListReferencesReq( 

294 to_user_id=user1.id, 

295 reference_type_filter=[ 

296 references_pb2.REFERENCE_TYPE_HOSTED, 

297 references_pb2.REFERENCE_TYPE_SURFED, 

298 references_pb2.REFERENCE_TYPE_FRIEND, 

299 ], 

300 page_token=res.next_page_token, 

301 page_size=5, 

302 ) 

303 ) 

304 assert [ref.reference_id for ref in res.references] == [ref5, ref4, ref3, ref2] 

305 assert not res.next_page_token 

306 

307 # received hosting references 

308 res = api.ListReferences( 

309 references_pb2.ListReferencesReq( 

310 to_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_HOSTED], page_size=3 

311 ) 

312 ) 

313 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8] 

314 

315 res = api.ListReferences( 

316 references_pb2.ListReferencesReq( 

317 to_user_id=user1.id, 

318 reference_type_filter=[references_pb2.REFERENCE_TYPE_HOSTED], 

319 page_token=res.next_page_token, 

320 page_size=3, 

321 ) 

322 ) 

323 assert [ref.reference_id for ref in res.references] == [ref5, ref3] 

324 assert not res.next_page_token 

325 

326 # written friend references 

327 res = api.ListReferences( 

328 references_pb2.ListReferencesReq( 

329 from_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_FRIEND] 

330 ) 

331 ) 

332 assert [ref.reference_id for ref in res.references] == [ref7b, ref4b] 

333 assert not res.next_page_token 

334 

335 # written surfing references 

336 res = api.ListReferences( 

337 references_pb2.ListReferencesReq( 

338 from_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_SURFED] 

339 ) 

340 ) 

341 assert [ref.reference_id for ref in res.references] == [ref8c, ref5b] 

342 assert not res.next_page_token 

343 

344 with references_session(token7) as api: 

345 # need to set at least one of from or to user 

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

347 api.ListReferences( 

348 references_pb2.ListReferencesReq(reference_type_filter=[references_pb2.REFERENCE_TYPE_SURFED]) 

349 ) 

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

351 assert e.value.details() == errors.NEED_TO_SPECIFY_AT_LEAST_ONE_USER 

352 

353 with references_session(token5) as api: 

354 # from user1 to user2 

355 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id, to_user_id=user2.id)) 

356 assert [ref.reference_id for ref in res.references] == [ref2b] 

357 assert not res.next_page_token 

358 

359 # from user5 to user1 

360 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user5.id, to_user_id=user1.id)) 

361 assert [ref.reference_id for ref in res.references] == [ref5] 

362 assert not res.next_page_token 

363 

364 

365def test_ListReference_banned_deleted_users(db): 

366 user1, token1 = generate_user() 

367 user2, token2 = generate_user() 

368 user3, token3 = generate_user() 

369 

370 with session_scope() as session: 

371 create_friend_reference(session, user2.id, user1.id, timedelta(days=15)) 

372 create_friend_reference(session, user3.id, user1.id, timedelta(days=16)) 

373 create_friend_reference(session, user1.id, user2.id, timedelta(days=15)) 

374 create_friend_reference(session, user1.id, user3.id, timedelta(days=16)) 

375 

376 with references_session(token1) as api: 

377 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references 

378 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references 

379 assert len(refs_rec) == 2 

380 assert len(refs_sent) == 2 

381 

382 # ban user2 

383 with session_scope() as session: 

384 user2 = session.execute(select(User).where(User.username == user2.username)).scalar_one() 

385 user2.is_banned = True 

386 session.commit() 

387 

388 # reference to and from banned user is hidden 

389 with references_session(token1) as api: 

390 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references 

391 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references 

392 assert len(refs_rec) == 1 

393 assert len(refs_sent) == 1 

394 

395 # delete user3 

396 with session_scope() as session: 

397 user3 = session.execute(select(User).where(User.username == user3.username)).scalar_one() 

398 user3.is_deleted = True 

399 session.commit() 

400 

401 # doesn't change; references to and from deleted users remain 

402 with references_session(token1) as api: 

403 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references 

404 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references 

405 assert len(refs_rec) == 1 

406 assert len(refs_sent) == 1 

407 

408 

409def test_WriteFriendReference(db): 

410 user1, token1 = generate_user() 

411 user2, token2 = generate_user() 

412 user3, token3 = generate_user() 

413 

414 with references_session(token1) as api: 

415 # can write normal friend reference 

416 res = api.WriteFriendReference( 

417 references_pb2.WriteFriendReferenceReq( 

418 to_user_id=user2.id, 

419 text="A test reference", 

420 was_appropriate=True, 

421 rating=0.5, 

422 ) 

423 ) 

424 assert res.from_user_id == user1.id 

425 assert res.to_user_id == user2.id 

426 assert res.reference_type == references_pb2.REFERENCE_TYPE_FRIEND 

427 assert res.text == "A test reference" 

428 assert now() - timedelta(hours=24) <= to_aware_datetime(res.written_time) <= now() 

429 assert not res.host_request_id 

430 

431 with references_session(token3) as api: 

432 # check it shows up 

433 res = api.ListReferences( 

434 references_pb2.ListReferencesReq( 

435 from_user_id=user1.id, to_user_id=user2.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_FRIEND] 

436 ) 

437 ) 

438 assert len(res.references) == 1 

439 ref = res.references[0] 

440 assert ref.from_user_id == user1.id 

441 assert ref.to_user_id == user2.id 

442 assert ref.reference_type == references_pb2.REFERENCE_TYPE_FRIEND 

443 assert ref.text == "A test reference" 

444 assert now() - timedelta(hours=24) <= to_aware_datetime(ref.written_time) <= now() 

445 assert not ref.host_request_id 

446 

447 with references_session(token1) as api: 

448 # can't write a second friend reference 

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

450 api.WriteFriendReference( 

451 references_pb2.WriteFriendReferenceReq( 

452 to_user_id=user2.id, 

453 text="A test reference", 

454 was_appropriate=True, 

455 rating=0.5, 

456 ) 

457 ) 

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

459 assert e.value.details() == errors.REFERENCE_ALREADY_GIVEN 

460 

461 with references_session(token2) as api: 

462 # can't write a reference about yourself 

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

464 api.WriteFriendReference( 

465 references_pb2.WriteFriendReferenceReq( 

466 to_user_id=user2.id, 

467 text="I'm really awesome", 

468 was_appropriate=True, 

469 rating=1.0, 

470 ) 

471 ) 

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

473 assert e.value.details() == errors.CANT_REFER_SELF 

474 

475 

476def test_WriteFriendReference_with_empty_text(db): 

477 user1, token1 = generate_user() 

478 user2, token2 = generate_user() 

479 

480 with references_session(token1) as api: 

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

482 api.WriteFriendReference( 

483 references_pb2.WriteFriendReferenceReq(to_user_id=user2.id, text=" ", was_appropriate=True, rating=0.8) 

484 ) 

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

486 assert e.value.details() == errors.REFERENCE_NO_TEXT 

487 

488 

489def test_WriteFriendReference_with_private_text(db, push_collector): 

490 user1, token1 = generate_user() 

491 user2, token2 = generate_user() 

492 

493 with references_session(token1) as api: 

494 with patch("couchers.email.queue_email") as mock1: 

495 with mock_notification_email() as mock2: 

496 api.WriteFriendReference( 

497 references_pb2.WriteFriendReferenceReq( 

498 to_user_id=user2.id, 

499 text="They were nice!", 

500 was_appropriate=True, 

501 rating=0.6, 

502 private_text="A bit of an odd ball, but a nice person nonetheless.", 

503 ) 

504 ) 

505 

506 # make sure an email was sent to the user receiving the ref as well as the mods 

507 assert mock1.call_count == 1 

508 assert mock2.call_count == 1 

509 e = email_fields(mock2) 

510 assert e.subject == f"[TEST] You've received a friend reference from {user1.name}!" 

511 assert e.recipient == user2.email 

512 

513 push_collector.assert_user_has_single_matching( 

514 user2.id, 

515 title=f"You've received a friend reference from {user1.name}!", 

516 body="They were nice!", 

517 ) 

518 

519 

520def test_host_request_states_references(db): 

521 user1, token1 = generate_user() 

522 user2, token2 = generate_user() 

523 

524 with session_scope() as session: 

525 # can't write ref 

526 hr1 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.pending) 

527 # can write ref 

528 hr2 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.accepted) 

529 # can't write ref 

530 hr3 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.rejected) 

531 # can write ref 

532 hr4 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.confirmed) 

533 # can't write ref 

534 hr5 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.cancelled) 

535 

536 with references_session(token1) as api: 

537 # pending 

538 api.WriteHostRequestReference( 

539 references_pb2.WriteHostRequestReferenceReq( 

540 host_request_id=hr2, 

541 text="Should work!", 

542 was_appropriate=True, 

543 rating=0.9, 

544 ) 

545 ) 

546 

547 # accepted 

548 api.WriteHostRequestReference( 

549 references_pb2.WriteHostRequestReferenceReq( 

550 host_request_id=hr4, 

551 text="Should work!", 

552 was_appropriate=True, 

553 rating=0.9, 

554 ) 

555 ) 

556 

557 # rejected 

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

559 api.WriteHostRequestReference( 

560 references_pb2.WriteHostRequestReferenceReq( 

561 host_request_id=hr1, 

562 text="Shouldn't work...", 

563 was_appropriate=True, 

564 rating=0.9, 

565 ) 

566 ) 

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

568 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST 

569 

570 # confirmed 

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

572 api.WriteHostRequestReference( 

573 references_pb2.WriteHostRequestReferenceReq( 

574 host_request_id=hr3, 

575 text="Shouldn't work...", 

576 was_appropriate=True, 

577 rating=0.9, 

578 ) 

579 ) 

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

581 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST 

582 

583 # cancelled 

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

585 api.WriteHostRequestReference( 

586 references_pb2.WriteHostRequestReferenceReq( 

587 host_request_id=hr5, 

588 text="Shouldn't work...", 

589 was_appropriate=True, 

590 rating=0.9, 

591 ) 

592 ) 

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

594 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST 

595 

596 

597def test_WriteHostRequestReference(db): 

598 user1, token1 = generate_user() 

599 user2, token2 = generate_user() 

600 user3, token3 = generate_user() 

601 user4, token4 = generate_user() 

602 

603 with session_scope() as session: 

604 # too old 

605 hr1 = create_host_request(session, user3.id, user1.id, timedelta(days=20)) 

606 # valid host req, surfer said we didn't show up but we can still write a req 

607 hr2 = create_host_request(session, user3.id, user1.id, timedelta(days=10), surfer_reason_didnt_meetup="No show") 

608 # valid surfing req 

609 hr3 = create_host_request(session, user1.id, user3.id, timedelta(days=7)) 

610 # not yet complete 

611 hr4 = create_host_request(session, user2.id, user1.id, timedelta(days=1), status=HostRequestStatus.pending) 

612 # we indicated we didn't meet 

613 hr5 = create_host_request(session, user4.id, user1.id, timedelta(days=7), host_reason_didnt_meetup="") 

614 # we will indicate we didn't meet 

615 hr6 = create_host_request(session, user4.id, user1.id, timedelta(days=8)) 

616 

617 with references_session(token3) as api: 

618 # can write for this one 

619 api.WriteHostRequestReference( 

620 references_pb2.WriteHostRequestReferenceReq( 

621 host_request_id=hr3, 

622 text="Should work!", 

623 was_appropriate=True, 

624 rating=0.9, 

625 ) 

626 ) 

627 

628 with references_session(token1) as api: 

629 # can't write reference for a HR that's not yet finished 

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

631 api.WriteHostRequestReference( 

632 references_pb2.WriteHostRequestReferenceReq( 

633 host_request_id=hr4, 

634 text="Shouldn't work...", 

635 was_appropriate=True, 

636 rating=0.9, 

637 ) 

638 ) 

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

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

641 

642 # can't write reference that's more than 2 weeks old 

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

644 api.WriteHostRequestReference( 

645 references_pb2.WriteHostRequestReferenceReq( 

646 host_request_id=hr1, 

647 text="Shouldn't work...", 

648 was_appropriate=True, 

649 rating=0.9, 

650 ) 

651 ) 

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

653 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST 

654 

655 # can write for this one 

656 api.WriteHostRequestReference( 

657 references_pb2.WriteHostRequestReferenceReq( 

658 host_request_id=hr2, 

659 text="Should work!", 

660 was_appropriate=True, 

661 rating=0.9, 

662 ) 

663 ) 

664 

665 # but can't write a second one for the same one 

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

667 api.WriteHostRequestReference( 

668 references_pb2.WriteHostRequestReferenceReq( 

669 host_request_id=hr2, 

670 text="Shouldn't work...", 

671 was_appropriate=True, 

672 rating=0.9, 

673 ) 

674 ) 

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

676 assert e.value.details() == errors.REFERENCE_ALREADY_GIVEN 

677 

678 # can write for this one too 

679 api.WriteHostRequestReference( 

680 references_pb2.WriteHostRequestReferenceReq( 

681 host_request_id=hr3, 

682 text="Should work!", 

683 was_appropriate=True, 

684 rating=0.9, 

685 ) 

686 ) 

687 

688 # can't write reference for a HR that we indicated we didn't show up 

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

690 api.WriteHostRequestReference( 

691 references_pb2.WriteHostRequestReferenceReq( 

692 host_request_id=hr5, 

693 text="Shouldn't work...", 

694 was_appropriate=True, 

695 rating=0.9, 

696 ) 

697 ) 

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

699 assert e.value.details() == errors.CANT_WRITE_REFERENCE_INDICATED_DIDNT_MEETUP 

700 

701 # can't write reference for a HR that we indicate we didn't show up for 

702 api.HostRequestIndicateDidntMeetup( 

703 references_pb2.HostRequestIndicateDidntMeetupReq( 

704 host_request_id=hr6, 

705 reason_didnt_meetup="No clue?", 

706 ) 

707 ) 

708 

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

710 api.WriteHostRequestReference( 

711 references_pb2.WriteHostRequestReferenceReq( 

712 host_request_id=hr6, 

713 text="Shouldn't work...", 

714 was_appropriate=True, 

715 rating=0.9, 

716 ) 

717 ) 

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

719 assert e.value.details() == errors.CANT_WRITE_REFERENCE_INDICATED_DIDNT_MEETUP 

720 

721 with references_session(token4) as api: 

722 # they can still write one 

723 api.WriteHostRequestReference( 

724 references_pb2.WriteHostRequestReferenceReq( 

725 host_request_id=hr6, 

726 text="Should work!", 

727 was_appropriate=True, 

728 rating=0.9, 

729 ) 

730 ) 

731 

732 

733def test_WriteHostRequestReference_private_text(db, push_collector): 

734 user1, token1 = generate_user() 

735 user2, token2 = generate_user() 

736 

737 with session_scope() as session: 

738 hr = create_host_request(session, user1.id, user2.id, timedelta(days=10)) 

739 

740 with references_session(token1) as api: 

741 with patch("couchers.email.queue_email") as mock1: 

742 with mock_notification_email() as mock2: 

743 api.WriteHostRequestReference( 

744 references_pb2.WriteHostRequestReferenceReq( 

745 host_request_id=hr, 

746 text="Should work!", 

747 was_appropriate=True, 

748 rating=0.9, 

749 private_text="Something", 

750 ) 

751 ) 

752 

753 # make sure an email was sent to the user receiving the ref as well as the mods 

754 assert mock1.call_count == 1 

755 assert mock2.call_count == 1 

756 

757 e = email_fields(mock2) 

758 assert e.subject == f"[TEST] You've received a reference from {user1.name}!" 

759 assert e.recipient == user2.email 

760 

761 push_collector.assert_user_has_single_matching( 

762 user2.id, 

763 title=f"You've received a reference from {user1.name}!", 

764 body="Please go and write a reference for them too. It's a nice gesture and helps us build a community together!", 

765 ) 

766 

767 

768def test_GetHostRequestReferenceStatus(db): 

769 user1, token1 = generate_user() 

770 user2, token2 = generate_user() 

771 

772 # user1 writes; RPC returns has_given True 

773 with session_scope() as session: 

774 hr1 = create_host_request(session, user1.id, user2.id, timedelta(days=7)) 

775 with references_session(token1) as api: 

776 api.WriteHostRequestReference( 

777 references_pb2.WriteHostRequestReferenceReq( 

778 host_request_id=hr1, text="Great stay!", was_appropriate=True, rating=0.9 

779 ) 

780 ) 

781 res = api.GetHostRequestReferenceStatus(references_pb2.GetHostRequestReferenceStatusReq(host_request_id=hr1)) 

782 assert res.has_given is True 

783 

784 # false: no reference written yet 

785 with session_scope() as session: 

786 hr2 = create_host_request(session, user1.id, user2.id, timedelta(days=7)) 

787 with references_session(token1) as api: 

788 res = api.GetHostRequestReferenceStatus(references_pb2.GetHostRequestReferenceStatusReq(host_request_id=hr2)) 

789 assert res.has_given is False 

790 

791 # false: other user wrote a reference 

792 with session_scope() as session: 

793 hr3 = create_host_request(session, user1.id, user2.id, timedelta(days=7)) 

794 with references_session(token2) as api: 

795 api.WriteHostRequestReference( 

796 references_pb2.WriteHostRequestReferenceReq( 

797 host_request_id=hr3, text="Lovely guest!", was_appropriate=True, rating=0.95 

798 ) 

799 ) 

800 with references_session(token1) as api: 

801 res = api.GetHostRequestReferenceStatus(references_pb2.GetHostRequestReferenceStatusReq(host_request_id=hr3)) 

802 assert res.has_given is False 

803 

804 # false: nonexistent host request id 

805 with references_session(token1) as api: 

806 res = api.GetHostRequestReferenceStatus(references_pb2.GetHostRequestReferenceStatusReq(host_request_id=999999)) 

807 assert res.has_given is False 

808 

809 # Additional status flags 

810 with session_scope() as session: 

811 # expired (too old) 

812 hr_expired = create_host_request(session, user2.id, user1.id, timedelta(days=20)) 

813 # current user (host) indicated didn't meet up 

814 hr_didnt_stay_host = create_host_request( 

815 session, user2.id, user1.id, timedelta(days=10), host_reason_didnt_meetup="" 

816 ) 

817 # other user (surfer) indicated didn't meet up 

818 hr_other_didnt_stay = create_host_request( 

819 session, user2.id, user1.id, timedelta(days=10), surfer_reason_didnt_meetup="No show" 

820 ) 

821 

822 # expired: is_expired true, can_write false, didnt_stay false 

823 with references_session(token1) as api: 

824 res = api.GetHostRequestReferenceStatus( 

825 references_pb2.GetHostRequestReferenceStatusReq(host_request_id=hr_expired) 

826 ) 

827 assert res.has_given is False 

828 assert res.is_expired is True 

829 assert res.can_write is False 

830 assert res.didnt_stay is False 

831 

832 # current user indicated didn't meet up: didnt_stay true, can_write false, not expired 

833 with references_session(token1) as api: 

834 res = api.GetHostRequestReferenceStatus( 

835 references_pb2.GetHostRequestReferenceStatusReq(host_request_id=hr_didnt_stay_host) 

836 ) 

837 assert res.has_given is False 

838 assert res.is_expired is False 

839 assert res.didnt_stay is True 

840 assert res.can_write is False 

841 

842 # other party indicated didn't meet up: didnt_stay false, can_write true (within window), not expired 

843 with references_session(token1) as api: 

844 res = api.GetHostRequestReferenceStatus( 

845 references_pb2.GetHostRequestReferenceStatusReq(host_request_id=hr_other_didnt_stay) 

846 ) 

847 assert res.has_given is False 

848 assert res.is_expired is False 

849 assert res.didnt_stay is False 

850 assert res.can_write is True 

851 

852 

853def test_AvailableWriteReferences_and_ListPendingReferencesToWrite(db): 

854 user1, token1 = generate_user() 

855 user2, token2 = generate_user() 

856 user3, token3 = generate_user() 

857 user4, token4 = generate_user() 

858 user5, token5 = generate_user(delete_user=True) 

859 user6, token6 = generate_user() 

860 user7, token7 = generate_user() 

861 user8, token8 = generate_user() 

862 user9, token9 = generate_user() 

863 user10, token10 = generate_user() 

864 user11, token11 = generate_user() 

865 make_user_block(user1, user6) 

866 make_user_block(user7, user1) 

867 

868 with session_scope() as session: 

869 # too old 

870 hr1 = create_host_request(session, user3.id, user1.id, timedelta(days=20)) 

871 

872 # already wrote friend ref to user3 

873 create_friend_reference(session, user1.id, user3.id, timedelta(days=15, seconds=70)) 

874 

875 # already given 

876 _, hr2 = create_host_reference(session, user2.id, user1.id, timedelta(days=10, seconds=110), surfing=True) 

877 create_host_reference(session, user1.id, user2.id, timedelta(days=10, seconds=100), host_request_id=hr2) 

878 

879 # valid hosted 

880 hr3 = create_host_request(session, user3.id, user1.id, timedelta(days=8)) 

881 

882 # valid surfed 

883 hr4 = create_host_request(session, user1.id, user4.id, timedelta(days=5)) 

884 

885 # not yet complete 

886 hr5 = create_host_request(session, user2.id, user1.id, timedelta(days=2), status=HostRequestStatus.pending) 

887 

888 # already wrote friend ref to user2 

889 create_friend_reference(session, user1.id, user2.id, timedelta(days=1)) 

890 

891 # user5 deleted, reference won't show up as pending 

892 create_host_request(session, user1.id, user5.id, timedelta(days=5)) 

893 

894 # user6 blocked, reference won't show up as pending 

895 create_host_request(session, user1.id, user6.id, timedelta(days=5)) 

896 

897 # user7 blocking, reference won't show up as pending 

898 create_host_request(session, user1.id, user7.id, timedelta(days=5)) 

899 

900 # hosted but we indicated we didn't meet up, no reason; should not show up 

901 create_host_request(session, user8.id, user1.id, timedelta(days=11), host_reason_didnt_meetup="") 

902 

903 # surfed but we indicated we didn't meet up, has reason; should not show up 

904 create_host_request( 

905 session, user1.id, user9.id, timedelta(days=10), surfer_reason_didnt_meetup="They never showed up!" 

906 ) 

907 

908 # surfed but they indicated we didn't meet up, no reason; should show up 

909 hr6 = create_host_request(session, user1.id, user10.id, timedelta(days=4), host_reason_didnt_meetup="") 

910 

911 # hosted but they indicated we didn't meet up, has reason; should show up 

912 hr7 = create_host_request( 

913 session, user11.id, user1.id, timedelta(days=3), surfer_reason_didnt_meetup="They never showed up!!" 

914 ) 

915 

916 refresh_materialized_views_rapid(None) 

917 

918 with references_session(token1) as api: 

919 # can't write reference for invisible user 

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

921 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user5.id)) 

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

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

924 

925 # can't write reference for blocking user 

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

927 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user7.id)) 

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

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

930 

931 # can't write reference for blocked user 

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

933 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user6.id)) 

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

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

936 

937 # can't write anything to myself 

938 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id)) 

939 assert not res.can_write_friend_reference 

940 assert len(res.available_write_references) == 0 

941 

942 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id)) 

943 # can't write friend ref to user2 

944 assert not res.can_write_friend_reference 

945 # none we can write for user2 

946 assert len(res.available_write_references) == 0 

947 

948 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user3.id)) 

949 # can't write friend ref to user3 

950 assert not res.can_write_friend_reference 

951 # can write one reference because we hosted user3 

952 assert len(res.available_write_references) == 1 

953 w = res.available_write_references[0] 

954 assert w.host_request_id == hr3 

955 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

956 assert now() + timedelta(days=6) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=7) 

957 

958 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user4.id)) 

959 # can write friend ref to user4 

960 assert res.can_write_friend_reference 

961 # can write one reference because we surfed with user4 

962 assert len(res.available_write_references) == 1 

963 w = res.available_write_references[0] 

964 assert w.host_request_id == hr4 

965 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED 

966 assert now() + timedelta(days=9) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=10) 

967 

968 # can't write a req if we indicated we didn't meet up 

969 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user8.id)) 

970 assert len(res.available_write_references) == 0 

971 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user9.id)) 

972 assert len(res.available_write_references) == 0 

973 

974 # can still write ref if the other person indicated we didn't meet up 

975 # surfed with them 

976 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user10.id)) 

977 assert len(res.available_write_references) == 1 

978 w = res.available_write_references[0] 

979 assert w.host_request_id == hr6 

980 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED 

981 assert now() + timedelta(days=10) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=11) 

982 # hosted them 

983 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user11.id)) 

984 assert len(res.available_write_references) == 1 

985 w = res.available_write_references[0] 

986 assert w.host_request_id == hr7 

987 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

988 assert now() + timedelta(days=11) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=12) 

989 

990 # finally check the general list 

991 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

992 assert len(res.pending_references) == 4 

993 w = res.pending_references[0] 

994 assert w.host_request_id == hr3 

995 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

996 assert now() + timedelta(days=6) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=7) 

997 w = res.pending_references[1] 

998 assert w.host_request_id == hr4 

999 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1000 assert now() + timedelta(days=9) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=10) 

1001 w = res.pending_references[2] 

1002 assert w.host_request_id == hr6 

1003 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1004 assert now() + timedelta(days=10) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=11) 

1005 w = res.pending_references[3] 

1006 assert w.host_request_id == hr7 

1007 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

1008 assert now() + timedelta(days=11) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=12) 

1009 

1010 with account_session(token1) as account: 

1011 reminders = account.GetReminders(empty_pb2.Empty()).reminders 

1012 assert [reminder.WhichOneof("reminder") for reminder in reminders] == [ 

1013 "write_reference_reminder", 

1014 "write_reference_reminder", 

1015 "write_reference_reminder", 

1016 "write_reference_reminder", 

1017 "complete_verification_reminder", 

1018 ] 

1019 assert reminders[0].write_reference_reminder.host_request_id == hr3 

1020 assert reminders[0].write_reference_reminder.reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

1021 assert reminders[0].write_reference_reminder.other_user.user_id == user3.id 

1022 assert reminders[1].write_reference_reminder.host_request_id == hr4 

1023 assert reminders[1].write_reference_reminder.reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1024 assert reminders[1].write_reference_reminder.other_user.user_id == user4.id 

1025 assert reminders[2].write_reference_reminder.host_request_id == hr6 

1026 assert reminders[2].write_reference_reminder.reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1027 assert reminders[2].write_reference_reminder.other_user.user_id == user10.id 

1028 assert reminders[3].write_reference_reminder.host_request_id == hr7 

1029 assert reminders[3].write_reference_reminder.reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

1030 assert reminders[3].write_reference_reminder.other_user.user_id == user11.id 

1031 

1032 

1033@pytest.mark.parametrize("hs", ["host", "surfer"]) 

1034def test_regression_disappearing_refs(db, hs): 

1035 """ 

1036 Roughly the reproduction steps are: 

1037 * Send a host request, then have both host and surfer accept 

1038 * Wait for it to elapse (or hack it with SQL like what you told me to do) 

1039 * On the surfer account, leave a reference 

1040 * Then on the host account, the option to leave a reference is then not available 

1041 """ 

1042 user1, token1 = generate_user() 

1043 user2, token2 = generate_user() 

1044 req_start = (today() + timedelta(days=2)).isoformat() 

1045 req_end = (today() + timedelta(days=3)).isoformat() 

1046 with requests_session(token1) as api: 

1047 res = api.CreateHostRequest( 

1048 requests_pb2.CreateHostRequestReq( 

1049 host_user_id=user2.id, from_date=req_start, to_date=req_end, text="Test request" 

1050 ) 

1051 ) 

1052 host_request_id = res.host_request_id 

1053 assert ( 

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

1055 .host_requests[0] 

1056 .latest_message.text.text 

1057 == "Test request" 

1058 ) 

1059 

1060 with requests_session(token2) as api: 

1061 api.RespondHostRequest( 

1062 requests_pb2.RespondHostRequestReq( 

1063 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED 

1064 ) 

1065 ) 

1066 

1067 with requests_session(token1) as api: 

1068 api.RespondHostRequest( 

1069 requests_pb2.RespondHostRequestReq( 

1070 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED 

1071 ) 

1072 ) 

1073 

1074 refresh_materialized_views_rapid(None) 

1075 

1076 with references_session(token1) as api: 

1077 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1078 assert len(res.pending_references) == 0 

1079 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id)) 

1080 assert len(res.available_write_references) == 0 

1081 

1082 with references_session(token2) as api: 

1083 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1084 assert len(res.pending_references) == 0 

1085 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id)) 

1086 assert len(res.available_write_references) == 0 

1087 

1088 # hack the time backwards 

1089 hack_req_start = today() - timedelta(days=10) + timedelta(days=2) 

1090 hack_req_end = today() - timedelta(days=10) + timedelta(days=3) 

1091 with session_scope() as session: 

1092 host_request = session.execute(select(HostRequest)).scalar_one() 

1093 assert host_request.conversation_id == host_request_id 

1094 host_request.from_date = hack_req_start 

1095 host_request.to_date = hack_req_end 

1096 

1097 with references_session(token1) as api: 

1098 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1099 assert len(res.pending_references) == 1 

1100 assert res.pending_references[0].host_request_id == host_request_id 

1101 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1102 

1103 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id)) 

1104 assert len(res.available_write_references) == 1 

1105 assert res.available_write_references[0].host_request_id == host_request_id 

1106 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1107 

1108 with references_session(token2) as api: 

1109 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1110 assert len(res.pending_references) == 1 

1111 assert res.pending_references[0].host_request_id == host_request_id 

1112 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

1113 

1114 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id)) 

1115 assert len(res.available_write_references) == 1 

1116 assert res.available_write_references[0].host_request_id == host_request_id 

1117 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

1118 

1119 if hs == "host": 

1120 with references_session(token2) as api: 

1121 api.WriteHostRequestReference( 

1122 references_pb2.WriteHostRequestReferenceReq( 

1123 host_request_id=host_request_id, 

1124 text="Good stuff", 

1125 was_appropriate=True, 

1126 rating=0.86, 

1127 ) 

1128 ) 

1129 

1130 with references_session(token2) as api: 

1131 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1132 assert len(res.pending_references) == 0 

1133 

1134 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id)) 

1135 assert len(res.available_write_references) == 0 

1136 

1137 with references_session(token1) as api: 

1138 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1139 assert len(res.pending_references) == 1 

1140 assert res.pending_references[0].host_request_id == host_request_id 

1141 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1142 

1143 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id)) 

1144 assert len(res.available_write_references) == 1 

1145 assert res.available_write_references[0].host_request_id == host_request_id 

1146 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED 

1147 else: 

1148 with references_session(token1) as api: 

1149 api.WriteHostRequestReference( 

1150 references_pb2.WriteHostRequestReferenceReq( 

1151 host_request_id=host_request_id, 

1152 text="Good stuff", 

1153 was_appropriate=True, 

1154 rating=0.86, 

1155 ) 

1156 ) 

1157 

1158 with references_session(token1) as api: 

1159 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1160 assert len(res.pending_references) == 0 

1161 

1162 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id)) 

1163 assert len(res.available_write_references) == 0 

1164 

1165 with references_session(token2) as api: 

1166 res = api.ListPendingReferencesToWrite(empty_pb2.Empty()) 

1167 assert len(res.pending_references) == 1 

1168 assert res.pending_references[0].host_request_id == host_request_id 

1169 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED 

1170 

1171 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id)) 

1172 assert len(res.available_write_references) == 1 

1173 assert res.available_write_references[0].host_request_id == host_request_id 

1174 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED