-
-
Notifications
You must be signed in to change notification settings - Fork 635
add database tests for albums and faces (#1238) #1342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Mansi2007275
wants to merge
2
commits into
AOSSIE-Org:main
Choose a base branch
from
Mansi2007275:add-database-tests-albums-faces
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+532
−0
Open
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,302 @@ | ||
| import pytest | ||
| import sqlite3 | ||
| import uuid | ||
| from unittest.mock import patch, MagicMock | ||
| from app.database.albums import ( | ||
| db_create_albums_table, | ||
| db_create_album_images_table, | ||
| db_get_all_albums, | ||
| db_get_album_by_name, | ||
| db_get_album, | ||
| db_insert_album, | ||
| db_update_album, | ||
| db_delete_album, | ||
| db_get_album_images, | ||
| db_remove_images_from_album, | ||
| verify_album_password, | ||
| ) | ||
|
|
||
|
|
||
| class TestDbCreateAlbumsTable: | ||
| # Tests that albums table is created without raising errors | ||
| def test_create_albums_table_success(self): | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_connect.return_value = mock_conn | ||
| db_create_albums_table() | ||
| mock_conn.cursor.return_value.execute.assert_called_once() | ||
| mock_conn.commit.assert_called_once() | ||
|
|
||
| # Tests that connection is closed even if an error occurs | ||
| def test_create_albums_table_closes_connection_on_error(self): | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_conn.cursor.return_value.execute.side_effect = sqlite3.Error("fail") | ||
| mock_connect.return_value = mock_conn | ||
| with pytest.raises(sqlite3.Error): | ||
| db_create_albums_table() | ||
| mock_conn.close.assert_called_once() | ||
|
|
||
|
|
||
| class TestDbCreateAlbumImagesTable: | ||
| # Tests that album_images table is created without raising errors | ||
| def test_create_album_images_table_success(self): | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_connect.return_value = mock_conn | ||
| db_create_album_images_table() | ||
| mock_conn.cursor.return_value.execute.assert_called_once() | ||
| mock_conn.commit.assert_called_once() | ||
|
|
||
|
|
||
| class TestDbGetAllAlbums: | ||
| # Tests that all visible albums are returned when show_hidden is False | ||
| def test_get_all_albums_public_only(self): | ||
| fake_albums = [ | ||
| ("id-1", "Album One", "Desc 1", 0, None), | ||
| ("id-2", "Album Two", "Desc 2", 0, None), | ||
| ] | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchall.return_value = fake_albums | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_all_albums(show_hidden=False) | ||
| assert result == fake_albums | ||
| mock_cursor.execute.assert_called_once_with( | ||
| "SELECT * FROM albums WHERE is_hidden = 0" | ||
| ) | ||
|
|
||
| # Tests that hidden albums are also returned when show_hidden is True | ||
| def test_get_all_albums_include_hidden(self): | ||
| fake_albums = [ | ||
| ("id-1", "Album One", "Desc 1", 0, None), | ||
| ("id-2", "Hidden Album", "Secret", 1, "hash"), | ||
| ] | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchall.return_value = fake_albums | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_all_albums(show_hidden=True) | ||
| assert result == fake_albums | ||
| mock_cursor.execute.assert_called_once_with("SELECT * FROM albums") | ||
|
|
||
| # Tests that an empty list is returned when no albums exist | ||
| def test_get_all_albums_empty(self): | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchall.return_value = [] | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_all_albums() | ||
| assert result == [] | ||
|
|
||
|
|
||
| class TestDbGetAlbumByName: | ||
| # Tests that correct album is returned when name matches | ||
| def test_get_album_by_name_found(self): | ||
| fake_album = ("id-1", "Summer Trip", "Fun times", 0, None) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = fake_album | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_album_by_name("Summer Trip") | ||
| assert result == fake_album | ||
|
|
||
| # Tests that None is returned when album name does not exist | ||
| def test_get_album_by_name_not_found(self): | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = None | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_album_by_name("Nonexistent") | ||
| assert result is None | ||
|
|
||
|
|
||
| class TestDbGetAlbum: | ||
| # Tests that correct album is returned when album_id matches | ||
| def test_get_album_found(self): | ||
| album_id = str(uuid.uuid4()) | ||
| fake_album = (album_id, "My Album", "Description", 0, None) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = fake_album | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_album(album_id) | ||
| assert result == fake_album | ||
|
|
||
| # Tests that None is returned when album_id does not exist | ||
| def test_get_album_not_found(self): | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = None | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_album("nonexistent-id") | ||
| assert result is None | ||
|
|
||
|
|
||
| class TestDbInsertAlbum: | ||
| # Tests that a basic album without password is inserted correctly | ||
| def test_insert_album_without_password(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| db_insert_album(album_id, "Test Album", "A description", False, None) | ||
| mock_cursor.execute.assert_called_once() | ||
| mock_conn.commit.assert_called_once() | ||
|
|
||
| # Tests that a password is hashed before being stored in the database | ||
| def test_insert_album_with_password_hashes_it(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| db_insert_album(album_id, "Secret Album", "Hidden", True, "mypassword") | ||
| call_args = mock_cursor.execute.call_args[0][1] | ||
| # password_hash should not be plain text | ||
| assert call_args[4] != "mypassword" | ||
| assert call_args[4] is not None | ||
|
|
||
|
|
||
| class TestDbUpdateAlbum: | ||
| # Tests that album fields are updated correctly without changing password | ||
| def test_update_album_without_password(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| db_update_album(album_id, "New Name", "New Desc", False, None) | ||
| mock_cursor.execute.assert_called_once() | ||
| mock_conn.commit.assert_called_once() | ||
|
|
||
| # Tests that password is hashed when updating album with a new password | ||
| def test_update_album_with_new_password(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| db_update_album(album_id, "New Name", "New Desc", True, "newpassword") | ||
| call_args = mock_cursor.execute.call_args[0][1] | ||
| assert call_args[3] != "newpassword" | ||
|
|
||
|
|
||
| class TestDbDeleteAlbum: | ||
| # Tests that delete is called with the correct album_id | ||
| def test_delete_album_success(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.get_db_connection") as mock_conn_ctx: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_conn_ctx.return_value.__enter__ = MagicMock(return_value=mock_conn) | ||
| mock_conn_ctx.return_value.__exit__ = MagicMock(return_value=False) | ||
| db_delete_album(album_id) | ||
| mock_cursor.execute.assert_called_once_with( | ||
| "DELETE FROM albums WHERE album_id = ?", (album_id,) | ||
| ) | ||
|
|
||
|
|
||
| class TestDbGetAlbumImages: | ||
| # Tests that list of image IDs is returned for a valid album | ||
| def test_get_album_images_returns_list(self): | ||
| album_id = str(uuid.uuid4()) | ||
| fake_images = [("img-1",), ("img-2",), ("img-3",)] | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchall.return_value = fake_images | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_album_images(album_id) | ||
| assert result == ["img-1", "img-2", "img-3"] | ||
|
|
||
| # Tests that empty list is returned when album has no images | ||
| def test_get_album_images_empty(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchall.return_value = [] | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = db_get_album_images(album_id) | ||
| assert result == [] | ||
|
|
||
|
|
||
| class TestDbRemoveImagesFromAlbum: | ||
| # Tests that multiple images are removed from album in one call | ||
| def test_remove_images_from_album(self): | ||
| album_id = str(uuid.uuid4()) | ||
| image_ids = ["img-1", "img-2"] | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| db_remove_images_from_album(album_id, image_ids) | ||
| mock_cursor.executemany.assert_called_once() | ||
| mock_conn.commit.assert_called_once() | ||
|
|
||
|
|
||
| class TestVerifyAlbumPassword: | ||
| # Tests that correct password returns True | ||
| def test_verify_correct_password(self): | ||
| import bcrypt | ||
| album_id = str(uuid.uuid4()) | ||
| password = "securepass" | ||
| hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = (hashed,) | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = verify_album_password(album_id, password) | ||
| assert result is True | ||
|
|
||
| # Tests that wrong password returns False | ||
| def test_verify_wrong_password(self): | ||
| import bcrypt | ||
| album_id = str(uuid.uuid4()) | ||
| hashed = bcrypt.hashpw("correct".encode(), bcrypt.gensalt()).decode() | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = (hashed,) | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = verify_album_password(album_id, "wrongpass") | ||
| assert result is False | ||
|
|
||
| # Tests that missing album returns False without error | ||
| def test_verify_album_not_found_returns_false(self): | ||
| album_id = str(uuid.uuid4()) | ||
| with patch("app.database.albums.sqlite3.connect") as mock_connect: | ||
| mock_conn = MagicMock() | ||
| mock_cursor = MagicMock() | ||
| mock_cursor.fetchone.return_value = None | ||
| mock_conn.cursor.return_value = mock_cursor | ||
| mock_connect.return_value = mock_conn | ||
| result = verify_album_password(album_id, "anypassword") | ||
| assert result is False | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.