/ justapi / benchmarks / smoke_crud.py
swadhinbiswas p4: Rust-native SELECT/UPDATE/DELETE CRUD (ADR-056 Step C) · 7/16/2026
4b112db
89 lines · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
"""Smoke test: Step C Rust-native CRUD through the real Python server."""
import sys, json, time, urllib.request, subprocess, socket

from justapi import JustAPIApp, Database

app = JustAPIApp()
app.set_database(
    Database('sqlite://:memory:', max_connections=1),
    init_sql="CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, qty INTEGER NOT NULL)",
)
app.post("/items", crud_table="items", crud_columns=["name", "qty"])
app.get("/items/{id}", crud_table="items", crud_columns=["name", "qty"])
app.put("/items/{id}", crud_table="items", crud_columns=["name", "qty"])
app.delete("/items/{id}", crud_table="items", crud_columns=["name", "qty"])


def free_port():
    s = socket.socket()
    s.bind(("", 0))
    p = s.getsockname()[1]
    s.close()
    return p


port = free_port()

# Start the server in a detached process.
proc = subprocess.Popen(
    [sys.executable, "-c",
     "import sys; sys.path.insert(0,'benchmarks');"
     "from justapi import JustAPIApp, Database;"
     "app=JustAPIApp();"
     "app.set_database(Database('sqlite://:memory:', max_connections=1), init_sql='CREATE TABLE items (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, qty INTEGER NOT NULL)');"
     "app.post('/items', crud_table='items', crud_columns=['name','qty']);"
     "app.get('/items/{id}', crud_table='items', crud_columns=['name','qty']);"
     "app.put('/items/{id}', crud_table='items', crud_columns=['name','qty']);"
     "app.delete('/items/{id}', crud_table='items', crud_columns=['name','qty']);"
     "app.run('127.0.0.1:%d')" % port],
    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
)
time.sleep(2.0)

base = "http://127.0.0.1:%d" % port


def req(method, path, body=None):
    data = json.dumps(body).encode() if body is not None else None
    r = urllib.request.Request(base + path, data=data, method=method,
                               headers={"content-type": "application/json"})
    try:
        with urllib.request.urlopen(r) as resp:
            return resp.status, resp.read()
    except urllib.error.HTTPError as e:
        return e.code, e.read()


try:
    # INSERT
    st, b = req("POST", "/items", {"name": "widget", "qty": 3})
    assert st == 200, (st, b)
    rid = json.loads(b)["id"]
    print("INSERT ok id=", rid)

    # SELECT
    st, b = req("GET", "/items/%d" % rid)
    assert st == 200, (st, b)
    assert json.loads(b)[0]["name"] == "widget"
    print("SELECT ok")

    # UPDATE
    st, b = req("PUT", "/items/%d" % rid, {"name": "gadget", "qty": 7})
    assert st == 200, (st, b)
    assert json.loads(b)["qty"] == 7
    print("UPDATE ok")

    # DELETE
    st, b = req("DELETE", "/items/%d" % rid)
    assert st == 200, (st, b)
    print("DELETE ok")

    # SELECT after delete -> empty array
    st, b = req("GET", "/items/%d" % rid)
    assert st == 200 and json.loads(b) == [], (st, b)
    print("SELECT-after-delete ok (empty)")

    print("SMOKE PASS")
finally:
    proc.terminate()