diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 57bd1a7..6f82b8e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,15 +6,15 @@ on: - '**' # This will run the workflow on every push to any branch jobs: - # build_and_test: - # runs-on: ubuntu-latest + build_and_test: + runs-on: ubuntu-latest - # steps: - # - name: Checkout repository - # uses: actions/checkout@v2 + steps: + - name: Checkout repository + uses: actions/checkout@v2 - # - name: Run tests - # run: make test-ci + - name: Run tests + run: make test-ci pypi-publish: if: github.ref == 'refs/heads/main' diff --git a/conftest.py b/conftest.py index 66082d8..fac2806 100644 --- a/conftest.py +++ b/conftest.py @@ -1,3 +1,4 @@ +import pytest from fractal.matrix.async_client import FractalAsyncClient @@ -5,3 +6,17 @@ def test_fractal_async_client(): test_object = FractalAsyncClient() print("work") return test_object + + +@pytest.fixture() +def mock_async_context_manager(): + class AsyncContextManager: + async def __aenter__(self): + # Perform setup actions here + yield "async_context_value" + + async def __aexit__(self, exc_type, exc, tb): + # Perform cleanup actions here + pass + + return AsyncContextManager diff --git a/fractal/matrix/async_client.py b/fractal/matrix/async_client.py index 9a26624..08b9f13 100644 --- a/fractal/matrix/async_client.py +++ b/fractal/matrix/async_client.py @@ -117,6 +117,9 @@ async def invite(self, user_id: str, room_id: str, admin: bool = False) -> None: if not admin: raise Exception("FIXME: Only admin invites are supported for now.") + # ensure that the provided matrix_id is a valid matrix id. + parse_matrix_id(user_id) + # check if user_id is lowercase if not user_id.split("@")[1].islower(): raise Exception("Matrix ids must be lowercase.") @@ -270,6 +273,7 @@ async def upload_file( Args: file_path (str): The path to the file to upload. monitor (Optional[TransferMonitor]): A transfer monitor to use. Defaults to None. + filename (Optional[str]): Uploads the file using this file name. Defaults to None. Returns: str: The content uri of the uploaded file. diff --git a/tests/test_fractal_async_client_invite.py b/tests/test_fractal_async_client_invite.py index 8ee7d11..57b5c7d 100644 --- a/tests/test_fractal_async_client_invite.py +++ b/tests/test_fractal_async_client_invite.py @@ -2,6 +2,7 @@ import pytest from fractal.matrix.async_client import FractalAsyncClient +from fractal.matrix.exceptions import InvalidMatrixIdException from nio import ( RoomGetStateEventError, RoomGetStateEventResponse, @@ -59,9 +60,9 @@ async def test_invite_raise_exception_for_userID(): sample_user_id = "sample_user:sample_domain" sample_room_id = "sample_id" client = FractalAsyncClient() - with pytest.raises(Exception) as e: + with pytest.raises(InvalidMatrixIdException) as e: await client.invite(user_id=sample_user_id, room_id=sample_room_id, admin=True) - assert "Expected UserID string to start with" in str(e.value) + assert f"{sample_user_id} is not a valid Matrix ID." in str(e.value) async def test_invite_get_power_levels(): diff --git a/tests/test_matrix.py b/tests/test_matrix.py index dfb8f2f..ae6d584 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -19,6 +19,9 @@ JoinError, RegisterResponse, SyncError, + TransferMonitor, + UploadError, + UploadResponse, ) from nio.http import TransportResponse @@ -269,10 +272,58 @@ async def test_register_with_token(): client.register_with_token = AsyncMock() -async def test_upload_file_logger(): +async def test_upload_file_success_no_monitor(mock_async_context_manager): client = FractalAsyncClient() + success = (UploadResponse("http://Someurl"), {}) + client.upload = AsyncMock(return_value=success) file_path = "sample/file/path" # create mock to use fake file path for - with patch("fractal.matrix.async_client.logger", new=MagicMock()) as mock_logger: - await client.upload_file(file_path=file_path) - mock_logger.info.assert_called_once_with(f"Uploading file: {file_path}") + with patch("fractal.matrix.async_client.aiofiles_os.stat", new=AsyncMock()) as mock_file_stat: + with patch( + "fractal.matrix.async_client.aiofiles_open", + new=MagicMock(spec=mock_async_context_manager), + ) as mock_file_open: + with patch("fractal.matrix.async_client.logger", new=MagicMock()) as mock_logger: + content_uri = await client.upload_file(file_path=file_path) + assert content_uri == "http://Someurl" + mock_logger.info.assert_called_once_with(f"Uploading file: {file_path}") + client.upload.assert_called() + assert "monitor" not in client.upload.call_args.kwargs + + +async def test_upload_file_uploaderror(mock_async_context_manager): + client = FractalAsyncClient() + failure = (UploadError("Failed to upload file."), {}) + client.upload = AsyncMock(return_value=failure) + file_path = "sample/file/path" + # create mock to use fake file path for + with patch("fractal.matrix.async_client.aiofiles_os.stat", new=AsyncMock()) as mock_file_stat: + with patch( + "fractal.matrix.async_client.aiofiles_open", + new=MagicMock(spec=mock_async_context_manager), + ) as mock_file_open: + with patch("fractal.matrix.async_client.logger", new=MagicMock()) as mock_logger: + with pytest.raises(Exception) as e: + await client.upload_file(file_path=file_path) + assert "Failed to upload file." in str(e.value) + + +async def test_upload_file_monitor_success(mock_async_context_manager): + client = FractalAsyncClient() + success = (UploadResponse("http://Someurl"), {}) + client.upload = AsyncMock(return_value=success) + file_path = "sample/file/path" + # create mock to use fake file path for + with patch("fractal.matrix.async_client.aiofiles_os.stat", new=AsyncMock()) as mock_file_stat: + with patch( + "fractal.matrix.async_client.aiofiles_open", + new=MagicMock(spec=mock_async_context_manager), + ) as mock_file_open: + with patch("fractal.matrix.async_client.logger", new=MagicMock()) as mock_logger: + trans_monitor = TransferMonitor(total_size=10) + content_uri = await client.upload_file(file_path=file_path, monitor=trans_monitor) + assert content_uri == "http://Someurl" + mock_logger.info.assert_called_once_with(f"Uploading file: {file_path}") + assert "http://Someurl" in content_uri + client.upload.assert_called() + assert client.upload.call_args.kwargs["monitor"].total_size == 10 \ No newline at end of file