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

1from datetime import timedelta 

2 

3import grpc 

4import pytest 

5from google.protobuf import empty_pb2, wrappers_pb2 

6 

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) 

33 

34 

35@pytest.fixture(autouse=True) 

36def _(testconfig): 

37 pass 

38 

39 

40def test_ping(db): 

41 user, token = generate_user() 

42 

43 with real_api_session(token) as api: 

44 res = api.Ping(api_pb2.PingReq()) 

45 

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 

57 

58 assert (res.user.lat, res.user.lng) == (user.coordinates or (0, 0)) 

59 

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 

65 

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 

68 

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 

78 

79 assert res.user.friends == api_pb2.User.FriendshipStatus.NA 

80 assert not res.user.HasField("pending_friend_request") 

81 

82 

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() 

87 

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 

95 

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 

102 

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)) 

107 

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 

112 

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 

117 

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 

123 

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 

128 

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 ) 

137 

138 assert not res.jailed 

139 assert not res.needs_to_update_location 

140 

141 res = jail.JailInfo(empty_pb2.Empty()) 

142 assert not res.jailed 

143 assert not res.needs_to_update_location 

144 

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 

151 

152 

153def test_get_user(db): 

154 user1, token1 = generate_user() 

155 user2, token2 = generate_user() 

156 

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 

162 

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 

168 

169 

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() 

174 

175 refresh_materialized_views_rapid(None) 

176 

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 

184 

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 

191 

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)) 

196 

197 refresh_materialized_views_rapid(None) 

198 

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 

203 

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 

208 

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 

214 

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 

219 

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 ) 

228 

229 assert not res.jailed 

230 assert not res.needs_to_update_location 

231 

232 res = jail.JailInfo(empty_pb2.Empty()) 

233 assert not res.jailed 

234 assert not res.needs_to_update_location 

235 

236 refresh_materialized_views_rapid(None) 

237 

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 

244 

245 

246def test_lite_get_user(db): 

247 user1, token1 = generate_user() 

248 user2, token2 = generate_user() 

249 

250 refresh_materialized_views_rapid(None) 

251 

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 

257 

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 

263 

264 

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() 

272 

273 make_user_block(user4, user1) 

274 

275 refresh_materialized_views_rapid(None) 

276 

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 ) 

293 

294 assert len(res.responses) == 9 

295 assert res.responses[0].query == user1.username 

296 assert res.responses[0].user.user_id == user1.id 

297 

298 assert res.responses[1].query == str(user1.id) 

299 assert res.responses[1].user.user_id == user1.id 

300 

301 assert res.responses[2].query == "nonexistent" 

302 assert res.responses[2].not_found 

303 

304 assert res.responses[3].query == str(user2.id) 

305 assert res.responses[3].user.user_id == user2.id 

306 

307 assert res.responses[4].query == "9994" 

308 assert res.responses[4].not_found 

309 

310 assert res.responses[5].query == user6.username 

311 assert res.responses[5].user.user_id == user6.id 

312 

313 assert res.responses[6].query == str(user5.id) 

314 assert res.responses[6].user.user_id == user5.id 

315 

316 assert res.responses[7].query == "notreal" 

317 assert res.responses[7].not_found 

318 

319 # blocked 

320 assert res.responses[8].query == user4.username 

321 assert res.responses[8].not_found 

322 

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 

328 

329 

330def test_update_profile(db): 

331 user, token = generate_user() 

332 

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 

338 

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 

345 

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 

352 

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 

359 

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 ) 

389 

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"] 

410 

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 ) 

430 

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 

446 

447 

448def test_update_profile_do_not_email(db): 

449 user, token = generate_user() 

450 

451 with notifications_session(token) as notifications: 

452 notifications.SetNotificationSettings(notifications_pb2.SetNotificationSettingsReq(enable_do_not_email=True)) 

453 

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 

459 

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 

464 

465 

466def test_language_abilities(db): 

467 user, token = generate_user() 

468 

469 with api_session(token) as api: 

470 res = api.GetUser(api_pb2.GetUserReq(user=user.username)) 

471 assert len(res.language_abilities) == 2 

472 

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 

489 

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) 

509 

510 # nothing changed 

511 res = api.GetUser(api_pb2.GetUserReq(user=user.username)) 

512 assert len(res.language_abilities) == 2 

513 

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 ) 

527 

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 

532 

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 ) 

546 

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 

551 

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 ) 

565 

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 

570 

571 # don't change it 

572 api.UpdateProfile(api_pb2.UpdateProfileReq()) 

573 

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 

578 

579 # remove value 

580 api.UpdateProfile( 

581 api_pb2.UpdateProfileReq( 

582 language_abilities=api_pb2.RepeatedLanguageAbilityValue( 

583 value=[], 

584 ), 

585 ) 

586 ) 

587 

588 res = api.GetUser(api_pb2.GetUserReq(user=user.username)) 

589 assert len(res.language_abilities) == 0 

590 

591 

592def test_pending_friend_request_count(db): 

593 user1, token1 = generate_user() 

594 user2, token2 = generate_user() 

595 user3, token3 = generate_user() 

596 

597 with api_session(token2) as api: 

598 res = api.Ping(api_pb2.PingReq()) 

599 assert res.pending_friend_request_count == 0 

600 

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 

607 

608 with api_session(token2) as api: 

609 res = api.Ping(api_pb2.PingReq()) 

610 assert res.pending_friend_request_count == 1 

611 

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 

617 

618 assert res.received[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING 

619 assert res.received[0].user_id == user1.id 

620 

621 fr_id = res.received[0].friend_request_id 

622 

623 # accept it 

624 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=True)) 

625 

626 res = api.Ping(api_pb2.PingReq()) 

627 assert res.pending_friend_request_count == 0 

628 

629 

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() 

634 

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)) 

639 

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 ) 

645 

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 

658 

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 

667 

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 

673 

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 

677 

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 

683 

684 assert res.received[0].state == api_pb2.FriendRequest.FriendRequestStatus.PENDING 

685 assert res.received[0].user_id == user1.id 

686 

687 fr_id = res.received[0].friend_request_id 

688 

689 # accept it 

690 with mock_notification_email() as mock: 

691 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=True)) 

692 

693 # check it's gone 

694 res = api.ListFriendRequests(empty_pb2.Empty()) 

695 assert len(res.sent) == 0 

696 assert len(res.received) == 0 

697 

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 

702 

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 ) 

709 

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 

722 

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 

728 

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 

733 

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 

740 

741 # we can unfriend 

742 res = api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user2.id)) 

743 

744 res = api.ListFriends(empty_pb2.Empty()) 

745 assert len(res.user_ids) == 0 

746 

747 

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() 

755 

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)) 

759 

760 with api_session(token5) as api: 

761 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user1.id)) 

762 

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)) 

766 

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 ) 

772 

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 ) 

778 

779 with api_session(token1) as api: 

780 res = api.ListFriends(empty_pb2.Empty()) 

781 assert sorted(res.user_ids) == [2, 4] 

782 

783 api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user2.id)) 

784 

785 res = api.ListFriends(empty_pb2.Empty()) 

786 assert sorted(res.user_ids) == [4] 

787 

788 api.RemoveFriend(api_pb2.RemoveFriendReq(user_id=user4.id)) 

789 

790 res = api.ListFriends(empty_pb2.Empty()) 

791 assert not res.user_ids 

792 

793 

794def test_cant_friend_request_twice(db): 

795 user1, token1 = generate_user() 

796 user2, token2 = generate_user() 

797 

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)) 

801 

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 

806 

807 

808def test_cant_friend_request_pending(db): 

809 user1, token1 = generate_user() 

810 user2, token2 = generate_user() 

811 

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)) 

815 

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 

821 

822 

823def test_cant_friend_request_already_friends(db): 

824 user1, token1 = generate_user() 

825 user2, token2 = generate_user() 

826 make_friends(user1, user2) 

827 

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 

833 

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 

839 

840 

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)) 

851 

852 assert mock_email.call_count == 0 

853 friend_user, _ = generate_user() 

854 _ = api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=friend_user.id)) 

855 

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 ) 

861 

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)) 

867 

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 

874 

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 

881 

882 

883def test_ListFriends(db): 

884 user1, token1 = generate_user() 

885 user2, token2 = generate_user() 

886 user3, token3 = generate_user() 

887 

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)) 

892 

893 with api_session(token3) as api: 

894 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id)) 

895 

896 with api_session(token2) as api: 

897 res = api.ListFriendRequests(empty_pb2.Empty()) 

898 assert len(res.received) == 2 

899 

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] 

903 

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 ) 

909 

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 ) 

915 

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 

921 

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 

926 

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)) 

933 

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 

938 

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 

944 

945 

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() 

952 

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) 

961 

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 

966 

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 

972 

973 # Check pending request doesn't have effect 

974 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user5.id)) 

975 

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 

979 

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 

985 

986 

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() 

992 

993 make_friends(user1, user2) 

994 make_friends(user2, user3) 

995 make_friends(user1, user4) 

996 

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 

1000 

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 

1004 

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 

1008 

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 

1012 

1013 

1014def test_CancelFriendRequest(db): 

1015 user1, token1 = generate_user() 

1016 user2, token2 = generate_user() 

1017 

1018 with api_session(token1) as api: 

1019 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id)) 

1020 

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 

1024 

1025 api.CancelFriendRequest(api_pb2.CancelFriendRequestReq(friend_request_id=fr_id)) 

1026 

1027 # check it's gone 

1028 res = api.ListFriendRequests(empty_pb2.Empty()) 

1029 assert len(res.sent) == 0 

1030 assert len(res.received) == 0 

1031 

1032 # check not friends 

1033 res = api.ListFriends(empty_pb2.Empty()) 

1034 assert len(res.user_ids) == 0 

1035 

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 

1041 

1042 # check we're not friends 

1043 res = api.ListFriends(empty_pb2.Empty()) 

1044 assert len(res.user_ids) == 0 

1045 

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)) 

1049 

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 

1053 

1054 

1055def test_accept_friend_request(db): 

1056 user1, token1 = generate_user() 

1057 user2, token2 = generate_user() 

1058 

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 

1064 

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 

1070 

1071 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=friend_request_id, accept=True)) 

1072 

1073 # check request is gone 

1074 res = api.ListFriendRequests(empty_pb2.Empty()) 

1075 assert len(res.sent) == 0 

1076 assert len(res.received) == 0 

1077 

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 

1082 

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 

1088 

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 

1093 

1094 

1095def test_reject_friend_request(db): 

1096 user1, token1 = generate_user() 

1097 user2, token2 = generate_user() 

1098 

1099 with api_session(token1) as api: 

1100 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id)) 

1101 

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 

1105 

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 

1110 

1111 fr_id = res.received[0].friend_request_id 

1112 

1113 # reject it 

1114 api.RespondFriendRequest(api_pb2.RespondFriendRequestReq(friend_request_id=fr_id, accept=False)) 

1115 

1116 # check it's gone 

1117 res = api.ListFriendRequests(empty_pb2.Empty()) 

1118 assert len(res.sent) == 0 

1119 assert len(res.received) == 0 

1120 

1121 # check not friends 

1122 res = api.ListFriends(empty_pb2.Empty()) 

1123 assert len(res.user_ids) == 0 

1124 

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 

1130 

1131 # check we're not friends 

1132 res = api.ListFriends(empty_pb2.Empty()) 

1133 assert len(res.user_ids) == 0 

1134 

1135 # check we can send another friend req 

1136 api.SendFriendRequest(api_pb2.SendFriendRequestReq(user_id=user2.id)) 

1137 

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 

1141 

1142 

1143def test_hosting_preferences(db): 

1144 user1, token1 = generate_user() 

1145 user2, token2 = generate_user() 

1146 

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") 

1172 

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 ) 

1200 

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 

1228 

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 ) 

1258 

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") 

1283 

1284 

1285def test_badges(db): 

1286 user1, _ = generate_user() 

1287 user2, _ = generate_user() 

1288 user3, _ = generate_user() 

1289 user4, token = generate_user() 

1290 

1291 update_badges(empty_pb2.Empty()) 

1292 

1293 founder_badge = get_badge_dict()["founder"] 

1294 board_member_badge = get_badge_dict()["board_member"] 

1295 

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 == [] 

1300 

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]