Coverage for src/tests/test_api.py: 100%
770 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-07-14 16:54 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-07-14 16:54 +0000
1from datetime import timedelta
3import grpc
4import pytest
5from google.protobuf import empty_pb2, wrappers_pb2
7from couchers import errors
8from couchers.db import session_scope
9from couchers.jobs.handlers import update_badges
10from couchers.materialized_views import refresh_materialized_views_rapid
11from couchers.models import FriendRelationship, FriendStatus, RateLimitAction
12from couchers.rate_limits.definitions import RATE_LIMIT_DEFINITIONS, RATE_LIMIT_INTERVAL_STRING
13from couchers.resources import get_badge_dict
14from couchers.sql import couchers_select as select
15from couchers.utils import create_coordinate, to_aware_datetime
16from proto import api_pb2, jail_pb2, notifications_pb2
17from tests.test_fixtures import ( # noqa
18 api_session,
19 blocking_session,
20 db,
21 email_fields,
22 generate_user,
23 make_friends,
24 make_user_block,
25 make_user_invisible,
26 mock_notification_email,
27 notifications_session,
28 push_collector,
29 real_api_session,
30 real_jail_session,
31 testconfig,
32)
35@pytest.fixture(autouse=True)
36def _(testconfig):
37 pass
40def test_ping(db):
41 user, token = generate_user()
43 with real_api_session(token) as api:
44 res = api.Ping(api_pb2.PingReq())
46 assert res.user.user_id == user.id
47 assert res.user.username == user.username
48 assert res.user.name == user.name
49 assert res.user.city == user.city
50 assert res.user.hometown == user.hometown
51 assert res.user.verification == 0.0
52 assert res.user.community_standing == user.community_standing
53 assert res.user.num_references == 0
54 assert res.user.gender == user.gender
55 assert res.user.pronouns == user.pronouns
56 assert res.user.age == user.age
58 assert (res.user.lat, res.user.lng) == (user.coordinates or (0, 0))
60 # the joined time is fuzzed
61 # but shouldn't be before actual joined time, or more than one hour behind
62 assert user.joined - timedelta(hours=1) <= to_aware_datetime(res.user.joined) <= user.joined
63 # same for last_active
64 assert user.last_active - timedelta(hours=1) <= to_aware_datetime(res.user.last_active) <= user.last_active
66 assert res.user.hosting_status == api_pb2.HOSTING_STATUS_CANT_HOST
67 assert res.user.meetup_status == api_pb2.MEETUP_STATUS_OPEN_TO_MEETUP
69 assert res.user.occupation == user.occupation
70 assert res.user.education == user.education
71 assert res.user.about_me == user.about_me
72 assert res.user.things_i_like == user.things_i_like
73 assert {language_ability.code for language_ability in res.user.language_abilities} == {"fin", "fra"}
74 assert res.user.about_place == user.about_place
75 assert res.user.regions_visited == ["FIN", "REU", "CHE"] # Tests alphabetization by region name
76 assert res.user.regions_lived == ["EST", "FRA", "ESP"] # Ditto
77 assert res.user.additional_information == user.additional_information
79 assert res.user.friends == api_pb2.User.FriendshipStatus.NA
80 assert not res.user.HasField("pending_friend_request")
83def test_coords(db):
84 # make them need to update location
85 user1, token1 = generate_user(geom=create_coordinate(1, 0), geom_radius=2000, needs_to_update_location=True)
86 user2, token2 = generate_user()
88 with api_session(token2) as api:
89 res = api.Ping(api_pb2.PingReq())
90 assert res.user.city == user2.city
91 lat, lng = user2.coordinates or (0, 0)
92 assert res.user.lat == lat
93 assert res.user.lng == lng
94 assert res.user.radius == user2.geom_radius
96 with api_session(token2) as api:
97 res = api.GetUser(api_pb2.GetUserReq(user=user1.username))
98 assert res.city == user1.city
99 assert res.lat == 1.0
100 assert res.lng == 0.0
101 assert res.radius == 2000.0
103 # Check coordinate wrapping
104 user3, token3 = generate_user(geom=create_coordinate(40.0, -180.5))
105 user4, token4 = generate_user(geom=create_coordinate(40.0, 20.0))
106 user5, token5 = generate_user(geom=create_coordinate(90.5, 20.0))
108 with api_session(token3) as api:
109 res = api.GetUser(api_pb2.GetUserReq(user=user3.username))
110 assert res.lat == 40.0
111 assert res.lng == 179.5
113 with api_session(token4) as api:
114 res = api.GetUser(api_pb2.GetUserReq(user=user4.username))
115 assert res.lat == 40.0
116 assert res.lng == 20.0
118 # PostGIS does not wrap longitude for latitude overflow
119 with api_session(token5) as api:
120 res = api.GetUser(api_pb2.GetUserReq(user=user5.username))
121 assert res.lat == 89.5
122 assert res.lng == 20.0
124 with real_jail_session(token1) as jail:
125 res = jail.JailInfo(empty_pb2.Empty())
126 assert res.jailed
127 assert res.needs_to_update_location
129 res = jail.SetLocation(
130 jail_pb2.SetLocationReq(
131 city="New York City",
132 lat=40.7812,
133 lng=-73.9647,
134 radius=250,
135 )
136 )
138 assert not res.jailed
139 assert not res.needs_to_update_location
141 res = jail.JailInfo(empty_pb2.Empty())
142 assert not res.jailed
143 assert not res.needs_to_update_location
145 with api_session(token2) as api:
146 res = api.GetUser(api_pb2.GetUserReq(user=user1.username))
147 assert res.city == "New York City"
148 assert res.lat == 40.7812
149 assert res.lng == -73.9647
150 assert res.radius == 250
153def test_get_user(db):
154 user1, token1 = generate_user()
155 user2, token2 = generate_user()
157 with api_session(token1) as api:
158 res = api.GetUser(api_pb2.GetUserReq(user=user2.username))
159 assert res.user_id == user2.id
160 assert res.username == user2.username
161 assert res.name == user2.name
163 with api_session(token1) as api:
164 res = api.GetUser(api_pb2.GetUserReq(user=str(user2.id)))
165 assert res.user_id == user2.id
166 assert res.username == user2.username
167 assert res.name == user2.name
170def test_lite_coords(db):
171 # make them need to update location
172 user1, token1 = generate_user(geom=create_coordinate(0, 0), geom_radius=0, needs_to_update_location=True)
173 user2, token2 = generate_user()
175 refresh_materialized_views_rapid(None)
177 with api_session(token2) as api:
178 res = api.Ping(api_pb2.PingReq())
179 assert res.user.city == user2.city
180 lat, lng = user2.coordinates or (0, 0)
181 assert res.user.lat == lat
182 assert res.user.lng == lng
183 assert res.user.radius == user2.geom_radius
185 with api_session(token2) as api:
186 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=user1.username))
187 assert res.city == user1.city
188 assert res.lat == 0.0
189 assert res.lng == 0.0
190 assert res.radius == 0.0
192 # Check coordinate wrapping
193 user3, token3 = generate_user(geom=create_coordinate(40.0, -180.5))
194 user4, token4 = generate_user(geom=create_coordinate(40.0, 20.0))
195 user5, token5 = generate_user(geom=create_coordinate(90.5, 20.0))
197 refresh_materialized_views_rapid(None)
199 with api_session(token3) as api:
200 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=user3.username))
201 assert res.lat == 40.0
202 assert res.lng == 179.5
204 with api_session(token4) as api:
205 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=user4.username))
206 assert res.lat == 40.0
207 assert res.lng == 20.0
209 # PostGIS does not wrap longitude for latitude overflow
210 with api_session(token5) as api:
211 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=user5.username))
212 assert res.lat == 89.5
213 assert res.lng == 20.0
215 with real_jail_session(token1) as jail:
216 res = jail.JailInfo(empty_pb2.Empty())
217 assert res.jailed
218 assert res.needs_to_update_location
220 res = jail.SetLocation(
221 jail_pb2.SetLocationReq(
222 city="New York City",
223 lat=40.7812,
224 lng=-73.9647,
225 radius=250,
226 )
227 )
229 assert not res.jailed
230 assert not res.needs_to_update_location
232 res = jail.JailInfo(empty_pb2.Empty())
233 assert not res.jailed
234 assert not res.needs_to_update_location
236 refresh_materialized_views_rapid(None)
238 with api_session(token2) as api:
239 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=user1.username))
240 assert res.city == "New York City"
241 assert res.lat == 40.7812
242 assert res.lng == -73.9647
243 assert res.radius == 250
246def test_lite_get_user(db):
247 user1, token1 = generate_user()
248 user2, token2 = generate_user()
250 refresh_materialized_views_rapid(None)
252 with api_session(token1) as api:
253 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=user2.username))
254 assert res.user_id == user2.id
255 assert res.username == user2.username
256 assert res.name == user2.name
258 with api_session(token1) as api:
259 res = api.GetLiteUser(api_pb2.GetLiteUserReq(user=str(user2.id)))
260 assert res.user_id == user2.id
261 assert res.username == user2.username
262 assert res.name == user2.name
265def test_GetLiteUsers(db):
266 user1, token1 = generate_user()
267 user2, _ = generate_user()
268 user3, _ = generate_user()
269 user4, _ = generate_user()
270 user5, _ = generate_user()
271 user6, _ = generate_user()
273 make_user_block(user4, user1)
275 refresh_materialized_views_rapid(None)
277 with api_session(token1) as api:
278 res = api.GetLiteUsers(
279 api_pb2.GetLiteUsersReq(
280 users=[
281 user1.username,
282 str(user1.id),
283 "nonexistent",
284 str(user2.id),
285 "9994",
286 user6.username,
287 str(user5.id),
288 "notreal",
289 user4.username,
290 ]
291 )
292 )
294 assert len(res.responses) == 9
295 assert res.responses[0].query == user1.username
296 assert res.responses[0].user.user_id == user1.id
298 assert res.responses[1].query == str(user1.id)
299 assert res.responses[1].user.user_id == user1.id
301 assert res.responses[2].query == "nonexistent"
302 assert res.responses[2].not_found
304 assert res.responses[3].query == str(user2.id)
305 assert res.responses[3].user.user_id == user2.id
307 assert res.responses[4].query == "9994"
308 assert res.responses[4].not_found
310 assert res.responses[5].query == user6.username
311 assert res.responses[5].user.user_id == user6.id
313 assert res.responses[6].query == str(user5.id)
314 assert res.responses[6].user.user_id == user5.id
316 assert res.responses[7].query == "notreal"
317 assert res.responses[7].not_found
319 # blocked
320 assert res.responses[8].query == user4.username
321 assert res.responses[8].not_found
323 with api_session(token1) as api:
324 with pytest.raises(grpc.RpcError) as e:
325 api.GetLiteUsers(api_pb2.GetLiteUsersReq(users=201 * [user1.username]))
326 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
327 assert e.value.details() == errors.REQUESTED_TOO_MANY_USERS
330def test_update_profile(db):
331 user, token = generate_user()
333 with api_session(token) as api:
334 with pytest.raises(grpc.RpcError) as e:
335 api.UpdateProfile(api_pb2.UpdateProfileReq(name=wrappers_pb2.StringValue(value=" ")))
336 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
337 assert e.value.details() == errors.INVALID_NAME
339 with pytest.raises(grpc.RpcError) as e:
340 api.UpdateProfile(
341 api_pb2.UpdateProfileReq(lat=wrappers_pb2.DoubleValue(value=0), lng=wrappers_pb2.DoubleValue(value=0))
342 )
343 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
344 assert e.value.details() == errors.INVALID_COORDINATE
346 with pytest.raises(grpc.RpcError) as e:
347 api.UpdateProfile(
348 api_pb2.UpdateProfileReq(regions_visited=api_pb2.RepeatedStringValue(value=["United States"]))
349 )
350 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
351 assert e.value.details() == errors.INVALID_REGION
353 with pytest.raises(grpc.RpcError) as e:
354 api.UpdateProfile(
355 api_pb2.UpdateProfileReq(regions_lived=api_pb2.RepeatedStringValue(value=["United Kingdom"]))
356 )
357 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
358 assert e.value.details() == errors.INVALID_REGION
360 api.UpdateProfile(
361 api_pb2.UpdateProfileReq(
362 name=wrappers_pb2.StringValue(value="New name"),
363 city=wrappers_pb2.StringValue(value="Timbuktu"),
364 hometown=api_pb2.NullableStringValue(value="Walla Walla"),
365 lat=wrappers_pb2.DoubleValue(value=0.01),
366 lng=wrappers_pb2.DoubleValue(value=-2),
367 radius=wrappers_pb2.DoubleValue(value=321),
368 pronouns=api_pb2.NullableStringValue(value="Ro, Robo, Robots"),
369 occupation=api_pb2.NullableStringValue(value="Testing"),
370 education=api_pb2.NullableStringValue(value="Couchers U"),
371 about_me=api_pb2.NullableStringValue(value="I rule"),
372 things_i_like=api_pb2.NullableStringValue(value="Couchers"),
373 about_place=api_pb2.NullableStringValue(value="My place"),
374 hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST,
375 meetup_status=api_pb2.MEETUP_STATUS_WANTS_TO_MEETUP,
376 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
377 value=[
378 api_pb2.LanguageAbility(
379 code="eng",
380 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT,
381 )
382 ],
383 ),
384 regions_visited=api_pb2.RepeatedStringValue(value=["CXR", "FIN"]),
385 regions_lived=api_pb2.RepeatedStringValue(value=["USA", "EST"]),
386 additional_information=api_pb2.NullableStringValue(value="I <3 Couchers"),
387 )
388 )
390 user_details = api.GetUser(api_pb2.GetUserReq(user=user.username))
391 assert user_details.name == "New name"
392 assert user_details.city == "Timbuktu"
393 assert user_details.hometown == "Walla Walla"
394 assert user_details.pronouns == "Ro, Robo, Robots"
395 assert user_details.education == "Couchers U"
396 assert user_details.things_i_like == "Couchers"
397 assert user_details.lat == 0.01
398 assert user_details.lng == -2
399 assert user_details.radius == 321
400 assert user_details.occupation == "Testing"
401 assert user_details.about_me == "I rule"
402 assert user_details.about_place == "My place"
403 assert user_details.hosting_status == api_pb2.HOSTING_STATUS_CAN_HOST
404 assert user_details.meetup_status == api_pb2.MEETUP_STATUS_WANTS_TO_MEETUP
405 assert user_details.language_abilities[0].code == "eng"
406 assert user_details.language_abilities[0].fluency == api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT
407 assert user_details.additional_information == "I <3 Couchers"
408 assert user_details.regions_visited == ["CXR", "FIN"]
409 assert user_details.regions_lived == ["EST", "USA"]
411 # Test unset values
412 api.UpdateProfile(
413 api_pb2.UpdateProfileReq(
414 hometown=api_pb2.NullableStringValue(is_null=True),
415 radius=wrappers_pb2.DoubleValue(value=0),
416 pronouns=api_pb2.NullableStringValue(is_null=True),
417 occupation=api_pb2.NullableStringValue(is_null=True),
418 education=api_pb2.NullableStringValue(is_null=True),
419 about_me=api_pb2.NullableStringValue(is_null=True),
420 things_i_like=api_pb2.NullableStringValue(is_null=True),
421 about_place=api_pb2.NullableStringValue(is_null=True),
422 hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST,
423 meetup_status=api_pb2.MEETUP_STATUS_WANTS_TO_MEETUP,
424 language_abilities=api_pb2.RepeatedLanguageAbilityValue(value=[]),
425 regions_visited=api_pb2.RepeatedStringValue(value=[]),
426 regions_lived=api_pb2.RepeatedStringValue(value=[]),
427 additional_information=api_pb2.NullableStringValue(is_null=True),
428 )
429 )
431 user_details = api.GetUser(api_pb2.GetUserReq(user=user.username))
432 assert not user_details.hometown
433 assert not user_details.radius
434 assert not user_details.pronouns
435 assert not user_details.occupation
436 assert not user_details.education
437 assert not user_details.about_me
438 assert not user_details.things_i_like
439 assert not user_details.about_place
440 assert user_details.hosting_status == api_pb2.HOSTING_STATUS_CAN_HOST
441 assert user_details.meetup_status == api_pb2.MEETUP_STATUS_WANTS_TO_MEETUP
442 assert not user_details.language_abilities
443 assert not user_details.regions_visited
444 assert not user_details.regions_lived
445 assert not user_details.additional_information
448def test_update_profile_do_not_email(db):
449 user, token = generate_user()
451 with notifications_session(token) as notifications:
452 notifications.SetNotificationSettings(notifications_pb2.SetNotificationSettingsReq(enable_do_not_email=True))
454 with api_session(token) as api:
455 with pytest.raises(grpc.RpcError) as e:
456 api.UpdateProfile(api_pb2.UpdateProfileReq(hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST))
457 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
458 assert e.value.details() == errors.DO_NOT_EMAIL_CANNOT_HOST
460 with pytest.raises(grpc.RpcError) as e:
461 api.UpdateProfile(api_pb2.UpdateProfileReq(meetup_status=api_pb2.MEETUP_STATUS_OPEN_TO_MEETUP))
462 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
463 assert e.value.details() == errors.DO_NOT_EMAIL_CANNOT_MEET
466def test_language_abilities(db):
467 user, token = generate_user()
469 with api_session(token) as api:
470 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
471 assert len(res.language_abilities) == 2
473 # can't add non-existent languages
474 with pytest.raises(grpc.RpcError) as e:
475 res = api.UpdateProfile(
476 api_pb2.UpdateProfileReq(
477 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
478 value=[
479 api_pb2.LanguageAbility(
480 code="QQQ",
481 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT,
482 )
483 ],
484 ),
485 )
486 )
487 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
488 assert e.value.details() == errors.INVALID_LANGUAGE
490 # can't have multiple languages of the same type
491 with pytest.raises(Exception) as e:
492 res = api.UpdateProfile(
493 api_pb2.UpdateProfileReq(
494 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
495 value=[
496 api_pb2.LanguageAbility(
497 code="eng",
498 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT,
499 ),
500 api_pb2.LanguageAbility(
501 code="eng",
502 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT,
503 ),
504 ],
505 ),
506 )
507 )
508 assert "violates unique constraint" in str(e.value)
510 # nothing changed
511 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
512 assert len(res.language_abilities) == 2
514 # now actually add a value
515 api.UpdateProfile(
516 api_pb2.UpdateProfileReq(
517 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
518 value=[
519 api_pb2.LanguageAbility(
520 code="eng",
521 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT,
522 )
523 ],
524 ),
525 )
526 )
528 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
529 assert len(res.language_abilities) == 1
530 assert res.language_abilities[0].code == "eng"
531 assert res.language_abilities[0].fluency == api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT
533 # change the value to a new one
534 api.UpdateProfile(
535 api_pb2.UpdateProfileReq(
536 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
537 value=[
538 api_pb2.LanguageAbility(
539 code="fin",
540 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_BEGINNER,
541 )
542 ],
543 ),
544 )
545 )
547 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
548 assert len(res.language_abilities) == 1
549 assert res.language_abilities[0].code == "fin"
550 assert res.language_abilities[0].fluency == api_pb2.LanguageAbility.Fluency.FLUENCY_BEGINNER
552 # should be able to set to same value still
553 api.UpdateProfile(
554 api_pb2.UpdateProfileReq(
555 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
556 value=[
557 api_pb2.LanguageAbility(
558 code="fin",
559 fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_BEGINNER,
560 )
561 ],
562 ),
563 )
564 )
566 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
567 assert len(res.language_abilities) == 1
568 assert res.language_abilities[0].code == "fin"
569 assert res.language_abilities[0].fluency == api_pb2.LanguageAbility.Fluency.FLUENCY_BEGINNER
571 # don't change it
572 api.UpdateProfile(api_pb2.UpdateProfileReq())
574 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
575 assert len(res.language_abilities) == 1
576 assert res.language_abilities[0].code == "fin"
577 assert res.language_abilities[0].fluency == api_pb2.LanguageAbility.Fluency.FLUENCY_BEGINNER
579 # remove value
580 api.UpdateProfile(
581 api_pb2.UpdateProfileReq(
582 language_abilities=api_pb2.RepeatedLanguageAbilityValue(
583 value=[],
584 ),
585 )
586 )
588 res = api.GetUser(api_pb2.GetUserReq(user=user.username))
589 assert len(res.language_abilities) == 0
592def test_pending_friend_request_count(db):
593 user1, token1 = generate_user()
594 user2, token2 = generate_user()
595 user3, token3 = generate_user()
597 with api_session(token2) as api:
598 res = api.Ping(api_pb2.PingReq())
599 assert res.pending_friend_request_count == 0
601 with api_session(token1) as api:
602 res = api.Ping(api_pb2.PingReq())
603 assert res.pending_friend_request_count == 0
604 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
605 res = api.Ping(api_pb2.PingReq())
606 assert res.pending_friend_request_count == 0
608 with api_session(token2) as api:
609 res = api.Ping(api_pb2.PingReq())
610 assert res.pending_friend_request_count == 1
612 with api_session(token2) as api:
613 # check it's there
614 res = api.ListFriendRequests(empty_pb2.Empty())
615 assert len(res.sent) == 0
616 assert len(res.received) == 1
618 assert res.received[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
619 assert res.received[0].user_id == user1.id
621 fr_id = res.received[0].friend_request_id
623 # accept it
624 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=True))
626 res = api.Ping(api_pb2.PingReq())
627 assert res.pending_friend_request_count == 0
630def test_friend_request_flow(db, push_collector):
631 user1, token1 = generate_user(complete_profile=True)
632 user2, token2 = generate_user(complete_profile=True)
633 user3, token3 = generate_user()
635 # send friend request from user1 to user2
636 with mock_notification_email() as mock:
637 with api_session(token1) as api:
638 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
640 push_collector.assert_user_has_single_matching(
641 user2.id,
642 title=f"{user1.name} wants to be your friend",
643 body=f"You've received a friend request from {user1.name}",
644 )
646 mock.assert_called_once()
647 e = email_fields(mock)
648 assert e.recipient == user2.email
649 assert e.subject == f"[TEST] {user1.name} wants to be your friend on Couchers.org!"
650 assert user2.name in e.plain
651 assert user2.name in e.html
652 assert user1.name in e.plain
653 assert user1.name in e.html
654 assert "http://localhost:5001/img/thumbnail/" not in e.plain
655 assert "http://localhost:5001/img/thumbnail/" in e.html
656 assert "http://localhost:3000/connections/friends/" in e.plain
657 assert "http://localhost:3000/connections/friends/" in e.html
659 with session_scope() as session:
660 friend_request_id = (
661 session.execute(
662 select(FriendRelationship).where(
663 FriendRelationship.from_user_id == user1.id and FriendRelationship.to_user_id == user2.id
664 )
665 ).scalar_one_or_none()
666 ).id
668 with api_session(token1) as api:
669 # check it went through
670 res = api.ListFriendRequests(empty_pb2.Empty())
671 assert len(res.sent) == 1
672 assert len(res.received) == 0
674 assert res.sent[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
675 assert res.sent[0].user_id == user2.id
676 assert res.sent[0].friend_request_id == friend_request_id
678 with api_session(token2) as api:
679 # check it's there
680 res = api.ListFriendRequests(empty_pb2.Empty())
681 assert len(res.sent) == 0
682 assert len(res.received) == 1
684 assert res.received[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
685 assert res.received[0].user_id == user1.id
687 fr_id = res.received[0].friend_request_id
689 # accept it
690 with mock_notification_email() as mock:
691 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=True))
693 # check it's gone
694 res = api.ListFriendRequests(empty_pb2.Empty())
695 assert len(res.sent) == 0
696 assert len(res.received) == 0
698 # check we're friends now
699 res = api.ListFriends(empty_pb2.Empty())
700 assert len(res.user_ids) == 1
701 assert res.user_ids[0] == user1.id
703 push_collector.assert_user_has_count(user2.id, 1)
704 push_collector.assert_user_push_matches_fields(
705 user1.id,
706 title=f"{user2.name} accepted your friend request!",
707 body=f"{user2.name} has accepted your friend request",
708 )
710 mock.assert_called_once()
711 e = email_fields(mock)
712 assert e.recipient == user1.email
713 assert e.subject == f"[TEST] {user2.name} accepted your friend request!"
714 assert user1.name in e.plain
715 assert user1.name in e.html
716 assert user2.name in e.plain
717 assert user2.name in e.html
718 assert "http://localhost:5001/img/thumbnail/" not in e.plain
719 assert "http://localhost:5001/img/thumbnail/" in e.html
720 assert f"http://localhost:3000/user/{user2.username}" in e.plain
721 assert f"http://localhost:3000/user/{user2.username}" in e.html
723 with api_session(token1) as api:
724 # check it's gone
725 res = api.ListFriendRequests(empty_pb2.Empty())
726 assert len(res.sent) == 0
727 assert len(res.received) == 0
729 # check we're friends now
730 res = api.ListFriends(empty_pb2.Empty())
731 assert len(res.user_ids) == 1
732 assert res.user_ids[0] == user2.id
734 with api_session(token1) as api:
735 # we can't unfriend if we aren't friends
736 with pytest.raises(grpc.RpcError) as e:
737 api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user3.id))
738 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
739 assert e.value.details() == errors.NOT_FRIENDS
741 # we can unfriend
742 res = api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user2.id))
744 res = api.ListFriends(empty_pb2.Empty())
745 assert len(res.user_ids) == 0
748def test_RemoveFriend_regression(db, push_collector):
749 user1, token1 = generate_user(complete_profile=True)
750 user2, token2 = generate_user(complete_profile=True)
751 user3, token3 = generate_user()
752 user4, token4 = generate_user()
753 user5, token5 = generate_user()
754 user6, token6 = generate_user()
756 with api_session(token4) as api:
757 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user1.id))
758 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
760 with api_session(token5) as api:
761 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user1.id))
763 with api_session(token1) as api:
764 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
765 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user3.id))
767 api.RespondFriendRequest(
768 api_pb2.RespondFriendRequestReq(
769 friend_request_id=api.ListFriendRequests(empty_pb2.Empty()).received[0].friend_request_id, accept=True
770 )
771 )
773 with api_session(token2) as api:
774 for fr in api.ListFriendRequests(empty_pb2.Empty()).received:
775 api.RespondFriendRequest(
776 api_pb2.RespondFriendRequestReq(friend_request_id=fr.friend_request_id, accept=True)
777 )
779 with api_session(token1) as api:
780 res = api.ListFriends(empty_pb2.Empty())
781 assert sorted(res.user_ids) == [2, 4]
783 api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user2.id))
785 res = api.ListFriends(empty_pb2.Empty())
786 assert sorted(res.user_ids) == [4]
788 api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user4.id))
790 res = api.ListFriends(empty_pb2.Empty())
791 assert not res.user_ids
794def test_cant_friend_request_twice(db):
795 user1, token1 = generate_user()
796 user2, token2 = generate_user()
798 # send friend request from user1 to user2
799 with api_session(token1) as api:
800 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
802 with pytest.raises(grpc.RpcError) as e:
803 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
804 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
805 assert e.value.details() == errors.FRIENDS_ALREADY_OR_PENDING
808def test_cant_friend_request_pending(db):
809 user1, token1 = generate_user()
810 user2, token2 = generate_user()
812 # send friend request from user1 to user2
813 with api_session(token1) as api:
814 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
816 with api_session(token2) as api:
817 with pytest.raises(grpc.RpcError) as e:
818 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user1.id))
819 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
820 assert e.value.details() == errors.FRIENDS_ALREADY_OR_PENDING
823def test_cant_friend_request_already_friends(db):
824 user1, token1 = generate_user()
825 user2, token2 = generate_user()
826 make_friends(user1, user2)
828 with api_session(token1) as api:
829 with pytest.raises(grpc.RpcError) as e:
830 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
831 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
832 assert e.value.details() == errors.FRIENDS_ALREADY_OR_PENDING
834 with api_session(token2) as api:
835 with pytest.raises(grpc.RpcError) as e:
836 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user1.id))
837 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
838 assert e.value.details() == errors.FRIENDS_ALREADY_OR_PENDING
841def test_excessive_friend_requests_are_reported(db):
842 """Test that excessive friend requests are first reported in a warning email and finally lead blocking of further requests."""
843 user, token = generate_user()
844 rate_limit_definition = RATE_LIMIT_DEFINITIONS[RateLimitAction.friend_request]
845 with api_session(token) as api:
846 # Test warning email
847 with mock_notification_email() as mock_email:
848 for _ in range(rate_limit_definition.warning_limit):
849 friend_user, _ = generate_user()
850 _ = api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=friend_user.id))
852 assert mock_email.call_count == 0
853 friend_user, _ = generate_user()
854 _ = api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=friend_user.id))
856 assert mock_email.call_count == 1
857 email = mock_email.mock_calls[0].kwargs["plain"]
858 assert email.startswith(
859 f"User {user.username} has sent {rate_limit_definition.warning_limit} friend requests in the past {RATE_LIMIT_INTERVAL_STRING}."
860 )
862 # Test ban after exceeding FRIEND_REQUEST_HARD_LIMIT
863 with mock_notification_email() as mock_email:
864 for _ in range(rate_limit_definition.hard_limit - rate_limit_definition.warning_limit - 1):
865 friend_user, _ = generate_user()
866 _ = api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=friend_user.id))
868 assert mock_email.call_count == 0
869 friend_user, _ = generate_user()
870 with pytest.raises(grpc.RpcError) as exc_info:
871 _ = api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=friend_user.id))
872 assert exc_info.value.code() == grpc.StatusCode.RESOURCE_EXHAUSTED
873 assert exc_info.value.details() == errors.FRIEND_REQUEST_RATE_LIMIT
875 assert mock_email.call_count == 1
876 email = mock_email.mock_calls[0].kwargs["plain"]
877 assert email.startswith(
878 f"User {user.username} has sent {rate_limit_definition.hard_limit} friend requests in the past {RATE_LIMIT_INTERVAL_STRING}."
879 )
880 assert "The user has been blocked from sending further friend requests for now." in email
883def test_ListFriends(db):
884 user1, token1 = generate_user()
885 user2, token2 = generate_user()
886 user3, token3 = generate_user()
888 # send friend request from user1 to user2 and user3
889 with api_session(token1) as api:
890 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
891 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user3.id))
893 with api_session(token3) as api:
894 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
896 with api_session(token2) as api:
897 res = api.ListFriendRequests(empty_pb2.Empty())
898 assert len(res.received) == 2
900 # order is an implementation detail
901 user1_req = [req for req in res.received if req.user_id == user1.id][0]
902 user3_req = [req for req in res.received if req.user_id == user3.id][0]
904 assert user1_req.state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
905 assert user1_req.user_id == user1.id
906 api.RespondFriendRequest(
907 api_pb2.RespondFriendRequestReq(friend_request_id=user1_req.friend_request_id, accept=True)
908 )
910 assert user3_req.state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
911 assert user3_req.user_id == user3.id
912 api.RespondFriendRequest(
913 api_pb2.RespondFriendRequestReq(friend_request_id=user3_req.friend_request_id, accept=True)
914 )
916 # check we now have two friends
917 res = api.ListFriends(empty_pb2.Empty())
918 assert len(res.user_ids) == 2
919 assert user1.id in res.user_ids
920 assert user3.id in res.user_ids
922 with api_session(token3) as api:
923 res = api.ListFriends(empty_pb2.Empty())
924 assert len(res.user_ids) == 1
925 assert user2.id in res.user_ids
927 res = api.ListFriendRequests(empty_pb2.Empty())
928 assert len(res.received) == 1
929 assert res.received[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
930 assert res.received[0].user_id == user1.id
931 fr_id = res.received[0].friend_request_id
932 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=True))
934 res = api.ListFriends(empty_pb2.Empty())
935 assert len(res.user_ids) == 2
936 assert user1.id in res.user_ids
937 assert user2.id in res.user_ids
939 with api_session(token1) as api:
940 res = api.ListFriends(empty_pb2.Empty())
941 assert len(res.user_ids) == 2
942 assert user2.id in res.user_ids
943 assert user3.id in res.user_ids
946def test_ListMutualFriends(db):
947 user1, token1 = generate_user()
948 user2, token2 = generate_user()
949 user3, token3 = generate_user()
950 user4, token4 = generate_user()
951 user5, token5 = generate_user()
953 # arrange friends like this: 1<->2, 1<->3, 1<->4, 1<->5, 3<->2, 3<->4,
954 # so 1 and 2 should have mutual friend 3 only
955 make_friends(user1, user2)
956 make_friends(user1, user3)
957 make_friends(user1, user4)
958 make_friends(user1, user5)
959 make_friends(user3, user2)
960 make_friends(user3, user4)
962 with api_session(token1) as api:
963 mutual_friends = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user2.id)).mutual_friends
964 assert len(mutual_friends) == 1
965 assert mutual_friends[0].user_id == user3.id
967 # and other way around same
968 with api_session(token2) as api:
969 mutual_friends = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user1.id)).mutual_friends
970 assert len(mutual_friends) == 1
971 assert mutual_friends[0].user_id == user3.id
973 # Check pending request doesn't have effect
974 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user5.id))
976 mutual_friends = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user1.id)).mutual_friends
977 assert len(mutual_friends) == 1
978 assert mutual_friends[0].user_id == user3.id
980 # both ways
981 with api_session(token1) as api:
982 mutual_friends = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user2.id)).mutual_friends
983 assert len(mutual_friends) == 1
984 assert mutual_friends[0].user_id == user3.id
987def test_mutual_friends_self(db):
988 user1, token1 = generate_user()
989 user2, token2 = generate_user()
990 user3, token3 = generate_user()
991 user4, token4 = generate_user()
993 make_friends(user1, user2)
994 make_friends(user2, user3)
995 make_friends(user1, user4)
997 with api_session(token1) as api:
998 res = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user1.id))
999 assert len(res.mutual_friends) == 0
1001 with api_session(token2) as api:
1002 res = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user2.id))
1003 assert len(res.mutual_friends) == 0
1005 with api_session(token3) as api:
1006 res = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user3.id))
1007 assert len(res.mutual_friends) == 0
1009 with api_session(token4) as api:
1010 res = api.ListMutualFriends(api_pb2.ListMutualFriendsReq(user_id=user4.id))
1011 assert len(res.mutual_friends) == 0
1014def test_CancelFriendRequest(db):
1015 user1, token1 = generate_user()
1016 user2, token2 = generate_user()
1018 with api_session(token1) as api:
1019 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
1021 res = api.ListFriendRequests(empty_pb2.Empty())
1022 assert res.sent[0].user_id == user2.id
1023 fr_id = res.sent[0].friend_request_id
1025 api.CancelFriendRequest(api_pb2.CancelFriendRequestReq(friend_request_id=fr_id))
1027 # check it's gone
1028 res = api.ListFriendRequests(empty_pb2.Empty())
1029 assert len(res.sent) == 0
1030 assert len(res.received) == 0
1032 # check not friends
1033 res = api.ListFriends(empty_pb2.Empty())
1034 assert len(res.user_ids) == 0
1036 with api_session(token2) as api:
1037 # check it's gone
1038 res = api.ListFriendRequests(empty_pb2.Empty())
1039 assert len(res.sent) == 0
1040 assert len(res.received) == 0
1042 # check we're not friends
1043 res = api.ListFriends(empty_pb2.Empty())
1044 assert len(res.user_ids) == 0
1046 with api_session(token1) as api:
1047 # check we can send another friend req
1048 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
1050 res = api.ListFriendRequests(empty_pb2.Empty())
1051 assert res.sent[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
1052 assert res.sent[0].user_id == user2.id
1055def test_accept_friend_request(db):
1056 user1, token1 = generate_user()
1057 user2, token2 = generate_user()
1059 with session_scope() as session:
1060 friend_request = FriendRelationship(from_user_id=user1.id, to_user_id=user2.id, status=FriendStatus.pending)
1061 session.add(friend_request)
1062 session.commit()
1063 friend_request_id = friend_request.id
1065 with api_session(token2) as api:
1066 # check request pending
1067 res = api.ListFriendRequests(empty_pb2.Empty())
1068 assert len(res.received) == 1
1069 assert res.received[0].user_id == user1.id
1071 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=friend_request_id, accept=True))
1073 # check request is gone
1074 res = api.ListFriendRequests(empty_pb2.Empty())
1075 assert len(res.sent) == 0
1076 assert len(res.received) == 0
1078 # check now friends
1079 res = api.ListFriends(empty_pb2.Empty())
1080 assert len(res.user_ids) == 1
1081 assert res.user_ids[0] == user1.id
1083 with api_session(token1) as api:
1084 # check request gone
1085 res = api.ListFriendRequests(empty_pb2.Empty())
1086 assert len(res.sent) == 0
1087 assert len(res.received) == 0
1089 # check now friends
1090 res = api.ListFriends(empty_pb2.Empty())
1091 assert len(res.user_ids) == 1
1092 assert res.user_ids[0] == user2.id
1095def test_reject_friend_request(db):
1096 user1, token1 = generate_user()
1097 user2, token2 = generate_user()
1099 with api_session(token1) as api:
1100 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
1102 res = api.ListFriendRequests(empty_pb2.Empty())
1103 assert res.sent[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
1104 assert res.sent[0].user_id == user2.id
1106 with api_session(token2) as api:
1107 res = api.ListFriendRequests(empty_pb2.Empty())
1108 assert res.received[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
1109 assert res.received[0].user_id == user1.id
1111 fr_id = res.received[0].friend_request_id
1113 # reject it
1114 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=False))
1116 # check it's gone
1117 res = api.ListFriendRequests(empty_pb2.Empty())
1118 assert len(res.sent) == 0
1119 assert len(res.received) == 0
1121 # check not friends
1122 res = api.ListFriends(empty_pb2.Empty())
1123 assert len(res.user_ids) == 0
1125 with api_session(token1) as api:
1126 # check it's gone
1127 res = api.ListFriendRequests(empty_pb2.Empty())
1128 assert len(res.sent) == 0
1129 assert len(res.received) == 0
1131 # check we're not friends
1132 res = api.ListFriends(empty_pb2.Empty())
1133 assert len(res.user_ids) == 0
1135 # check we can send another friend req
1136 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id))
1138 res = api.ListFriendRequests(empty_pb2.Empty())
1139 assert res.sent[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING
1140 assert res.sent[0].user_id == user2.id
1143def test_hosting_preferences(db):
1144 user1, token1 = generate_user()
1145 user2, token2 = generate_user()
1147 with api_session(token1) as api:
1148 res = api.GetUser(api_pb2.GetUserReq(user=user1.username))
1149 assert not res.HasField("max_guests")
1150 assert not res.HasField("last_minute")
1151 assert not res.HasField("has_pets")
1152 assert not res.HasField("accepts_pets")
1153 assert not res.HasField("pet_details")
1154 assert not res.HasField("has_kids")
1155 assert not res.HasField("accepts_kids")
1156 assert not res.HasField("kid_details")
1157 assert not res.HasField("has_housemates")
1158 assert not res.HasField("housemate_details")
1159 assert not res.HasField("wheelchair_accessible")
1160 assert res.smoking_allowed == api_pb2.SMOKING_LOCATION_UNKNOWN
1161 assert not res.HasField("smokes_at_home")
1162 assert not res.HasField("drinking_allowed")
1163 assert not res.HasField("drinks_at_home")
1164 assert not res.HasField("other_host_info")
1165 assert res.sleeping_arrangement == api_pb2.SLEEPING_ARRANGEMENT_UNKNOWN
1166 assert not res.HasField("sleeping_details")
1167 assert not res.HasField("area")
1168 assert not res.HasField("house_rules")
1169 assert not res.HasField("parking")
1170 assert res.parking_details == api_pb2.PARKING_DETAILS_UNKNOWN
1171 assert not res.HasField("camping_ok")
1173 api.UpdateProfile(
1174 api_pb2.UpdateProfileReq(
1175 max_guests=api_pb2.NullableUInt32Value(value=3),
1176 last_minute=api_pb2.NullableBoolValue(value=True),
1177 has_pets=api_pb2.NullableBoolValue(value=False),
1178 accepts_pets=api_pb2.NullableBoolValue(value=True),
1179 pet_details=api_pb2.NullableStringValue(value="I love dogs"),
1180 has_kids=api_pb2.NullableBoolValue(value=False),
1181 accepts_kids=api_pb2.NullableBoolValue(value=True),
1182 kid_details=api_pb2.NullableStringValue(value="I hate kids"),
1183 has_housemates=api_pb2.NullableBoolValue(value=False),
1184 housemate_details=api_pb2.NullableStringValue(value="I have 7 housemates"),
1185 wheelchair_accessible=api_pb2.NullableBoolValue(value=True),
1186 smoking_allowed=api_pb2.SMOKING_LOCATION_WINDOW,
1187 area=api_pb2.NullableStringValue(value="area!"),
1188 smokes_at_home=api_pb2.NullableBoolValue(value=False),
1189 drinking_allowed=api_pb2.NullableBoolValue(value=True),
1190 drinks_at_home=api_pb2.NullableBoolValue(value=False),
1191 other_host_info=api_pb2.NullableStringValue(value="I'm pretty swell"),
1192 sleeping_arrangement=api_pb2.SLEEPING_ARRANGEMENT_COMMON,
1193 sleeping_details=api_pb2.NullableStringValue(value="Couch in living room"),
1194 house_rules=api_pb2.NullableStringValue(value="RULES!"),
1195 parking=api_pb2.NullableBoolValue(value=True),
1196 parking_details=api_pb2.PARKING_DETAILS_PAID_ONSITE,
1197 camping_ok=api_pb2.NullableBoolValue(value=False),
1198 )
1199 )
1201 # Use a second user to view the hosting preferences just to check
1202 # that it is public information.
1203 with api_session(token2) as api:
1204 res = api.GetUser(api_pb2.GetUserReq(user=user1.username))
1205 assert res.max_guests.value == 3
1206 assert res.last_minute.value
1207 assert not res.has_pets.value
1208 assert res.accepts_pets.value
1209 assert res.pet_details.value == "I love dogs"
1210 assert not res.has_kids.value
1211 assert res.accepts_kids.value
1212 assert res.kid_details.value == "I hate kids"
1213 assert not res.has_housemates.value
1214 assert res.housemate_details.value == "I have 7 housemates"
1215 assert res.wheelchair_accessible.value
1216 assert res.smoking_allowed == api_pb2.SMOKING_LOCATION_WINDOW
1217 assert not res.smokes_at_home.value
1218 assert res.drinking_allowed.value
1219 assert not res.drinks_at_home.value
1220 assert res.other_host_info.value == "I'm pretty swell"
1221 assert res.sleeping_arrangement == api_pb2.SLEEPING_ARRANGEMENT_COMMON
1222 assert res.sleeping_details.value == "Couch in living room"
1223 assert res.area.value == "area!"
1224 assert res.house_rules.value == "RULES!"
1225 assert res.parking.value
1226 assert res.parking_details == api_pb2.PARKING_DETAILS_PAID_ONSITE
1227 assert not res.camping_ok.value
1229 # test unsetting
1230 with api_session(token1) as api:
1231 api.UpdateProfile(
1232 api_pb2.UpdateProfileReq(
1233 max_guests=api_pb2.NullableUInt32Value(is_null=True),
1234 last_minute=api_pb2.NullableBoolValue(is_null=True),
1235 has_pets=api_pb2.NullableBoolValue(is_null=True),
1236 accepts_pets=api_pb2.NullableBoolValue(is_null=True),
1237 pet_details=api_pb2.NullableStringValue(is_null=True),
1238 has_kids=api_pb2.NullableBoolValue(is_null=True),
1239 accepts_kids=api_pb2.NullableBoolValue(is_null=True),
1240 kid_details=api_pb2.NullableStringValue(is_null=True),
1241 has_housemates=api_pb2.NullableBoolValue(is_null=True),
1242 housemate_details=api_pb2.NullableStringValue(is_null=True),
1243 wheelchair_accessible=api_pb2.NullableBoolValue(is_null=True),
1244 smoking_allowed=api_pb2.SMOKING_LOCATION_UNKNOWN,
1245 area=api_pb2.NullableStringValue(is_null=True),
1246 smokes_at_home=api_pb2.NullableBoolValue(is_null=True),
1247 drinking_allowed=api_pb2.NullableBoolValue(is_null=True),
1248 drinks_at_home=api_pb2.NullableBoolValue(is_null=True),
1249 other_host_info=api_pb2.NullableStringValue(is_null=True),
1250 sleeping_arrangement=api_pb2.SLEEPING_ARRANGEMENT_UNKNOWN,
1251 sleeping_details=api_pb2.NullableStringValue(is_null=True),
1252 house_rules=api_pb2.NullableStringValue(is_null=True),
1253 parking=api_pb2.NullableBoolValue(is_null=True),
1254 parking_details=api_pb2.PARKING_DETAILS_UNKNOWN,
1255 camping_ok=api_pb2.NullableBoolValue(is_null=True),
1256 )
1257 )
1259 res = api.GetUser(api_pb2.GetUserReq(user=user1.username))
1260 assert not res.HasField("max_guests")
1261 assert not res.HasField("last_minute")
1262 assert not res.HasField("has_pets")
1263 assert not res.HasField("accepts_pets")
1264 assert not res.HasField("pet_details")
1265 assert not res.HasField("has_kids")
1266 assert not res.HasField("accepts_kids")
1267 assert not res.HasField("kid_details")
1268 assert not res.HasField("has_housemates")
1269 assert not res.HasField("housemate_details")
1270 assert not res.HasField("wheelchair_accessible")
1271 assert res.smoking_allowed == api_pb2.SMOKING_LOCATION_UNKNOWN
1272 assert not res.HasField("smokes_at_home")
1273 assert not res.HasField("drinking_allowed")
1274 assert not res.HasField("drinks_at_home")
1275 assert not res.HasField("other_host_info")
1276 assert res.sleeping_arrangement == api_pb2.SLEEPING_ARRANGEMENT_UNKNOWN
1277 assert not res.HasField("sleeping_details")
1278 assert not res.HasField("area")
1279 assert not res.HasField("house_rules")
1280 assert not res.HasField("parking")
1281 assert res.parking_details == api_pb2.PARKING_DETAILS_UNKNOWN
1282 assert not res.HasField("camping_ok")
1285def test_badges(db):
1286 user1, _ = generate_user()
1287 user2, _ = generate_user()
1288 user3, _ = generate_user()
1289 user4, token = generate_user()
1291 update_badges(empty_pb2.Empty())
1293 founder_badge = get_badge_dict()["founder"]
1294 board_member_badge = get_badge_dict()["board_member"]
1296 with api_session(token) as api:
1297 assert api.GetUser(api_pb2.GetUserReq(user=user1.username)).badges == ["founder", "board_member"]
1298 assert api.GetUser(api_pb2.GetUserReq(user=user2.username)).badges == ["founder", "board_member"]
1299 assert api.GetUser(api_pb2.GetUserReq(user=user3.username)).badges == []
1301 assert api.ListBadgeUsers(api_pb2.ListBadgeUsersReq(badge_id=founder_badge["id"])).user_ids == [1, 2]
1302 res = api.ListBadgeUsers(api_pb2.ListBadgeUsersReq(badge_id=board_member_badge["id"], page_size=1))
1303 assert res.user_ids == [1]
1304 res2 = api.ListBadgeUsers(
1305 api_pb2.ListBadgeUsersReq(badge_id=board_member_badge["id"], page_token=res.next_page_token)
1306 )
1307 assert res2.user_ids == [2]