Coverage for tests/model_tests/test_user.py: 99%

327 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-05 14:02 +0000

1"""Tests for the User model.""" 

2 

3import os 

4import sys 

5from dotenv import load_dotenv 

6import pytest 

7from passlib.hash import pbkdf2_sha512 

8 

9from flask import session 

10 

11 

12# flake8: noqa: F811 

13 

14# Add the root directory to the Python path 

15sys.path.append( 

16 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 

17) 

18from core import shared 

19from core.database_mongo_manager import DatabaseMongoManager 

20 

21os.environ["IS_TEST"] = "True" 

22 

23load_dotenv() 

24 

25 

26@pytest.fixture() 

27def app(): 

28 """Fixture to create a test client.""" 

29 from ...app import app # pylint: disable=import-outside-toplevel 

30 

31 app.config["TESTING"] = True 

32 return app 

33 

34 

35@pytest.fixture() 

36def user_model(): 

37 """Fixture to create a user model.""" 

38 from user.models import User 

39 

40 return User() 

41 

42 

43@pytest.fixture() 

44def database(): 

45 """Fixture to create a test database.""" 

46 

47 database = DatabaseMongoManager( 

48 shared.getenv("MONGO_URI"), shared.getenv("MONGO_DB_TEST", "cs3528_testing") 

49 ) 

50 

51 yield database 

52 

53 tables = [ 

54 "users", 

55 "students", 

56 "employers", 

57 ] 

58 

59 for table in tables: 

60 database.delete_all_by_field(table, "email", "dummy@dummy.com") 

61 

62 # Cleanup code 

63 database.connection.close() 

64 

65 

66def test_start_session(app, user_model): 

67 """Tests the start_session method of the User model.""" 

68 user = { 

69 "_id": "123", 

70 "name": "Test User", 

71 "email": "dummy@dummy.com", 

72 "password": "password", 

73 } 

74 

75 with app.app_context(): 

76 with app.test_request_context(): # Add this line 

77 response = user_model.start_session(user) 

78 json_data = response[0].get_json() 

79 assert response[1] == 200 

80 assert json_data["message"] == "/user/home" 

81 assert "password" not in json_data 

82 

83 

84def test_register_success(app, database, user_model): 

85 """Tests the register method of the User model.""" 

86 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

87 user = { 

88 "_id": "124", 

89 "name": "New User", 

90 "email": "dummy@dummy.com", 

91 "password": "password", 

92 } 

93 

94 with app.app_context(): 

95 with app.test_request_context(): 

96 session["superuser"] = True 

97 response = user_model.register(user) 

98 json_data = response[0].get_json() 

99 assert response[1] == 201 

100 assert json_data["message"] == "User registered successfully" 

101 session.clear() 

102 

103 # Delete the user from the database 

104 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

105 

106 

107def test_register_email_in_use(app, database, user_model): 

108 """Tests the register method of the User model when the email is already in use.""" 

109 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

110 user = { 

111 "_id": "125", 

112 "name": "Existing User", 

113 "email": "dummy@dummy.com", 

114 "password": "password", 

115 } 

116 

117 database.insert("users", user) 

118 

119 with app.app_context(): 

120 with app.test_request_context(): 

121 response = user_model.register(user) 

122 json_data = response[0].get_json() 

123 assert response[1] == 400 

124 assert json_data["error"] == "Email address already in use" 

125 

126 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

127 

128 

129def test_register_failure(app, user_model): 

130 """Tests the register method of the User model when 

131 the request is missing the email or password.""" 

132 

133 with app.app_context(): 

134 with app.test_request_context(): 

135 response = user_model.register({}) 

136 json_data = response[0].get_json() 

137 assert response[1] == 400 

138 assert json_data["error"] == "Missing email or password" 

139 

140 

141def test_login_success(app, database, user_model): 

142 """Tests the login method of the User model.""" 

143 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

144 user = { 

145 "_id": "126", 

146 "name": "Login User", 

147 "email": "dummy@dummy.com", 

148 "password": pbkdf2_sha512.hash("dummy"), 

149 } 

150 

151 # Insert the user into the database 

152 database.insert("users", user) 

153 

154 attempt_user = { 

155 "email": "dummy@dummy.com", 

156 "password": "dummy", 

157 } 

158 

159 with app.app_context(): 

160 with app.test_request_context(): 

161 response = user_model.login(attempt_user) 

162 json_data = response[0].get_json() 

163 assert "logged_in" in session 

164 assert response[1] == 200 

165 assert json_data["message"] == "/user/home" 

166 assert "password" not in json_data 

167 session.clear() 

168 

169 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

170 

171 

172def test_login_invalid_credentials(app, database, user_model): 

173 """Tests the login method of the User model when the credentials are invalid.""" 

174 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

175 user = { 

176 "_id": "127", 

177 "name": "Invalid User", 

178 "email": "dummy@dummy.com", 

179 "password": pbkdf2_sha512.hash("password"), 

180 } 

181 

182 # Insert the user into the database 

183 database.insert("users", user) 

184 

185 attempt_user = { 

186 "email": "dummy@dummy.com", 

187 "password": "wrongpassword", 

188 } 

189 

190 with app.app_context(): 

191 with app.test_request_context(): 

192 response = user_model.login(attempt_user) 

193 json_data = response[0].get_json() 

194 assert response[1] == 401 

195 assert json_data["error"] == "Invalid login credentials" 

196 

197 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

198 

199 

200def test_login_user_not_found(app, database, user_model): 

201 """Tests the login method of the User model when the user is not found.""" 

202 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

203 

204 attempt_user = { 

205 "email": "dummy@dummy.com", 

206 "password": "password", 

207 } 

208 

209 with app.app_context(): 

210 with app.test_request_context(): 

211 response = user_model.login(attempt_user) 

212 json_data = response[0].get_json() 

213 assert response[1] == 401 

214 assert json_data["error"] == "Invalid login credentials" 

215 

216 

217def test_update_deadlines_success(app, database, user_model): 

218 """Tests the change_deadline method of the User model.""" 

219 deadlines = database.get_all("deadline") 

220 if deadlines: 

221 database.delete_all("deadline") 

222 

223 database.insert("deadline", {"type": 0, "deadline": "2022-10-10"}) 

224 database.insert("deadline", {"type": 1, "deadline": "2022-10-12"}) 

225 database.insert("deadline", {"type": 2, "deadline": "2022-10-15"}) 

226 

227 with app.app_context(): 

228 with app.test_request_context(): 

229 response = user_model.change_deadline( 

230 "2023-12-31", "2024-01-15", "2024-01-31" 

231 ) 

232 json_data = response[0].get_json() 

233 assert response[1] == 200 

234 assert json_data["message"] == "All deadlines updated successfully" 

235 assert ( 

236 database.get_one_by_field("deadline", "type", 0)["deadline"] 

237 == "2023-12-31" 

238 ) 

239 assert ( 

240 database.get_one_by_field("deadline", "type", 1)["deadline"] 

241 == "2024-01-15" 

242 ) 

243 assert ( 

244 database.get_one_by_field("deadline", "type", 2)["deadline"] 

245 == "2024-01-31" 

246 ) 

247 

248 database.delete_all("deadline") 

249 for deadline in deadlines: 

250 database.insert("deadline", deadline) 

251 

252 

253def test_update_deadlines_invalid_format(app, database, user_model): 

254 """Tests the change_deadline method of the User model with an invalid date format.""" 

255 deadlines = database.get_all("deadline") 

256 if deadlines: 

257 database.delete_all("deadline") 

258 

259 database.insert("deadline", {"type": 0, "deadline": "2022-10-10"}) 

260 database.insert("deadline", {"type": 1, "deadline": "2022-10-12"}) 

261 database.insert("deadline", {"type": 2, "deadline": "2022-10-15"}) 

262 

263 with app.app_context(): 

264 with app.test_request_context(): 

265 response = user_model.change_deadline( 

266 "invalid-date", "2024-01-15", "2024-01-31" 

267 ) 

268 json_data = response[0].get_json() 

269 assert response[1] == 400 

270 assert json_data["error"] == "Invalid deadline format. Use YYYY-MM-DD." 

271 

272 database.delete_all("deadline") 

273 for deadline in deadlines: 

274 database.insert("deadline", deadline) 

275 

276 

277def test_update_deadlines_details_later_than_student_ranking(app, database, user_model): 

278 """Tests the change_deadline method of the User model 

279 with the details deadline later than the student ranking deadline.""" 

280 deadlines = database.get_all("deadline") 

281 if deadlines: 

282 database.delete_all("deadline") 

283 

284 database.insert("deadline", {"type": 0, "deadline": "2022-10-10"}) 

285 database.insert("deadline", {"type": 1, "deadline": "2022-10-12"}) 

286 database.insert("deadline", {"type": 2, "deadline": "2022-10-15"}) 

287 

288 with app.app_context(): 

289 with app.test_request_context(): 

290 response = user_model.change_deadline( 

291 "2024-01-16", "2024-01-15", "2024-01-31" 

292 ) 

293 json_data = response[0].get_json() 

294 assert response[1] == 400 

295 assert ( 

296 json_data["error"] 

297 == "Details deadline cannot be later than Student Ranking deadline." 

298 ) 

299 

300 database.delete_all("deadline") 

301 for deadline in deadlines: 

302 database.insert("deadline", deadline) 

303 

304 

305def test_update_deadlines_student_ranking_later_than_opportunities_ranking( 

306 app, database, user_model 

307): 

308 """Tests the change_deadline method of the User model 

309 with the student ranking deadline later than the opportunities ranking deadline.""" 

310 deadlines = database.get_all("deadline") 

311 if deadlines: 

312 database.delete_all("deadline") 

313 

314 database.insert("deadline", {"type": 0, "deadline": "2022-10-10"}) 

315 database.insert("deadline", {"type": 1, "deadline": "2022-10-12"}) 

316 database.insert("deadline", {"type": 2, "deadline": "2022-10-15"}) 

317 

318 with app.app_context(): 

319 with app.test_request_context(): 

320 response = user_model.change_deadline( 

321 "2024-01-15", "2024-01-31", "2024-01-30" 

322 ) 

323 json_data = response[0].get_json() 

324 assert response[1] == 400 

325 assert ( 

326 json_data["error"] 

327 == "Student Ranking deadline cannot be later than Opportunities Ranking deadline." 

328 ) 

329 

330 database.delete_all("deadline") 

331 for deadline in deadlines: 

332 database.insert("deadline", deadline) 

333 

334 

335def test_send_match_email(app, database, user_model): 

336 """Tests the send_match_email method of the User model.""" 

337 database.delete_all_by_field("students", "email", "dummy@dummy.com") 

338 database.delete_all_by_field("employers", "email", "dummy@dummy.com") 

339 database.delete_all_by_field("opportunities", "employer_id", "employer-uuid") 

340 

341 student_uuid = "student-uuid" 

342 student = { 

343 "_id": "student-uuid", 

344 "first_name": "Student", 

345 "last_name": "User", 

346 "email": "dummy@dummy.com", 

347 } 

348 database.insert("students", student) 

349 opportunity_uuid = "opportunity-uuid" 

350 opportunity = { 

351 "_id": "opportunity-uuid", 

352 "title": "Software Developer", 

353 "employer_id": "employer-uuid", 

354 } 

355 database.insert("opportunities", opportunity) 

356 

357 employer = { 

358 "_id": "employer-uuid", 

359 "company_name": "Employer", 

360 "email": "dummy@dummy.com", 

361 } 

362 database.insert("employers", employer) 

363 

364 with app.app_context(): 

365 with app.test_request_context(): 

366 response = user_model.send_match_email(student_uuid, opportunity_uuid) 

367 json_data = response[0].get_json() 

368 assert response[1] == 200 

369 assert json_data["message"] == "Email Sent" 

370 

371 database.delete_all_by_field("students", "email", "dummy@dummy.com") 

372 database.delete_all_by_field("employers", "email", "dummy@dummy.com") 

373 database.delete_all_by_field("opportunities", "employer_id", "employer-uuid") 

374 

375 

376def test_delete_user_success(app, database, user_model): 

377 """Tests the delete_user_by_uuid method of the User model.""" 

378 database.delete_all_by_field("users", "email", "delete@dummy.com") 

379 

380 user_uuid = "delete-success-uuid" 

381 user = { 

382 "_id": user_uuid, 

383 "name": "Delete User", 

384 "email": "delete@dummy.com", 

385 "password": "password", 

386 } 

387 

388 database.insert("users", user) 

389 

390 with app.app_context(): 

391 with app.test_request_context(): 

392 response = user_model.delete_user_by_uuid(user_uuid) 

393 json_data = response[0].get_json() 

394 assert response[1] == 200 

395 assert json_data["message"] == "User deleted successfully" 

396 assert database.get_one_by_id("users", user_uuid) is None 

397 

398 database.delete_all_by_field("users", "email", "delete@dummy.com") 

399 

400 

401def test_delete_user_not_found(app, user_model): 

402 """Tests the delete_user_by_uuid method of the User model when the user is not found.""" 

403 user_uuid = "non-existent-uuid" 

404 

405 with app.app_context(): 

406 with app.test_request_context(): 

407 response = user_model.delete_user_by_uuid(user_uuid) 

408 json_data = response[0].get_json() 

409 assert response[1] == 404 

410 assert json_data["error"] == "User not found" 

411 

412 

413def test_get_user_by_uuid_success(app, database, user_model): 

414 """Tests the get_user_by_uuid method of the User model.""" 

415 database.delete_all_by_field("users", "email", "get@dummy.com") 

416 

417 user_uuid = "get-success-uuid" 

418 user = { 

419 "_id": user_uuid, 

420 "name": "Get User", 

421 "email": "get@dummy.com", 

422 "password": "password", 

423 } 

424 

425 # Insert the user into the database 

426 database.insert("users", user) 

427 

428 with app.app_context(): 

429 with app.test_request_context(): 

430 retrieved_user = user_model.get_user_by_uuid(user_uuid) 

431 assert retrieved_user is not None 

432 assert retrieved_user["_id"] == user_uuid 

433 assert retrieved_user["email"] == "get@dummy.com" 

434 

435 database.delete_all_by_field("users", "email", "get@dummy.com") 

436 

437 

438def test_get_user_by_uuid_not_found(app, user_model): 

439 """Tests the get_user_by_uuid method of the User model when the user is not found.""" 

440 user_uuid = "non-existent-uuid" 

441 

442 with app.app_context(): 

443 with app.test_request_context(): 

444 retrieved_user = user_model.get_user_by_uuid(user_uuid) 

445 assert retrieved_user is None 

446 

447 

448def test_get_users_without_passwords(app, database, user_model): 

449 """Tests the get_users_without_passwords method of the User model.""" 

450 database.delete_all_by_field("users", "email", "nopassword1@dummy.com") 

451 database.delete_all_by_field("users", "email", "nopassword2@dummy.com") 

452 existing_users = database.get_all("users") 

453 database.delete_all("users") 

454 

455 user1 = { 

456 "_id": "user1-uuid", 

457 "name": "User One", 

458 "email": "nopassword1@dummy.com", 

459 "password": "password1", 

460 } 

461 user2 = { 

462 "_id": "user2-uuid", 

463 "name": "User Two", 

464 "email": "nopassword2@dummy.com", 

465 "password": "password2", 

466 } 

467 

468 database.insert("users", user1) 

469 database.insert("users", user2) 

470 

471 with app.app_context(): 

472 with app.test_request_context(): 

473 users = user_model.get_users_without_passwords() 

474 assert len(users) == 2 

475 for user in users: 

476 assert "password" not in user 

477 

478 database.delete_all_by_field("users", "email", "nopassword1@dummy.com") 

479 database.delete_all_by_field("users", "email", "nopassword2@dummy.com") 

480 

481 for user in existing_users: 

482 database.insert("users", user) 

483 

484 

485def test_update_user_success(app, database, user_model): 

486 """Tests the update_user method of the User model.""" 

487 database.delete_all_by_field("users", "email", "update@dummy.com") 

488 database.delete_all_by_field("users", "email", "updated@dummy.com") 

489 

490 user_uuid = "update-success-uuid" 

491 user = { 

492 "_id": user_uuid, 

493 "name": "Update User", 

494 "email": "update@dummy.com", 

495 "password": "password", 

496 } 

497 

498 database.insert("users", user) 

499 

500 with app.app_context(): 

501 with app.test_request_context(): 

502 response = user_model.update_user( 

503 user_uuid, "Updated Name", "updated@dummy.com" 

504 ) 

505 json_data = response[0].get_json() 

506 assert response[1] == 200 

507 assert json_data["message"] == "User updated successfully" 

508 updated_user = database.get_one_by_id("users", user_uuid) 

509 assert updated_user["name"] == "Updated Name" 

510 assert updated_user["email"] == "updated@dummy.com" 

511 

512 database.delete_all_by_field("users", "email", "update@dummy.com") 

513 database.delete_all_by_field("users", "email", "updated@dummy.com") 

514 

515 

516def test_update_user_email_in_use(app, database, user_model): 

517 """Tests the update_user method of the User model when the email is already in use.""" 

518 database.delete_all_by_field("users", "email", "update@dummy.com") 

519 database.delete_all_by_field("users", "email", "existing@dummy.com") 

520 

521 user_uuid = "update-email-in-use-uuid" 

522 user = { 

523 "_id": user_uuid, 

524 "name": "Update User", 

525 "email": "update@dummy.com", 

526 "password": "password", 

527 } 

528 

529 existing_user = { 

530 "_id": "existing-uuid", 

531 "name": "Existing User", 

532 "email": "existing@dummy.com", 

533 "password": "password", 

534 } 

535 

536 database.insert("users", user) 

537 database.insert("users", existing_user) 

538 

539 with app.app_context(): 

540 with app.test_request_context(): 

541 response = user_model.update_user( 

542 user_uuid, "Updated Name", "existing@dummy.com" 

543 ) 

544 json_data = response[0].get_json() 

545 assert response[1] == 400 

546 assert json_data["error"] == "Email address already in use" 

547 

548 database.delete_all_by_field("users", "email", "update@dummy.com") 

549 database.delete_all_by_field("users", "email", "existing@dummy.com") 

550 

551 

552def test_update_user_not_found(app, database, user_model): 

553 """Tests the update_user method of the User model when the user is not found.""" 

554 database.delete_all_by_field("users", "email", "update@dummy.com") 

555 

556 user_uuid = "non-existent-uuid" 

557 

558 with app.app_context(): 

559 with app.test_request_context(): 

560 response = user_model.update_user( 

561 user_uuid, "Updated Name", "update@dummy.com" 

562 ) 

563 json_data = response[0].get_json() 

564 assert response[1] == 404 

565 assert json_data["error"] == "User not found" 

566 

567 

568def test_change_password_success(app, database, user_model): 

569 """Tests the change_password method of the User model.""" 

570 database.delete_all_by_field("users", "email", "changepassword@dummy.com") 

571 

572 user_uuid = "change-password-uuid" 

573 user = { 

574 "_id": user_uuid, 

575 "name": "Change Password User", 

576 "email": "changepassword@dummy.com", 

577 "password": pbkdf2_sha512.hash("oldpassword"), 

578 } 

579 

580 database.insert("users", user) 

581 

582 with app.app_context(): 

583 with app.test_request_context(): 

584 response = user_model.change_password( 

585 user_uuid, "newpassword", "newpassword" 

586 ) 

587 json_data = response[0].get_json() 

588 assert response[1] == 200 

589 assert json_data["message"] == "Password updated successfully" 

590 updated_user = database.get_one_by_id("users", user_uuid) 

591 assert pbkdf2_sha512.verify("newpassword", updated_user["password"]) 

592 

593 database.delete_all_by_field("users", "email", "changepassword@dummy.com") 

594 

595 

596def test_change_password_mismatch(app, database, user_model): 

597 """Tests the change_password method of the User model when passwords don't match.""" 

598 database.delete_all_by_field("users", "email", "changepassword@dummy.com") 

599 

600 user_uuid = "change-password-uuid" 

601 user = { 

602 "_id": user_uuid, 

603 "name": "Change Password User", 

604 "email": "changepassword@dummy.com", 

605 "password": pbkdf2_sha512.hash("oldpassword"), 

606 } 

607 

608 database.insert("users", user) 

609 

610 with app.app_context(): 

611 with app.test_request_context(): 

612 response = user_model.change_password( 

613 user_uuid, "newpassword", "differentpassword" 

614 ) 

615 json_data = response[0].get_json() 

616 assert response[1] == 400 

617 assert json_data["error"] == "Passwords don't match" 

618 

619 database.delete_all_by_field("users", "email", "changepassword@dummy.com") 

620 

621 

622def test_register_missing_name(app, database, user_model): 

623 """Tests the register method of the User model when the request is missing the name.""" 

624 database.delete_all_by_field("users", "email", "dummy@dummy.com") 

625 user = { 

626 "_id": "128", 

627 "email": "dummy@dummy.com", 

628 "password": "password", 

629 } 

630 

631 with app.app_context(): 

632 with app.test_request_context(): 

633 response = user_model.register(user) 

634 json_data = response[0].get_json() 

635 assert response[1] == 400 

636 assert json_data["error"] == "Missing name" 

637 

638 database.delete_all_by_field("users", "email", "dummy@dummy.com")