Coverage for app / backend / src / tests / test_blocking.py: 100%
179 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-19 14:14 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-19 14:14 +0000
1import grpc
2import pytest
3from google.protobuf import empty_pb2
4from sqlalchemy import select
6from couchers.db import session_scope
7from couchers.models import User, UserBlock
8from couchers.proto import blocking_pb2
9from couchers.servicers.blocking import is_not_visible
10from couchers.utils import now
11from tests.fixtures.db import generate_user, make_user_block
12from tests.fixtures.sessions import blocking_session
15@pytest.fixture(autouse=True)
16def _(testconfig):
17 pass
20def test_BlockUser(db):
21 user1, token1 = generate_user()
22 user2, token2 = generate_user()
24 with session_scope() as session:
25 blocked_user_list = (
26 session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all()
27 )
28 assert len(blocked_user_list) == 0
30 with blocking_session(token1) as user_blocks:
31 with pytest.raises(grpc.RpcError) as e:
32 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user1.username))
33 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
34 assert e.value.details() == "You can't block yourself."
36 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user2.username))
38 with pytest.raises(grpc.RpcError) as e:
39 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user2.username))
40 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
41 assert e.value.details() == "Target user has already been blocked."
43 with session_scope() as session:
44 blocked_user_list = (
45 session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all()
46 )
47 assert len(blocked_user_list) == 1
50def test_make_user_block(db):
51 user1, token1 = generate_user()
52 user2, token2 = generate_user()
54 make_user_block(user1, user2)
56 with session_scope() as session:
57 blocked_user_list = (
58 session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all()
59 )
60 assert len(blocked_user_list) == 1
63def test_UnblockUser(db):
64 user1, token1 = generate_user()
65 user2, token2 = generate_user()
66 make_user_block(user1, user2)
68 with blocking_session(token1) as user_blocks:
69 user_blocks.UnblockUser(blocking_pb2.UnblockUserReq(username=user2.username))
71 with session_scope() as session:
72 blocked_users = session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all()
73 assert len(blocked_users) == 0
75 with blocking_session(token1) as user_blocks:
76 with pytest.raises(grpc.RpcError) as e:
77 user_blocks.UnblockUser(blocking_pb2.UnblockUserReq(username=user2.username))
78 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
79 assert e.value.details() == "Target user is not blocked."
81 # Test re-blocking
82 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user2.username))
84 with session_scope() as session:
85 blocked_users = session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all()
86 assert len(blocked_users) == 1
89def test_GetBlockedUsers(db):
90 user1, token1 = generate_user()
91 user2, token2 = generate_user()
92 user3, token3 = generate_user()
94 with blocking_session(token1) as user_blocks:
95 # Check no blocked users to start
96 blocked_user_list = user_blocks.GetBlockedUsers(empty_pb2.Empty())
97 assert len(blocked_user_list.blocked_users) == 0
99 make_user_block(user1, user2)
100 make_user_block(user1, user3)
101 blocked_user_list = user_blocks.GetBlockedUsers(empty_pb2.Empty())
102 assert len(blocked_user_list.blocked_users) == 2
104 blocked_usernames = [user.username for user in blocked_user_list.blocked_users]
105 blocked_names = [user.name for user in blocked_user_list.blocked_users]
107 assert user2.username in blocked_usernames
108 assert user3.username in blocked_usernames
109 assert user2.name in blocked_names
110 assert user3.name in blocked_names
113def test_relationships_userblock_dot_user(db):
114 user1, token1 = generate_user()
115 user2, token2 = generate_user()
117 make_user_block(user1, user2)
119 with session_scope() as session:
120 block = session.execute(
121 select(UserBlock).where((UserBlock.blocking_user_id == user1.id) & (UserBlock.blocked_user_id == user2.id))
122 ).scalar_one()
124 blocking_user_username = block.blocking_user.username
125 blocking_user_name = block.blocking_user.name
127 blocked_user_username = block.blocked_user.username
128 blocked_user_name = block.blocked_user.name
130 assert blocking_user_username == user1.username
131 assert blocked_user_username == user2.username
132 assert blocking_user_name == user1.name
133 assert blocked_user_name == user2.name
136def test_is_not_visible(db):
137 """
138 Comprehensive tests for is_not_visible function covering:
139 1. Normal visible users (not blocked, not banned, not deleted) - should be visible to each other
140 2. User1 blocks User2 - not visible
141 3. User2 blocks User1 - not visible
142 4. Mutual blocking - not visible
143 5. User1 is deleted - not visible
144 6. User2 is deleted - not visible
145 7. Both users deleted - not visible
146 8. User1 is banned - not visible
147 9. User2 is banned - not visible
148 10. Both users banned - not visible
149 11. Mixed: User1 deleted and User2 banned - not visible
150 12. None user_id cases with visible users
151 13. None user_id cases with hidden users (banned/deleted)
152 14. Ensure we have extra users in DB to avoid edge cases with empty database
153 """
155 # Create extra users to ensure the database is not empty - these should remain visible
156 extra_user1, _ = generate_user()
157 extra_user2, _ = generate_user()
158 extra_user3, _ = generate_user()
160 # Create users for testing - all start as visible
161 normal_user1, _ = generate_user()
162 normal_user2, _ = generate_user()
164 # Users for blocking tests
165 blocker_user, _ = generate_user()
166 blockee_user, _ = generate_user()
168 # Users for reverse blocking tests
169 reverse_blocker, _ = generate_user()
170 reverse_blockee, _ = generate_user()
172 # Users for mutual blocking tests
173 mutual_blocker1, _ = generate_user()
174 mutual_blocker2, _ = generate_user()
176 # Users for deletion tests
177 deleted_user1, _ = generate_user()
178 visible_for_deleted, _ = generate_user()
179 deleted_user2, _ = generate_user()
180 both_deleted1, _ = generate_user()
181 both_deleted2, _ = generate_user()
183 # Users for ban tests
184 banned_user1, _ = generate_user()
185 visible_for_banned, _ = generate_user()
186 banned_user2, _ = generate_user()
187 both_banned1, _ = generate_user()
188 both_banned2, _ = generate_user()
190 # User for mixed test
191 mixed_deleted, _ = generate_user()
192 mixed_banned, _ = generate_user()
194 with session_scope() as session:
195 # Test 1: Two normal visible users - should be visible to each other
196 assert not is_not_visible(session, normal_user1.id, normal_user2.id)
197 assert not is_not_visible(session, normal_user2.id, normal_user1.id)
199 # Test 2: User1 blocks User2 - should not be visible
200 make_user_block(blocker_user, blockee_user)
201 assert is_not_visible(session, blocker_user.id, blockee_user.id)
202 assert is_not_visible(session, blockee_user.id, blocker_user.id) # symmetric
204 # Test 3: User2 blocks User1 (reverse block) - should not be visible
205 make_user_block(reverse_blockee, reverse_blocker)
206 assert is_not_visible(session, reverse_blocker.id, reverse_blockee.id)
207 assert is_not_visible(session, reverse_blockee.id, reverse_blocker.id) # symmetric
209 # Test 4: Mutual blocking - should not be visible
210 make_user_block(mutual_blocker1, mutual_blocker2)
211 make_user_block(mutual_blocker2, mutual_blocker1)
212 assert is_not_visible(session, mutual_blocker1.id, mutual_blocker2.id)
213 assert is_not_visible(session, mutual_blocker2.id, mutual_blocker1.id)
215 # Test 5: User1 is deleted - should not be visible
216 deleted_user1_db = session.get_one(User, deleted_user1.id)
217 deleted_user1_db.deleted_at = now()
218 session.commit()
219 assert is_not_visible(session, deleted_user1.id, visible_for_deleted.id)
220 assert is_not_visible(session, visible_for_deleted.id, deleted_user1.id)
222 # Test 6: User2 is deleted - should not be visible
223 deleted_user2_db = session.get_one(User, deleted_user2.id)
224 deleted_user2_db.deleted_at = now()
225 session.commit()
226 assert is_not_visible(session, normal_user1.id, deleted_user2.id)
227 assert is_not_visible(session, deleted_user2.id, normal_user1.id)
229 # Test 7: Both users deleted - should not be visible
230 both_deleted1_db = session.get_one(User, both_deleted1.id)
231 both_deleted2_db = session.get_one(User, both_deleted2.id)
232 both_deleted1_db.deleted_at = now()
233 both_deleted2_db.deleted_at = now()
234 session.commit()
235 assert is_not_visible(session, both_deleted1.id, both_deleted2.id)
236 assert is_not_visible(session, both_deleted2.id, both_deleted1.id)
238 # Test 8: User1 is banned - should not be visible
239 banned_user1_db = session.get_one(User, banned_user1.id)
240 banned_user1_db.banned_at = now()
241 session.commit()
242 assert is_not_visible(session, banned_user1.id, visible_for_banned.id)
243 assert is_not_visible(session, visible_for_banned.id, banned_user1.id)
245 # Test 9: User2 is banned - should not be visible
246 banned_user2_db = session.get_one(User, banned_user2.id)
247 banned_user2_db.banned_at = now()
248 session.commit()
249 assert is_not_visible(session, normal_user2.id, banned_user2.id)
250 assert is_not_visible(session, banned_user2.id, normal_user2.id)
252 # Test 10: Both users banned - should not be visible
253 both_banned1_db = session.get_one(User, both_banned1.id)
254 both_banned2_db = session.get_one(User, both_banned2.id)
255 both_banned1_db.banned_at = now()
256 both_banned2_db.banned_at = now()
257 session.commit()
258 assert is_not_visible(session, both_banned1.id, both_banned2.id)
259 assert is_not_visible(session, both_banned2.id, both_banned1.id)
261 # Test 11: Mixed - one deleted, one banned - should not be visible
262 mixed_deleted_db = session.get_one(User, mixed_deleted.id)
263 mixed_banned_db = session.get_one(User, mixed_banned.id)
264 mixed_deleted_db.deleted_at = now()
265 mixed_banned_db.banned_at = now()
266 session.commit()
267 assert is_not_visible(session, mixed_deleted.id, mixed_banned.id)
268 assert is_not_visible(session, mixed_banned.id, mixed_deleted.id)
270 # Test 12: None user_id cases with visible users - should be visible
271 assert not is_not_visible(session, None, normal_user1.id)
272 assert not is_not_visible(session, normal_user1.id, None)
273 assert not is_not_visible(session, None, None)
275 # Test 13: None user_id cases with hidden users (deleted/banned) - should not be visible
276 assert is_not_visible(session, None, deleted_user1.id)
277 assert is_not_visible(session, deleted_user1.id, None)
278 assert is_not_visible(session, None, banned_user1.id)
279 assert is_not_visible(session, banned_user1.id, None)
281 # Test 14: Verify extra users are still visible (database not empty)
282 assert not is_not_visible(session, extra_user1.id, extra_user2.id)
283 assert not is_not_visible(session, extra_user2.id, extra_user3.id)
284 assert not is_not_visible(session, extra_user1.id, extra_user3.id)
286 # Additional edge case: Check that normal users are still visible to each other after all the above
287 assert not is_not_visible(session, normal_user1.id, normal_user2.id)
288 assert not is_not_visible(session, normal_user1.id, extra_user1.id)