diff --git a/modules/odr_core/odr_core/models/base.py b/modules/odr_core/odr_core/models/base.py index 0433648..90b3490 100644 --- a/modules/odr_core/odr_core/models/base.py +++ b/modules/odr_core/odr_core/models/base.py @@ -1,3 +1,3 @@ -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import declarative_base # Create Base class Base = declarative_base() diff --git a/modules/odr_core/odr_core/models/content.py b/modules/odr_core/odr_core/models/content.py index 36ed82f..a7ccc53 100644 --- a/modules/odr_core/odr_core/models/content.py +++ b/modules/odr_core/odr_core/models/content.py @@ -10,26 +10,26 @@ ARRAY, DateTime, ) -from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import relationship from sqlalchemy.sql import func from odr_core.models.base import Base +from sqlalchemy import Enum as SQLAlchemyEnum import enum class ContentType(enum.Enum): - IMAGE = "image" - VIDEO = "video" - VOICE = "voice" - MUSIC = "music" - TEXT = "text" + IMAGE = "IMAGE" + VIDEO = "VIDEO" + VOICE = "VOICE" + MUSIC = "MUSIC" + TEXT = "TEXT" class ContentStatus(enum.Enum): - PENDING = "pending" - AVAILABLE = "available" - UNAVAILABLE = "unavailable" - DELISTED = "delisted" + PENDING = "PENDING" + AVAILABLE = "AVAILABLE" + UNAVAILABLE = "UNAVAILABLE" + DELISTED = "DELISTED" class ContentSourceType(enum.Enum): @@ -44,13 +44,15 @@ class Content(Base): id = Column(Integer, primary_key=True, index=True) name = Column(String, nullable=True) type = Column(Enum(ContentType)) + type = Column(SQLAlchemyEnum(ContentType)) hash = Column(String, index=True) phash = Column(String, index=True) + url = Column(String, nullable=True) width = Column(Integer, nullable=True) height = Column(Integer, nullable=True) format = Column(String) size = Column(Integer) - status = Column(Enum(ContentStatus), default=ContentStatus.PENDING) + status = Column(SQLAlchemyEnum(ContentStatus), default=ContentStatus.PENDING) license = Column(String) license_url = Column(String, nullable=True) flags = Column(Integer, default=0) @@ -91,7 +93,7 @@ class ContentSource(Base): content_id = Column(Integer, ForeignKey("contents.id")) type = Column(Enum(ContentSourceType)) value = Column(String, unique=True) - source_metadata = Column(JSONB, nullable=True) + source_metadata = Column(String, nullable=True) # JSON created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) diff --git a/modules/odr_core/odr_core/models/team.py b/modules/odr_core/odr_core/models/team.py index aa28460..ad7ee7a 100644 --- a/modules/odr_core/odr_core/models/team.py +++ b/modules/odr_core/odr_core/models/team.py @@ -27,8 +27,5 @@ class UserTeam(Base): team_id = Column(Integer, ForeignKey("teams.id"), primary_key=True) role = Column(String) # e.g., 'admin', 'member' - user = relationship("User", back_populates="team_users") - team = relationship("Team", back_populates="team_users") - created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) diff --git a/modules/odr_core/odr_core/schemas/content.py b/modules/odr_core/odr_core/schemas/content.py index d6fbdab..64c46f6 100644 --- a/modules/odr_core/odr_core/schemas/content.py +++ b/modules/odr_core/odr_core/schemas/content.py @@ -5,24 +5,24 @@ class ContentType(str, Enum): - IMAGE = "image" - VIDEO = "video" - VOICE = "voice" - MUSIC = "music" - TEXT = "text" + IMAGE = "IMAGE" + VIDEO = "VIDEO" + VOICE = "VOICE" + MUSIC = "MUSIC" + TEXT = "TEXT" class ContentStatus(str, Enum): - PENDING = "pending" - AVAILABLE = "available" - UNAVAILABLE = "unavailable" - DELISTED = "delisted" + PENDING = "PENDING" + AVAILABLE = "AVAILABLE" + UNAVAILABLE = "UNAVAILABLE" + DELISTED = "DELISTED" class ContentSourceType(str, Enum): - URL = "url" - PATH = "path" - HUGGING_FACE = "hugging_face" + URL = "URL" + PATH = "PATH" + HUGGING_FACE = "HUGGING_FACE" class ContentAuthorBase(BaseModel): @@ -79,6 +79,7 @@ class ContentBase(BaseModel): phash: str width: Optional[int] = None height: Optional[int] = None + url: List[HttpUrl] = [] format: str size: int status: ContentStatus = ContentStatus.PENDING diff --git a/modules/odr_core/pytest.ini b/modules/odr_core/pytest.ini new file mode 100644 index 0000000..db66e77 --- /dev/null +++ b/modules/odr_core/pytest.ini @@ -0,0 +1,9 @@ +[pytest] +pythonpath = . +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* +markers = + unit: marks unit tests + integration: marks integration tests diff --git a/modules/odr_core/tests/conftest.py b/modules/odr_core/tests/conftest.py new file mode 100644 index 0000000..e4a34cf --- /dev/null +++ b/modules/odr_core/tests/conftest.py @@ -0,0 +1,40 @@ +import pytest +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from odr_core.models.base import Base +from odr_core.schemas.user import UserCreate +from odr_core.crud.user import create_user + +# Use an in-memory SQLite database for testing +SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:" + + +@pytest.fixture(scope="session") +def engine(): + return create_engine(SQLALCHEMY_DATABASE_URL) + + +@pytest.fixture(scope="session") +def TestingSessionLocal(engine): + return sessionmaker(autocommit=False, autoflush=False, bind=engine) + + +@pytest.fixture(scope="function") +def db(TestingSessionLocal, engine): + Base.metadata.create_all(bind=engine) + db = TestingSessionLocal() + try: + yield db + finally: + db.close() + Base.metadata.drop_all(bind=engine) + + +@pytest.fixture(scope="function") +def test_user(db): + user_data = UserCreate( + username="testuser", + email="test@example.com", + password="testpassword" + ) + return create_user(db, user_data) diff --git a/modules/odr_core/tests/integration/api/test_content_api.py b/modules/odr_core/tests/integration/api/test_content_api.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/integration/api/test_team_api.py b/modules/odr_core/tests/integration/api/test_team_api.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/integration/api/test_user_api.py b/modules/odr_core/tests/integration/api/test_user_api.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/test_database.py b/modules/odr_core/tests/integration/db/test_database.py similarity index 100% rename from modules/odr_core/tests/test_database.py rename to modules/odr_core/tests/integration/db/test_database.py diff --git a/modules/odr_core/tests/test_db_manager.py b/modules/odr_core/tests/integration/db/test_db_manager.py similarity index 100% rename from modules/odr_core/tests/test_db_manager.py rename to modules/odr_core/tests/integration/db/test_db_manager.py diff --git a/modules/odr_core/tests/test_user.py b/modules/odr_core/tests/test_user.py deleted file mode 100644 index 98255eb..0000000 --- a/modules/odr_core/tests/test_user.py +++ /dev/null @@ -1,68 +0,0 @@ -import pytest -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker -from odr_core.models.user import User -from odr_core.schemas.user import UserCreate, User as UserSchema -from odr_core.models.base import Base - -# Use an in-memory SQLite database for testing -SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:" - -engine = create_engine(SQLALCHEMY_DATABASE_URL) -TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - - -@pytest.fixture(scope="function") -def db(): - Base.metadata.create_all(bind=engine) - db = TestingSessionLocal() - try: - yield db - finally: - db.close() - Base.metadata.drop_all(bind=engine) - - -def test_create_user(db): - user_data = UserCreate( - username="testuser", - email="test@example.com", - password="testpassword" - ) - db_user = User( - username=user_data.username, - email=user_data.email, - hashed_password="hashed_" + user_data.password - ) - db.add(db_user) - db.commit() - db.refresh(db_user) - - assert db_user.id is not None - assert db_user.username == "testuser" - assert db_user.email == "test@example.com" - assert db_user.hashed_password == "hashed_testpassword" - assert db_user.is_active is True - assert db_user.is_superuser is False - - -def test_user_schema(): - user_data = { - "id": 1, - "username": "testuser", - "email": "test@example.com", - "is_active": True, - "is_superuser": False, - "created_at": "2023-01-01T00:00:00", - "updated_at": "2023-01-01T00:00:00" - } - user = UserSchema(**user_data) - assert user.id == 1 - assert user.username == "testuser" - assert user.email == "test@example.com" - assert user.is_active is True - assert user.is_superuser is False - - -if __name__ == "__main__": - pytest.main([__file__]) diff --git a/modules/odr_core/tests/test_user_crud.py b/modules/odr_core/tests/test_user_crud.py deleted file mode 100644 index 383368d..0000000 --- a/modules/odr_core/tests/test_user_crud.py +++ /dev/null @@ -1,93 +0,0 @@ -import pytest -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker -from odr_core.models.user import User -from odr_core.schemas.user import UserCreate -from odr_core.crud.user import create_user, get_user, get_user_by_email, get_user_by_username -from odr_core.models.base import Base - -# Use an in-memory SQLite database for testing -SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:" - -engine = create_engine(SQLALCHEMY_DATABASE_URL) -TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - - -@pytest.fixture(scope="function") -def db(): - Base.metadata.create_all(bind=engine) - db = TestingSessionLocal() - try: - yield db - finally: - db.close() - Base.metadata.drop_all(bind=engine) - - -def test_create_user(db): - user_data = UserCreate( - username="testuser", - email="test@example.com", - password="testpassword" - ) - db_user = create_user(db, user_data) - assert db_user.id is not None - assert db_user.username == "testuser" - assert db_user.email == "test@example.com" - assert db_user.hashed_password == "testpassword_notreallyhashed" - assert db_user.is_active is True - assert db_user.is_superuser is False - - -def test_get_user(db): - user_data = UserCreate( - username="testuser", - email="test@example.com", - password="testpassword" - ) - created_user = create_user(db, user_data) - - retrieved_user = get_user(db, created_user.id) - assert retrieved_user is not None - assert retrieved_user.id == created_user.id - assert retrieved_user.username == "testuser" - assert retrieved_user.email == "test@example.com" - - -def test_get_user_by_email(db): - user_data = UserCreate( - username="testuser", - email="test@example.com", - password="testpassword" - ) - created_user = create_user(db, user_data) - - retrieved_user = get_user_by_email(db, "test@example.com") - assert retrieved_user is not None - assert retrieved_user.id == created_user.id - assert retrieved_user.username == "testuser" - assert retrieved_user.email == "test@example.com" - - -def test_get_user_by_username(db): - user_data = UserCreate( - username="testuser", - email="test@example.com", - password="testpassword" - ) - created_user = create_user(db, user_data) - - retrieved_user = get_user_by_username(db, "testuser") - assert retrieved_user is not None - assert retrieved_user.id == created_user.id - assert retrieved_user.username == "testuser" - assert retrieved_user.email == "test@example.com" - - -def test_get_non_existent_user(db): - non_existent_user = get_user(db, 999) # Assuming 999 is not a valid user id - assert non_existent_user is None - - -if __name__ == "__main__": - pytest.main([__file__]) diff --git a/modules/odr_core/tests/test_config.py b/modules/odr_core/tests/unit/config/test_config.py similarity index 80% rename from modules/odr_core/tests/test_config.py rename to modules/odr_core/tests/unit/config/test_config.py index e39c8f0..c906281 100644 --- a/modules/odr_core/tests/test_config.py +++ b/modules/odr_core/tests/unit/config/test_config.py @@ -4,7 +4,7 @@ def test_settings(): assert settings.get_db_url().startswith("postgresql://") assert settings.API_V1_STR == "/api/v1" - assert settings.PROJECT_NAME == "Open Data Repository" + assert settings.PROJECT_NAME == "OMI-DataModel" if __name__ == "__main__": diff --git a/modules/odr_core/tests/unit/crud/test_content_crud.py b/modules/odr_core/tests/unit/crud/test_content_crud.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/unit/crud/test_team_crud.py b/modules/odr_core/tests/unit/crud/test_team_crud.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/unit/crud/test_user_crud.py b/modules/odr_core/tests/unit/crud/test_user_crud.py new file mode 100644 index 0000000..c5b8528 --- /dev/null +++ b/modules/odr_core/tests/unit/crud/test_user_crud.py @@ -0,0 +1,92 @@ +import pytest +from odr_core.crud.user import create_user, get_user, get_user_by_email, update_user, delete_user, get_user_by_username +from odr_core.schemas.user import UserCreate, UserUpdate + + +def test_create_user(db): + user_data = UserCreate( + username="newuser", + email="newuser@example.com", + password="newpassword" + ) + user = create_user(db, user_data) + assert user.id is not None + assert user.username == "newuser" + assert user.email == "newuser@example.com" + assert user.hashed_password != "newpassword" + assert user.is_active is True + assert user.is_superuser is False + + +def test_get_user(db): + user_data = UserCreate( + username="getuser", + email="getuser@example.com", + password="getpassword" + ) + created_user = create_user(db, user_data) + retrieved_user = get_user(db, user_id=created_user.id) + assert retrieved_user is not None + assert retrieved_user.id == created_user.id + assert retrieved_user.username == "getuser" + assert retrieved_user.email == "getuser@example.com" + + +def test_update_user(db): + user_data = UserCreate( + username="updateuser_before", + email="updateuser_before@example.com", + password="updatepassword" + ) + created_user = create_user(db, user_data) + update_data = UserUpdate(username="updateduser_after", email="updateuser_after@example.com") + updated_user = update_user(db, user_id=created_user.id, user=update_data) + assert updated_user.username == "updateduser_after" + assert updated_user.email == "updateuser_after@example.com" + + +def test_delete_user(db): + user_data = UserCreate( + username="deleteuser", + email="deleteuser@example.com", + password="deletepassword" + ) + created_user = create_user(db, user_data) + delete_user(db, user_id=created_user.id) + deleted_user = get_user(db, user_id=created_user.id) + assert deleted_user is None + + +def test_get_user_by_email(db): + user_data = UserCreate( + username="testuser", + email="test@example.com", + password="testpassword" + ) + created_user = create_user(db, user_data) + + retrieved_user = get_user_by_email(db, "test@example.com") + assert retrieved_user is not None + assert retrieved_user.id == created_user.id + assert retrieved_user.username == "testuser" + assert retrieved_user.email == "test@example.com" + + +def test_get_user_by_username(db): + user_data = UserCreate( + username="testuser", + email="test@example.com", + password="testpassword" + ) + created_user = create_user(db, user_data) + + retrieved_user = get_user_by_username(db, "testuser") + assert retrieved_user is not None + assert retrieved_user.id == created_user.id + assert retrieved_user.username == "testuser" + assert retrieved_user.email == "test@example.com" + + +def test_get_non_existent_user(db): + non_existent_user = get_user(db, 999) # Assuming 999 is not a valid user id + assert non_existent_user is None diff --git a/modules/odr_core/tests/test_content_model.py b/modules/odr_core/tests/unit/models/test_content.py similarity index 55% rename from modules/odr_core/tests/test_content_model.py rename to modules/odr_core/tests/unit/models/test_content.py index f1c898d..a7b5dfb 100644 --- a/modules/odr_core/tests/test_content_model.py +++ b/modules/odr_core/tests/unit/models/test_content.py @@ -1,24 +1,6 @@ import pytest from odr_core.models.content import Content, ContentType, ContentStatus, ContentAuthor from odr_core.schemas.content import ContentCreate, Content as ContentSchema -from .test_db_manager import TestDBManager - - -@pytest.fixture(scope="module", autouse=True) -def setup_test_db(): - TestDBManager.setup_test_db() - yield - TestDBManager.drop_test_db() - - -@pytest.fixture(scope="function") -def db(): - session = TestDBManager.get_test_db_session() - try: - yield session - finally: - TestDBManager.teardown_test_db(session) - session.close() def test_create_content(db): @@ -28,21 +10,21 @@ def test_create_content(db): hash="abcdef123456", phash="123456abcdef", url=["http://example.com/image1.jpg", "http://example.com/image1.png"], + sources=[], format="png", size=1024, license="CC0", - from_user_id=1 ) + url_list = [str(url) for url in content_data.url] db_content = Content( name=content_data.name, type=content_data.type, hash=content_data.hash, phash=content_data.phash, - url=content_data.url, + url=' '.join(url_list), format=content_data.format, size=content_data.size, license=content_data.license, - from_user_id=content_data.from_user_id ) db.add(db_content) db.commit() @@ -53,8 +35,7 @@ def test_create_content(db): assert db_content.type == ContentType.IMAGE assert db_content.hash == "abcdef123456" assert db_content.status == ContentStatus.PENDING - assert db_content.from_user_id == 1 - assert len(db_content.url) == 2 + assert len(db_content.url.split(' ')) == 2 assert "http://example.com/image1.jpg" in db_content.url @@ -64,7 +45,7 @@ def test_content_author_relationship(db): type=ContentType.IMAGE, hash="abcdef123456", phash="123456abcdef", - url=["http://example.com/image2.jpg"], + url="http://example.com/image2.jpg", format="png", size=1024, license="CC0", @@ -81,31 +62,5 @@ def test_content_author_relationship(db): assert content.content_authors[0].name == "John Doe" -def test_content_schema(): - content_data = { - "id": 1, - "name": "Test Image", - "type": "image", - "hash": "abcdef123456", - "phash": "123456abcdef", - "url": ["http://example.com/image3.jpg"], - "format": "png", - "size": 1024, - "status": "pending", - "license": "CC0", - "from_user_id": 1, - "created_at": "2023-01-01T00:00:00", - "updated_at": "2023-01-01T00:00:00" - } - content = ContentSchema(**content_data) - assert content.id == 1 - assert content.name == "Test Image" - assert content.type == ContentType.IMAGE - assert content.hash == "abcdef123456" - assert content.status == ContentStatus.PENDING - assert len(content.url) == 1 - assert content.url[0] == "http://example.com/image3.jpg" - - if __name__ == "__main__": pytest.main([__file__]) diff --git a/modules/odr_core/tests/unit/models/test_team.py b/modules/odr_core/tests/unit/models/test_team.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/unit/models/test_user.py b/modules/odr_core/tests/unit/models/test_user.py new file mode 100644 index 0000000..5b0bd11 --- /dev/null +++ b/modules/odr_core/tests/unit/models/test_user.py @@ -0,0 +1,13 @@ +import pytest +from odr_core.models.user import User + + +def test_user_model_creation(): + user = User( + username="testuser", + email="test@example.com", + hashed_password="hashedpassword" + ) + assert user.username == "testuser" + assert user.email == "test@example.com" + assert user.hashed_password == "hashedpassword" diff --git a/modules/odr_core/tests/unit/schemas/test_content_schema.py b/modules/odr_core/tests/unit/schemas/test_content_schema.py new file mode 100644 index 0000000..4be5656 --- /dev/null +++ b/modules/odr_core/tests/unit/schemas/test_content_schema.py @@ -0,0 +1,33 @@ +import pytest +from odr_core.models.content import ContentType, ContentStatus +from odr_core.schemas.content import Content as ContentSchema + + +def test_content_schema(): + content_data = { + "id": 1, + "name": "Test Image", + "type": ContentType.IMAGE, + "hash": "abcdef123456", + "phash": "123456abcdef", + "url": ["http://example.com/image3.jpg"], + "format": "png", + "size": 1024, + "status": ContentStatus.PENDING, + "license": "CC0", + "from_user_id": 1, + "created_at": "2023-01-01T00:00:00", + "updated_at": "2023-01-01T00:00:00" + } + content = ContentSchema(**content_data) + assert content.id == 1 + assert content.name == "Test Image" + assert content.type == ContentType.IMAGE.value + assert content.hash == "abcdef123456" + assert content.status == ContentStatus.PENDING.value + assert len(content.url) == 1 + assert content.url[0].unicode_string() == "http://example.com/image3.jpg" + + +if __name__ == "__main__": + pytest.main([__file__]) diff --git a/modules/odr_core/tests/unit/schemas/test_team_schema.py b/modules/odr_core/tests/unit/schemas/test_team_schema.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/odr_core/tests/unit/schemas/test_user_schema.py b/modules/odr_core/tests/unit/schemas/test_user_schema.py new file mode 100644 index 0000000..03b8d90 --- /dev/null +++ b/modules/odr_core/tests/unit/schemas/test_user_schema.py @@ -0,0 +1,19 @@ +from odr_core.schemas.user import UserCreate, User as UserSchema + + +def test_user_schema(): + user_data = { + "id": 1, + "username": "testuser", + "email": "test@example.com", + "is_active": True, + "is_superuser": False, + "created_at": "2023-01-01T00:00:00", + "updated_at": "2023-01-01T00:00:00" + } + user = UserSchema(**user_data) + assert user.id == 1 + assert user.username == "testuser" + assert user.email == "test@example.com" + assert user.is_active is True + assert user.is_superuser is False