feat(clients): professional clients with tests, CI/CD, and examples

- Python: pyproject.toml, pytest suite (unit + integration), README, examples
- JavaScript: package.json, TypeScript definitions, node:test suite, README, examples
- Nim: integration tests, examples, README, improved nimble tasks
- Rust: fixed nodelay/localhost IPv6 bug, integration tests, examples, README
- Added GitHub Actions CI for all 4 clients against Docker server
- Added docker-compose.test.yml for local integration testing
- Added .gitignore for each client
This commit is contained in:
2026-05-08 00:18:34 +03:00
parent e9d3c7e9de
commit ae2e07e626
31 changed files with 2651 additions and 12 deletions
+142
View File
@@ -0,0 +1,142 @@
"""
Unit tests for BaraDB Python client wire protocol.
No running server required.
"""
import struct
import pytest
from baradb import WireValue, FieldKind, MsgKind, ResultFormat
class TestWireValue:
"""Tests for WireValue serialization / deserialization."""
def test_null(self):
wv = WireValue.null()
assert wv.kind == FieldKind.NULL
data = wv.serialize()
assert data == b"\x00"
def test_bool_true(self):
wv = WireValue.bool_val(True)
assert wv.serialize() == b"\x01\x01"
def test_bool_false(self):
wv = WireValue.bool_val(False)
assert wv.serialize() == b"\x01\x00"
def test_int8(self):
wv = WireValue.int8(-42)
data = wv.serialize()
assert data[0] == FieldKind.INT8
assert struct.unpack(">b", data[1:])[0] == -42
def test_int16(self):
wv = WireValue.int16(-1000)
data = wv.serialize()
assert data[0] == FieldKind.INT16
assert struct.unpack(">h", data[1:])[0] == -1000
def test_int32(self):
wv = WireValue.int32(123456)
data = wv.serialize()
assert data[0] == FieldKind.INT32
assert struct.unpack(">i", data[1:])[0] == 123456
def test_int64(self):
wv = WireValue.int64(9999999999)
data = wv.serialize()
assert data[0] == FieldKind.INT64
assert struct.unpack(">q", data[1:])[0] == 9999999999
def test_float32(self):
wv = WireValue.float32(3.14)
data = wv.serialize()
assert data[0] == FieldKind.FLOAT32
assert abs(struct.unpack(">f", data[1:])[0] - 3.14) < 0.01
def test_float64(self):
wv = WireValue.float64(2.718281828)
data = wv.serialize()
assert data[0] == FieldKind.FLOAT64
assert abs(struct.unpack(">d", data[1:])[0] - 2.718281828) < 1e-9
def test_string(self):
wv = WireValue.string("hello")
data = wv.serialize()
assert data[0] == FieldKind.STRING
length = struct.unpack(">I", data[1:5])[0]
assert length == 5
assert data[5:] == b"hello"
def test_bytes(self):
wv = WireValue.bytes_val(b"\xde\xad\xbe\xef")
data = wv.serialize()
assert data[0] == FieldKind.BYTES
length = struct.unpack(">I", data[1:5])[0]
assert length == 4
assert data[5:] == b"\xde\xad\xbe\xef"
def test_vector(self):
wv = WireValue.vector([1.0, 2.0, 3.0])
data = wv.serialize()
assert data[0] == FieldKind.VECTOR
dim = struct.unpack(">I", data[1:5])[0]
assert dim == 3
floats = [struct.unpack(">f", data[5 + i * 4 : 9 + i * 4])[0] for i in range(3)]
assert floats == [1.0, 2.0, 3.0]
def test_json(self):
wv = WireValue.json_val('{"key": "value"}')
data = wv.serialize()
assert data[0] == FieldKind.JSON
length = struct.unpack(">I", data[1:5])[0]
assert length == 16
def test_array(self):
inner = [WireValue.string("a"), WireValue.string("b")]
wv = WireValue.array_val(inner)
data = wv.serialize()
assert data[0] == FieldKind.ARRAY
count = struct.unpack(">I", data[1:5])[0]
assert count == 2
def test_object(self):
inner = {"name": WireValue.string("Bara"), "age": WireValue.int32(42)}
wv = WireValue.object_val(inner)
data = wv.serialize()
assert data[0] == FieldKind.OBJECT
count = struct.unpack(">I", data[1:5])[0]
assert count == 2
class TestMessageKinds:
"""Sanity checks for protocol constants."""
def test_client_kinds(self):
assert MsgKind.CLIENT_HANDSHAKE == 0x01
assert MsgKind.QUERY == 0x02
assert MsgKind.QUERY_PARAMS == 0x03
assert MsgKind.EXECUTE == 0x04
assert MsgKind.BATCH == 0x05
assert MsgKind.TRANSACTION == 0x06
assert MsgKind.CLOSE == 0x07
assert MsgKind.PING == 0x08
assert MsgKind.AUTH == 0x09
def test_server_kinds(self):
assert MsgKind.SERVER_HANDSHAKE == 0x80
assert MsgKind.READY == 0x81
assert MsgKind.DATA == 0x82
assert MsgKind.COMPLETE == 0x83
assert MsgKind.ERROR == 0x84
assert MsgKind.AUTH_CHALLENGE == 0x85
assert MsgKind.AUTH_OK == 0x86
assert MsgKind.SCHEMA_CHANGE == 0x87
assert MsgKind.PONG == 0x88
assert MsgKind.TRANSACTION_STATE == 0x89
def test_result_formats(self):
assert ResultFormat.BINARY == 0x00
assert ResultFormat.JSON == 0x01
assert ResultFormat.TEXT == 0x02