Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install psql and mysql clients
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq postgresql-client default-mysql-client
- name: Run integration tests
env:
INTEGRATION: "1"
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- Clarified that seed phases with only `create_if_missing` can omit the `seed_sets` field entirely (`seed_sets` defaults to empty via `#[serde(default)]`); updated integration test YAML specs accordingly

### Added
- Integration tests with docker-compose for end-to-end testing against real Postgres 16, MySQL 8.0, and nginx services (`tests/integration_test.rs`): wait-for TCP/HTTP/timeout/multiple targets, render template, fetch HTTP, exec command, seed PostgreSQL and MySQL with cross-table reference verification, create database/schema, idempotency, and reset mode
- Additional create-if-missing integration tests: 2 PostgreSQL and 2 MySQL tests using known non-existing database names (`initium_noexist_alpha`, `initium_noexist_beta`) to verify database creation, existence checks, and idempotent re-runs
- `tests/docker-compose.yml` with Postgres, MySQL, and HTTP health-check server definitions
- `tests/fixtures/` with seed spec files and template for integration tests
- `tests/input/` with seed spec files and template for integration tests
- Separate GitHub Actions workflow (`.github/workflows/integration.yml`) for integration tests with service containers
- Helm chart unit tests using helm-unittest plugin (`charts/initium/tests/deployment_test.yaml`) covering deployment rendering, securityContext enforcement, disabled sampleDeployment, multiple initContainers, extraVolumes/extraVolumeMounts, image configuration, workdir mount, and labels
- `helm unittest` step added to CI helm-lint job with automatic plugin installation
Expand Down
47 changes: 33 additions & 14 deletions src/seed/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ impl Database for PostgresDb {
Ok(())
}

// Seed values are untyped strings that may target columns of any type
// (INTEGER, TEXT, etc.). Parameterized queries with $N send values as
// TEXT, which postgres cannot implicitly cast to other types. String
// literals have type `unknown` and auto-cast to the target column type,
// so we use escaped literals here. Identifiers are still sanitized.
fn insert_row(
&mut self,
table: &str,
Expand All @@ -319,20 +324,34 @@ impl Database for PostgresDb {
.map(|c| format!("\"{}\"", sanitize_identifier(c)))
.collect();
let value_list: Vec<String> = values.iter().map(|v| escape_sql_value(v)).collect();
let returning_col = sanitize_identifier(auto_id_column.unwrap_or("id"));
let sql = format!(
"INSERT INTO \"{}\" ({}) VALUES ({}) RETURNING COALESCE(CAST(\"{}\" AS BIGINT), 0)",
sanitize_identifier(table),
col_list.join(", "),
value_list.join(", "),
returning_col
);
let row = self
.client
.query_one(&sql, &[])
.map_err(|e| format!("inserting row into '{}': {}", table, e))?;
let id: i64 = row.get(0);
Ok(Some(id))

if let Some(auto_col) = auto_id_column {
let returning_col = sanitize_identifier(auto_col);
let sql = format!(
"INSERT INTO \"{}\" ({}) VALUES ({}) RETURNING COALESCE(CAST(\"{}\" AS BIGINT), 0)",
sanitize_identifier(table),
col_list.join(", "),
value_list.join(", "),
returning_col
);
let row = self
.client
.query_one(&sql, &[])
.map_err(|e| format!("inserting row into '{}': {}", table, e))?;
let id: i64 = row.get(0);
Ok(Some(id))
} else {
let sql = format!(
"INSERT INTO \"{}\" ({}) VALUES ({})",
sanitize_identifier(table),
col_list.join(", "),
value_list.join(", "),
);
self.client
.execute(&sql, &[])
.map_err(|e| format!("inserting row into '{}': {}", table, e))?;
Ok(None)
}
}

fn row_exists(
Expand Down
2 changes: 1 addition & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ docker compose -f tests/docker-compose.yml down
| `test_waitfor_tcp_postgres` | wait-for TCP against Postgres succeeds |
| `test_waitfor_tcp_mysql` | wait-for TCP against MySQL succeeds |
| `test_waitfor_http_server` | wait-for HTTP against nginx returns 200 |
| `test_waitfor_nonexistent_service` | wait-for against closed port fails with exit code 1 |
| `test_waitfor_nonexistent_service_timeout` | wait-for against closed port fails with exit code 1 |
| `test_waitfor_multiple_targets` | wait-for with Postgres + MySQL + HTTP all reachable |
| `test_render_template` | render envsubst template produces correct output |
| `test_fetch_from_http_server` | fetch from nginx writes HTML to file |
Expand Down
15 changes: 15 additions & 0 deletions tests/input/create-db-mysql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
database:
driver: mysql
url_env: MYSQL_URL
tracking_table: initium_seed

phases:
- name: create_db
order: 1
database: initium_created_db
create_if_missing: true
seed_sets:
- name: placeholder
tables:
- table: products
rows: []
15 changes: 15 additions & 0 deletions tests/input/create-db-postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
database:
driver: postgres
url_env: POSTGRES_URL
tracking_table: initium_seed

phases:
- name: create_db
order: 1
database: initium_created_db
create_if_missing: true
seed_sets:
- name: placeholder
tables:
- table: departments
rows: []
10 changes: 10 additions & 0 deletions tests/input/create-nonexistent-db-alpha-mysql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
database:
driver: mysql
url_env: MYSQL_URL
tracking_table: initium_seed

phases:
- name: create_alpha
order: 1
database: initium_noexist_alpha
create_if_missing: true
10 changes: 10 additions & 0 deletions tests/input/create-nonexistent-db-alpha-postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
database:
driver: postgres
url_env: POSTGRES_URL
tracking_table: initium_seed

phases:
- name: create_alpha
order: 1
database: initium_noexist_alpha
create_if_missing: true
10 changes: 10 additions & 0 deletions tests/input/create-nonexistent-db-beta-mysql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
database:
driver: mysql
url_env: MYSQL_URL
tracking_table: initium_seed

phases:
- name: create_beta
order: 1
database: initium_noexist_beta
create_if_missing: true
10 changes: 10 additions & 0 deletions tests/input/create-nonexistent-db-beta-postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
database:
driver: postgres
url_env: POSTGRES_URL
tracking_table: initium_seed

phases:
- name: create_beta
order: 1
database: initium_noexist_beta
create_if_missing: true
15 changes: 15 additions & 0 deletions tests/input/create-schema-postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
database:
driver: postgres
url_env: POSTGRES_URL
tracking_table: initium_seed

phases:
- name: create_schema
order: 1
schema: test_analytics
create_if_missing: true
seed_sets:
- name: placeholder
tables:
- table: departments
rows: []
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading