|
| 1 | +# Duckgres PostgreSQL Compatibility Integration Tests |
| 2 | + |
| 3 | +This directory contains a comprehensive integration test suite to verify Duckgres compatibility with PostgreSQL 16 for OLAP workloads. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The test suite runs queries against both a real PostgreSQL 16 instance and Duckgres, comparing results to ensure semantic equivalence. This approach catches compatibility issues that unit tests might miss. |
| 8 | + |
| 9 | +### Test Architecture |
| 10 | + |
| 11 | +``` |
| 12 | +┌─────────────────────────────────────────────────────────────────────────┐ |
| 13 | +│ Test Runner (Go) │ |
| 14 | +├─────────────────────────────────────────────────────────────────────────┤ |
| 15 | +│ │ |
| 16 | +│ ┌─────────────────────┐ ┌─────────────────────┐ │ |
| 17 | +│ │ PostgreSQL 16 │ │ Duckgres │ │ |
| 18 | +│ │ (Docker) │ │ (In-Process) │ │ |
| 19 | +│ │ Port: 35432 │ │ Port: dynamic │ │ |
| 20 | +│ └─────────────────────┘ └─────────────────────┘ │ |
| 21 | +│ │ │ │ |
| 22 | +│ └────────────┬───────────────────────┘ │ |
| 23 | +│ │ │ |
| 24 | +│ ▼ │ |
| 25 | +│ ┌──────────────────────┐ │ |
| 26 | +│ │ Result Comparator │ │ |
| 27 | +│ │ - Column names │ │ |
| 28 | +│ │ - Row data │ │ |
| 29 | +│ │ - Type coercion │ │ |
| 30 | +│ └──────────────────────┘ │ |
| 31 | +│ │ |
| 32 | +└─────────────────────────────────────────────────────────────────────────┘ |
| 33 | +``` |
| 34 | + |
| 35 | +## Quick Start |
| 36 | + |
| 37 | +### Prerequisites |
| 38 | + |
| 39 | +- Go 1.21+ |
| 40 | +- Docker and Docker Compose |
| 41 | +- GCC C++ compiler (for DuckDB native bindings - provides libstdc++ for linking) |
| 42 | + |
| 43 | +```bash |
| 44 | +# Fedora/RHEL |
| 45 | +sudo dnf install gcc-c++ |
| 46 | + |
| 47 | +# Ubuntu/Debian |
| 48 | +sudo apt install g++ |
| 49 | + |
| 50 | +# macOS (included with Xcode Command Line Tools) |
| 51 | +xcode-select --install |
| 52 | +``` |
| 53 | + |
| 54 | +### Running Tests |
| 55 | + |
| 56 | +```bash |
| 57 | +# Start PostgreSQL container |
| 58 | +docker-compose -f tests/integration/docker-compose.yml up -d |
| 59 | + |
| 60 | +# Wait for PostgreSQL to be ready (about 5 seconds) |
| 61 | +sleep 5 |
| 62 | + |
| 63 | +# Run all integration tests |
| 64 | +go test -v ./tests/integration/... |
| 65 | + |
| 66 | +# Run without PostgreSQL (Duckgres-only mode) |
| 67 | +# Tests will automatically fall back if PostgreSQL isn't running |
| 68 | +go test -v ./tests/integration/... |
| 69 | + |
| 70 | +# Stop PostgreSQL when done |
| 71 | +docker-compose -f tests/integration/docker-compose.yml down -v |
| 72 | +``` |
| 73 | + |
| 74 | +### Running Specific Test Categories |
| 75 | + |
| 76 | +```bash |
| 77 | +# Data Query Language tests |
| 78 | +go test -v ./tests/integration/... -run TestDQL |
| 79 | + |
| 80 | +# Data Definition Language tests |
| 81 | +go test -v ./tests/integration/... -run TestDDL |
| 82 | + |
| 83 | +# Data Manipulation Language tests |
| 84 | +go test -v ./tests/integration/... -run TestDML |
| 85 | + |
| 86 | +# Data type tests |
| 87 | +go test -v ./tests/integration/... -run TestTypes |
| 88 | + |
| 89 | +# Function tests |
| 90 | +go test -v ./tests/integration/... -run TestFunctions |
| 91 | + |
| 92 | +# System catalog tests |
| 93 | +go test -v ./tests/integration/... -run TestCatalog |
| 94 | + |
| 95 | +# Session command tests |
| 96 | +go test -v ./tests/integration/... -run TestSession |
| 97 | + |
| 98 | +# Wire protocol tests |
| 99 | +go test -v ./tests/integration/... -run TestProtocol |
| 100 | + |
| 101 | +# Client tool compatibility tests |
| 102 | +go test -v ./tests/integration/clients/... |
| 103 | +``` |
| 104 | + |
| 105 | +## Test Coverage |
| 106 | + |
| 107 | +| Category | Test Cases | Description | |
| 108 | +|----------|-----------|-------------| |
| 109 | +| **DQL** | ~150 | SELECT, WHERE, ORDER BY, GROUP BY, JOINs, CTEs, Window functions, Set operations | |
| 110 | +| **DDL** | ~50 | CREATE/ALTER/DROP TABLE, VIEW, INDEX, SCHEMA, constraints | |
| 111 | +| **DML** | ~45 | INSERT, UPDATE, DELETE, RETURNING, ON CONFLICT (UPSERT) | |
| 112 | +| **Types** | ~80 | Numeric, string, date/time, boolean, JSON, arrays, UUID, NULL handling | |
| 113 | +| **Functions** | ~180 | String, numeric, date/time, aggregate, JSON, array, conditional | |
| 114 | +| **Catalog** | ~50 | pg_catalog tables, information_schema, psql meta-commands | |
| 115 | +| **Session** | ~40 | SET, SHOW, RESET, transaction commands | |
| 116 | +| **Protocol** | ~40 | Simple query, prepared statements, transactions, error handling | |
| 117 | +| **Clients** | ~50 | Metabase, Grafana, Superset, Tableau, DBeaver, Fivetran, Airbyte, dbt | |
| 118 | +| **Total** | **~700** | | |
| 119 | + |
| 120 | +## Directory Structure |
| 121 | + |
| 122 | +``` |
| 123 | +tests/integration/ |
| 124 | +├── README.md # This file |
| 125 | +├── docker-compose.yml # PostgreSQL 16 container definition |
| 126 | +├── harness.go # Test harness for side-by-side testing |
| 127 | +├── compare.go # Result comparison utilities |
| 128 | +├── setup_test.go # Test initialization and helpers |
| 129 | +├── fixtures/ |
| 130 | +│ ├── schema.sql # Test table definitions (18 tables, 3 views) |
| 131 | +│ └── data.sql # Test data |
| 132 | +├── dql_test.go # Data Query Language tests |
| 133 | +├── ddl_test.go # Data Definition Language tests |
| 134 | +├── dml_test.go # Data Manipulation Language tests |
| 135 | +├── types_test.go # Data type tests |
| 136 | +├── functions_test.go # Function compatibility tests |
| 137 | +├── catalog_test.go # pg_catalog/information_schema tests |
| 138 | +├── session_test.go # SET/SHOW/transaction tests |
| 139 | +├── protocol_test.go # Wire protocol tests |
| 140 | +└── clients/ |
| 141 | + └── clients_test.go # BI/ETL tool compatibility tests |
| 142 | +``` |
| 143 | + |
| 144 | +## Comparison Strategy |
| 145 | + |
| 146 | +The test suite uses **semantic equivalence** rather than byte-identical comparison: |
| 147 | + |
| 148 | +- **Column names**: Case-insensitive comparison |
| 149 | +- **Row data**: Same values after type normalization |
| 150 | +- **Ordering**: Respects ORDER BY; otherwise treats results as sets |
| 151 | +- **NULL handling**: NULL == NULL for comparison purposes |
| 152 | +- **Numeric precision**: Float tolerance of 1e-9 |
| 153 | +- **Timestamps**: Tolerance of 1 microsecond |
| 154 | +- **JSON**: Parsed and compared structurally |
| 155 | + |
| 156 | +## Skipped Tests |
| 157 | + |
| 158 | +Some tests are skipped with documented reasons: |
| 159 | + |
| 160 | +| Skip Reason | Description | |
| 161 | +|-------------|-------------| |
| 162 | +| `SkipUnsupportedByDuckDB` | Feature not available in DuckDB | |
| 163 | +| `SkipDifferentBehavior` | Intentionally different (documented) | |
| 164 | +| `SkipOLTPFeature` | OLTP feature out of scope | |
| 165 | +| `SkipNetworkType` | Network types (INET, CIDR) not supported | |
| 166 | +| `SkipGeometricType` | Geometric types not supported | |
| 167 | +| `SkipRangeType` | Range types not supported | |
| 168 | +| `SkipTextSearch` | Full-text search not supported | |
| 169 | + |
| 170 | +## Client Tool Compatibility |
| 171 | + |
| 172 | +The test suite includes real queries used by popular tools: |
| 173 | + |
| 174 | +### BI Tools |
| 175 | +- **Metabase**: Schema discovery, table introspection, column metadata |
| 176 | +- **Grafana**: Time column detection, table autocomplete |
| 177 | +- **Superset**: Table listing, column type discovery |
| 178 | +- **Tableau**: Schema/table/column discovery with full metadata |
| 179 | +- **DBeaver**: Catalog info, table and column metadata with descriptions |
| 180 | + |
| 181 | +### ETL Tools |
| 182 | +- **Fivetran**: Schema sync, primary key detection, commented queries |
| 183 | +- **Airbyte**: Table discovery, column introspection |
| 184 | +- **dbt**: Relation existence checks, schema management, transactions |
| 185 | + |
| 186 | +## Adding New Tests |
| 187 | + |
| 188 | +### QueryTest Structure |
| 189 | + |
| 190 | +```go |
| 191 | +tests := []QueryTest{ |
| 192 | + { |
| 193 | + Name: "test_name", // Unique test name |
| 194 | + Query: "SELECT 1", // SQL to execute |
| 195 | + Skip: "", // Skip reason (empty = don't skip) |
| 196 | + DuckgresOnly: false, // true = skip PostgreSQL comparison |
| 197 | + ExpectError: false, // true = expect query to fail |
| 198 | + Options: DefaultCompareOptions(), // Comparison options |
| 199 | + }, |
| 200 | +} |
| 201 | +runQueryTests(t, tests) |
| 202 | +``` |
| 203 | + |
| 204 | +### Custom Comparison Options |
| 205 | + |
| 206 | +```go |
| 207 | +opts := CompareOptions{ |
| 208 | + IgnoreColumnOrder: true, // Compare columns by name, not position |
| 209 | + IgnoreRowOrder: true, // Treat results as sets |
| 210 | + FloatTolerance: 1e-6, // Custom float tolerance |
| 211 | + IgnoreCase: true, // Case-insensitive string comparison |
| 212 | +} |
| 213 | +``` |
| 214 | + |
| 215 | +## Troubleshooting |
| 216 | + |
| 217 | +### PostgreSQL container won't start |
| 218 | + |
| 219 | +```bash |
| 220 | +# Check if port 35432 is in use |
| 221 | +lsof -i :35432 |
| 222 | + |
| 223 | +# View container logs |
| 224 | +docker-compose -f tests/integration/docker-compose.yml logs |
| 225 | +``` |
| 226 | + |
| 227 | +### Tests timeout |
| 228 | + |
| 229 | +```bash |
| 230 | +# Increase test timeout |
| 231 | +go test -v -timeout 10m ./tests/integration/... |
| 232 | +``` |
| 233 | + |
| 234 | +### Connection refused errors |
| 235 | + |
| 236 | +The test harness automatically retries connections. If you still see errors: |
| 237 | + |
| 238 | +```bash |
| 239 | +# Ensure PostgreSQL is ready |
| 240 | +docker-compose -f tests/integration/docker-compose.yml exec postgres pg_isready |
| 241 | + |
| 242 | +# Check Duckgres can start |
| 243 | +go test -v ./tests/integration/... -run TestProtocolSimpleQuery |
| 244 | +``` |
| 245 | + |
| 246 | +## Contributing |
| 247 | + |
| 248 | +1. Add new test cases to the appropriate `*_test.go` file |
| 249 | +2. Use `DuckgresOnly: true` for queries that can't be compared to PostgreSQL |
| 250 | +3. Document skip reasons clearly |
| 251 | +4. Run the full suite before submitting: |
| 252 | + ```bash |
| 253 | + go test -v ./tests/integration/... |
| 254 | + ``` |
0 commit comments