Coverage for app / backend / src / tests / test_blocking.py: 100%

178 statements  

« prev     ^ index     » next       coverage.py v7.13.2, created at 2026-02-03 06:18 +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 tests.fixtures.db import generate_user, make_user_block 

11from tests.fixtures.sessions import blocking_session 

12 

13 

14@pytest.fixture(autouse=True) 

15def _(testconfig): 

16 pass 

17 

18 

19def test_BlockUser(db): 

20 user1, token1 = generate_user() 

21 user2, token2 = generate_user() 

22 

23 with session_scope() as session: 

24 blocked_user_list = ( 

25 session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all() 

26 ) 

27 assert len(blocked_user_list) == 0 

28 

29 with blocking_session(token1) as user_blocks: 

30 with pytest.raises(grpc.RpcError) as e: 

31 user_blocks.BlockUser(blocking_pb2.BlockUserReq(username=user1.username)) 

32 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

33 assert e.value.details() == "You can't block yourself." 

34 

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

36 

37 with pytest.raises(grpc.RpcError) as e: 

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

39 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

40 assert e.value.details() == "Target user has already been blocked." 

41 

42 with session_scope() as session: 

43 blocked_user_list = ( 

44 session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all() 

45 ) 

46 assert len(blocked_user_list) == 1 

47 

48 

49def test_make_user_block(db): 

50 user1, token1 = generate_user() 

51 user2, token2 = generate_user() 

52 

53 make_user_block(user1, user2) 

54 

55 with session_scope() as session: 

56 blocked_user_list = ( 

57 session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all() 

58 ) 

59 assert len(blocked_user_list) == 1 

60 

61 

62def test_UnblockUser(db): 

63 user1, token1 = generate_user() 

64 user2, token2 = generate_user() 

65 make_user_block(user1, user2) 

66 

67 with blocking_session(token1) as user_blocks: 

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

69 

70 with session_scope() as session: 

71 blocked_users = session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all() 

72 assert len(blocked_users) == 0 

73 

74 with blocking_session(token1) as user_blocks: 

75 with pytest.raises(grpc.RpcError) as e: 

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

77 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

78 assert e.value.details() == "Target user is not blocked." 

79 

80 # Test re-blocking 

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

82 

83 with session_scope() as session: 

84 blocked_users = session.execute(select(UserBlock).where(UserBlock.blocking_user_id == user1.id)).scalars().all() 

85 assert len(blocked_users) == 1 

86 

87 

88def test_GetBlockedUsers(db): 

89 user1, token1 = generate_user() 

90 user2, token2 = generate_user() 

91 user3, token3 = generate_user() 

92 

93 with blocking_session(token1) as user_blocks: 

94 # Check no blocked users to start 

95 blocked_user_list = user_blocks.GetBlockedUsers(empty_pb2.Empty()) 

96 assert len(blocked_user_list.blocked_users) == 0 

97 

98 make_user_block(user1, user2) 

99 make_user_block(user1, user3) 

100 blocked_user_list = user_blocks.GetBlockedUsers(empty_pb2.Empty()) 

101 assert len(blocked_user_list.blocked_users) == 2 

102 

103 blocked_usernames = [user.username for user in blocked_user_list.blocked_users] 

104 blocked_names = [user.name for user in blocked_user_list.blocked_users] 

105 

106 assert user2.username in blocked_usernames 

107 assert user3.username in blocked_usernames 

108 assert user2.name in blocked_names 

109 assert user3.name in blocked_names 

110 

111 

112def test_relationships_userblock_dot_user(db): 

113 user1, token1 = generate_user() 

114 user2, token2 = generate_user() 

115 

116 make_user_block(user1, user2) 

117 

118 with session_scope() as session: 

119 block = session.execute( 

120 select(UserBlock).where((UserBlock.blocking_user_id == user1.id) & (UserBlock.blocked_user_id == user2.id)) 

121 ).scalar_one() 

122 

123 blocking_user_username = block.blocking_user.username 

124 blocking_user_name = block.blocking_user.name 

125 

126 blocked_user_username = block.blocked_user.username 

127 blocked_user_name = block.blocked_user.name 

128 

129 assert blocking_user_username == user1.username 

130 assert blocked_user_username == user2.username 

131 assert blocking_user_name == user1.name 

132 assert blocked_user_name == user2.name 

133 

134 

135def test_is_not_visible(db): 

136 """ 

137 Comprehensive tests for is_not_visible function covering: 

138 1. Normal visible users (not blocked, not banned, not deleted) - should be visible to each other 

139 2. User1 blocks User2 - not visible 

140 3. User2 blocks User1 - not visible 

141 4. Mutual blocking - not visible 

142 5. User1 is deleted - not visible 

143 6. User2 is deleted - not visible 

144 7. Both users deleted - not visible 

145 8. User1 is banned - not visible 

146 9. User2 is banned - not visible 

147 10. Both users banned - not visible 

148 11. Mixed: User1 deleted and User2 banned - not visible 

149 12. None user_id cases with visible users 

150 13. None user_id cases with hidden users (banned/deleted) 

151 14. Ensure we have extra users in DB to avoid edge cases with empty database 

152 """ 

153 

154 # Create extra users to ensure the database is not empty - these should remain visible 

155 extra_user1, _ = generate_user() 

156 extra_user2, _ = generate_user() 

157 extra_user3, _ = generate_user() 

158 

159 # Create users for testing - all start as visible 

160 normal_user1, _ = generate_user() 

161 normal_user2, _ = generate_user() 

162 

163 # Users for blocking tests 

164 blocker_user, _ = generate_user() 

165 blockee_user, _ = generate_user() 

166 

167 # Users for reverse blocking tests 

168 reverse_blocker, _ = generate_user() 

169 reverse_blockee, _ = generate_user() 

170 

171 # Users for mutual blocking tests 

172 mutual_blocker1, _ = generate_user() 

173 mutual_blocker2, _ = generate_user() 

174 

175 # Users for deletion tests 

176 deleted_user1, _ = generate_user() 

177 visible_for_deleted, _ = generate_user() 

178 deleted_user2, _ = generate_user() 

179 both_deleted1, _ = generate_user() 

180 both_deleted2, _ = generate_user() 

181 

182 # Users for ban tests 

183 banned_user1, _ = generate_user() 

184 visible_for_banned, _ = generate_user() 

185 banned_user2, _ = generate_user() 

186 both_banned1, _ = generate_user() 

187 both_banned2, _ = generate_user() 

188 

189 # User for mixed test 

190 mixed_deleted, _ = generate_user() 

191 mixed_banned, _ = generate_user() 

192 

193 with session_scope() as session: 

194 # Test 1: Two normal visible users - should be visible to each other 

195 assert not is_not_visible(session, normal_user1.id, normal_user2.id) 

196 assert not is_not_visible(session, normal_user2.id, normal_user1.id) 

197 

198 # Test 2: User1 blocks User2 - should not be visible 

199 make_user_block(blocker_user, blockee_user) 

200 assert is_not_visible(session, blocker_user.id, blockee_user.id) 

201 assert is_not_visible(session, blockee_user.id, blocker_user.id) # symmetric 

202 

203 # Test 3: User2 blocks User1 (reverse block) - should not be visible 

204 make_user_block(reverse_blockee, reverse_blocker) 

205 assert is_not_visible(session, reverse_blocker.id, reverse_blockee.id) 

206 assert is_not_visible(session, reverse_blockee.id, reverse_blocker.id) # symmetric 

207 

208 # Test 4: Mutual blocking - should not be visible 

209 make_user_block(mutual_blocker1, mutual_blocker2) 

210 make_user_block(mutual_blocker2, mutual_blocker1) 

211 assert is_not_visible(session, mutual_blocker1.id, mutual_blocker2.id) 

212 assert is_not_visible(session, mutual_blocker2.id, mutual_blocker1.id) 

213 

214 # Test 5: User1 is deleted - should not be visible 

215 deleted_user1_db = session.get_one(User, deleted_user1.id) 

216 deleted_user1_db.is_deleted = True 

217 session.commit() 

218 assert is_not_visible(session, deleted_user1.id, visible_for_deleted.id) 

219 assert is_not_visible(session, visible_for_deleted.id, deleted_user1.id) 

220 

221 # Test 6: User2 is deleted - should not be visible 

222 deleted_user2_db = session.get_one(User, deleted_user2.id) 

223 deleted_user2_db.is_deleted = True 

224 session.commit() 

225 assert is_not_visible(session, normal_user1.id, deleted_user2.id) 

226 assert is_not_visible(session, deleted_user2.id, normal_user1.id) 

227 

228 # Test 7: Both users deleted - should not be visible 

229 both_deleted1_db = session.get_one(User, both_deleted1.id) 

230 both_deleted2_db = session.get_one(User, both_deleted2.id) 

231 both_deleted1_db.is_deleted = True 

232 both_deleted2_db.is_deleted = True 

233 session.commit() 

234 assert is_not_visible(session, both_deleted1.id, both_deleted2.id) 

235 assert is_not_visible(session, both_deleted2.id, both_deleted1.id) 

236 

237 # Test 8: User1 is banned - should not be visible 

238 banned_user1_db = session.get_one(User, banned_user1.id) 

239 banned_user1_db.is_banned = True 

240 session.commit() 

241 assert is_not_visible(session, banned_user1.id, visible_for_banned.id) 

242 assert is_not_visible(session, visible_for_banned.id, banned_user1.id) 

243 

244 # Test 9: User2 is banned - should not be visible 

245 banned_user2_db = session.get_one(User, banned_user2.id) 

246 banned_user2_db.is_banned = True 

247 session.commit() 

248 assert is_not_visible(session, normal_user2.id, banned_user2.id) 

249 assert is_not_visible(session, banned_user2.id, normal_user2.id) 

250 

251 # Test 10: Both users banned - should not be visible 

252 both_banned1_db = session.get_one(User, both_banned1.id) 

253 both_banned2_db = session.get_one(User, both_banned2.id) 

254 both_banned1_db.is_banned = True 

255 both_banned2_db.is_banned = True 

256 session.commit() 

257 assert is_not_visible(session, both_banned1.id, both_banned2.id) 

258 assert is_not_visible(session, both_banned2.id, both_banned1.id) 

259 

260 # Test 11: Mixed - one deleted, one banned - should not be visible 

261 mixed_deleted_db = session.get_one(User, mixed_deleted.id) 

262 mixed_banned_db = session.get_one(User, mixed_banned.id) 

263 mixed_deleted_db.is_deleted = True 

264 mixed_banned_db.is_banned = True 

265 session.commit() 

266 assert is_not_visible(session, mixed_deleted.id, mixed_banned.id) 

267 assert is_not_visible(session, mixed_banned.id, mixed_deleted.id) 

268 

269 # Test 12: None user_id cases with visible users - should be visible 

270 assert not is_not_visible(session, None, normal_user1.id) 

271 assert not is_not_visible(session, normal_user1.id, None) 

272 assert not is_not_visible(session, None, None) 

273 

274 # Test 13: None user_id cases with hidden users (deleted/banned) - should not be visible 

275 assert is_not_visible(session, None, deleted_user1.id) 

276 assert is_not_visible(session, deleted_user1.id, None) 

277 assert is_not_visible(session, None, banned_user1.id) 

278 assert is_not_visible(session, banned_user1.id, None) 

279 

280 # Test 14: Verify extra users are still visible (database not empty) 

281 assert not is_not_visible(session, extra_user1.id, extra_user2.id) 

282 assert not is_not_visible(session, extra_user2.id, extra_user3.id) 

283 assert not is_not_visible(session, extra_user1.id, extra_user3.id) 

284 

285 # Additional edge case: Check that normal users are still visible to each other after all the above 

286 assert not is_not_visible(session, normal_user1.id, normal_user2.id) 

287 assert not is_not_visible(session, normal_user1.id, extra_user1.id)