added circle CI config with basic unit tests
This commit is contained in:
38
.circleci/config.yml
Normal file
38
.circleci/config.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
version: 2.1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup:
|
||||||
|
docker:
|
||||||
|
- image: circleci/python:3.10
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -e .
|
||||||
|
pip install pytest pytest-mock
|
||||||
|
|
||||||
|
test:
|
||||||
|
docker:
|
||||||
|
- image: circleci/python:3.10
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Install dependencies
|
||||||
|
command: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -e .
|
||||||
|
pip install pytest pytest-mock
|
||||||
|
- run:
|
||||||
|
name: Run tests
|
||||||
|
command: pytest
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
test_workflow:
|
||||||
|
jobs:
|
||||||
|
- setup
|
||||||
|
- test:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
@@ -12,7 +12,9 @@ dependencies = [
|
|||||||
"tidalapi==0.7.6",
|
"tidalapi==0.7.6",
|
||||||
"pyyaml~=6.0",
|
"pyyaml~=6.0",
|
||||||
"tqdm~=4.64",
|
"tqdm~=4.64",
|
||||||
"sqlalchemy~=2.0"
|
"sqlalchemy~=2.0",
|
||||||
|
"pytest~=7.0",
|
||||||
|
"pytest-mock~=3.8"
|
||||||
]
|
]
|
||||||
|
|
||||||
[tools.setuptools.packages."spotify_to_tidal"]
|
[tools.setuptools.packages."spotify_to_tidal"]
|
||||||
|
|||||||
6
pytest.ini
Normal file
6
pytest.ini
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[pytest]
|
||||||
|
addopts = --maxfail=1 --disable-warnings
|
||||||
|
testpaths = tests
|
||||||
|
python_files = test_*.py
|
||||||
|
python_classes = Test*
|
||||||
|
python_functions = test_*
|
||||||
5
tests/conftest.py
Normal file
5
tests/conftest.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Add the src directory to the Python path
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")))
|
||||||
0
tests/unit/__init__.py
Normal file
0
tests/unit/__init__.py
Normal file
73
tests/unit/test_auth.py
Normal file
73
tests/unit/test_auth.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# tests/unit/test_auth.py
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import spotipy
|
||||||
|
import tidalapi
|
||||||
|
import yaml
|
||||||
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
from spotify_to_tidal.auth import open_spotify_session, open_tidal_session
|
||||||
|
|
||||||
|
|
||||||
|
def test_open_spotify_session(mocker):
|
||||||
|
# Mock the SpotifyOAuth class
|
||||||
|
mock_spotify_oauth = mocker.patch(
|
||||||
|
"spotify_to_tidal.auth.spotipy.SpotifyOAuth", autospec=True
|
||||||
|
)
|
||||||
|
mock_spotify_instance = mocker.patch(
|
||||||
|
"spotify_to_tidal.auth.spotipy.Spotify", autospec=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define a mock configuration
|
||||||
|
mock_config = {
|
||||||
|
"username": "test_user",
|
||||||
|
"client_id": "test_client_id",
|
||||||
|
"client_secret": "test_client_secret",
|
||||||
|
"redirect_uri": "http://localhost/",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a mock SpotifyOAuth instance
|
||||||
|
mock_oauth_instance = mock_spotify_oauth.return_value
|
||||||
|
mock_oauth_instance.get_access_token.return_value = "mock_access_token"
|
||||||
|
|
||||||
|
# Call the function under test
|
||||||
|
spotify_instance = open_spotify_session(mock_config)
|
||||||
|
|
||||||
|
# Assert that the SpotifyOAuth was called with correct parameters
|
||||||
|
mock_spotify_oauth.assert_called_once_with(
|
||||||
|
username="test_user",
|
||||||
|
scope="playlist-read-private",
|
||||||
|
client_id="test_client_id",
|
||||||
|
client_secret="test_client_secret",
|
||||||
|
redirect_uri="http://localhost/",
|
||||||
|
requests_timeout=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assert that the Spotify instance was created
|
||||||
|
mock_spotify_instance.assert_called_once_with(oauth_manager=mock_oauth_instance)
|
||||||
|
assert spotify_instance == mock_spotify_instance.return_value
|
||||||
|
|
||||||
|
|
||||||
|
def test_open_spotify_session_oauth_error(mocker):
|
||||||
|
# Mock the SpotifyOAuth class and simulate an OAuth error
|
||||||
|
mock_spotify_oauth = mocker.patch(
|
||||||
|
"spotify_to_tidal.auth.spotipy.SpotifyOAuth", autospec=True
|
||||||
|
)
|
||||||
|
mock_spotify_oauth.return_value.get_access_token.side_effect = (
|
||||||
|
spotipy.SpotifyOauthError("mock error")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define a mock configuration
|
||||||
|
mock_config = {
|
||||||
|
"username": "test_user",
|
||||||
|
"client_id": "test_client_id",
|
||||||
|
"client_secret": "test_client_secret",
|
||||||
|
"redirect_uri": "http://localhost/",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mock sys.exit to prevent the test from exiting
|
||||||
|
mock_sys_exit = mocker.patch("sys.exit")
|
||||||
|
|
||||||
|
# Call the function under test and assert sys.exit is called
|
||||||
|
open_spotify_session(mock_config)
|
||||||
|
mock_sys_exit.assert_called_once()
|
||||||
80
tests/unit/test_cache.py
Normal file
80
tests/unit/test_cache.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# tests/unit/test_cache.py
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import datetime
|
||||||
|
import sqlalchemy
|
||||||
|
from sqlalchemy import create_engine, select
|
||||||
|
from unittest import mock
|
||||||
|
from spotify_to_tidal.cache import MatchFailureDatabase, TrackMatchCache
|
||||||
|
|
||||||
|
|
||||||
|
# Setup an in-memory SQLite database for testing
|
||||||
|
@pytest.fixture
|
||||||
|
def in_memory_db():
|
||||||
|
engine = create_engine("sqlite:///:memory:")
|
||||||
|
return engine
|
||||||
|
|
||||||
|
|
||||||
|
# Test MatchFailureDatabase
|
||||||
|
def test_cache_match_failure(in_memory_db, mocker):
|
||||||
|
mocker.patch(
|
||||||
|
"spotify_to_tidal.cache.sqlalchemy.create_engine", return_value=in_memory_db
|
||||||
|
)
|
||||||
|
failure_db = MatchFailureDatabase()
|
||||||
|
|
||||||
|
track_id = "test_track"
|
||||||
|
failure_db.cache_match_failure(track_id)
|
||||||
|
|
||||||
|
with failure_db.engine.connect() as connection:
|
||||||
|
result = connection.execute(
|
||||||
|
select(failure_db.match_failures).where(
|
||||||
|
failure_db.match_failures.c.track_id == track_id
|
||||||
|
)
|
||||||
|
).fetchone()
|
||||||
|
assert result is not None
|
||||||
|
assert result.track_id == track_id
|
||||||
|
|
||||||
|
|
||||||
|
def test_has_match_failure(in_memory_db, mocker):
|
||||||
|
mocker.patch(
|
||||||
|
"spotify_to_tidal.cache.sqlalchemy.create_engine", return_value=in_memory_db
|
||||||
|
)
|
||||||
|
failure_db = MatchFailureDatabase()
|
||||||
|
|
||||||
|
track_id = "test_track"
|
||||||
|
failure_db.cache_match_failure(track_id)
|
||||||
|
|
||||||
|
assert failure_db.has_match_failure(track_id) is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_remove_match_failure(in_memory_db, mocker):
|
||||||
|
mocker.patch(
|
||||||
|
"spotify_to_tidal.cache.sqlalchemy.create_engine", return_value=in_memory_db
|
||||||
|
)
|
||||||
|
failure_db = MatchFailureDatabase()
|
||||||
|
|
||||||
|
track_id = "test_track"
|
||||||
|
failure_db.cache_match_failure(track_id)
|
||||||
|
failure_db.remove_match_failure(track_id)
|
||||||
|
|
||||||
|
with failure_db.engine.connect() as connection:
|
||||||
|
result = connection.execute(
|
||||||
|
select(failure_db.match_failures).where(
|
||||||
|
failure_db.match_failures.c.track_id == track_id
|
||||||
|
)
|
||||||
|
).fetchone()
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
|
||||||
|
# Test TrackMatchCache
|
||||||
|
def test_track_match_cache_insert():
|
||||||
|
track_cache = TrackMatchCache()
|
||||||
|
track_cache.insert(("spotify_id", 123))
|
||||||
|
assert track_cache.get("spotify_id") == 123
|
||||||
|
|
||||||
|
|
||||||
|
def test_track_match_cache_get():
|
||||||
|
track_cache = TrackMatchCache()
|
||||||
|
track_cache.insert(("spotify_id", 123))
|
||||||
|
assert track_cache.get("spotify_id") == 123
|
||||||
|
assert track_cache.get("nonexistent_id") is None
|
||||||
Reference in New Issue
Block a user