From 7adba41c572cdbcf88d70c14615047c7edda7924 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Sat, 1 Feb 2025 23:53:11 +0000 Subject: [PATCH] Improve workflows and tests (#152) --- .github/actions/action.yml | 46 --------------- .github/workflows/stability.yml | 33 ++++++----- .github/workflows/tests.yml | 58 +++++++++++++++++++ .github/workflows/unit_tests.yml | 39 ------------- src/surrealdb/connections/async_ws.py | 4 +- .../connections/invalidate/test_async_http.py | 28 ++++----- .../connections/invalidate/test_async_ws.py | 30 +++++----- .../invalidate/test_blocking_http.py | 28 ++++----- .../invalidate/test_blocking_ws.py | 20 ++----- 9 files changed, 118 insertions(+), 168 deletions(-) delete mode 100644 .github/actions/action.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 .github/workflows/unit_tests.yml diff --git a/.github/actions/action.yml b/.github/actions/action.yml deleted file mode 100644 index 402fdae2..00000000 --- a/.github/actions/action.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Build Poetry - -description: 'Build Poetry' - -runs: - using: 'composite' - - steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.10 - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - - name: Get full Python version - id: full-python-version - run: echo "version=$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")" >> $GITHUB_OUTPUT - shell: bash - - - name: Bootstrap poetry - run: curl -sL https://install.python-poetry.org | python - -y - shell: bash - - - name: Update PATH - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - shell: bash - - - name: Configure poetry - run: poetry config virtualenvs.in-project true - shell: bash - - - name: Set up cache - uses: actions/cache@v3 - id: cache - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ inputs.working-directory }}-${{ hashFiles('**/poetry.lock') }} - - - name: Ensure cache is healthy - if: steps.cache.outputs.cache-hit == 'true' - run: timeout 10s poetry run pip --version || rm -rf .venv - shell: bash - - - name: Install Dependencies - run: poetry install - shell: bash diff --git a/.github/workflows/stability.yml b/.github/workflows/stability.yml index 8a0cad67..231a6b92 100644 --- a/.github/workflows/stability.yml +++ b/.github/workflows/stability.yml @@ -1,4 +1,4 @@ -name: Code Stability +name: Code stability on: push: @@ -6,7 +6,7 @@ on: - main pull_request: branches: - - main + - "*" concurrency: group: stability-${{ github.head_ref || github.ref }} @@ -14,25 +14,26 @@ concurrency: jobs: stability: - name: Code Stability + name: Code stability runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Build Python - uses: ./.github/actions + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.13 - name: Install tools - run: poetry install --only dev + run: pip install black ruff - - id: ruff - if: always() - run: poetry run ruff check surrealdb/ + - name: Run ruff checks + run: ruff check src/ - - id: Black - if: always() - run: poetry run black surrealdb/ --check --verbose --diff --color + - name: Run black checks + run: black --check --verbose --diff --color src/ - - id: mypy - if: always() - run: poetry run mypy surrealdb/ + - name: Run mypy checks + run: mypy src/ diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..2c4c1cad --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,58 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + branches: + - "*" + +concurrency: + group: tests-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + run-unit-tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + surrealdb-version: ["v2.1.0", "v2.1.1", "v2.1.2", "v2.1.3", "v2.1.4"] # v2.0.0 has different UPSERT behaviour + name: Python ${{ matrix.python-version }} - SurrealDB ${{ matrix.surrealdb-version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install surrealdb + run: curl -sSf https://install.surrealdb.com | sh -s -- --version ${{ matrix.surrealdb-version }} + + - name: Start surrealdb + run: surreal start --allow-all -u root -p root --log trace & + + - name: Wait for startup + run: sleep 5 + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Run unit tests (HTTP) + run: python -m unittest discover -s tests + env: + PYTHONPATH: ./src + SURREALDB_URL: http://localhost:8000 + + - name: Run unit tests (WebSocket) + run: python -m unittest discover -s tests + env: + PYTHONPATH: ./src + SURREALDB_URL: ws://localhost:8000 + + + diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml deleted file mode 100644 index cf0dfbaa..00000000 --- a/.github/workflows/unit_tests.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Unit tests - -on: - push: - branches: - - main - pull_request: - branches: - - "*" - -jobs: - run-unit-tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] - surrealdb-version: ["v2.1.1", "v2.1.2"] # Issue with v2.1.0 - name: Run unit test SurrealDB ${{ matrix.surrealdb-version }} - Python Version ${{ matrix.python-version }} - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Download and install surrealdb - run: curl -sSf https://install.surrealdb.com | sh -s -- --version ${{ matrix.surrealdb-version }} - - - name: Start surrealdb - run: surreal start memory -u root -p root --log trace & sleep 5 & - - - name: Install dependencies - run: pip install -r requirements.txt - - - name: Run unit tests - env: - SURREALDB_URL: "http://localhost:8000" - run: export DOCKER_RUN="TRUE" && export PYTHONPATH="./src" && python -m unittest discover -s tests - - - diff --git a/src/surrealdb/connections/async_ws.py b/src/surrealdb/connections/async_ws.py index 16427b9d..97b062b4 100644 --- a/src/surrealdb/connections/async_ws.py +++ b/src/surrealdb/connections/async_ws.py @@ -351,8 +351,8 @@ async def upsert( self.check_response_for_result(response, "upsert") return response["result"] - def close(self): - self.socket.close() + async def close(self): + await self.socket.close() async def __aenter__(self) -> "AsyncWsSurrealConnection": """ diff --git a/tests/unit_tests/connections/invalidate/test_async_http.py b/tests/unit_tests/connections/invalidate/test_async_http.py index 64340d78..4e6df53e 100644 --- a/tests/unit_tests/connections/invalidate/test_async_http.py +++ b/tests/unit_tests/connections/invalidate/test_async_http.py @@ -25,16 +25,7 @@ async def asyncSetUp(self): _ = await self.connection.signin(self.vars_params) _ = await self.connection.use(namespace=self.namespace, database=self.database_name) - async def running_through_docker(self): - _ = await self.connection.invalidate() - with self.assertRaises(Exception) as context: - _ = await self.connection.query("CREATE user:jaime SET name = 'Jaime';") - self.assertEqual( - "IAM error: Not enough permissions" in str(context.exception), - True - ) - - async def running_through_binary(self): + async def test_invalidate(self): outcome = await self.connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) outcome = await self.main_connection.query("SELECT * FROM user;") @@ -47,14 +38,17 @@ async def running_through_binary(self): outcome = await self.main_connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) - await self.main_connection.query("DELETE user;") - - async def test_invalidate(self): - if os.environ.get("DOCKER_RUN") == "TRUE": - await self.running_through_docker() - else: - await self.running_through_binary() + ''' + # Exceptions are raised only when SurrealDB doesn't allow guest mode + with self.assertRaises(Exception) as context: + _ = await self.connection.query("CREATE user:jaime SET name = 'Jaime';") + self.assertEqual( + "IAM error: Not enough permissions" in str(context.exception), + True + ) + ''' + await self.main_connection.query("DELETE user;") if __name__ == "__main__": main() diff --git a/tests/unit_tests/connections/invalidate/test_async_ws.py b/tests/unit_tests/connections/invalidate/test_async_ws.py index f127d83d..efa4e5e9 100644 --- a/tests/unit_tests/connections/invalidate/test_async_ws.py +++ b/tests/unit_tests/connections/invalidate/test_async_ws.py @@ -25,16 +25,7 @@ async def asyncSetUp(self): _ = await self.connection.signin(self.vars_params) _ = await self.connection.use(namespace=self.namespace, database=self.database_name) - async def running_through_docker(self): - _ = await self.connection.invalidate() - with self.assertRaises(Exception) as context: - _ = await self.connection.query("CREATE user:jaime SET name = 'Jaime';") - self.assertEqual( - "IAM error: Not enough permissions" in str(context.exception), - True - ) - - async def running_through_binary(self): + async def test_invalidate(self): outcome = await self.connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) outcome = await self.main_connection.query("SELECT * FROM user;") @@ -47,14 +38,19 @@ async def running_through_binary(self): outcome = await self.main_connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) - await self.main_connection.query("DELETE user;") - - async def test_invalidate(self): - if os.environ.get("DOCKER_RUN") == "TRUE": - await self.running_through_docker() - else: - await self.running_through_binary() + ''' + # Exceptions are raised only when SurrealDB doesn't allow guest mode + with self.assertRaises(Exception) as context: + _ = await self.connection.query("CREATE user:jaime SET name = 'Jaime';") + self.assertEqual( + "IAM error: Not enough permissions" in str(context.exception), + True + ) + ''' + await self.main_connection.query("DELETE user;") + await self.main_connection.close() + await self.connection.close() if __name__ == "__main__": main() diff --git a/tests/unit_tests/connections/invalidate/test_blocking_http.py b/tests/unit_tests/connections/invalidate/test_blocking_http.py index bef5329e..b181cf33 100644 --- a/tests/unit_tests/connections/invalidate/test_blocking_http.py +++ b/tests/unit_tests/connections/invalidate/test_blocking_http.py @@ -25,16 +25,7 @@ def setUp(self): _ = self.connection.signin(self.vars_params) _ = self.connection.use(namespace=self.namespace, database=self.database_name) - def running_through_docker(self): - _ = self.connection.invalidate() - with self.assertRaises(Exception) as context: - _ = self.connection.query("CREATE user:jaime SET name = 'Jaime';") - self.assertEqual( - "IAM error: Not enough permissions" in str(context.exception), - True - ) - - def running_through_binary(self): + def test_invalidate(self): outcome = self.connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) outcome = self.main_connection.query("SELECT * FROM user;") @@ -47,14 +38,17 @@ def running_through_binary(self): outcome = self.main_connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) - self.main_connection.query("DELETE user;") - - def test_invalidate(self): - if os.environ.get("DOCKER_RUN") == "TRUE": - self.running_through_docker() - else: - self.running_through_binary() + ''' + # Exceptions are raised only when SurrealDB doesn't allow guest mode + with self.assertRaises(Exception) as context: + _ = self.connection.query("CREATE user:jaime SET name = 'Jaime';") + self.assertEqual( + "IAM error: Not enough permissions" in str(context.exception), + True + ) + ''' + self.main_connection.query("DELETE user;") if __name__ == "__main__": main() diff --git a/tests/unit_tests/connections/invalidate/test_blocking_ws.py b/tests/unit_tests/connections/invalidate/test_blocking_ws.py index dfe158c0..ad841d18 100644 --- a/tests/unit_tests/connections/invalidate/test_blocking_ws.py +++ b/tests/unit_tests/connections/invalidate/test_blocking_ws.py @@ -25,7 +25,7 @@ def setUp(self): _ = self.connection.signin(self.vars_params) _ = self.connection.use(namespace=self.namespace, database=self.database_name) - def running_through_binary(self): + def test_invalidate(self): outcome = self.connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) outcome = self.main_connection.query("SELECT * FROM user;") @@ -38,27 +38,19 @@ def running_through_binary(self): outcome = self.main_connection.query("SELECT * FROM user;") self.assertEqual(1, len(outcome)) - self.main_connection.query("DELETE user;") - self.main_connection.close() - self.connection.close() - - def running_through_docker(self): - _ = self.connection.invalidate() + ''' + # Exceptions are raised only when SurrealDB doesn't allow guest mode with self.assertRaises(Exception) as context: _ = self.connection.query("CREATE user:jaime SET name = 'Jaime';") self.assertEqual( "IAM error: Not enough permissions" in str(context.exception), True ) + ''' + + self.main_connection.query("DELETE user;") self.main_connection.close() self.connection.close() - def test_invalidate(self): - if os.environ.get("DOCKER_RUN") == "TRUE": - self.running_through_docker() - else: - self.running_through_binary() - - if __name__ == "__main__": main()