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

1import grpc 

2import pytest 

3from google.protobuf import empty_pb2 

4from sqlalchemy import select 

5 

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 

13 

14 

15@pytest.fixture(autouse=True) 

16def _(testconfig): 

17 pass 

18 

19 

20def test_BlockUser(db): 

21 user1, token1 = generate_user() 

22 user2, token2 = generate_user() 

23 

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 

29 

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

35 

36 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user2.username)) 

37 

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

42 

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 

48 

49 

50def test_make_user_block(db): 

51 user1, token1 = generate_user() 

52 user2, token2 = generate_user() 

53 

54 make_user_block(user1, user2) 

55 

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 

61 

62 

63def test_UnblockUser(db): 

64 user1, token1 = generate_user() 

65 user2, token2 = generate_user() 

66 make_user_block(user1, user2) 

67 

68 with blocking_session(token1) as user_blocks: 

69 user_blocks.UnblockUser(blocking_pb2.UnblockUserReq(username=user2.username)) 

70 

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 

74 

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

80 

81 # Test re-blocking 

82 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user2.username)) 

83 

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 

87 

88 

89def test_GetBlockedUsers(db): 

90 user1, token1 = generate_user() 

91 user2, token2 = generate_user() 

92 user3, token3 = generate_user() 

93 

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 

98 

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 

103 

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] 

106 

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 

111 

112 

113def test_relationships_userblock_dot_user(db): 

114 user1, token1 = generate_user() 

115 user2, token2 = generate_user() 

116 

117 make_user_block(user1, user2) 

118 

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

123 

124 blocking_user_username = block.blocking_user.username 

125 blocking_user_name = block.blocking_user.name 

126 

127 blocked_user_username = block.blocked_user.username 

128 blocked_user_name = block.blocked_user.name 

129 

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 

134 

135 

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

154 

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

159 

160 # Create users for testing - all start as visible 

161 normal_user1, _ = generate_user() 

162 normal_user2, _ = generate_user() 

163 

164 # Users for blocking tests 

165 blocker_user, _ = generate_user() 

166 blockee_user, _ = generate_user() 

167 

168 # Users for reverse blocking tests 

169 reverse_blocker, _ = generate_user() 

170 reverse_blockee, _ = generate_user() 

171 

172 # Users for mutual blocking tests 

173 mutual_blocker1, _ = generate_user() 

174 mutual_blocker2, _ = generate_user() 

175 

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

182 

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

189 

190 # User for mixed test 

191 mixed_deleted, _ = generate_user() 

192 mixed_banned, _ = generate_user() 

193 

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) 

198 

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 

203 

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 

208 

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) 

214 

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) 

221 

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) 

228 

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) 

237 

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) 

244 

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) 

251 

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) 

260 

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) 

269 

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) 

274 

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) 

280 

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) 

285 

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)