Coverage for src/tests/test_references.py: 100%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from datetime import timedelta
2from unittest.mock import patch
4import grpc
5import pytest
6from google.protobuf import empty_pb2
8from couchers import errors
9from couchers.db import session_scope
10from couchers.models import (
11 Conversation,
12 HostRequest,
13 HostRequestStatus,
14 Message,
15 MessageType,
16 Reference,
17 ReferenceType,
18 User,
19)
20from couchers.sql import couchers_select as select
21from couchers.utils import now, to_aware_datetime, today
22from proto import conversations_pb2, references_pb2, requests_pb2
23from tests.test_fixtures import ( # noqa
24 db,
25 generate_user,
26 make_user_block,
27 references_session,
28 requests_session,
29 testconfig,
30)
33@pytest.fixture(autouse=True)
34def _(testconfig):
35 pass
38def create_host_request(
39 session, surfer_user_id, host_user_id, host_request_age=timedelta(days=15), status=HostRequestStatus.confirmed
40):
41 """
42 Create a host request that's `host_request_age` old
43 """
44 from_date = today() - host_request_age - timedelta(days=2)
45 to_date = today() - host_request_age
46 fake_created = now() - host_request_age - timedelta(days=3)
47 conversation = Conversation()
48 session.add(conversation)
49 session.flush()
50 session.add(
51 Message(
52 time=fake_created + timedelta(seconds=1),
53 conversation_id=conversation.id,
54 author_id=surfer_user_id,
55 message_type=MessageType.chat_created,
56 )
57 )
58 message = Message(
59 time=fake_created + timedelta(seconds=2),
60 conversation_id=conversation.id,
61 author_id=surfer_user_id,
62 text="Hi, I'm requesting to be hosted.",
63 message_type=MessageType.text,
64 )
65 session.add(message)
66 session.flush()
67 host_request = HostRequest(
68 conversation_id=conversation.id,
69 surfer_user_id=surfer_user_id,
70 host_user_id=host_user_id,
71 from_date=from_date,
72 to_date=to_date,
73 status=status,
74 surfer_last_seen_message_id=message.id,
75 )
76 session.add(host_request)
77 session.commit()
78 return host_request.conversation_id
81def create_host_reference(session, from_user_id, to_user_id, reference_age, *, surfing=True, host_request_id=None):
82 if host_request_id:
83 actual_host_request_id = host_request_id
84 else:
85 if surfing:
86 actual_host_request_id = host_request_id or create_host_request(
87 session, from_user_id, to_user_id, reference_age + timedelta(days=1)
88 )
89 else:
90 actual_host_request_id = host_request_id or create_host_request(
91 session, to_user_id, from_user_id, reference_age + timedelta(days=1)
92 )
94 host_request = session.execute(
95 select(HostRequest).where(HostRequest.conversation_id == actual_host_request_id)
96 ).scalar_one()
98 reference = Reference(
99 time=now() - reference_age,
100 from_user_id=from_user_id,
101 host_request_id=host_request.conversation_id,
102 text="Dummy reference",
103 rating=0.5,
104 was_appropriate=True,
105 )
107 if host_request.surfer_user_id == from_user_id:
108 reference.reference_type = ReferenceType.surfed
109 reference.to_user_id = host_request.host_user_id
110 assert from_user_id == host_request.surfer_user_id
111 else:
112 reference.reference_type = ReferenceType.hosted
113 reference.to_user_id = host_request.surfer_user_id
114 assert from_user_id == host_request.host_user_id
116 session.add(reference)
117 session.commit()
118 return reference.id, actual_host_request_id
121def create_friend_reference(session, from_user_id, to_user_id, reference_age):
122 reference = Reference(
123 time=now() - reference_age,
124 from_user_id=from_user_id,
125 to_user_id=to_user_id,
126 reference_type=ReferenceType.friend,
127 text="Test friend request",
128 rating=0.4,
129 was_appropriate=True,
130 )
131 session.add(reference)
132 session.commit()
133 return reference.id
136def test_ListPagination(db):
137 user1, token1 = generate_user()
138 user2, token2 = generate_user()
139 user3, token3 = generate_user()
140 user4, token4 = generate_user()
141 user5, token5 = generate_user()
142 user6, token6 = generate_user()
143 user7, token7 = generate_user()
144 user8, token8 = generate_user()
145 user9, token9 = generate_user()
147 with session_scope() as session:
148 # bidirectional references
149 ref2, hr2 = create_host_reference(session, user2.id, user1.id, timedelta(days=16, seconds=110), surfing=True)
150 ref2b, _ = create_host_reference(
151 session, user1.id, user2.id, timedelta(days=16, seconds=100), host_request_id=hr2
152 )
154 ref3, _ = create_host_reference(session, user3.id, user1.id, timedelta(days=16, seconds=90), surfing=False)
155 ref4, _ = create_host_reference(session, user4.id, user1.id, timedelta(days=16, seconds=80), surfing=True)
156 ref4b = create_friend_reference(session, user1.id, user4.id, timedelta(days=16, seconds=70))
158 ref5, hr5 = create_host_reference(session, user5.id, user1.id, timedelta(days=16, seconds=60), surfing=False)
159 ref5b, _ = create_host_reference(
160 session, user1.id, user5.id, timedelta(days=16, seconds=50), host_request_id=hr5
161 )
163 ref6, _ = create_host_reference(session, user6.id, user1.id, timedelta(days=16, seconds=40), surfing=True)
165 ref7 = create_friend_reference(session, user7.id, user1.id, timedelta(days=16, seconds=30))
167 ref8, _ = create_host_reference(session, user8.id, user1.id, timedelta(days=16, seconds=20), surfing=False)
168 ref9, _ = create_host_reference(session, user9.id, user1.id, timedelta(days=16, seconds=10), surfing=False)
170 # should be visible even under 2 weeks
171 ref7b = create_friend_reference(session, user1.id, user7.id, timedelta(days=9))
173 # hidden because it's less than 2 weeks
174 ref6hidden, _ = create_host_reference(session, user6.id, user1.id, timedelta(days=5), surfing=False)
176 # visible because both were written
177 ref8b, hr8 = create_host_reference(session, user8.id, user1.id, timedelta(days=3, seconds=20), surfing=False)
178 ref8c, _ = create_host_reference(
179 session, user1.id, user8.id, timedelta(days=3, seconds=10), host_request_id=hr8
180 )
182 # note that visibility tests don't really test real logic
184 # these check the right refs are in the right requests and appear in the right order (latest first)
186 with references_session(token2) as api:
187 # written by user1
188 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id, page_size=2))
189 assert [ref.reference_id for ref in res.references] == [ref8c, ref7b]
191 res = api.ListReferences(
192 references_pb2.ListReferencesReq(from_user_id=user1.id, page_token=res.next_page_token, page_size=2)
193 )
194 assert [ref.reference_id for ref in res.references] == [ref5b, ref4b]
196 res = api.ListReferences(
197 references_pb2.ListReferencesReq(from_user_id=user1.id, page_token=res.next_page_token, page_size=2)
198 )
199 assert [ref.reference_id for ref in res.references] == [ref2b]
200 assert not res.next_page_token
202 # received by user1
203 res = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id, page_size=5))
204 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8, ref7, ref6]
206 res = api.ListReferences(
207 references_pb2.ListReferencesReq(to_user_id=user1.id, page_token=res.next_page_token, page_size=5)
208 )
209 assert [ref.reference_id for ref in res.references] == [ref5, ref4, ref3, ref2]
210 assert not res.next_page_token
212 # same thing but with filters
213 res = api.ListReferences(
214 references_pb2.ListReferencesReq(
215 to_user_id=user1.id,
216 reference_type_filter=[
217 references_pb2.REFERENCE_TYPE_HOSTED,
218 references_pb2.REFERENCE_TYPE_SURFED,
219 references_pb2.REFERENCE_TYPE_FRIEND,
220 ],
221 page_size=5,
222 )
223 )
224 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8, ref7, ref6]
226 res = api.ListReferences(
227 references_pb2.ListReferencesReq(
228 to_user_id=user1.id,
229 reference_type_filter=[
230 references_pb2.REFERENCE_TYPE_HOSTED,
231 references_pb2.REFERENCE_TYPE_SURFED,
232 references_pb2.REFERENCE_TYPE_FRIEND,
233 ],
234 page_token=res.next_page_token,
235 page_size=5,
236 )
237 )
238 assert [ref.reference_id for ref in res.references] == [ref5, ref4, ref3, ref2]
239 assert not res.next_page_token
241 # received hosting references
242 res = api.ListReferences(
243 references_pb2.ListReferencesReq(
244 to_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_HOSTED], page_size=3
245 )
246 )
247 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8]
249 res = api.ListReferences(
250 references_pb2.ListReferencesReq(
251 to_user_id=user1.id,
252 reference_type_filter=[references_pb2.REFERENCE_TYPE_HOSTED],
253 page_token=res.next_page_token,
254 page_size=3,
255 )
256 )
257 assert [ref.reference_id for ref in res.references] == [ref5, ref3]
258 assert not res.next_page_token
260 # written friend references
261 res = api.ListReferences(
262 references_pb2.ListReferencesReq(
263 from_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_FRIEND]
264 )
265 )
266 assert [ref.reference_id for ref in res.references] == [ref7b, ref4b]
267 assert not res.next_page_token
269 # written surfing references
270 res = api.ListReferences(
271 references_pb2.ListReferencesReq(
272 from_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_SURFED]
273 )
274 )
275 assert [ref.reference_id for ref in res.references] == [ref8c, ref5b]
276 assert not res.next_page_token
278 with references_session(token7) as api:
279 # need to set at least one of from or to user
280 with pytest.raises(grpc.RpcError) as e:
281 api.ListReferences(
282 references_pb2.ListReferencesReq(reference_type_filter=[references_pb2.REFERENCE_TYPE_SURFED])
283 )
284 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
285 assert e.value.details() == errors.NEED_TO_SPECIFY_AT_LEAST_ONE_USER
287 with references_session(token5) as api:
288 # from user1 to user2
289 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id, to_user_id=user2.id))
290 assert [ref.reference_id for ref in res.references] == [ref2b]
291 assert not res.next_page_token
293 # from user5 to user1
294 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user5.id, to_user_id=user1.id))
295 assert [ref.reference_id for ref in res.references] == [ref5]
296 assert not res.next_page_token
299def test_ListReference_banned_deleted_users(db):
300 user1, token1 = generate_user()
301 user2, token2 = generate_user()
302 user3, token3 = generate_user()
304 with session_scope() as session:
305 create_friend_reference(session, user2.id, user1.id, timedelta(days=15))
306 create_friend_reference(session, user3.id, user1.id, timedelta(days=16))
307 create_friend_reference(session, user1.id, user2.id, timedelta(days=15))
308 create_friend_reference(session, user1.id, user3.id, timedelta(days=16))
310 with references_session(token1) as api:
311 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references
312 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references
313 assert len(refs_rec) == 2
314 assert len(refs_sent) == 2
316 # ban user2
317 with session_scope() as session:
318 user2 = session.execute(select(User).where(User.username == user2.username)).scalar_one()
319 user2.is_banned = True
320 session.commit()
322 # reference to and from banned user is hidden
323 with references_session(token1) as api:
324 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references
325 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references
326 assert len(refs_rec) == 1
327 assert len(refs_sent) == 1
329 # delete user3
330 with session_scope() as session:
331 user3 = session.execute(select(User).where(User.username == user3.username)).scalar_one()
332 user3.is_deleted = True
333 session.commit()
335 # doesn't change; references to and from deleted users remain
336 with references_session(token1) as api:
337 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references
338 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references
339 assert len(refs_rec) == 1
340 assert len(refs_sent) == 1
343def test_WriteFriendReference(db):
344 user1, token1 = generate_user()
345 user2, token2 = generate_user()
346 user3, token3 = generate_user()
348 with references_session(token1) as api:
349 # can write normal friend reference
350 res = api.WriteFriendReference(
351 references_pb2.WriteFriendReferenceReq(
352 to_user_id=user2.id,
353 text="A test reference",
354 was_appropriate=True,
355 rating=0.5,
356 )
357 )
358 assert res.from_user_id == user1.id
359 assert res.to_user_id == user2.id
360 assert res.reference_type == references_pb2.REFERENCE_TYPE_FRIEND
361 assert res.text == "A test reference"
362 assert now() - timedelta(hours=24) <= to_aware_datetime(res.written_time) <= now()
363 assert not res.host_request_id
365 with references_session(token3) as api:
366 # check it shows up
367 res = api.ListReferences(
368 references_pb2.ListReferencesReq(
369 from_user_id=user1.id, to_user_id=user2.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_FRIEND]
370 )
371 )
372 assert len(res.references) == 1
373 ref = res.references[0]
374 assert ref.from_user_id == user1.id
375 assert ref.to_user_id == user2.id
376 assert ref.reference_type == references_pb2.REFERENCE_TYPE_FRIEND
377 assert ref.text == "A test reference"
378 assert now() - timedelta(hours=24) <= to_aware_datetime(ref.written_time) <= now()
379 assert not ref.host_request_id
381 with references_session(token1) as api:
382 # can't write a second friend reference
383 with pytest.raises(grpc.RpcError) as e:
384 api.WriteFriendReference(
385 references_pb2.WriteFriendReferenceReq(
386 to_user_id=user2.id,
387 text="A test reference",
388 was_appropriate=True,
389 rating=0.5,
390 )
391 )
392 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
393 assert e.value.details() == errors.REFERENCE_ALREADY_GIVEN
395 with references_session(token2) as api:
396 # can't write a reference about yourself
397 with pytest.raises(grpc.RpcError) as e:
398 api.WriteFriendReference(
399 references_pb2.WriteFriendReferenceReq(
400 to_user_id=user2.id,
401 text="I'm really awesome",
402 was_appropriate=True,
403 rating=1.0,
404 )
405 )
406 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
407 assert e.value.details() == errors.CANT_REFER_SELF
410def test_WriteFriendReference_with_empty_text(db):
411 user1, token1 = generate_user()
412 user2, token2 = generate_user()
414 with references_session(token1) as api:
415 with pytest.raises(grpc.RpcError) as e:
416 api.WriteFriendReference(
417 references_pb2.WriteFriendReferenceReq(to_user_id=user2.id, text=" ", was_appropriate=True, rating=0.8)
418 )
419 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
420 assert e.value.details() == errors.REFERENCE_NO_TEXT
423def test_WriteFriendReference_with_private_text(db):
424 user1, token1 = generate_user()
425 user2, token2 = generate_user()
427 with references_session(token1) as api:
428 with patch("couchers.email.queue_email") as mock:
429 api.WriteFriendReference(
430 references_pb2.WriteFriendReferenceReq(
431 to_user_id=user2.id,
432 text="They were nice!",
433 was_appropriate=True,
434 rating=0.6,
435 private_text="A bit of an odd ball, but a nice person nonetheless.",
436 )
437 )
439 # make sure an email was sent to the user receiving the ref as well as the mods
440 assert mock.call_count == 2
443def test_host_request_states_references(db):
444 user1, token1 = generate_user()
445 user2, token2 = generate_user()
447 with session_scope() as session:
448 # can't write ref
449 hr1 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.pending)
450 # can write ref
451 hr2 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.accepted)
452 # can't write ref
453 hr3 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.rejected)
454 # can write ref
455 hr4 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.confirmed)
456 # can't write ref
457 hr5 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.cancelled)
459 with references_session(token1) as api:
460 # pending
461 api.WriteHostRequestReference(
462 references_pb2.WriteHostRequestReferenceReq(
463 host_request_id=hr2,
464 text="Should work!",
465 was_appropriate=True,
466 rating=0.9,
467 )
468 )
470 # accepted
471 api.WriteHostRequestReference(
472 references_pb2.WriteHostRequestReferenceReq(
473 host_request_id=hr4,
474 text="Should work!",
475 was_appropriate=True,
476 rating=0.9,
477 )
478 )
480 # rejected
481 with pytest.raises(grpc.RpcError) as e:
482 api.WriteHostRequestReference(
483 references_pb2.WriteHostRequestReferenceReq(
484 host_request_id=hr1,
485 text="Shouldn't work...",
486 was_appropriate=True,
487 rating=0.9,
488 )
489 )
490 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
491 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
493 # confirmed
494 with pytest.raises(grpc.RpcError) as e:
495 api.WriteHostRequestReference(
496 references_pb2.WriteHostRequestReferenceReq(
497 host_request_id=hr3,
498 text="Shouldn't work...",
499 was_appropriate=True,
500 rating=0.9,
501 )
502 )
503 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
504 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
506 # cancelled
507 with pytest.raises(grpc.RpcError) as e:
508 api.WriteHostRequestReference(
509 references_pb2.WriteHostRequestReferenceReq(
510 host_request_id=hr5,
511 text="Shouldn't work...",
512 was_appropriate=True,
513 rating=0.9,
514 )
515 )
516 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
517 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
520def test_WriteHostRequestReference(db):
521 user1, token1 = generate_user()
522 user2, token2 = generate_user()
523 user3, token3 = generate_user()
525 with session_scope() as session:
526 # too old
527 hr1 = create_host_request(session, user3.id, user1.id, timedelta(days=20))
528 # valid host req
529 hr2 = create_host_request(session, user3.id, user1.id, timedelta(days=10))
530 # valid surfing req
531 hr3 = create_host_request(session, user1.id, user3.id, timedelta(days=7))
532 # not yet complete
533 hr4 = create_host_request(session, user2.id, user1.id, timedelta(days=1), status=HostRequestStatus.pending)
535 with references_session(token3) as api:
536 # can write for this one
537 api.WriteHostRequestReference(
538 references_pb2.WriteHostRequestReferenceReq(
539 host_request_id=hr3,
540 text="Should work!",
541 was_appropriate=True,
542 rating=0.9,
543 )
544 )
546 with references_session(token1) as api:
547 # can't write reference for a HR that's not yet finished
548 with pytest.raises(grpc.RpcError) as e:
549 api.WriteHostRequestReference(
550 references_pb2.WriteHostRequestReferenceReq(
551 host_request_id=hr4,
552 text="Shouldn't work...",
553 was_appropriate=True,
554 rating=0.9,
555 )
556 )
557 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
558 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
560 # can't write reference that's more than 2 weeks old
561 with pytest.raises(grpc.RpcError) as e:
562 api.WriteHostRequestReference(
563 references_pb2.WriteHostRequestReferenceReq(
564 host_request_id=hr1,
565 text="Shouldn't work...",
566 was_appropriate=True,
567 rating=0.9,
568 )
569 )
570 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
571 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
573 # can write for this one
574 api.WriteHostRequestReference(
575 references_pb2.WriteHostRequestReferenceReq(
576 host_request_id=hr2,
577 text="Should work!",
578 was_appropriate=True,
579 rating=0.9,
580 )
581 )
583 # but can't write a second one for the same one
584 with pytest.raises(grpc.RpcError) as e:
585 api.WriteHostRequestReference(
586 references_pb2.WriteHostRequestReferenceReq(
587 host_request_id=hr2,
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.REFERENCE_ALREADY_GIVEN
596 # can write for this one too
597 api.WriteHostRequestReference(
598 references_pb2.WriteHostRequestReferenceReq(
599 host_request_id=hr3,
600 text="Should work!",
601 was_appropriate=True,
602 rating=0.9,
603 )
604 )
607def test_WriteHostRequestReference_private_text(db):
608 user1, token1 = generate_user()
609 user2, token2 = generate_user()
611 with session_scope() as session:
612 hr = create_host_request(session, user1.id, user2.id, timedelta(days=10))
614 with references_session(token1) as api:
615 with patch("couchers.email.queue_email") as mock:
616 api.WriteHostRequestReference(
617 references_pb2.WriteHostRequestReferenceReq(
618 host_request_id=hr,
619 text="Should work!",
620 was_appropriate=True,
621 rating=0.9,
622 private_text="Something",
623 )
624 )
626 # make sure an email was sent to the user receiving the ref as well as the mods
627 assert mock.call_count == 2
630def test_AvailableWriteReferences_and_ListPendingReferencesToWrite(db):
631 user1, token1 = generate_user()
632 user2, token2 = generate_user()
633 user3, token3 = generate_user()
634 user4, token4 = generate_user()
635 user5, token5 = generate_user(delete_user=True)
636 user6, token6 = generate_user()
637 user7, token7 = generate_user()
638 make_user_block(user1, user6)
639 make_user_block(user7, user1)
641 with session_scope() as session:
642 # too old
643 hr1 = create_host_request(session, user3.id, user1.id, timedelta(days=20))
645 # already wrote friend ref to user3
646 create_friend_reference(session, user1.id, user3.id, timedelta(days=15, seconds=70))
648 # already given
649 _, hr2 = create_host_reference(session, user2.id, user1.id, timedelta(days=10, seconds=110), surfing=True)
650 create_host_reference(session, user1.id, user2.id, timedelta(days=10, seconds=100), host_request_id=hr2)
652 # valid hosted
653 hr3 = create_host_request(session, user3.id, user1.id, timedelta(days=8))
655 # valid surfed
656 hr4 = create_host_request(session, user1.id, user4.id, timedelta(days=5))
658 # not yet complete
659 hr5 = create_host_request(session, user2.id, user1.id, timedelta(days=2), status=HostRequestStatus.pending)
661 # already wrote friend ref to user2
662 create_friend_reference(session, user1.id, user2.id, timedelta(days=1))
664 # user5 deleted, reference won't show up as pending
665 create_host_request(session, user1.id, user5.id, timedelta(days=5))
667 # user6 blocked, reference won't show up as pending
668 create_host_request(session, user1.id, user6.id, timedelta(days=5))
670 # user7 blocking, reference won't show up as pending
671 create_host_request(session, user1.id, user7.id, timedelta(days=5))
673 with references_session(token1) as api:
674 # can't write reference for invisible user
675 with pytest.raises(grpc.RpcError) as e:
676 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user5.id))
677 assert e.value.code() == grpc.StatusCode.NOT_FOUND
678 assert e.value.details() == errors.USER_NOT_FOUND
680 # can't write reference for blocking user
681 with pytest.raises(grpc.RpcError) as e:
682 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user7.id))
683 assert e.value.code() == grpc.StatusCode.NOT_FOUND
684 assert e.value.details() == errors.USER_NOT_FOUND
686 # can't write reference for blocked user
687 with pytest.raises(grpc.RpcError) as e:
688 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user6.id))
689 assert e.value.code() == grpc.StatusCode.NOT_FOUND
690 assert e.value.details() == errors.USER_NOT_FOUND
692 # can't write anything to myself
693 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
694 assert not res.can_write_friend_reference
695 assert len(res.available_write_references) == 0
697 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
698 # can't write friend ref to user2
699 assert not res.can_write_friend_reference
700 # none we can write for user2
701 assert len(res.available_write_references) == 0
703 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user3.id))
704 # can't write friend ref to user3
705 assert not res.can_write_friend_reference
706 # can write one reference because we hosted user3
707 assert len(res.available_write_references) == 1
708 w = res.available_write_references[0]
709 assert w.host_request_id == hr3
710 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED
711 assert now() + timedelta(days=6) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=7)
713 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user4.id))
714 # can write friend ref to user4
715 assert res.can_write_friend_reference
716 # can write one reference because we surfed with user4
717 assert len(res.available_write_references) == 1
718 w = res.available_write_references[0]
719 assert w.host_request_id == hr4
720 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED
721 assert now() + timedelta(days=9) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=10)
723 # finally check the general list
724 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
725 assert len(res.pending_references) == 2
726 w = res.pending_references[0]
727 assert w.host_request_id == hr3
728 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED
729 assert now() + timedelta(days=6) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=7)
730 w = res.pending_references[1]
731 assert w.host_request_id == hr4
732 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED
733 assert now() + timedelta(days=9) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=10)
736@pytest.mark.parametrize("hs", ["host", "surfer"])
737def test_regression_disappearing_refs(db, hs):
738 """
739 Roughly the reproduction steps are:
740 * Send a host request, then have both host and surfer accept
741 * Wait for it to elapse (or hack it with SQL like what you told me to do)
742 * On the surfer account, leave a reference
743 * Then on the host account, the option to leave a reference is then not available
744 """
745 user1, token1 = generate_user()
746 user2, token2 = generate_user()
747 req_start = (today() + timedelta(days=2)).isoformat()
748 req_end = (today() + timedelta(days=3)).isoformat()
749 with requests_session(token1) as api:
750 res = api.CreateHostRequest(
751 requests_pb2.CreateHostRequestReq(
752 host_user_id=user2.id, from_date=req_start, to_date=req_end, text="Test request"
753 )
754 )
755 host_request_id = res.host_request_id
756 assert (
757 api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_sent=True))
758 .host_requests[0]
759 .latest_message.text.text
760 == "Test request"
761 )
763 with requests_session(token2) as api:
764 api.RespondHostRequest(
765 requests_pb2.RespondHostRequestReq(
766 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED
767 )
768 )
770 with requests_session(token1) as api:
771 api.RespondHostRequest(
772 requests_pb2.RespondHostRequestReq(
773 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED
774 )
775 )
777 with references_session(token1) as api:
778 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
779 assert len(res.pending_references) == 0
780 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
781 assert len(res.available_write_references) == 0
783 with references_session(token2) as api:
784 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
785 assert len(res.pending_references) == 0
786 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
787 assert len(res.available_write_references) == 0
789 # hack the time backwards
790 hack_req_start = today() - timedelta(days=10) + timedelta(days=2)
791 hack_req_end = today() - timedelta(days=10) + timedelta(days=3)
792 with session_scope() as session:
793 host_request = session.execute(select(HostRequest)).scalar_one()
794 assert host_request.conversation_id == host_request_id
795 host_request.from_date = hack_req_start
796 host_request.to_date = hack_req_end
798 with references_session(token1) as api:
799 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
800 assert len(res.pending_references) == 1
801 assert res.pending_references[0].host_request_id == host_request_id
802 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
804 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
805 assert len(res.available_write_references) == 1
806 assert res.available_write_references[0].host_request_id == host_request_id
807 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
809 with references_session(token2) as api:
810 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
811 assert len(res.pending_references) == 1
812 assert res.pending_references[0].host_request_id == host_request_id
813 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED
815 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
816 assert len(res.available_write_references) == 1
817 assert res.available_write_references[0].host_request_id == host_request_id
818 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED
820 if hs == "host":
821 with references_session(token2) as api:
822 api.WriteHostRequestReference(
823 references_pb2.WriteHostRequestReferenceReq(
824 host_request_id=host_request_id,
825 text="Good stuff",
826 was_appropriate=True,
827 rating=0.86,
828 )
829 )
831 with references_session(token2) as api:
832 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
833 assert len(res.pending_references) == 0
835 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
836 assert len(res.available_write_references) == 0
838 with references_session(token1) as api:
839 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
840 assert len(res.pending_references) == 1
841 assert res.pending_references[0].host_request_id == host_request_id
842 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
844 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
845 assert len(res.available_write_references) == 1
846 assert res.available_write_references[0].host_request_id == host_request_id
847 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
848 else:
849 with references_session(token1) as api:
850 api.WriteHostRequestReference(
851 references_pb2.WriteHostRequestReferenceReq(
852 host_request_id=host_request_id,
853 text="Good stuff",
854 was_appropriate=True,
855 rating=0.86,
856 )
857 )
859 with references_session(token1) as api:
860 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
861 assert len(res.pending_references) == 0
863 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
864 assert len(res.available_write_references) == 0
866 with references_session(token2) as api:
867 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
868 assert len(res.pending_references) == 1
869 assert res.pending_references[0].host_request_id == host_request_id
870 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED
872 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
873 assert len(res.available_write_references) == 1
874 assert res.available_write_references[0].host_request_id == host_request_id
875 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED