Coverage for src/tests/test_references.py: 100%
417 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-12-20 18:03 +0000
« prev ^ index » next coverage.py v7.5.0, created at 2024-12-20 18:03 +0000
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 email_fields,
26 generate_user,
27 make_user_block,
28 mock_notification_email,
29 push_collector,
30 references_session,
31 requests_session,
32 testconfig,
33)
36@pytest.fixture(autouse=True)
37def _(testconfig):
38 pass
41def create_host_request(
42 session, surfer_user_id, host_user_id, host_request_age=timedelta(days=15), status=HostRequestStatus.confirmed
43):
44 """
45 Create a host request that's `host_request_age` old
46 """
47 from_date = today() - host_request_age - timedelta(days=2)
48 to_date = today() - host_request_age
49 fake_created = now() - host_request_age - timedelta(days=3)
50 conversation = Conversation()
51 session.add(conversation)
52 session.flush()
53 session.add(
54 Message(
55 time=fake_created + timedelta(seconds=1),
56 conversation_id=conversation.id,
57 author_id=surfer_user_id,
58 message_type=MessageType.chat_created,
59 )
60 )
61 message = Message(
62 time=fake_created + timedelta(seconds=2),
63 conversation_id=conversation.id,
64 author_id=surfer_user_id,
65 text="Hi, I'm requesting to be hosted.",
66 message_type=MessageType.text,
67 )
68 session.add(message)
69 session.flush()
70 host_request = HostRequest(
71 conversation_id=conversation.id,
72 surfer_user_id=surfer_user_id,
73 host_user_id=host_user_id,
74 from_date=from_date,
75 to_date=to_date,
76 status=status,
77 surfer_last_seen_message_id=message.id,
78 )
79 session.add(host_request)
80 session.commit()
81 return host_request.conversation_id
84def create_host_reference(session, from_user_id, to_user_id, reference_age, *, surfing=True, host_request_id=None):
85 if host_request_id:
86 actual_host_request_id = host_request_id
87 else:
88 if surfing:
89 actual_host_request_id = host_request_id or create_host_request(
90 session, from_user_id, to_user_id, reference_age + timedelta(days=1)
91 )
92 else:
93 actual_host_request_id = host_request_id or create_host_request(
94 session, to_user_id, from_user_id, reference_age + timedelta(days=1)
95 )
97 host_request = session.execute(
98 select(HostRequest).where(HostRequest.conversation_id == actual_host_request_id)
99 ).scalar_one()
101 reference = Reference(
102 time=now() - reference_age,
103 from_user_id=from_user_id,
104 host_request_id=host_request.conversation_id,
105 text="Dummy reference",
106 rating=0.5,
107 was_appropriate=True,
108 )
110 if host_request.surfer_user_id == from_user_id:
111 reference.reference_type = ReferenceType.surfed
112 reference.to_user_id = host_request.host_user_id
113 assert from_user_id == host_request.surfer_user_id
114 else:
115 reference.reference_type = ReferenceType.hosted
116 reference.to_user_id = host_request.surfer_user_id
117 assert from_user_id == host_request.host_user_id
119 session.add(reference)
120 session.commit()
121 return reference.id, actual_host_request_id
124def create_friend_reference(session, from_user_id, to_user_id, reference_age):
125 reference = Reference(
126 time=now() - reference_age,
127 from_user_id=from_user_id,
128 to_user_id=to_user_id,
129 reference_type=ReferenceType.friend,
130 text="Test friend request",
131 rating=0.4,
132 was_appropriate=True,
133 )
134 session.add(reference)
135 session.commit()
136 return reference.id
139def test_ListPagination(db):
140 user1, token1 = generate_user()
141 user2, token2 = generate_user()
142 user3, token3 = generate_user()
143 user4, token4 = generate_user()
144 user5, token5 = generate_user()
145 user6, token6 = generate_user()
146 user7, token7 = generate_user()
147 user8, token8 = generate_user()
148 user9, token9 = generate_user()
150 with session_scope() as session:
151 # bidirectional references
152 ref2, hr2 = create_host_reference(session, user2.id, user1.id, timedelta(days=16, seconds=110), surfing=True)
153 ref2b, _ = create_host_reference(
154 session, user1.id, user2.id, timedelta(days=16, seconds=100), host_request_id=hr2
155 )
157 ref3, _ = create_host_reference(session, user3.id, user1.id, timedelta(days=16, seconds=90), surfing=False)
158 ref4, _ = create_host_reference(session, user4.id, user1.id, timedelta(days=16, seconds=80), surfing=True)
159 ref4b = create_friend_reference(session, user1.id, user4.id, timedelta(days=16, seconds=70))
161 ref5, hr5 = create_host_reference(session, user5.id, user1.id, timedelta(days=16, seconds=60), surfing=False)
162 ref5b, _ = create_host_reference(
163 session, user1.id, user5.id, timedelta(days=16, seconds=50), host_request_id=hr5
164 )
166 ref6, _ = create_host_reference(session, user6.id, user1.id, timedelta(days=16, seconds=40), surfing=True)
168 ref7 = create_friend_reference(session, user7.id, user1.id, timedelta(days=16, seconds=30))
170 ref8, _ = create_host_reference(session, user8.id, user1.id, timedelta(days=16, seconds=20), surfing=False)
171 ref9, _ = create_host_reference(session, user9.id, user1.id, timedelta(days=16, seconds=10), surfing=False)
173 # should be visible even under 2 weeks
174 ref7b = create_friend_reference(session, user1.id, user7.id, timedelta(days=9))
176 # hidden because it's less than 2 weeks
177 ref6hidden, _ = create_host_reference(session, user6.id, user1.id, timedelta(days=5), surfing=False)
179 # visible because both were written
180 ref8b, hr8 = create_host_reference(session, user8.id, user1.id, timedelta(days=3, seconds=20), surfing=False)
181 ref8c, _ = create_host_reference(
182 session, user1.id, user8.id, timedelta(days=3, seconds=10), host_request_id=hr8
183 )
185 # note that visibility tests don't really test real logic
187 # these check the right refs are in the right requests and appear in the right order (latest first)
189 with references_session(token2) as api:
190 # written by user1
191 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id, page_size=2))
192 assert [ref.reference_id for ref in res.references] == [ref8c, ref7b]
194 res = api.ListReferences(
195 references_pb2.ListReferencesReq(from_user_id=user1.id, page_token=res.next_page_token, page_size=2)
196 )
197 assert [ref.reference_id for ref in res.references] == [ref5b, ref4b]
199 res = api.ListReferences(
200 references_pb2.ListReferencesReq(from_user_id=user1.id, page_token=res.next_page_token, page_size=2)
201 )
202 assert [ref.reference_id for ref in res.references] == [ref2b]
203 assert not res.next_page_token
205 # received by user1
206 res = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id, page_size=5))
207 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8, ref7, ref6]
209 res = api.ListReferences(
210 references_pb2.ListReferencesReq(to_user_id=user1.id, page_token=res.next_page_token, page_size=5)
211 )
212 assert [ref.reference_id for ref in res.references] == [ref5, ref4, ref3, ref2]
213 assert not res.next_page_token
215 # same thing but with filters
216 res = api.ListReferences(
217 references_pb2.ListReferencesReq(
218 to_user_id=user1.id,
219 reference_type_filter=[
220 references_pb2.REFERENCE_TYPE_HOSTED,
221 references_pb2.REFERENCE_TYPE_SURFED,
222 references_pb2.REFERENCE_TYPE_FRIEND,
223 ],
224 page_size=5,
225 )
226 )
227 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8, ref7, ref6]
229 res = api.ListReferences(
230 references_pb2.ListReferencesReq(
231 to_user_id=user1.id,
232 reference_type_filter=[
233 references_pb2.REFERENCE_TYPE_HOSTED,
234 references_pb2.REFERENCE_TYPE_SURFED,
235 references_pb2.REFERENCE_TYPE_FRIEND,
236 ],
237 page_token=res.next_page_token,
238 page_size=5,
239 )
240 )
241 assert [ref.reference_id for ref in res.references] == [ref5, ref4, ref3, ref2]
242 assert not res.next_page_token
244 # received hosting references
245 res = api.ListReferences(
246 references_pb2.ListReferencesReq(
247 to_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_HOSTED], page_size=3
248 )
249 )
250 assert [ref.reference_id for ref in res.references] == [ref8b, ref9, ref8]
252 res = api.ListReferences(
253 references_pb2.ListReferencesReq(
254 to_user_id=user1.id,
255 reference_type_filter=[references_pb2.REFERENCE_TYPE_HOSTED],
256 page_token=res.next_page_token,
257 page_size=3,
258 )
259 )
260 assert [ref.reference_id for ref in res.references] == [ref5, ref3]
261 assert not res.next_page_token
263 # written friend references
264 res = api.ListReferences(
265 references_pb2.ListReferencesReq(
266 from_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_FRIEND]
267 )
268 )
269 assert [ref.reference_id for ref in res.references] == [ref7b, ref4b]
270 assert not res.next_page_token
272 # written surfing references
273 res = api.ListReferences(
274 references_pb2.ListReferencesReq(
275 from_user_id=user1.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_SURFED]
276 )
277 )
278 assert [ref.reference_id for ref in res.references] == [ref8c, ref5b]
279 assert not res.next_page_token
281 with references_session(token7) as api:
282 # need to set at least one of from or to user
283 with pytest.raises(grpc.RpcError) as e:
284 api.ListReferences(
285 references_pb2.ListReferencesReq(reference_type_filter=[references_pb2.REFERENCE_TYPE_SURFED])
286 )
287 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
288 assert e.value.details() == errors.NEED_TO_SPECIFY_AT_LEAST_ONE_USER
290 with references_session(token5) as api:
291 # from user1 to user2
292 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id, to_user_id=user2.id))
293 assert [ref.reference_id for ref in res.references] == [ref2b]
294 assert not res.next_page_token
296 # from user5 to user1
297 res = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user5.id, to_user_id=user1.id))
298 assert [ref.reference_id for ref in res.references] == [ref5]
299 assert not res.next_page_token
302def test_ListReference_banned_deleted_users(db):
303 user1, token1 = generate_user()
304 user2, token2 = generate_user()
305 user3, token3 = generate_user()
307 with session_scope() as session:
308 create_friend_reference(session, user2.id, user1.id, timedelta(days=15))
309 create_friend_reference(session, user3.id, user1.id, timedelta(days=16))
310 create_friend_reference(session, user1.id, user2.id, timedelta(days=15))
311 create_friend_reference(session, user1.id, user3.id, timedelta(days=16))
313 with references_session(token1) as api:
314 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references
315 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references
316 assert len(refs_rec) == 2
317 assert len(refs_sent) == 2
319 # ban user2
320 with session_scope() as session:
321 user2 = session.execute(select(User).where(User.username == user2.username)).scalar_one()
322 user2.is_banned = True
323 session.commit()
325 # reference to and from banned user is hidden
326 with references_session(token1) as api:
327 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references
328 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references
329 assert len(refs_rec) == 1
330 assert len(refs_sent) == 1
332 # delete user3
333 with session_scope() as session:
334 user3 = session.execute(select(User).where(User.username == user3.username)).scalar_one()
335 user3.is_deleted = True
336 session.commit()
338 # doesn't change; references to and from deleted users remain
339 with references_session(token1) as api:
340 refs_rec = api.ListReferences(references_pb2.ListReferencesReq(to_user_id=user1.id)).references
341 refs_sent = api.ListReferences(references_pb2.ListReferencesReq(from_user_id=user1.id)).references
342 assert len(refs_rec) == 1
343 assert len(refs_sent) == 1
346def test_WriteFriendReference(db):
347 user1, token1 = generate_user()
348 user2, token2 = generate_user()
349 user3, token3 = generate_user()
351 with references_session(token1) as api:
352 # can write normal friend reference
353 res = api.WriteFriendReference(
354 references_pb2.WriteFriendReferenceReq(
355 to_user_id=user2.id,
356 text="A test reference",
357 was_appropriate=True,
358 rating=0.5,
359 )
360 )
361 assert res.from_user_id == user1.id
362 assert res.to_user_id == user2.id
363 assert res.reference_type == references_pb2.REFERENCE_TYPE_FRIEND
364 assert res.text == "A test reference"
365 assert now() - timedelta(hours=24) <= to_aware_datetime(res.written_time) <= now()
366 assert not res.host_request_id
368 with references_session(token3) as api:
369 # check it shows up
370 res = api.ListReferences(
371 references_pb2.ListReferencesReq(
372 from_user_id=user1.id, to_user_id=user2.id, reference_type_filter=[references_pb2.REFERENCE_TYPE_FRIEND]
373 )
374 )
375 assert len(res.references) == 1
376 ref = res.references[0]
377 assert ref.from_user_id == user1.id
378 assert ref.to_user_id == user2.id
379 assert ref.reference_type == references_pb2.REFERENCE_TYPE_FRIEND
380 assert ref.text == "A test reference"
381 assert now() - timedelta(hours=24) <= to_aware_datetime(ref.written_time) <= now()
382 assert not ref.host_request_id
384 with references_session(token1) as api:
385 # can't write a second friend reference
386 with pytest.raises(grpc.RpcError) as e:
387 api.WriteFriendReference(
388 references_pb2.WriteFriendReferenceReq(
389 to_user_id=user2.id,
390 text="A test reference",
391 was_appropriate=True,
392 rating=0.5,
393 )
394 )
395 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
396 assert e.value.details() == errors.REFERENCE_ALREADY_GIVEN
398 with references_session(token2) as api:
399 # can't write a reference about yourself
400 with pytest.raises(grpc.RpcError) as e:
401 api.WriteFriendReference(
402 references_pb2.WriteFriendReferenceReq(
403 to_user_id=user2.id,
404 text="I'm really awesome",
405 was_appropriate=True,
406 rating=1.0,
407 )
408 )
409 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
410 assert e.value.details() == errors.CANT_REFER_SELF
413def test_WriteFriendReference_with_empty_text(db):
414 user1, token1 = generate_user()
415 user2, token2 = generate_user()
417 with references_session(token1) as api:
418 with pytest.raises(grpc.RpcError) as e:
419 api.WriteFriendReference(
420 references_pb2.WriteFriendReferenceReq(to_user_id=user2.id, text=" ", was_appropriate=True, rating=0.8)
421 )
422 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
423 assert e.value.details() == errors.REFERENCE_NO_TEXT
426def test_WriteFriendReference_with_private_text(db, push_collector):
427 user1, token1 = generate_user()
428 user2, token2 = generate_user()
430 with references_session(token1) as api:
431 with patch("couchers.email.queue_email") as mock1:
432 with mock_notification_email() as mock2:
433 api.WriteFriendReference(
434 references_pb2.WriteFriendReferenceReq(
435 to_user_id=user2.id,
436 text="They were nice!",
437 was_appropriate=True,
438 rating=0.6,
439 private_text="A bit of an odd ball, but a nice person nonetheless.",
440 )
441 )
443 # make sure an email was sent to the user receiving the ref as well as the mods
444 assert mock1.call_count == 1
445 assert mock2.call_count == 1
446 e = email_fields(mock2)
447 assert e.subject == f"[TEST] You've received a friend reference from {user1.name}!"
448 assert e.recipient == user2.email
450 push_collector.assert_user_has_single_matching(
451 user2.id,
452 title=f"You've received a friend reference from {user1.name}!",
453 body="They were nice!",
454 )
457def test_host_request_states_references(db):
458 user1, token1 = generate_user()
459 user2, token2 = generate_user()
461 with session_scope() as session:
462 # can't write ref
463 hr1 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.pending)
464 # can write ref
465 hr2 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.accepted)
466 # can't write ref
467 hr3 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.rejected)
468 # can write ref
469 hr4 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.confirmed)
470 # can't write ref
471 hr5 = create_host_request(session, user2.id, user1.id, timedelta(days=10), status=HostRequestStatus.cancelled)
473 with references_session(token1) as api:
474 # pending
475 api.WriteHostRequestReference(
476 references_pb2.WriteHostRequestReferenceReq(
477 host_request_id=hr2,
478 text="Should work!",
479 was_appropriate=True,
480 rating=0.9,
481 )
482 )
484 # accepted
485 api.WriteHostRequestReference(
486 references_pb2.WriteHostRequestReferenceReq(
487 host_request_id=hr4,
488 text="Should work!",
489 was_appropriate=True,
490 rating=0.9,
491 )
492 )
494 # rejected
495 with pytest.raises(grpc.RpcError) as e:
496 api.WriteHostRequestReference(
497 references_pb2.WriteHostRequestReferenceReq(
498 host_request_id=hr1,
499 text="Shouldn't work...",
500 was_appropriate=True,
501 rating=0.9,
502 )
503 )
504 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
505 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
507 # confirmed
508 with pytest.raises(grpc.RpcError) as e:
509 api.WriteHostRequestReference(
510 references_pb2.WriteHostRequestReferenceReq(
511 host_request_id=hr3,
512 text="Shouldn't work...",
513 was_appropriate=True,
514 rating=0.9,
515 )
516 )
517 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
518 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
520 # cancelled
521 with pytest.raises(grpc.RpcError) as e:
522 api.WriteHostRequestReference(
523 references_pb2.WriteHostRequestReferenceReq(
524 host_request_id=hr5,
525 text="Shouldn't work...",
526 was_appropriate=True,
527 rating=0.9,
528 )
529 )
530 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
531 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
534def test_WriteHostRequestReference(db):
535 user1, token1 = generate_user()
536 user2, token2 = generate_user()
537 user3, token3 = generate_user()
539 with session_scope() as session:
540 # too old
541 hr1 = create_host_request(session, user3.id, user1.id, timedelta(days=20))
542 # valid host req
543 hr2 = create_host_request(session, user3.id, user1.id, timedelta(days=10))
544 # valid surfing req
545 hr3 = create_host_request(session, user1.id, user3.id, timedelta(days=7))
546 # not yet complete
547 hr4 = create_host_request(session, user2.id, user1.id, timedelta(days=1), status=HostRequestStatus.pending)
549 with references_session(token3) as api:
550 # can write for this one
551 api.WriteHostRequestReference(
552 references_pb2.WriteHostRequestReferenceReq(
553 host_request_id=hr3,
554 text="Should work!",
555 was_appropriate=True,
556 rating=0.9,
557 )
558 )
560 with references_session(token1) as api:
561 # can't write reference for a HR that's not yet finished
562 with pytest.raises(grpc.RpcError) as e:
563 api.WriteHostRequestReference(
564 references_pb2.WriteHostRequestReferenceReq(
565 host_request_id=hr4,
566 text="Shouldn't work...",
567 was_appropriate=True,
568 rating=0.9,
569 )
570 )
571 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
572 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
574 # can't write reference that's more than 2 weeks old
575 with pytest.raises(grpc.RpcError) as e:
576 api.WriteHostRequestReference(
577 references_pb2.WriteHostRequestReferenceReq(
578 host_request_id=hr1,
579 text="Shouldn't work...",
580 was_appropriate=True,
581 rating=0.9,
582 )
583 )
584 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
585 assert e.value.details() == errors.CANT_WRITE_REFERENCE_FOR_REQUEST
587 # can write for this one
588 api.WriteHostRequestReference(
589 references_pb2.WriteHostRequestReferenceReq(
590 host_request_id=hr2,
591 text="Should work!",
592 was_appropriate=True,
593 rating=0.9,
594 )
595 )
597 # but can't write a second one for the same one
598 with pytest.raises(grpc.RpcError) as e:
599 api.WriteHostRequestReference(
600 references_pb2.WriteHostRequestReferenceReq(
601 host_request_id=hr2,
602 text="Shouldn't work...",
603 was_appropriate=True,
604 rating=0.9,
605 )
606 )
607 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
608 assert e.value.details() == errors.REFERENCE_ALREADY_GIVEN
610 # can write for this one too
611 api.WriteHostRequestReference(
612 references_pb2.WriteHostRequestReferenceReq(
613 host_request_id=hr3,
614 text="Should work!",
615 was_appropriate=True,
616 rating=0.9,
617 )
618 )
621def test_WriteHostRequestReference_private_text(db, push_collector):
622 user1, token1 = generate_user()
623 user2, token2 = generate_user()
625 with session_scope() as session:
626 hr = create_host_request(session, user1.id, user2.id, timedelta(days=10))
628 with references_session(token1) as api:
629 with patch("couchers.email.queue_email") as mock1:
630 with mock_notification_email() as mock2:
631 api.WriteHostRequestReference(
632 references_pb2.WriteHostRequestReferenceReq(
633 host_request_id=hr,
634 text="Should work!",
635 was_appropriate=True,
636 rating=0.9,
637 private_text="Something",
638 )
639 )
641 # make sure an email was sent to the user receiving the ref as well as the mods
642 assert mock1.call_count == 1
643 assert mock2.call_count == 1
645 e = email_fields(mock2)
646 assert e.subject == f"[TEST] You've received a reference from {user1.name}!"
647 assert e.recipient == user2.email
649 push_collector.assert_user_has_single_matching(
650 user2.id,
651 title=f"You've received a reference from {user1.name}!",
652 body="Please go and write a reference for them too. It's a nice gesture and helps us build a community together!",
653 )
656def test_AvailableWriteReferences_and_ListPendingReferencesToWrite(db):
657 user1, token1 = generate_user()
658 user2, token2 = generate_user()
659 user3, token3 = generate_user()
660 user4, token4 = generate_user()
661 user5, token5 = generate_user(delete_user=True)
662 user6, token6 = generate_user()
663 user7, token7 = generate_user()
664 make_user_block(user1, user6)
665 make_user_block(user7, user1)
667 with session_scope() as session:
668 # too old
669 hr1 = create_host_request(session, user3.id, user1.id, timedelta(days=20))
671 # already wrote friend ref to user3
672 create_friend_reference(session, user1.id, user3.id, timedelta(days=15, seconds=70))
674 # already given
675 _, hr2 = create_host_reference(session, user2.id, user1.id, timedelta(days=10, seconds=110), surfing=True)
676 create_host_reference(session, user1.id, user2.id, timedelta(days=10, seconds=100), host_request_id=hr2)
678 # valid hosted
679 hr3 = create_host_request(session, user3.id, user1.id, timedelta(days=8))
681 # valid surfed
682 hr4 = create_host_request(session, user1.id, user4.id, timedelta(days=5))
684 # not yet complete
685 hr5 = create_host_request(session, user2.id, user1.id, timedelta(days=2), status=HostRequestStatus.pending)
687 # already wrote friend ref to user2
688 create_friend_reference(session, user1.id, user2.id, timedelta(days=1))
690 # user5 deleted, reference won't show up as pending
691 create_host_request(session, user1.id, user5.id, timedelta(days=5))
693 # user6 blocked, reference won't show up as pending
694 create_host_request(session, user1.id, user6.id, timedelta(days=5))
696 # user7 blocking, reference won't show up as pending
697 create_host_request(session, user1.id, user7.id, timedelta(days=5))
699 with references_session(token1) as api:
700 # can't write reference for invisible user
701 with pytest.raises(grpc.RpcError) as e:
702 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user5.id))
703 assert e.value.code() == grpc.StatusCode.NOT_FOUND
704 assert e.value.details() == errors.USER_NOT_FOUND
706 # can't write reference for blocking user
707 with pytest.raises(grpc.RpcError) as e:
708 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user7.id))
709 assert e.value.code() == grpc.StatusCode.NOT_FOUND
710 assert e.value.details() == errors.USER_NOT_FOUND
712 # can't write reference for blocked user
713 with pytest.raises(grpc.RpcError) as e:
714 api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user6.id))
715 assert e.value.code() == grpc.StatusCode.NOT_FOUND
716 assert e.value.details() == errors.USER_NOT_FOUND
718 # can't write anything to myself
719 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
720 assert not res.can_write_friend_reference
721 assert len(res.available_write_references) == 0
723 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
724 # can't write friend ref to user2
725 assert not res.can_write_friend_reference
726 # none we can write for user2
727 assert len(res.available_write_references) == 0
729 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user3.id))
730 # can't write friend ref to user3
731 assert not res.can_write_friend_reference
732 # can write one reference because we hosted user3
733 assert len(res.available_write_references) == 1
734 w = res.available_write_references[0]
735 assert w.host_request_id == hr3
736 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED
737 assert now() + timedelta(days=6) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=7)
739 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user4.id))
740 # can write friend ref to user4
741 assert res.can_write_friend_reference
742 # can write one reference because we surfed with user4
743 assert len(res.available_write_references) == 1
744 w = res.available_write_references[0]
745 assert w.host_request_id == hr4
746 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED
747 assert now() + timedelta(days=9) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=10)
749 # finally check the general list
750 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
751 assert len(res.pending_references) == 2
752 w = res.pending_references[0]
753 assert w.host_request_id == hr3
754 assert w.reference_type == references_pb2.REFERENCE_TYPE_HOSTED
755 assert now() + timedelta(days=6) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=7)
756 w = res.pending_references[1]
757 assert w.host_request_id == hr4
758 assert w.reference_type == references_pb2.REFERENCE_TYPE_SURFED
759 assert now() + timedelta(days=9) <= to_aware_datetime(w.time_expires) <= now() + timedelta(days=10)
762@pytest.mark.parametrize("hs", ["host", "surfer"])
763def test_regression_disappearing_refs(db, hs):
764 """
765 Roughly the reproduction steps are:
766 * Send a host request, then have both host and surfer accept
767 * Wait for it to elapse (or hack it with SQL like what you told me to do)
768 * On the surfer account, leave a reference
769 * Then on the host account, the option to leave a reference is then not available
770 """
771 user1, token1 = generate_user()
772 user2, token2 = generate_user()
773 req_start = (today() + timedelta(days=2)).isoformat()
774 req_end = (today() + timedelta(days=3)).isoformat()
775 with requests_session(token1) as api:
776 res = api.CreateHostRequest(
777 requests_pb2.CreateHostRequestReq(
778 host_user_id=user2.id, from_date=req_start, to_date=req_end, text="Test request"
779 )
780 )
781 host_request_id = res.host_request_id
782 assert (
783 api.ListHostRequests(requests_pb2.ListHostRequestsReq(only_sent=True))
784 .host_requests[0]
785 .latest_message.text.text
786 == "Test request"
787 )
789 with requests_session(token2) as api:
790 api.RespondHostRequest(
791 requests_pb2.RespondHostRequestReq(
792 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_ACCEPTED
793 )
794 )
796 with requests_session(token1) as api:
797 api.RespondHostRequest(
798 requests_pb2.RespondHostRequestReq(
799 host_request_id=host_request_id, status=conversations_pb2.HOST_REQUEST_STATUS_CONFIRMED
800 )
801 )
803 with references_session(token1) as api:
804 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
805 assert len(res.pending_references) == 0
806 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
807 assert len(res.available_write_references) == 0
809 with references_session(token2) as api:
810 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
811 assert len(res.pending_references) == 0
812 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
813 assert len(res.available_write_references) == 0
815 # hack the time backwards
816 hack_req_start = today() - timedelta(days=10) + timedelta(days=2)
817 hack_req_end = today() - timedelta(days=10) + timedelta(days=3)
818 with session_scope() as session:
819 host_request = session.execute(select(HostRequest)).scalar_one()
820 assert host_request.conversation_id == host_request_id
821 host_request.from_date = hack_req_start
822 host_request.to_date = hack_req_end
824 with references_session(token1) as api:
825 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
826 assert len(res.pending_references) == 1
827 assert res.pending_references[0].host_request_id == host_request_id
828 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
830 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
831 assert len(res.available_write_references) == 1
832 assert res.available_write_references[0].host_request_id == host_request_id
833 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
835 with references_session(token2) as api:
836 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
837 assert len(res.pending_references) == 1
838 assert res.pending_references[0].host_request_id == host_request_id
839 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED
841 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
842 assert len(res.available_write_references) == 1
843 assert res.available_write_references[0].host_request_id == host_request_id
844 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED
846 if hs == "host":
847 with references_session(token2) as api:
848 api.WriteHostRequestReference(
849 references_pb2.WriteHostRequestReferenceReq(
850 host_request_id=host_request_id,
851 text="Good stuff",
852 was_appropriate=True,
853 rating=0.86,
854 )
855 )
857 with references_session(token2) as api:
858 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
859 assert len(res.pending_references) == 0
861 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
862 assert len(res.available_write_references) == 0
864 with references_session(token1) as api:
865 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
866 assert len(res.pending_references) == 1
867 assert res.pending_references[0].host_request_id == host_request_id
868 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
870 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user2.id))
871 assert len(res.available_write_references) == 1
872 assert res.available_write_references[0].host_request_id == host_request_id
873 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_SURFED
874 else:
875 with references_session(token1) as api:
876 api.WriteHostRequestReference(
877 references_pb2.WriteHostRequestReferenceReq(
878 host_request_id=host_request_id,
879 text="Good stuff",
880 was_appropriate=True,
881 rating=0.86,
882 )
883 )
885 with references_session(token1) as api:
886 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
887 assert len(res.pending_references) == 0
889 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
890 assert len(res.available_write_references) == 0
892 with references_session(token2) as api:
893 res = api.ListPendingReferencesToWrite(empty_pb2.Empty())
894 assert len(res.pending_references) == 1
895 assert res.pending_references[0].host_request_id == host_request_id
896 assert res.pending_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED
898 res = api.AvailableWriteReferences(references_pb2.AvailableWriteReferencesReq(to_user_id=user1.id))
899 assert len(res.available_write_references) == 1
900 assert res.available_write_references[0].host_request_id == host_request_id
901 assert res.available_write_references[0].reference_type == references_pb2.REFERENCE_TYPE_HOSTED