KeiSeiKit-1.0/_primitives/_rust/kei-entity-store/tests/verb_smoke.rs
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

161 lines
4.8 KiB
Rust

//! Per-verb integration smoke tests on a fixture schema.
use kei_entity_store::schema::{EdgeKeyKind, EntitySchema, FieldDef};
use kei_entity_store::verbs::{create, delete, get, link, list, rank, search, update};
use kei_entity_store::Store;
use serde_json::json;
static FIELDS: &[FieldDef] = &[
FieldDef::pk("id"),
FieldDef::text_nn("title"),
FieldDef::text("description"),
FieldDef::text_default("status", "pending"),
FieldDef::text_default("priority", "medium"),
FieldDef::integer("parent_id"),
FieldDef::created_at(),
FieldDef::updated_at(),
];
static SCHEMA: EntitySchema = EntitySchema {
name: "note",
table: "notes",
fields: FIELDS,
enabled_verbs: &["create", "get", "list", "search", "update", "delete", "link", "rank"],
fts_columns: Some(&["title", "description"]),
edge_table: Some("note_edges"),
edge_key_kind: EdgeKeyKind::IntegerPair,
archived_field: None,
custom_migrations: &[],
};
fn mk() -> Store { Store::open_memory(&[&SCHEMA]).unwrap() }
fn create_one(s: &Store, title: &str) -> i64 {
let v = create::run(s.conn(), &SCHEMA, json!({ "title": title })).unwrap();
v["id"].as_i64().unwrap()
}
#[test]
fn create_then_get() {
let s = mk();
let id = create_one(&s, "alpha");
let out = get::run(s.conn(), &SCHEMA, json!({ "id": id })).unwrap();
assert_eq!(out["title"], "alpha");
assert_eq!(out["status"], "pending");
assert_eq!(out["priority"], "medium");
assert!(out["created_at"].as_i64().unwrap() > 0);
}
#[test]
fn create_returns_id_and_created_at() {
let s = mk();
let v = create::run(s.conn(), &SCHEMA, json!({ "title": "x" })).unwrap();
assert!(v["id"].as_i64().unwrap() >= 1);
assert!(v["created_at"].as_i64().unwrap() > 0);
}
#[test]
fn list_paginated() {
let s = mk();
for i in 0..5 {
create_one(&s, &format!("n{i}"));
}
let v = list::run(s.conn(), &SCHEMA, json!({ "limit": 3 })).unwrap();
assert_eq!(v["results"].as_array().unwrap().len(), 3);
}
#[test]
fn search_fts() {
let s = mk();
create::run(
s.conn(),
&SCHEMA,
json!({ "title": "refactor router", "description": "split monolith" }),
)
.unwrap();
create_one(&s, "unrelated");
let v = search::run(s.conn(), &SCHEMA, json!({ "query": "refactor" })).unwrap();
assert_eq!(v["results"].as_array().unwrap().len(), 1);
}
#[test]
fn update_partial() {
let s = mk();
let id = create_one(&s, "orig");
update::run(
s.conn(),
&SCHEMA,
json!({ "id": id, "status": "in_progress" }),
)
.unwrap();
let out = get::run(s.conn(), &SCHEMA, json!({ "id": id })).unwrap();
assert_eq!(out["status"], "in_progress");
assert_eq!(out["title"], "orig");
}
#[test]
fn update_not_found_errors() {
let s = mk();
let err = update::run(
s.conn(),
&SCHEMA,
json!({ "id": 9999, "status": "x" }),
)
.unwrap_err();
assert_eq!(err.exit_code(), 2);
}
#[test]
fn delete_removes_row() {
let s = mk();
let id = create_one(&s, "gone");
delete::run(s.conn(), &SCHEMA, json!({ "id": id })).unwrap();
let err = get::run(s.conn(), &SCHEMA, json!({ "id": id })).unwrap_err();
assert_eq!(err.exit_code(), 2);
}
#[test]
fn link_and_rank() {
let s = mk();
let a = create_one(&s, "a");
let b = create_one(&s, "b");
let c = create_one(&s, "c");
link::run(s.conn(), &SCHEMA, json!({ "from": a, "to": b })).unwrap();
link::run(s.conn(), &SCHEMA, json!({ "from": a, "to": c })).unwrap();
link::run(s.conn(), &SCHEMA, json!({ "from": b, "to": c })).unwrap();
let v = rank::run(s.conn(), &SCHEMA, json!({})).unwrap();
let results = v["results"].as_array().unwrap();
assert_eq!(results.len(), 3);
// c receives 2 inbound edges → highest rank.
assert_eq!(results[0]["id"], c);
}
#[test]
fn create_missing_title_becomes_empty_string() {
let s = mk();
// engine does NOT validate NOT NULL content — the sibling atom does
// (e.g. kei-task::atoms::create rejects empty title). Engine only
// enforces SQL-level NOT NULL; defaults to empty string.
let v = create::run(s.conn(), &SCHEMA, json!({})).unwrap();
let id = v["id"].as_i64().unwrap();
let out = get::run(s.conn(), &SCHEMA, json!({ "id": id })).unwrap();
assert_eq!(out["title"], "");
}
#[test]
fn disabled_verb_errors() {
static DISABLED: EntitySchema = EntitySchema {
name: "ro",
table: "ro_items",
fields: FIELDS,
enabled_verbs: &["get", "list"],
fts_columns: None,
edge_table: None,
edge_key_kind: EdgeKeyKind::IntegerPair,
archived_field: None,
custom_migrations: &[],
};
let s = Store::open_memory(&[&DISABLED]).unwrap();
let err = create::run(s.conn(), &DISABLED, json!({ "title": "x" })).unwrap_err();
assert_eq!(err.exit_code(), 2);
}