fix(clients): repair Python & Rust tests, add container test orchestration
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled

- Python: fix wire protocol test method names (bool_val -> bool, etc.)
- Python: make integration tests and example fully async with pytest-asyncio
- Rust: add tokio dev-dependency and convert integration tests to async/await
- Rust: update ping_test example to async
- Nim: remove committed ELF build artifact
- Docker: add BARADB_HOST/BARADB_PORT env vars to test containers
- Docker: fix docker-compose.test.yml usage (remove --abort-on-container-exit)
- Add scripts/test-clients.sh for sequential client test runs
- Remove docker-compose.test.yml from .gitignore so it is tracked
- Fix repository URLs in Python and Rust READMEs
This commit is contained in:
2026-05-14 23:35:45 +03:00
parent c55d3080cf
commit 359f945170
14 changed files with 311 additions and 129 deletions
+42 -39
View File
@@ -5,13 +5,16 @@ Requires a running BaraDB server on localhost:9472.
These tests are skipped automatically if the server is unreachable.
"""
import asyncio
import os
import socket
import pytest
import pytest_asyncio
from baradb import Client, WireValue, QueryBuilder
BARADB_HOST = "localhost"
BARADB_PORT = 9472
BARADB_HOST = os.environ.get("BARADB_HOST", "localhost")
BARADB_PORT = int(os.environ.get("BARADB_PORT", "9472"))
def _server_available() -> bool:
@@ -29,41 +32,41 @@ pytestmark = pytest.mark.skipif(
)
@pytest.fixture
def client():
@pytest_asyncio.fixture
async def client():
c = Client(BARADB_HOST, BARADB_PORT)
c.connect()
await c.connect()
yield c
c.close()
await c.close()
class TestConnection:
def test_connect_and_close(self):
async def test_connect_and_close(self):
c = Client(BARADB_HOST, BARADB_PORT)
assert not c.is_connected()
c.connect()
await c.connect()
assert c.is_connected()
c.close()
await c.close()
assert not c.is_connected()
def test_context_manager(self):
with Client(BARADB_HOST, BARADB_PORT) as c:
async def test_context_manager(self):
async with Client(BARADB_HOST, BARADB_PORT) as c:
assert c.is_connected()
assert not c.is_connected()
class TestPing:
def test_ping(self, client):
assert client.ping() is True
async def test_ping(self, client):
assert await client.ping() is True
class TestQuery:
def test_simple_select(self, client):
result = client.query("SELECT 1 as one")
async def test_simple_select(self, client):
result = await client.query("SELECT 1 as one")
assert result.row_count >= 0 # server may return rows or empty
def test_query_with_params(self, client):
result = client.query_params(
async def test_query_with_params(self, client):
result = await client.query_params(
"SELECT $1 as num, $2 as txt",
[WireValue.int64(42), WireValue.string("hello")],
)
@@ -71,22 +74,22 @@ class TestQuery:
class TestExecute:
def test_create_table_and_insert(self, client):
async def test_create_table_and_insert(self, client):
# Clean up first (best-effort)
try:
client.execute("DROP TABLE IF EXISTS test_users")
await client.execute("DROP TABLE IF EXISTS test_users")
except Exception:
pass
client.execute(
await client.execute(
"CREATE TABLE test_users (id INT PRIMARY KEY, name STRING, age INT)"
)
affected = client.execute(
affected = await client.execute(
"INSERT INTO test_users (id, name, age) VALUES (1, 'Alice', 30)"
)
assert affected >= 0
result = client.query("SELECT name, age FROM test_users WHERE id = 1")
result = await client.query("SELECT name, age FROM test_users WHERE id = 1")
assert result.row_count == 1
row = result.rows[0]
# Server returns all columns; map by name via dict iteration
@@ -94,20 +97,20 @@ class TestExecute:
assert row_dict["name"] == "Alice"
assert row_dict["age"] == 30
client.execute("DROP TABLE test_users")
await client.execute("DROP TABLE test_users")
class TestQueryBuilder:
def test_builder_exec(self, client):
async def test_builder_exec(self, client):
try:
client.execute("DROP TABLE IF EXISTS test_products")
await client.execute("DROP TABLE IF EXISTS test_products")
except Exception:
pass
client.execute(
await client.execute(
"CREATE TABLE test_products (id INT PRIMARY KEY, name STRING, price FLOAT)"
)
client.execute(
await client.execute(
"INSERT INTO test_products (id, name, price) VALUES (1, 'Widget', 9.99)"
)
@@ -117,36 +120,36 @@ class TestQueryBuilder:
.from_("test_products")
.where("id = 1")
)
result = qb.exec()
result = await qb.exec()
assert result.row_count == 1
client.execute("DROP TABLE test_products")
await client.execute("DROP TABLE test_products")
class TestAuth:
def test_auth_with_dummy_token(self, client):
async def test_auth_with_dummy_token(self, client):
# Server uses default JWT secret in dev mode, any token format is accepted
# depending on server config. We just verify the method does not crash.
try:
client.auth("dummy-token-for-testing")
await client.auth("dummy-token-for-testing")
except Exception as exc:
# Auth may fail with invalid token — that's acceptable for this test
assert "Auth" in str(exc) or "error" in str(exc).lower()
class TestTransactions:
def test_transaction_begin_commit(self, client):
async def test_transaction_begin_commit(self, client):
try:
client.execute("DROP TABLE IF EXISTS test_txn")
await client.execute("DROP TABLE IF EXISTS test_txn")
except Exception:
pass
client.execute("CREATE TABLE test_txn (id INT PRIMARY KEY)")
await client.execute("CREATE TABLE test_txn (id INT PRIMARY KEY)")
client.execute("BEGIN")
client.execute("INSERT INTO test_txn (id) VALUES (1)")
client.execute("COMMIT")
await client.execute("BEGIN")
await client.execute("INSERT INTO test_txn (id) VALUES (1)")
await client.execute("COMMIT")
result = client.query("SELECT COUNT(*) FROM test_txn")
result = await client.query("SELECT COUNT(*) FROM test_txn")
assert result.row_count >= 0
client.execute("DROP TABLE test_txn")
await client.execute("DROP TABLE test_txn")
+6 -6
View File
@@ -18,11 +18,11 @@ class TestWireValue:
assert data == b"\x00"
def test_bool_true(self):
wv = WireValue.bool_val(True)
wv = WireValue.bool(True)
assert wv.serialize() == b"\x01\x01"
def test_bool_false(self):
wv = WireValue.bool_val(False)
wv = WireValue.bool(False)
assert wv.serialize() == b"\x01\x00"
def test_int8(self):
@@ -70,7 +70,7 @@ class TestWireValue:
assert data[5:] == b"hello"
def test_bytes(self):
wv = WireValue.bytes_val(b"\xde\xad\xbe\xef")
wv = WireValue.bytes(b"\xde\xad\xbe\xef")
data = wv.serialize()
assert data[0] == FieldKind.BYTES
length = struct.unpack(">I", data[1:5])[0]
@@ -87,7 +87,7 @@ class TestWireValue:
assert floats == [1.0, 2.0, 3.0]
def test_json(self):
wv = WireValue.json_val('{"key": "value"}')
wv = WireValue.json('{"key": "value"}')
data = wv.serialize()
assert data[0] == FieldKind.JSON
length = struct.unpack(">I", data[1:5])[0]
@@ -95,7 +95,7 @@ class TestWireValue:
def test_array(self):
inner = [WireValue.string("a"), WireValue.string("b")]
wv = WireValue.array_val(inner)
wv = WireValue.array(inner)
data = wv.serialize()
assert data[0] == FieldKind.ARRAY
count = struct.unpack(">I", data[1:5])[0]
@@ -103,7 +103,7 @@ class TestWireValue:
def test_object(self):
inner = {"name": WireValue.string("Bara"), "age": WireValue.int32(42)}
wv = WireValue.object_val(inner)
wv = WireValue.object(inner)
data = wv.serialize()
assert data[0] == FieldKind.OBJECT
count = struct.unpack(">I", data[1:5])[0]