Skip to content

Commit 33cec3f

Browse files
committed
test(eventually-postgres): add testcontainers to run postgres
1 parent cfe712d commit 33cec3f

File tree

5 files changed

+85
-37
lines changed

5 files changed

+85
-37
lines changed

Diff for: .github/workflows/ci.yml

-14
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,6 @@ jobs:
2020
required: false
2121
toolchain: nightly
2222

23-
services:
24-
postgres:
25-
env:
26-
POSTGRES_USER: eventually
27-
POSTGRES_PASSWORD: password
28-
POSTGRES_DB: eventually
29-
image: postgres:latest
30-
ports: ["5432:5432"]
31-
options: >-
32-
--health-cmd pg_isready
33-
--health-interval 10s
34-
--health-timeout 5s
35-
--health-retries 5
36-
3723
steps:
3824
- name: Install Protoc
3925
uses: arduino/setup-protoc@v3

Diff for: eventually-postgres/Cargo.toml

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ keywords = ["postgres", "postgresql", "database", "ddd", "event-sourcing"]
1414
[dependencies]
1515
anyhow = "1.0.97"
1616
async-trait = "0.1.77"
17-
chrono = "0.4.34"
17+
chrono = "0.4.40"
1818
eventually = { path = "../eventually", version = "0.5.0", features = [
1919
"serde-json",
2020
] }
21-
futures = "0.3.30"
22-
lazy_static = "1.4.0"
23-
regex = "1.10.3"
21+
futures = "0.3.31"
22+
regex = "1.11.1"
2423
sqlx = { version = "0.8.3", features = [
2524
"runtime-tokio-rustls",
2625
"postgres",
@@ -29,10 +28,11 @@ sqlx = { version = "0.8.3", features = [
2928
thiserror = "2.0.12"
3029

3130
[dev-dependencies]
32-
tokio = { version = "1.36.0", features = ["macros", "rt"] }
31+
tokio = { version = "1.44.1", features = ["macros", "rt"] }
3332
eventually = { path = "../eventually", version = "0.5.0", features = [
3433
"serde-json",
3534
] }
3635
eventually-macros = { path = "../eventually-macros", version = "0.1.0" }
37-
serde = { version = "1.0.197", features = ["derive"] }
36+
serde = { version = "1.0.219", features = ["derive"] }
3837
rand = "0.9.0"
38+
testcontainers-modules = { version = "0.11.6", features = ["postgres"] }

Diff for: eventually-postgres/tests/aggregate_repository.rs

+32-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,29 @@ use eventually::aggregate::repository::{self, GetError, Getter, Saver};
22
use eventually::serde;
33
use eventually_postgres::aggregate;
44
use rand::Rng;
5+
use testcontainers_modules::postgres::Postgres;
6+
use testcontainers_modules::testcontainers::runners::AsyncRunner;
57

68
mod setup;
79

810
#[tokio::test]
911
async fn it_works() {
10-
let pool = setup::connect_to_database()
12+
let container = Postgres::default()
13+
.start()
1114
.await
12-
.expect("connection to the database should work");
15+
.expect("the postgres container should start");
16+
17+
let (host, port) = futures::try_join!(container.get_host(), container.get_host_port_ipv4(5432))
18+
.expect("the postgres container should have both a host and a port exposed");
19+
20+
println!("postgres container is running at {host}:{port}");
21+
22+
let pool = sqlx::PgPool::connect(&format!(
23+
"postgres://postgres:postgres@{}:{}/postgres",
24+
host, port,
25+
))
26+
.await
27+
.expect("should be able to create a connection with the database");
1328

1429
let aggregate_repository = aggregate::Repository::new(
1530
pool,
@@ -56,9 +71,22 @@ async fn it_works() {
5671

5772
#[tokio::test]
5873
async fn it_detects_data_races_and_returns_conflict_error() {
59-
let pool = setup::connect_to_database()
74+
let container = Postgres::default()
75+
.start()
6076
.await
61-
.expect("connection to the database should work");
77+
.expect("the postgres container should start");
78+
79+
let (host, port) = futures::try_join!(container.get_host(), container.get_host_port_ipv4(5432))
80+
.expect("the postgres container should have both a host and a port exposed");
81+
82+
println!("postgres container is running at {host}:{port}");
83+
84+
let pool = sqlx::PgPool::connect(&format!(
85+
"postgres://postgres:postgres@{}:{}/postgres",
86+
host, port,
87+
))
88+
.await
89+
.expect("should be able to create a connection with the database");
6290

6391
let aggregate_repository = aggregate::Repository::new(
6492
pool,

Diff for: eventually-postgres/tests/event_store.rs

+47-6
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,29 @@ use eventually::{serde, version};
77
use eventually_postgres::event;
88
use futures::TryStreamExt;
99
use rand::Rng;
10+
use testcontainers_modules::postgres::Postgres;
11+
use testcontainers_modules::testcontainers::runners::AsyncRunner;
1012

1113
mod setup;
1214

1315
#[tokio::test]
1416
async fn append_with_no_version_check_works() {
15-
let pool = setup::connect_to_database()
17+
let container = Postgres::default()
18+
.start()
1619
.await
17-
.expect("connection to the database should work");
20+
.expect("the postgres container should start");
21+
22+
let (host, port) = futures::try_join!(container.get_host(), container.get_host_port_ipv4(5432))
23+
.expect("the postgres container should have both a host and a port exposed");
24+
25+
println!("postgres container is running at {host}:{port}");
26+
27+
let pool = sqlx::PgPool::connect(&format!(
28+
"postgres://postgres:postgres@{}:{}/postgres",
29+
host, port,
30+
))
31+
.await
32+
.expect("should be able to create a connection with the database");
1833

1934
let event_store = event::Store::new(pool, serde::Json::<setup::TestDomainEvent>::default())
2035
.await
@@ -68,9 +83,22 @@ async fn append_with_no_version_check_works() {
6883

6984
#[tokio::test]
7085
async fn it_works_with_version_check_for_conflict() {
71-
let pool = setup::connect_to_database()
86+
let container = Postgres::default()
87+
.start()
7288
.await
73-
.expect("connection to the database should work");
89+
.expect("the postgres container should start");
90+
91+
let (host, port) = futures::try_join!(container.get_host(), container.get_host_port_ipv4(5432))
92+
.expect("the postgres container should have both a host and a port exposed");
93+
94+
println!("postgres container is running at {host}:{port}");
95+
96+
let pool = sqlx::PgPool::connect(&format!(
97+
"postgres://postgres:postgres@{}:{}/postgres",
98+
host, port,
99+
))
100+
.await
101+
.expect("should be able to create a connection with the database");
74102

75103
let event_store = event::Store::new(pool, serde::Json::<setup::TestDomainEvent>::default())
76104
.await
@@ -143,9 +171,22 @@ async fn it_works_with_version_check_for_conflict() {
143171

144172
#[tokio::test]
145173
async fn it_handles_concurrent_writes_to_the_same_stream() {
146-
let pool = setup::connect_to_database()
174+
let container = Postgres::default()
175+
.start()
147176
.await
148-
.expect("connection to the database should work");
177+
.expect("the postgres container should start");
178+
179+
let (host, port) = futures::try_join!(container.get_host(), container.get_host_port_ipv4(5432))
180+
.expect("the postgres container should have both a host and a port exposed");
181+
182+
println!("postgres container is running at {host}:{port}");
183+
184+
let pool = sqlx::PgPool::connect(&format!(
185+
"postgres://postgres:postgres@{}:{}/postgres",
186+
host, port,
187+
))
188+
.await
189+
.expect("should be able to create a connection with the database");
149190

150191
let event_store = event::Store::new(pool, serde::Json::<setup::TestDomainEvent>::default())
151192
.await

Diff for: eventually-postgres/tests/setup/mod.rs

-7
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ use eventually::aggregate::Aggregate;
66
use eventually::message::Message;
77
use eventually_macros::aggregate_root;
88
use serde::{Deserialize, Serialize};
9-
use sqlx::PgPool;
10-
11-
pub async fn connect_to_database() -> Result<PgPool, sqlx::Error> {
12-
let url = std::env::var("DATABASE_URL").expect("the env var DATABASE_URL is required");
13-
14-
sqlx::PgPool::connect(&url).await
15-
}
169

1710
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1811
pub struct TestAggregateId(pub i64);

0 commit comments

Comments
 (0)