diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..fc1c232 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,131 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is **test_factory**, a PostgreSQL extension that provides a framework for managing unit test data in databases. It solves the common problem of creating and maintaining test data by providing a system to register test data definitions once and retrieve them efficiently with automatic dependency resolution. + +## Build System & Development Commands + +This project uses PGXNtool for build management. Key commands: + +### Building and Installation +```bash +make # Build the extension +make install # Install to PostgreSQL +make clean # Clean build artifacts +make distclean # Clean all generated files including META.json +``` + +### Testing +```bash +make test # Run full test suite (install, then test) +make installcheck # Run tests only (no clean/install) +make results # Update expected test results (only after verifying tests pass!) +``` + +### Distribution +```bash +make tag # Create git tag for current version +make dist # Create distribution zip file +make forcetag # Force recreate tag if it exists +make forcedist # Force tag + distribution +``` + +## Architecture & Key Components + +### Core API Functions +- `tf.register(table_name, test_sets[])` - Register test data definitions for a table +- `tf.get(table_type, set_name)` - Retrieve test data, creating it if it doesn't exist +- `tf.tap(table_name, set_name)` - pgTAP integration wrapper for testing + +### Database Schema Organization +- `tf` schema: User-facing API (functions, types) +- `_tf` schema: Internal implementation (tables, security definer functions) +- `_test_factory_test_data` schema: Cached test data storage +- Uses dedicated `test_factory__owner` role for security isolation + +### Security Model +- Role-based access with `test_factory__owner` for data management +- Security definer functions with `search_path=pg_catalog` +- Proper permission isolation between user and system operations + +### Key Data Structures +```sql +CREATE TYPE tf.test_set AS ( + set_name text, -- Name to reference this test data set + insert_sql text -- SQL command that returns test data rows +); +``` + +### Test Data Workflow +1. **Registration**: Use `tf.register()` to define how test data is created +2. **Retrieval**: Call `tf.get()` to obtain test data (creates on first call) +3. **Caching**: Test data is stored permanently for fast subsequent access +4. **Dependencies**: Test sets can reference other test sets via embedded `tf.get()` calls + +### Performance & Caching +- Test data created once and cached in permanent tables +- Subsequent `tf.get()` calls return cached data without recreation +- Data remains available even if source tables are modified/truncated +- Dependency resolution handled automatically during creation + +## File Structure Key Points + +### SQL Files +- `sql/test_factory.sql` and `sql/test_factory--0.5.0.sql`: Main extension code +- Complex role management and schema setup with proper cleanup +- Security definer functions for safe cross-schema operations + +### Build Configuration +- `META.in.json`: Template for PGXN metadata (processed to `META.json`) +- `test_factory.control`: PostgreSQL extension control file +- `Makefile`: Simple inclusion of pgxntool's build system + +## Development Workflow + +1. **Making Changes**: Modify source files in `sql/` directory +2. **Testing**: Run `make test` to ensure all tests pass +3. **Version Updates**: Update version in both `META.in.json` and `test_factory.control` +4. **Distribution**: Use `make dist` to create release packages + +## Extension Architecture Details + +The extension handles complex bootstrapping during installation: +- Creates temporary role tracking for safe installation +- Sets up three schemas with proper ownership and permissions +- Uses security definer pattern for controlled access to internal functions +- Automatically restores original database role after installation +- Implements dependency resolution through recursive `tf.get()` calls + +## Usage Patterns + +### Basic Registration +```sql +SELECT tf.register( + 'customer', + array[ + row('base', 'INSERT INTO customer VALUES (DEFAULT, ''Test'', ''User'') RETURNING *')::tf.test_set + ] +); +``` + +### With Dependencies +```sql +SELECT tf.register( + 'invoice', + array[ + row('base', 'INSERT INTO invoice VALUES (DEFAULT, (tf.get(NULL::customer, ''base'')).customer_id, current_date) RETURNING *')::tf.test_set + ] +); +``` + +### Data Retrieval +```sql +-- Gets customer test data, creating it if needed +SELECT * FROM tf.get(NULL::customer, 'base'); + +-- Gets invoice test data, automatically creating dependent customer data +SELECT * FROM tf.get(NULL::invoice, 'base'); +``` \ No newline at end of file diff --git a/test/CLAUDE.md b/test/CLAUDE.md new file mode 100644 index 0000000..ac12354 --- /dev/null +++ b/test/CLAUDE.md @@ -0,0 +1,132 @@ +# Test Framework Documentation + +This file provides guidance for understanding and working with the test_factory extension test suite. + +## Test Framework Overview + +The test_factory extension uses **pgTAP** (PostgreSQL's unit testing framework) for comprehensive testing. Tests are organized using PGXNtool's standardized testing infrastructure. + +## Test Structure + +### Test Files +- `test/sql/base.sql` - Core functionality tests (22 tests) +- `test/sql/install.sql` - Extension installation/uninstallation tests +- `test/sql/pgtap.sql` - pgTAP integration and `tf.tap()` function tests + +### Expected Results +- `test/expected/*.out` - Expected test output for regression testing +- `test/results/*.out` - Actual test output (generated during test runs) + +### Test Helpers +- `test/helpers/setup.sql` - Test environment initialization and pgTAP setup +- `test/helpers/create.sql` - Test data registration and security validation +- `test/helpers/create_extension.sql` - Extension creation wrapper +- `test/helpers/deps.sql` - Test dependency management +- Other helper files for role management and pgTAP integration + +## Test Coverage Analysis + +### Core Functionality Tests (`base.sql`) +1. **Extension Setup** - Creates extension and test tables +2. **Data Registration** - Tests `tf.register()` with multiple test sets +3. **Basic Retrieval** - Tests `tf.get()` returns correct data +4. **Dependency Resolution** - Tests automatic creation of dependent data (customer → invoice) +5. **Caching Behavior** - Verifies data consistency across multiple `tf.get()` calls +6. **Table Independence** - Tests that cached data persists after source table changes +7. **Function-based Test Data** - Tests using functions as test data sources + +### Security Tests (`create.sql`) +- **Role Management** - Validates proper role restoration after installation +- **Security Definer Functions** - Ensures all privileged functions use `search_path=pg_catalog` +- **Permission Isolation** - Tests with unprivileged `test_role` +- **Temp Table Cleanup** - Verifies temporary installation objects are removed + +### Installation Tests (`install.sql`) +- **Dependency Validation** - Tests extension dependency requirements +- **Clean Installation** - Tests CREATE EXTENSION without conflicts +- **Clean Removal** - Tests DROP EXTENSION without orphaned objects + +### pgTAP Integration Tests (`pgtap.sql`) +- **tf.tap() Function** - Tests pgTAP wrapper functionality +- **Error Handling** - Tests proper error reporting for invalid inputs +- **Extension Dependencies** - Validates test_factory_pgtap requires test_factory + +## Test Data Model + +### Test Tables +```sql +CREATE TABLE customer( + customer_id serial PRIMARY KEY, + first_name text NOT NULL, + last_name text NOT NULL +); + +CREATE TABLE invoice( + invoice_id serial PRIMARY KEY, + customer_id int NOT NULL REFERENCES customer, + invoice_date date NOT NULL, + due_date date +); +``` + +### Test Data Sets +- **customer 'insert'** - Simple INSERT statement returning customer data +- **customer 'function'** - Function-based test data creation +- **invoice 'base'** - Invoice with dependency on customer 'insert' set + +## Running Tests + +### Basic Test Execution +```bash +make test # Full test suite with clean install +make installcheck # Run tests against already installed extension +``` + +### Test Development Workflow +```bash +# Make changes to test files +vim test/sql/base.sql + +# Run tests to verify +make test + +# If tests pass but output differs, update expected results +make results +``` + +### Test Debugging +- Test output appears in `test/results/` +- Differences shown in `test/regression.diffs` if tests fail +- Use `\set ECHO all` in test SQL files for detailed debugging + +## Test Architecture Details + +### pgTAP Integration +- Tests use pgTAP assertion functions: `is()`, `results_eq()`, `bag_eq()`, `lives_ok()` +- `no_plan()` allows dynamic test counting +- Tests run in transactions with automatic rollback + +### Security Testing Strategy +- Creates unprivileged `test_role` to validate security boundaries +- Tests run with restricted permissions to catch privilege escalation issues +- Validates all security definer functions use safe search_path settings + +### Dependency Testing +- Tests multi-level dependencies (invoice → customer) +- Validates data creation order and consistency +- Tests that dependency data is created automatically and cached + +### Error Condition Testing +- Tests invalid table names and missing test sets +- Validates proper error messages and SQL state codes +- Tests edge cases like non-existent tables in tf.tap() + +## Test Data Lifecycle + +1. **Setup Phase** - Creates test role, schemas, and tables +2. **Registration Phase** - Registers test data definitions +3. **Execution Phase** - Calls tf.get() to trigger data creation +4. **Validation Phase** - Verifies data correctness and caching behavior +5. **Cleanup Phase** - Transaction rollback removes all test data + +This comprehensive test suite ensures the test_factory extension works correctly across different PostgreSQL versions and usage patterns, with particular attention to security and data integrity. \ No newline at end of file