diff --git a/.agents/skills/writing-tests/SKILL.md b/.agents/skills/writing-tests/SKILL.md new file mode 100644 index 000000000..6a2e0a009 --- /dev/null +++ b/.agents/skills/writing-tests/SKILL.md @@ -0,0 +1,148 @@ +--- +name: writing-tests +description: > + Testing patterns for Vert.x SQL Client: test frameworks, async testing, + test locations, and how to run tests. +--- + +# Writing Tests + +Vert.x SQL Client uses JUnit 4 with Vert.x-specific test utilities. Tests and documentation are mandatory for contributions. + +## Test Framework + +- **JUnit 4** (version 4.13.1) - Standard test framework +- **VertxUnitRunner** - JUnit 4 runner for async tests +- **TestContext** - Async test utility for handling asynchronous operations +- **Docker** - Required for integration tests (database containers) + +## Test Annotations and Extensions + +### Standard Test Patterns + +#### Pattern 1: Using Async with Simple Callback + +```java +@RunWith(VertxUnitRunner.class) +public class MyTest { + + @Test + public void testWithAsync(TestContext ctx) { + Async async = ctx.async(); + vertx.runOnContext(v -> async.complete()); + } +} +``` + +#### Pattern 2: Using asyncAssertSuccess Directly + +When using `asyncAssertSuccess`, do not call `async.complete()` as it creates an async internally: + +```java +@RunWith(VertxUnitRunner.class) +public class MyTest { + + @Test + public void testAsyncAssertSuccess(TestContext ctx) { + client.query("SELECT 1") + .execute() + .onComplete(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + })); + } +} +``` + +#### Pattern 3: Using asyncAssertSuccess from runOnContext + +When calling `asyncAssertSuccess` from `runOnContext`, you need an explicit async: + +```java +@RunWith(VertxUnitRunner.class) +public class MyTest { + + @Test + public void testAsyncAssertSuccessFromRunOnContext(TestContext ctx) { + Async async = ctx.async(); + vertx.runOnContext(v -> { + client.query("SELECT 1") + .execute() + .onComplete(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + async.complete(); + })); + }); + } +} +``` + +## Test Location + +- **Unit tests**: Same module as code under test, in `src/test/java/` +- **Integration tests**: May be in separate test modules or `src/test/java/` +- **Database-specific tests**: In respective client module + - PostgreSQL: `vertx-pg-client/src/test/` + - MySQL: `vertx-mysql-client/src/test/` + - MSSQL: `vertx-mssql-client/src/test/` + - DB2: `vertx-db2-client/src/test/` + - Oracle: `vertx-oracle-client/src/test/` + +## Test Data Setup + +### Using SQL Scripts + +Place initialization scripts in `src/test/resources/`: + +```sql +-- init.sql +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL +); + +INSERT INTO users (name) VALUES ('Alice'), ('Bob'); +``` + +### Programmatic Setup + +```java +@Before +public void setUp(TestContext ctx) { + Async async = ctx.async(); + client.query("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name VARCHAR(100))") + .execute() + .compose(v -> client.query("INSERT INTO users (name) VALUES ('Alice'), ('Bob')").execute()) + .onComplete(ctx.asyncAssertSuccess(v -> async.complete())); +} + +@After +public void tearDown(TestContext ctx) { + Async async = ctx.async(); + client.query("DROP TABLE IF EXISTS users") + .execute() + .onComplete(ctx.asyncAssertSuccess(v -> async.complete())); +} +``` + +Prefer temporary tables when testing databases that support it (automatically dropped when the connection is closed). + +## Test Requirements + +- **All new features must include tests** +- **Integration tests must clean up resources** (connections, containers) + +## Assertions + +### TestContext Assertions (JUnit 4 style) + +```java +ctx.assertEquals(expected, actual); +ctx.assertTrue(condition); +ctx.assertFalse(condition); +ctx.assertNull(value); +ctx.assertNotNull(value); +``` + +## Common Pitfalls + +1. **Forgetting to complete async tests** - Always call `async.complete()` diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..7aa211c0a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,194 @@ +# Agent Guidelines - vertx-sql-client + +Instructions for AI coding agents working in this repository. +Checkout relevant `.agents/skills/` to accomplish specific tasks. + +## Build & Verify Commands + +```bash +mvn test-compile # compile code and tests +mvn test # run all tests (requires Docker for database interactions) +mvn spotless:check # verify formatting +mvn spotless:apply # auto-fix formatting +``` + +## Project Structure + +This is a multi-module Maven project with the following key modules: + +- **vertx-sql-client**: Core SQL client API and base implementations +- **vertx-sql-client-codec**: Shared codec utilities for data type encoding/decoding +- **vertx-sql-client-templates**: SQL template support for type-safe queries +- **vertx-pg-client**: PostgreSQL-specific client implementation +- **vertx-mysql-client**: MySQL/MariaDB-specific client implementation +- **vertx-mssql-client**: Microsoft SQL Server client implementation +- **vertx-db2-client**: IBM DB2 client implementation +- **vertx-oracle-client**: Oracle Database client implementation + +### Module Layout Pattern + +Each database-specific client follows this structure: +- `src/main/java/`: Public API interfaces and implementation classes + - Top package (e.g., `io.vertx.pgclient`): Public API interfaces + - `impl/` subpackage: Implementation classes (not exported) +- `src/main/asciidoc/`: Module-specific documentation +- `src/test/java/`: Unit and integration tests +- `module-info.java`: Defines module exports and dependencies + +## General Coding Rules + +These rules apply when **writing or modifying code**. Code review is the checkpoint where compliance is verified. + +### Logging + +In production code, use the Vert.x internal logger, never SLF4J, Log4j, or `java.util.logging` directly. + +```java +import io.vertx.core.internal.logging.Logger; +import io.vertx.core.internal.logging.LoggerFactory; + +private static final Logger logger = LoggerFactory.getLogger(MyClass.class); +``` + +Vert.x internal logging API doesn't support parameters placeholders. +Check the active level before debug or trace logging. + +```java +if (logger.isDebugEnabled()) { + logger.debug("Prepared parameters: " + paramDesc); +} +``` + +### Async Patterns + +Use Vert.x `Future` and `Promise` throughout. Do not use raw callbacks or `CompletableFuture` in production code. + +### API Design + +- Public contracts are interfaces in the top package (`io.vertx.sqlclient`, `io.vertx.pgclient`, …) +- Implementations go in `impl/` subpackages +- Annotate public API interfaces and methods with `@VertxGen` for code-generation support +- Expose construction via static factory methods, not constructors + +### Module Boundaries + +`module-info.java` governs exports. +Internal packages are exported only to their corresponding test modules, do not widen exports without discussion. +Test module descriptors (`src/test/java/module-info.java`) can be modified freely, e.g. to add a `requires` for a new dependency used in tests. + +### Copyright Header + +New Java files must include the dual-license header matching existing files: + +```java +/* + * Copyright (c) 2011-2026 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + */ +``` + +The range is always `2011-[current year]`. + +## Testing Guidelines + +For comprehensive testing patterns and examples, see `.agents/skills/writing-tests/SKILL.md`. + +### Test Framework + +- Use **JUnit 4** (version 4.13.1) for all tests +- Async tests use **VertxUnitRunner** (JUnit 4 runner) and **TestContext** +- Integration tests require **Docker** for database containers + +### Test Patterns + +```java +@RunWith(VertxUnitRunner.class) +public class MyTest { + + @Test + public void testAsyncOperation(TestContext ctx) { + Async async = ctx.async(); + client.query("SELECT 1") + .execute() + .onComplete(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + async.complete(); + })); + } +} +``` + +### Test Location + +- **Unit tests**: Same module as code under test, in `src/test/java/` +- **Integration tests**: May be in separate test modules or `src/test/java/` +- **Database-specific tests**: In respective client module (e.g., `vertx-pg-client/src/test/`) + +### Running Tests + +```bash +mvn test # Run all tests (requires Docker) +mvn test -Dtest=MyTest # Run specific test class +mvn test -Dtest=MyTest#testMethod # Run specific test method + +# When your change spans modules (e.g. modifying vertx-sql-client-codec and +# testing in vertx-pg-client), use -am to rebuild dependencies: +mvn test -pl vertx-pg-client -am -Dtest=MyTest +``` + +### Test Requirements + +- All new features must include tests +- Database tests must clean up resources (connections, containers) + +## Development Workflow + +### Incremental Development + +When making changes: +1. Compile frequently: `mvn compile -pl ` +2. Run affected tests: `mvn test -pl ` +3. Verify formatting: `mvn spotless:check` +4. Run full build before PR: `mvn clean install` + +### Build Optimization + +```bash +# Skip tests during development +mvn compile -DskipTests + +# Build specific module and dependencies +mvn install -pl vertx-pg-client -am +``` + +## Specialized Skills + +When performing specific tasks, read the relevant skill file for detailed guidance: + +- **Writing tests** - Read `.agents/skills/writing-tests/SKILL.md` when creating or modifying tests + +## Contribution Process + +- All commits must be signed off: `git commit -s` (DCO) +- Commit messages should end with: `Assisted-by: [Provider] [Model-Family] ([Version/ID])` (replace placeholders) +- Contributors must have signed the [Eclipse Contributor Agreement (ECA)](https://www.eclipse.org/legal/ECA.php) + +See [CONTRIBUTING.md](CONTRIBUTING.md) for the full contribution workflow. + +## Code Review Guidelines + +### Verify + +- General coding rules above are followed +- Test coverage is present; async tests use `VertxUnitRunner` and `TestContext` +- No breaking changes to public interfaces without prior discussion + +### Do Not Comment On + +- Patterns already used consistently throughout the codebase diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..211f907d0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,9 @@ +@AGENTS.md + +# Agent Guidelines - vertx-sql-client + +## Specialized Skills + +When performing specific tasks, read the relevant skill file for detailed guidance: + +- **Writing tests** - Read `.agents/skills/writing-tests/SKILL.md` when creating or modifying tests