From c447110e82b71e76d8552f494cfc82c51974193b Mon Sep 17 00:00:00 2001 From: mrzengel <99219497+mrzengel@users.noreply.github.com> Date: Tue, 23 Jul 2024 17:16:06 +0200 Subject: [PATCH] Unit testing (#41) * developed unit testing * fixed asynchronous errors * test action script * fix * test * fix * test * took out redundant workflow * took out debug * secret test * attempted fix * test * unmocking * fix --- .github/actions/setup/action.yml | 75 ------------------- .github/actions/test/action.yml | 10 +++ .github/workflows/build.yaml | 6 ++ requirements.txt | 4 +- zenodo_jupyterlab/server/handlers.py | 4 +- zenodo_jupyterlab/server/testConnection.py | 5 +- zenodo_jupyterlab/server/tests/test_search.py | 74 ++++++++++++++++++ .../server/tests/test_testConnection.py | 37 +++++++++ 8 files changed, 134 insertions(+), 81 deletions(-) delete mode 100644 .github/actions/setup/action.yml create mode 100644 .github/actions/test/action.yml create mode 100644 zenodo_jupyterlab/server/tests/test_search.py create mode 100644 zenodo_jupyterlab/server/tests/test_testConnection.py diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml deleted file mode 100644 index c2098b6..0000000 --- a/.github/actions/setup/action.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: "Setup" -runs: - using: "composite" - steps: - # - name: Install Node - # uses: actions/setup-node@v4 - # with: - # node-version: '20.x' - - - name: Setup Conda - uses: conda-incubator/setup-miniconda@v3 - with: - auto-update-conda: true - - - name: Testing conda env in separate job - run: | - conda deactivate - conda info --envs - shell: bash -l {0} - - - name: Create and activate conda environment - run: | - conda config --set always_yes yes --set changeps1 no - conda init bash - source ~/.bashrc - conda create -n jupyterlab-ext --override-channels --strict-channel-priority -c conda-forge -c nodefaults jupyterlab=4 nodejs=20 git copier=9 jinja2-time - conda info --envs - conda activate jupyterlab-ext - conda info --envs - shell: bash -l {0} - - - name: Verify Node.js Installation - run: | - source ~/.bashrc - conda activate jupyterlab-ext - node -v - npm -v - shell: bash - - - name: Clearing cache to ensure correct yarn usage - run: | - rm -rf node_modules - rm -rf .yarn/cache - shell: bash - - - name: Install yarn - run: | - source ~/.bashrc - conda activate jupyterlab-ext - npm install -g yarn@1.22.22 - export PATH=$(npm bin -g):$PATH - which yarn - sed -i 's/yarnPath/# yarnPath/' .yarnrc.yml - yarn --version - echo $PATH - which yarn - yarn --version - yarn cache clean - yarn install - yarn --version - shell: bash -l {0} - - - name: Verify yarn installation - run: | - source ~/.bashrc - conda activate jupyterlab-ext - yarn --version - shell: bash - - - name: Running Yarn Build - run: | - source ~/.bashrc - conda activate jupyterlab-ext - yarn run build - shell: bash \ No newline at end of file diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml new file mode 100644 index 0000000..29f7ac2 --- /dev/null +++ b/.github/actions/test/action.yml @@ -0,0 +1,10 @@ +name: "Test" + +runs: + using: "composite" + steps: + - name: Run Pytest + env: + CI_ZENODO_API_KEY: ${{ secrets.CI_ZENODO_API_KEY }} + run: pytest zenodo_jupyterlab/server/tests + shell: bash \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1b2cdef..287fddc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -77,6 +77,12 @@ jobs: jupyter server extension enable zenodo_jupyterlab.server shell: bash + - name: Run Pytest + env: + CI_ZENODO_API_KEY: ${{ secrets.CI_ZENODO_API_KEY }} + run: pytest zenodo_jupyterlab/server/tests + shell: bash + # install_extension: # runs-on: ubuntu-latest diff --git a/requirements.txt b/requirements.txt index 64eda07..3f047ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ jupyterlab>4,<5 notebook<7 -eossr \ No newline at end of file +eossr +pytest +pytest-asyncio \ No newline at end of file diff --git a/zenodo_jupyterlab/server/handlers.py b/zenodo_jupyterlab/server/handlers.py index 38963bd..7ce592c 100644 --- a/zenodo_jupyterlab/server/handlers.py +++ b/zenodo_jupyterlab/server/handlers.py @@ -3,7 +3,7 @@ from jupyter_server.base.handlers import APIHandler, JupyterHandler from jupyter_server.utils import url_path_join import os -from .testConnection import testZenodoConnection +from .testConnection import checkZenodoConnection from .search import searchRecords, searchCommunities, recordInformation @@ -25,7 +25,7 @@ async def post(self): class ZenodoTestHandler(APIHandler): async def get(self): - response = await testZenodoConnection() + response = await checkZenodoConnection(sandbox = False) self.finish({'status': response}) class XSRFTokenHandler(JupyterHandler): diff --git a/zenodo_jupyterlab/server/testConnection.py b/zenodo_jupyterlab/server/testConnection.py index bf97f9d..7ed6dce 100644 --- a/zenodo_jupyterlab/server/testConnection.py +++ b/zenodo_jupyterlab/server/testConnection.py @@ -1,12 +1,11 @@ from eossr.api.zenodo import ZenodoAPI -from eossr.api.zenodo import http_status import os #ZenodoHTTPStatus -async def testZenodoConnection(): +async def checkZenodoConnection(sandbox: bool): access_token = os.environ['ZENODO_API_KEY'] - z = ZenodoAPI(access_token=access_token) + z = ZenodoAPI(access_token=access_token, sandbox = sandbox) try: response = z.query_user_deposits() return response.status_code diff --git a/zenodo_jupyterlab/server/tests/test_search.py b/zenodo_jupyterlab/server/tests/test_search.py new file mode 100644 index 0000000..dce0d08 --- /dev/null +++ b/zenodo_jupyterlab/server/tests/test_search.py @@ -0,0 +1,74 @@ +from unittest.mock import Mock, patch, AsyncMock +from eossr.api.zenodo import search_records, search_communities, get_record +import pytest +from zenodo_jupyterlab.server.search import searchRecords, searchCommunities, recordInformation # Replace `your_module` with the actual module name + +@pytest.mark.asyncio +@patch('zenodo_jupyterlab.server.search.search_records') +async def test_searchRecords_success(mock_search_records): + mock_search_records.return_value = [ + Mock(id='1', title='Record One', metadata={'publication_date': '2022-01-01', 'resource_type': {'title': 'Dataset'}}), + Mock(id='2', title='Record Two', metadata={'publication_date': '2023-01-01', 'resource_type': {'title': 'Article'}}) + ] + + response = await searchRecords('', 1) + expected_response = [ + {'id': '1', 'title': 'Record One', 'date': '2022-01-01', 'resource_type': 'Dataset'}, + {'id': '2', 'title': 'Record Two', 'date': '2023-01-01', 'resource_type': 'Article'} + ] + + assert response == expected_response + +@pytest.mark.asyncio +@patch('zenodo_jupyterlab.server.search.search_records') +async def test_searchRecords_failure(mock_search_records): + mock_search_records.side_effect = Exception('API Error') + + response = await searchRecords('test', 1) + assert response == ["failed"] + +@pytest.mark.asyncio +@patch('zenodo_jupyterlab.server.search.search_communities') +async def test_searchCommunities_success(mock_search_communities): + mock_search_communities.return_value = [ + {'id': '1', 'metadata': {'title': 'Community One'}, 'created': '2022-01-01T00:00:00Z'}, + {'id': '2', 'metadata': {'title': 'Community Two'}, 'created': '2023-01-01T00:00:00Z'} + ] + + response = await searchCommunities('test', 1) + expected_response = [ + {'id': '1', 'title': 'Community One', 'date': '2022-01-01'}, + {'id': '2', 'title': 'Community Two', 'date': '2023-01-01'} + ] + assert response == expected_response + +@pytest.mark.asyncio +@patch('zenodo_jupyterlab.server.search.search_communities') +async def test_searchCommunities_failure(mock_search_communities): + mock_search_communities.side_effect = Exception('API Error') + + response = await searchCommunities('test', 1) + assert response == ["failed"] + +@pytest.mark.asyncio +@patch('zenodo_jupyterlab.server.search.get_record') +async def test_recordInformation_success(mock_get_record): + mock_get_record.return_value = AsyncMock( + metadata={'creators': [{'name': 'Author One'}, {'name': 'Author Two'}]}, + filelist=['file1.pdf', 'file2.pdf'] + ) + + response = await recordInformation('12345') + expected_response = { + 'authors': [{'name': 'Author One'}, {'name': 'Author Two'}], + 'filelist': ['file1.pdf', 'file2.pdf'] + } + assert response == expected_response + +@pytest.mark.asyncio +@patch('zenodo_jupyterlab.server.search.get_record') +async def test_recordInformation_failure(mock_get_record): + mock_get_record.side_effect = Exception('API Error') + + response = await recordInformation('12345') + assert response == {'status': 'failed'} \ No newline at end of file diff --git a/zenodo_jupyterlab/server/tests/test_testConnection.py b/zenodo_jupyterlab/server/tests/test_testConnection.py new file mode 100644 index 0000000..5898e2f --- /dev/null +++ b/zenodo_jupyterlab/server/tests/test_testConnection.py @@ -0,0 +1,37 @@ +import pytest +from unittest.mock import patch, Mock +from eossr.api.zenodo import ZenodoAPI +import os +from zenodo_jupyterlab.server.testConnection import checkZenodoConnection + +@pytest.mark.asyncio +async def test_zenodo_connection_success(): + # Mock the ZenodoAPI instance and its method + """ mock_instance = MockZenodoAPI.return_value + mock_instance.query_user_deposits = Mock() + mock_instance.query_user_deposits.return_value.status_code = 200 """ + + # Mock the environment variable + with patch.dict(os.environ, {'ZENODO_API_KEY': os.environ['CI_ZENODO_API_KEY']}): + # Call the function to test + status_code = await checkZenodoConnection(sandbox = True) + + print(f"Returned status code: {status_code}") + + # Assert the expected status code + assert status_code == 200 + +@pytest.mark.asyncio +async def test_zenodo_connection_failure(): + # Mock the ZenodoAPI instance to raise an exception + """ mock_instance = MockZenodoAPI.return_value + mock_instance.query_user_deposits = Mock() + mock_instance.query_user_deposits.side_effect = Exception('Failed') """ + + # Mock the environment variable + with patch.dict('os.environ', {'ZENODO_API_KEY': 'fake_false_api_key'}): + # Call the function to test + status_code = await checkZenodoConnection(sandbox = True) + + # Assert the expected status code + assert status_code == 0 \ No newline at end of file