From bb8841d2dec8c79d000b8afcfacf4bc2cb36b47a Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Tue, 16 Jun 2026 15:10:37 +0200 Subject: [PATCH 1/3] Instructions for coding agents This is an attempt to guide coding agents when contributing or reviewing code. AGENTS.md and SKILL.md are standards that should be understood by most coding agents. Signed-off-by: Thomas Segismont --- .agents/skills/writing-tests/SKILL.md | 109 +++++++++++++++ AGENTS.md | 189 ++++++++++++++++++++++++++ CLAUDE.md | 9 ++ 3 files changed, 307 insertions(+) create mode 100644 .agents/skills/writing-tests/SKILL.md create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/.agents/skills/writing-tests/SKILL.md b/.agents/skills/writing-tests/SKILL.md new file mode 100644 index 000000000..04c0fdbb2 --- /dev/null +++ b/.agents/skills/writing-tests/SKILL.md @@ -0,0 +1,109 @@ +--- +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 Pattern + +```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 + - 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..3f76ae81c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,189 @@ +# 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. + +### 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 +``` + +### 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 From c2d18ac1b62e66594692cd21d57aaccd49b877c0 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Tue, 16 Jun 2026 17:09:55 +0200 Subject: [PATCH 2/3] Improvements for testing Signed-off-by: Thomas Segismont --- AGENTS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 3f76ae81c..7aa211c0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -74,6 +74,7 @@ Use Vert.x `Future` and `Promise` throughout. Do not use raw callbacks or `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 @@ -135,6 +136,10 @@ public class MyTest { 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 From adc1e1a51f712f14f06a9cb94d7ca5bb745ba96e Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Thu, 18 Jun 2026 14:48:17 +0200 Subject: [PATCH 3/3] Changes after review Signed-off-by: Thomas Segismont --- .agents/skills/writing-tests/SKILL.md | 45 +++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/.agents/skills/writing-tests/SKILL.md b/.agents/skills/writing-tests/SKILL.md index 04c0fdbb2..6a2e0a009 100644 --- a/.agents/skills/writing-tests/SKILL.md +++ b/.agents/skills/writing-tests/SKILL.md @@ -18,25 +18,64 @@ Vert.x SQL Client uses JUnit 4 with Vert.x-specific test utilities. Tests and do ## Test Annotations and Extensions -### Standard Test Pattern +### Standard Test Patterns + +#### Pattern 1: Using Async with Simple Callback ```java @RunWith(VertxUnitRunner.class) public class MyTest { @Test - public void testAsyncOperation(TestContext ctx) { + 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()); - async.complete(); })); } } ``` +#### 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/`