Skip to content

Commit fe2135a

Browse files
authored
Merge pull request #1 from qaspen-python/feature/add_tests
Added tests and test actions
2 parents dc1040c + 79049e5 commit fe2135a

File tree

13 files changed

+474
-14
lines changed

13 files changed

+474
-14
lines changed
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@ name: CI
22

33
on:
44
push:
5-
branches:
6-
- main
7-
- master
85
tags:
96
- '*'
10-
pull_request:
11-
workflow_dispatch:
127

138
permissions:
149
contents: read

.github/workflows/test.yaml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: 'Testing package'
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
py-lint:
8+
strategy:
9+
matrix:
10+
cmd:
11+
- black
12+
- isort
13+
- ruff
14+
- mypy
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v2
18+
- name: Set up Python
19+
uses: actions/setup-python@v4
20+
with:
21+
python-version: "3.12"
22+
- name: Run lint check
23+
uses: pre-commit/action@v3.0.0
24+
with:
25+
extra_args: -a ${{ matrix.cmd }}
26+
fmt:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v1
30+
- uses: actions-rs/toolchain@v1
31+
with:
32+
toolchain: stable
33+
components: rustfmt
34+
override: true
35+
- name: Check code format
36+
run: cargo fmt -- --check --config use_try_shorthand=true,imports_granularity=Crate
37+
38+
clippy:
39+
permissions:
40+
checks: write
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@v1
44+
- uses: actions-rs/toolchain@v1
45+
with:
46+
toolchain: stable
47+
components: clippy
48+
override: true
49+
- uses: actions-rs/clippy-check@v1
50+
with:
51+
token: ${{ secrets.GITHUB_TOKEN }}
52+
args: -p psqlpy --all-features -- -W clippy::all -W clippy::pedantic -D warnings
53+
pytest:
54+
name: ${{matrix.job.os}}-${{matrix.py_version}}
55+
strategy:
56+
matrix:
57+
py_version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
58+
job:
59+
- os: ubuntu-latest
60+
ssl_cmd: sudo apt-get update && sudo apt-get install libssl-dev openssl
61+
runs-on: ${{matrix.job.os}}
62+
steps:
63+
- uses: actions/checkout@v1
64+
- uses: ikalnytskyi/action-setup-postgres@v4
65+
with:
66+
username: postgres
67+
password: postgres
68+
database: psqlpy_test
69+
id: postgres
70+
- uses: actions-rs/toolchain@v1
71+
with:
72+
toolchain: stable
73+
components: clippy
74+
override: true
75+
- name: Setup OpenSSL
76+
run: ${{matrix.job.ssl_cmd}}
77+
- name: Setup python for test ${{ matrix.py_version }}
78+
uses: actions/setup-python@v4
79+
with:
80+
python-version: ${{ matrix.py_version }}
81+
- name: Install tox
82+
run: pip install "tox-gh>=1.2,<2"
83+
- name: Run pytest
84+
run: tox -v
85+

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ ignore = [
101101
]
102102
exclude = [".venv/"]
103103
mccabe = { max-complexity = 10 }
104-
line-length = 88
104+
line-length = 79
105105

106106
[tool.ruff.per-file-ignores]
107107
"python/psqlpy/*" = ["PYI021"]

python/psqlpy/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1-
from ._internal import IsolationLevel, PSQLPool, QueryResult, ReadVariant, Transaction
1+
from ._internal import (
2+
Connection,
3+
Cursor,
4+
IsolationLevel,
5+
PSQLPool,
6+
QueryResult,
7+
ReadVariant,
8+
Transaction,
9+
)
210

311
__all__ = [
412
"PSQLPool",
513
"QueryResult",
614
"Transaction",
715
"IsolationLevel",
816
"ReadVariant",
17+
"Connection",
18+
"Cursor",
919
]

python/psqlpy/_internal/__init__.pyi

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import types
12
from enum import Enum
23
from typing import Any, Dict, List, Optional
34

@@ -153,6 +154,13 @@ class Transaction:
153154
`.transaction()`.
154155
"""
155156

157+
async def __aenter__(self: Self) -> Self: ...
158+
async def __aexit__(
159+
self: Self,
160+
exception_type: type[BaseException] | None,
161+
exception: BaseException | None,
162+
traceback: types.TracebackType | None,
163+
) -> None: ...
156164
async def begin(self: Self) -> None:
157165
"""Start the transaction.
158166
@@ -492,7 +500,8 @@ class PSQLPool:
492500
[100],
493501
)
494502
dict_result: List[Dict[Any, Any]] = query_result.result()
495-
# you don't need to close the pool, it will be dropped on Rust side.
503+
# you don't need to close the pool,
504+
# it will be dropped on Rust side.
496505
```
497506
"""
498507
async def connection(self: Self) -> Connection:

python/psqlpy/exceptions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818
"DBPoolConfigurationError",
1919
"UUIDValueConvertError",
2020
"CursorError",
21+
"DBTransactionError",
2122
]

python/tests/conftest.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
import os
2+
import random
3+
from typing import AsyncGenerator
4+
15
import pytest
26

7+
from psqlpy import PSQLPool
8+
39

4-
@pytest.fixture(scope="session")
10+
@pytest.fixture()
511
def anyio_backend() -> str:
612
"""
713
Anyio backend.
@@ -10,3 +16,83 @@ def anyio_backend() -> str:
1016
:return: backend name.
1117
"""
1218
return "asyncio"
19+
20+
21+
def random_string(length: int = 10) -> str:
22+
return "".join(random.choice("AbCdEfG") for _ in range(length))
23+
24+
25+
@pytest.fixture()
26+
def postgres_host() -> str:
27+
return os.environ.get("POSTGRES_HOST", "localhost")
28+
29+
30+
@pytest.fixture()
31+
def postgres_user() -> str:
32+
return os.environ.get("POSTGRES_USER", "postgres")
33+
34+
35+
@pytest.fixture()
36+
def postgres_password() -> str:
37+
return os.environ.get("POSTGRES_PASSWORD", "postgres")
38+
39+
40+
@pytest.fixture()
41+
def postgres_port() -> int:
42+
return int(os.environ.get("POSTGRES_PORT", 5432))
43+
44+
45+
@pytest.fixture()
46+
def postgres_dbname() -> str:
47+
return os.environ.get("POSTGRES_DBNAME", "psqlpy_test")
48+
49+
50+
@pytest.fixture()
51+
def table_name() -> str:
52+
return random_string()
53+
54+
55+
@pytest.fixture()
56+
def number_database_records() -> int:
57+
return random.randint(10, 35)
58+
59+
60+
@pytest.fixture()
61+
async def psql_pool(
62+
postgres_host: str,
63+
postgres_user: str,
64+
postgres_password: str,
65+
postgres_port: int,
66+
postgres_dbname: str,
67+
) -> AsyncGenerator[PSQLPool, None]:
68+
pg_pool = PSQLPool(
69+
username=postgres_user,
70+
password=postgres_password,
71+
host=postgres_host,
72+
port=postgres_port,
73+
db_name=postgres_dbname,
74+
)
75+
await pg_pool.startup()
76+
yield pg_pool
77+
78+
79+
@pytest.fixture(autouse=True)
80+
async def create_deafult_data_for_tests(
81+
psql_pool: PSQLPool,
82+
table_name: str,
83+
number_database_records: int,
84+
) -> AsyncGenerator[None, None]:
85+
await psql_pool.execute(
86+
f"CREATE TABLE {table_name} (id SERIAL, name VARCHAR(255))",
87+
)
88+
89+
for table_id in range(1, number_database_records + 1):
90+
new_name = random_string()
91+
await psql_pool.execute(
92+
querystring=f"INSERT INTO {table_name} VALUES ($1, $2)",
93+
parameters=[table_id, new_name],
94+
)
95+
yield
96+
await psql_pool.execute(
97+
f"DROP TABLE {table_name}",
98+
)

python/tests/test_connection.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
3+
from psqlpy import PSQLPool, QueryResult, Transaction
4+
5+
6+
@pytest.mark.anyio
7+
async def test_connection_execute(
8+
psql_pool: PSQLPool,
9+
table_name: str,
10+
number_database_records: int,
11+
) -> None:
12+
"""Test that single connection can execute queries."""
13+
connection = await psql_pool.connection()
14+
15+
conn_result = await connection.execute(
16+
querystring=f"SELECT * FROM {table_name}",
17+
)
18+
assert isinstance(conn_result, QueryResult)
19+
assert len(conn_result.result()) == number_database_records
20+
21+
22+
@pytest.mark.anyio
23+
async def test_connection_transaction(
24+
psql_pool: PSQLPool,
25+
) -> None:
26+
"""Test that connection can create transactions."""
27+
connection = await psql_pool.connection()
28+
transaction = connection.transaction()
29+
30+
assert isinstance(transaction, Transaction)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
3+
from psqlpy import Connection, PSQLPool, QueryResult
4+
5+
6+
@pytest.mark.anyio
7+
async def test_pool_execute(
8+
psql_pool: PSQLPool,
9+
table_name: str,
10+
number_database_records: int,
11+
) -> None:
12+
"""Test that PSQLPool can execute queries."""
13+
select_result = await psql_pool.execute(
14+
f"SELECT * FROM {table_name}",
15+
)
16+
17+
assert type(select_result) == QueryResult
18+
19+
inner_result = select_result.result()
20+
assert isinstance(inner_result, list)
21+
assert len(inner_result) == number_database_records
22+
23+
24+
@pytest.mark.anyio
25+
async def test_pool_connection(
26+
psql_pool: PSQLPool,
27+
) -> None:
28+
"""Test that PSQLPool can return single connection from the pool."""
29+
connection = await psql_pool.connection()
30+
assert isinstance(connection, Connection)

python/tests/test_cursor.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pytest
2+
3+
from psqlpy import PSQLPool
4+
5+
6+
@pytest.mark.anyio
7+
async def test_cursor_fetch(
8+
psql_pool: PSQLPool,
9+
table_name: str,
10+
number_database_records: int,
11+
) -> None:
12+
connection = await psql_pool.connection()
13+
transaction = connection.transaction()
14+
await transaction.begin()
15+
await transaction.cursor(
16+
querystring=f"SELECT * FROM {table_name}",
17+
)
18+
19+
await transaction.commit()

0 commit comments

Comments
 (0)