Files
cleveragents-core/features/database_handler_crud.feature
freemo ec52acffb7 feat(resource): implement DatabaseResourceHandler CRUD and checkpoint methods
Implements all missing CRUD and checkpoint methods on DatabaseResourceHandler per issue #1241 (Epic #825 ResourceHandler Protocol Completion):

- read(): SQLite queries sqlite_master for schema; remote returns connection-info
- write(): SQLite executes SQL statements; remote returns not-supported result
- delete(): SQLite executes DROP TABLE IF EXISTS; remote returns not-supported
- list_children(): SQLite lists tables/views from sqlite_master; remote returns []
- diff(): compares schemas via content_hash on both sides
- create_checkpoint(): SQLite creates SAVEPOINT on open connection; remote uses content-hash fallback
- rollback_to(): SQLite executes ROLLBACK TO SAVEPOINT; remote returns not-supported

All methods handle errors gracefully (no unhandled exceptions). Adds comprehensive Behave BDD tests covering all methods for both SQLite and remote database types.

ISSUES CLOSED: #1241

Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
2026-04-02 17:08:05 +00:00

220 lines
10 KiB
Gherkin

Feature: DatabaseResourceHandler CRUD and checkpoint methods
As a CleverAgents developer
I want DatabaseResourceHandler to implement full CRUD and checkpoint methods
So that SQLite databases can be read, written, deleted, listed, diffed, and checkpointed
Issue #1241: DatabaseResourceHandler CRUD and checkpoint methods
# ============================================================
# read() SQLite schema query
# ============================================================
Scenario: read() returns schema for SQLite database with tables
Given a SQLite database with tables "users" and "orders"
When I read from the database handler
Then the db read content should contain "users"
And the db read content should contain "orders"
And the db read content encoding should be "utf-8"
And the db read content hash should not be empty
Scenario: read() returns empty schema for empty SQLite database
Given an empty SQLite database file
When I read from the database handler
Then the db read content encoding should be "utf-8"
And the db read content data should be empty or whitespace
Scenario: read() returns connection-info summary for remote database
Given a remote postgres database resource with location "postgresql://localhost/mydb"
When I read from the database handler
Then the db read content should contain "postgres"
And the db read content should contain "mydb"
And the db read content encoding should be "utf-8"
Scenario: read() returns empty content for resource with no location
Given a database resource with no location
When I read from the database handler
Then the db read content data should be empty or whitespace
Scenario: read() handles SQLite error gracefully
Given a database resource pointing to a non-existent SQLite path
When I read from the database handler
Then no db exceptions should have been raised
# ============================================================
# write() — SQLite SQL execution
# ============================================================
Scenario: write() executes SQL on SQLite database
Given a SQLite database with table "items"
When I write SQL "INSERT INTO items (id, name) VALUES (1, 'apple')" to the database handler
Then the db write result should be successful
And the SQLite table "items" should contain 1 row
Scenario: write() creates a new table via SQL
Given an empty SQLite database file
When I write SQL "CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT)" to the database handler
Then the db write result should be successful
And the SQLite database should have table "products"
Scenario: write() returns not-supported for remote postgres database
Given a remote postgres database resource with location "postgresql://localhost/mydb"
When I write SQL "SELECT 1" to the database handler
Then the db write result should not be successful
And the db write result message should mention "not supported"
Scenario: write() returns not-supported for remote mysql database
Given a remote mysql database resource with location "mysql://localhost/mydb"
When I write SQL "SELECT 1" to the database handler
Then the db write result should not be successful
And the db write result message should mention "not supported"
Scenario: write() returns failure for resource with no location
Given a database resource with no location
When I write SQL "SELECT 1" to the database handler
Then the db write result should not be successful
Scenario: write() returns failure for invalid SQL
Given an empty SQLite database file
When I write SQL "THIS IS NOT SQL" to the database handler
Then the db write result should not be successful
And the db write result message should mention "error"
# ============================================================
# delete() — SQLite DROP TABLE
# ============================================================
Scenario: delete() drops a table from SQLite database
Given a SQLite database with table "temp_data"
When I delete table "temp_data" from the database handler
Then the db delete result should be successful
And the SQLite database should not have table "temp_data"
Scenario: delete() with non-existent table succeeds (DROP TABLE IF EXISTS)
Given an empty SQLite database file
When I delete table "ghost_table" from the database handler
Then the db delete result should be successful
Scenario: delete() with empty path returns failure
Given an empty SQLite database file
When I delete with empty path from the database handler
Then the db delete result should not be successful
And the db delete result message should mention "table name"
Scenario: delete() returns not-supported for remote postgres database
Given a remote postgres database resource with location "postgresql://localhost/mydb"
When I delete table "users" from the database handler
Then the db delete result should not be successful
And the db delete result message should mention "not supported"
Scenario: delete() returns failure for resource with no location
Given a database resource with no location
When I delete table "users" from the database handler
Then the db delete result should not be successful
# ============================================================
# list_children() — SQLite tables/views
# ============================================================
Scenario: list_children() returns table names for SQLite database
Given a SQLite database with tables "alpha" and "beta"
When I list children from the database handler
Then the db children list should contain "alpha"
And the db children list should contain "beta"
And the db children list should be sorted
Scenario: list_children() returns empty list for empty SQLite database
Given an empty SQLite database file
When I list children from the database handler
Then the db children list should be empty
Scenario: list_children() returns empty list for remote database
Given a remote postgres database resource with location "postgresql://localhost/mydb"
When I list children from the database handler
Then the db children list should be empty
Scenario: list_children() returns empty list for resource with no location
Given a database resource with no location
When I list children from the database handler
Then the db children list should be empty
# ============================================================
# diff() — schema hash comparison
# ============================================================
Scenario: diff() detects no changes between identical SQLite databases
Given a SQLite database with table "same_table"
And a second SQLite database with the same schema
When I diff the database handler against the second database
Then the db diff result should have no changes
Scenario: diff() detects changes between different SQLite databases
Given a SQLite database with table "table_a"
And a second SQLite database with table "table_b"
When I diff the database handler against the second database
Then the db diff result should have changes
Scenario: diff() compares remote database by identity hash
Given a remote postgres database resource with location "postgresql://localhost/db1"
And a second remote database location "postgresql://localhost/db2"
When I diff the database handler against the second remote location
Then the db diff result should have changes
# ============================================================
# create_checkpoint() — SQLite SAVEPOINT
# ============================================================
Scenario: create_checkpoint() creates a SAVEPOINT on SQLite database
Given a SQLite database with table "checkpoint_test"
And a mock sandbox manager
When I create a checkpoint with plan "PLAN-CKPT-001" on the database handler
Then the db checkpoint result should have a checkpoint_id
And the db checkpoint result plan_id should be "PLAN-CKPT-001"
And the db checkpoint result message should mention "SAVEPOINT"
Scenario: create_checkpoint() returns content-hash checkpoint for remote database
Given a remote postgres database resource with location "postgresql://localhost/mydb"
And a mock sandbox manager
When I create a checkpoint with plan "PLAN-CKPT-002" on the database handler
Then the db checkpoint result should have a checkpoint_id
And the db checkpoint result message should mention "hash"
# ============================================================
# rollback_to() — SQLite ROLLBACK TO SAVEPOINT
# ============================================================
Scenario: rollback_to() rolls back SQLite changes to SAVEPOINT
Given a SQLite database with table "rollback_test"
And a mock sandbox manager
When I create a checkpoint with plan "PLAN-RB-001" on the database handler
And I insert a row into "rollback_test" via the database handler
And I rollback to the last checkpoint on the database handler
Then the db rollback result should be successful
And the SQLite table "rollback_test" should contain 0 rows
Scenario: rollback_to() returns failure for unknown checkpoint_id
Given a SQLite database with table "rollback_test2"
And a mock sandbox manager
When I rollback to checkpoint "nonexistent-ckpt" on the database handler
Then the db rollback result should not be successful
And the db rollback result message should mention "not found"
Scenario: rollback_to() returns not-supported for remote database
Given a remote postgres database resource with location "postgresql://localhost/mydb"
And a mock sandbox manager
When I rollback to checkpoint "some-ckpt" on the database handler
Then the db rollback result should not be successful
And the db rollback result message should mention "not supported"
# ============================================================
# Error handling
# ============================================================
Scenario: All methods handle missing location gracefully
Given a database resource with no location
And a mock sandbox manager
When I read from the database handler
And I write SQL "SELECT 1" to the database handler
And I delete with empty path from the database handler
And I list children from the database handler
Then no db exceptions should have been raised