diff --git a/AGENTS.md b/AGENTS.md index bbdc51b3d..32346b400 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -113,5 +113,6 @@ Do not open a PR with code changes when the required checks fail. - `crates/iam/AGENTS.md` - `crates/kms/AGENTS.md` - `crates/policy/AGENTS.md` +- `crates/targets/AGENTS.md` - `rustfs/src/admin/AGENTS.md` - `rustfs/src/storage/AGENTS.md` diff --git a/crates/targets/AGENTS.md b/crates/targets/AGENTS.md index 79e6e5771..bb2cdabd9 100644 --- a/crates/targets/AGENTS.md +++ b/crates/targets/AGENTS.md @@ -4,9 +4,9 @@ Applies to `crates/targets/`. `rustfs-targets` provides the notification target abstraction layer: the `Target` trait, built-in implementations (Webhook, Kafka, MQTT, -NATS, Pulsar, MySQL), persistent queue store, DSN/configuration -builders, and the `ChannelTargetType` registry that maps target types -to their runtime factories. +NATS, Pulsar, MySQL, Postgres, Redis), persistent queue store, +DSN/configuration builders, and the `ChannelTargetType` registry that +maps target types to their runtime factories. ## Library Design @@ -27,34 +27,12 @@ to their runtime factories. ## Integration Tests -### MySQL Integration Tests +Integration tests under `tests/` are `#[ignore]` by default so CI never runs +them. See the module-level doc comment in each test file for prerequisites +and run commands: -Integration tests in `tests/mysql_integration.rs` require a running MySQL 8.0+ -or TiDB 8.5+ instance. They are `#[ignore]` by default so CI never runs them. - -Start a test MySQL instance with Podman: - -```bash -podman run -d --name rustfs-mysql-test \ - -e MYSQL_ROOT_PASSWORD=testpass \ - -e MYSQL_DATABASE=testdb \ - -p 3306:3306 \ - docker.io/library/mysql:8.0.36 -``` - -Wait for MySQL to be ready (look for `ready for connections` in logs), -then run the integration tests: - -```bash -RUSTFS_MYSQL_TEST_DSN="root:testpass@tcp(127.0.0.1:3306)/testdb" \ - cargo test -p rustfs-targets -- --ignored -``` - -Clean up: - -```bash -podman rm -f rustfs-mysql-test -``` +- `tests/mysql_integration.rs` — MySQL 8.0+ / TiDB 8.5+ +- `tests/postgres_integration.rs` — PostgreSQL ## Suggested Validation diff --git a/crates/targets/src/target/mod.rs b/crates/targets/src/target/mod.rs index 066f4e23c..7f6581b72 100644 --- a/crates/targets/src/target/mod.rs +++ b/crates/targets/src/target/mod.rs @@ -270,18 +270,21 @@ impl QueuedPayload { /// /// It includes: /// - `Amqp`: Represents an AMQP 0-9-1 target for sending notifications to a broker. -/// - `Webhook`: Represents a webhook target for sending notifications via HTTP requests. -/// - `Kafka`: Represents a Kafka target for sending notifications to a Kafka topic. -/// - `Mqtt`: Represents an MQTT target for sending notifications via MQTT protocol. -/// - `Nats`: Represents a NATS target for sending notifications to a subject. -/// - `Pulsar`: Represents a Pulsar target for sending notifications to a topic. +/// - `Webhook`: Sends notifications via HTTP POST requests. +/// - `Kafka`: Publishes notifications to a Kafka topic. +/// - `Mqtt`: Publishes notifications via MQTT protocol. +/// - `MySql`: Writes notifications to a MySQL/TiDB table. +/// - `Nats`: Publishes notifications to a NATS subject. +/// - `Postgres`: Writes notifications to a PostgreSQL table (namespace or access format). +/// - `Pulsar`: Publishes notifications to a Pulsar topic. +/// - `Redis`: Publishes notifications to a Redis channel (pub/sub). /// /// Each variant has an associated string representation that can be used for serialization /// or logging purposes. /// The `as_str` method returns the string representation of the target type, /// and the `Display` implementation allows for easy formatting of the target type as a string. /// -/// example usage: +/// Example usage: /// ```rust /// use rustfs_targets::target::ChannelTargetType; /// @@ -289,9 +292,6 @@ impl QueuedPayload { /// assert_eq!(target_type.as_str(), "webhook"); /// println!("Target type: {}", target_type); /// ``` -/// -/// example output: -/// Target type: webhook pub enum ChannelTargetType { Amqp, Webhook, diff --git a/crates/targets/tests/mysql_integration.rs b/crates/targets/tests/mysql_integration.rs index 430b70f4f..5f737090e 100644 --- a/crates/targets/tests/mysql_integration.rs +++ b/crates/targets/tests/mysql_integration.rs @@ -15,11 +15,27 @@ //! MySQL notification target integration tests. //! //! These tests require a running MySQL 8.0+ or TiDB 8.5+ instance. -//! Set `RUSTFS_MYSQL_TEST_DSN` to enable them: +//! They are `#[ignore]` by default so CI never runs them. To run locally +//! (podman recommended; docker works too): //! //! ```bash -//! RUSTFS_MYSQL_TEST_DSN="user:pass@tcp(127.0.0.1:3306)/testdb" \ -//! cargo test -p rustfs-targets -- --ignored +//! podman run -d --name rustfs-mysql-test -p 3306:3306 \ +//! -e MYSQL_ROOT_PASSWORD=testpass -e MYSQL_DATABASE=testdb \ +//! docker.io/library/mysql:8.0.36 +//! ``` +//! +//! Wait for MySQL to be ready (look for `ready for connections` in logs), +//! then set `RUSTFS_TEST_MYSQL_DSN` and run: +//! +//! ```bash +//! export RUSTFS_TEST_MYSQL_DSN="root:testpass@tcp(127.0.0.1:3306)/testdb" +//! cargo test -p rustfs-targets --test mysql_integration -- --ignored +//! ``` +//! +//! Clean up: +//! +//! ```bash +//! podman rm -f rustfs-mysql-test //! ``` use mysql_async::{Opts, OptsBuilder, Pool, SslOpts, prelude::Queryable}; @@ -30,7 +46,7 @@ use tempfile::TempDir; use uuid::Uuid; fn test_dsn() -> String { - env::var("RUSTFS_MYSQL_TEST_DSN").expect("RUSTFS_MYSQL_TEST_DSN must be set") + env::var("RUSTFS_TEST_MYSQL_DSN").expect("RUSTFS_TEST_MYSQL_DSN must be set") } fn table_name(prefix: &str) -> String { diff --git a/crates/targets/tests/postgres_integration.rs b/crates/targets/tests/postgres_integration.rs index 33eae7fa4..89d6072fe 100644 --- a/crates/targets/tests/postgres_integration.rs +++ b/crates/targets/tests/postgres_integration.rs @@ -12,20 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Integration tests for the PostgreSQL notification target. +//! PostgreSQL notification target integration tests. //! -//! All tests in this file are `#[ignore]` because they require a running -//! PostgreSQL server. CI does not run them by default. To run locally: +//! These tests require a running PostgreSQL server. They are `#[ignore]` by +//! default so CI never runs them. To run locally +//! (podman recommended; docker works too): //! //! ```bash -//! docker run -d --name rustfs-pg -p 5432:5432 \ -//! -e POSTGRES_PASSWORD=rustfs -e POSTGRES_DB=rustfs_events postgres:16 -//! export RUSTFS_TEST_PG_DSN="postgres://postgres:rustfs@localhost:5432/rustfs_events?search_path=public" +//! podman run -d --name rustfs-pg-test -p 5432:5432 \ +//! -e POSTGRES_PASSWORD=rustfs -e POSTGRES_DB=rustfs_events \ +//! docker.io/library/postgres:16 +//! ``` +//! +//! Wait for PostgreSQL to be ready (look for `database system is ready` in logs), +//! then set `RUSTFS_TEST_PG_DSN` and run: +//! +//! ```bash +//! export RUSTFS_TEST_PG_DSN="postgres://postgres:rustfs@localhost:5432/rustfs_events" //! cargo test -p rustfs-targets --test postgres_integration -- --ignored //! ``` //! -//! Connection parameters can be overridden via environment variable: -//! `RUSTFS_TEST_PG_DSN`. +//! Clean up: +//! +//! ```bash +//! podman rm -f rustfs-pg-test +//! ``` use rustfs_s3_common::EventName; use rustfs_targets::Target; @@ -44,10 +55,7 @@ fn env_or(key: &str, default: &str) -> String { } fn test_args(table: &str, format: PostgresFormat) -> PostgresArgs { - let dsn = env_or( - "RUSTFS_TEST_PG_DSN", - "postgres://postgres:rustfs@localhost:5432/rustfs_events?search_path=public", - ); + let dsn = env_or("RUSTFS_TEST_PG_DSN", "postgres://postgres:rustfs@localhost:5432/rustfs_events"); let schema = PostgresDsn::parse(&dsn) .expect("RUSTFS_TEST_PG_DSN must be a valid PostgreSQL DSN") .schema;