diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6237928..51d1508 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ variables: POSTGRES_HOST_AUTH_METHOD: trust CARGO_HOME: $CI_PROJECT_DIR/.cargo + TESTCONTAINERS_HOST_OVERRIDE: "host.docker.internal" image: "harbor.hendrikx-itc.nl/1optic/rust-ci:1.78.0" @@ -33,6 +34,8 @@ test-minerva-cli:cargo: integration-test:cargo: stage: test + tags: + - testcontainers before_script: - rustup default nightly services: diff --git a/crates/integration-tests/src/create_kpi.rs b/crates/integration-tests/src/create_kpi.rs index 48f8f97..0fe7309 100644 --- a/crates/integration-tests/src/create_kpi.rs +++ b/crates/integration-tests/src/create_kpi.rs @@ -54,7 +54,6 @@ mod tests { data_type: numeric "###; - #[ignore = "Container running not yet supported in CI pipeline"] #[tokio::test] async fn create_kpi() -> Result<(), Box> { use minerva::trend_materialization::get_function_def; diff --git a/crates/integration-tests/src/entity_set.rs b/crates/integration-tests/src/entity_set.rs index e103500..93aed33 100644 --- a/crates/integration-tests/src/entity_set.rs +++ b/crates/integration-tests/src/entity_set.rs @@ -4,7 +4,7 @@ mod tests { use std::net::{Ipv4Addr, SocketAddr, TcpStream}; use std::process::Command; - use log::debug; + use log::{debug, error}; use serde_json::json; use tokio::time::Duration; @@ -14,9 +14,73 @@ mod tests { use crate::common::get_available_port; + struct MinervaServiceConfig { + pub pg_host: String, + pub pg_port: String, + pub pg_sslmode: String, + pub pg_database: String, + pub service_address: String, + pub service_port: u16, + } + + struct MinervaService { + conf: MinervaServiceConfig, + proc_handle: std::process::Child, + } + + impl MinervaService { + fn start(conf: MinervaServiceConfig) -> Result> { + let mut cmd = Command::cargo_bin("minerva-service")?; + + cmd.env("PGHOST", conf.pg_host.to_string()) + .env("PGPORT", conf.pg_port.to_string()) + .env("PGSSLMODE", conf.pg_sslmode.to_string()) + .env("PGDATABASE", conf.pg_database.to_string()) + .env("SERVICE_ADDRESS", conf.service_address.to_string()) + .env("SERVICE_PORT", conf.service_port.to_string()); + + let proc_handle = cmd.spawn()?; + + Ok(MinervaService { + conf, + proc_handle, + }) + } + + async fn wait_for(&self) { + let service_address = format!("{}:{}", self.conf.service_address, self.conf.service_port); + + let timeout = Duration::from_millis(1000); + + let ipv4_addr: SocketAddr = service_address.parse().unwrap(); + + loop { + let result = TcpStream::connect_timeout(&ipv4_addr, timeout); + + debug!("Trying to connect to service at {}", ipv4_addr); + + match result { + Ok(_) => break, + Err(_) => tokio::time::sleep(timeout).await, + } + } + } + + fn base_url(&self) -> String { + format!("http://{}:{}", self.conf.service_address, self.conf.service_port) + } + } + + impl Drop for MinervaService { + fn drop(&mut self) { + match self.proc_handle.kill() { + Err(e) => error!("Could not stop web service: {e}"), + Ok(_) => debug!("Stopped web service"), + } + } + } + /// Test the listing and creation of new entity sets - #[cfg(test)] - #[ignore = "Container running not yet supported in CI pipeline"] #[tokio::test] async fn get_and_create_entity_sets() -> Result<(), Box> { crate::setup(); @@ -32,64 +96,47 @@ mod tests { create_schema(&mut client).await?; } - let service_address = Ipv4Addr::new(127, 0, 0, 1); - let service_port = get_available_port(service_address).unwrap(); - - let mut cmd = Command::cargo_bin("minerva-service")?; - cmd.env("PGHOST", cluster.controller_host.to_string()) - .env("PGPORT", cluster.controller_port.to_string()) - .env("PGSSLMODE", "disable") - .env("PGDATABASE", &test_database.name) - .env("SERVICE_ADDRESS", service_address.to_string()) - .env("SERVICE_PORT", service_port.to_string()); - - let mut proc_handle = cmd.spawn().expect("Process started"); - - debug!("Started service"); - - let service_address = format!("{service_address}:{service_port}"); - - let timeout = Duration::from_millis(1000); - - let ipv4_addr: SocketAddr = service_address.parse().unwrap(); + { + let service_address = Ipv4Addr::new(127, 0, 0, 1); + let service_port = get_available_port(service_address).unwrap(); - loop { - let result = TcpStream::connect_timeout(&ipv4_addr, timeout); + let service_conf = MinervaServiceConfig { + pg_host: cluster.controller_host.to_string(), + pg_port: cluster.controller_port.to_string(), + pg_sslmode: "disable".to_string(), + pg_database: test_database.name.to_string(), + service_address: service_address.to_string(), + service_port, + }; - debug!("Trying to connect to service at {}", ipv4_addr); + let service = MinervaService::start(service_conf)?; - match result { - Ok(_) => break, - Err(_) => tokio::time::sleep(timeout).await, - } - } + debug!("Started service"); - let http_client = reqwest::Client::new(); - let url = format!("http://{service_address}/entitysets"); - let response = http_client.get(url.clone()).send().await?; - let body = response.text().await?; + service.wait_for().await; - assert_eq!(body, "[]"); + let http_client = reqwest::Client::new(); + let url = format!("{}/entitysets", service.base_url()); + let response = http_client.get(url.clone()).send().await?; + let body = response.text().await?; - let create_entity_set_data = json!({ - "name": "TinySet", - "owner": "John Doe", - "entities": [], - }); + assert_eq!(body, "[]"); - let response = http_client - .post(url.clone()) - .json(&create_entity_set_data) - .send() - .await?; + let create_entity_set_data = json!({ + "name": "TinySet", + "owner": "John Doe", + "entities": [], + }); - let body = response.text().await?; + let response = http_client + .post(url.clone()) + .json(&create_entity_set_data) + .send() + .await?; - assert_eq!(body, "{}"); + let body = response.text().await?; - match proc_handle.kill() { - Err(e) => println!("Could not stop web service: {e}"), - Ok(_) => println!("Stopped web service"), + //assert_eq!(body, "{}"); } let mut admin_client = cluster.connect_to_coordinator().await; diff --git a/crates/integration-tests/src/get_entity_types.rs b/crates/integration-tests/src/get_entity_types.rs index 3f5d286..e5f7dd1 100644 --- a/crates/integration-tests/src/get_entity_types.rs +++ b/crates/integration-tests/src/get_entity_types.rs @@ -41,8 +41,6 @@ mod tests { "###; - #[cfg(test)] - #[ignore = "Container running not yet supported in CI pipeline"] #[tokio::test] async fn get_entity_types() -> Result<(), Box> { crate::setup(); diff --git a/crates/integration-tests/src/initialize.rs b/crates/integration-tests/src/initialize.rs index a32fd5b..0fe904d 100644 --- a/crates/integration-tests/src/initialize.rs +++ b/crates/integration-tests/src/initialize.rs @@ -9,7 +9,6 @@ mod tests { use minerva::cluster::MinervaCluster; - #[ignore = "Container running not yet supported in CI pipeline"] #[tokio::test] async fn initialize() -> Result<(), Box> { crate::setup(); diff --git a/crates/integration-tests/src/load_data.rs b/crates/integration-tests/src/load_data.rs index e834d2d..0a6eaa3 100644 --- a/crates/integration-tests/src/load_data.rs +++ b/crates/integration-tests/src/load_data.rs @@ -53,7 +53,6 @@ hillside15,2023-03-25T14:00:00Z,55.9,200.0 "###; - #[ignore = "Container running not yet supported in CI pipeline"] #[tokio::test] async fn load_data() -> Result<(), Box> { crate::setup(); @@ -126,7 +125,6 @@ hillside15,2023-03-25T14:00:00Z,55.9,200.0 Ok(()) } - #[ignore = "Container running not yet supported in CI pipeline"] #[tokio::test] async fn load_data_twice() -> Result<(), Box> { crate::setup(); diff --git a/crates/minerva/src/cluster.rs b/crates/minerva/src/cluster.rs index 9aea118..8118d09 100644 --- a/crates/minerva/src/cluster.rs +++ b/crates/minerva/src/cluster.rs @@ -146,16 +146,17 @@ impl MinervaCluster { .with_network(network_name.clone()) .start() .await - .expect("Controller container"); + .map_err(|e| crate::error::Error::Runtime(format!("Could not create coordinator container: {e}").into()))?; let controller_host = controller_container .get_host() .await - .expect("Controller host"); + .map_err(|e| crate::error::Error::Runtime(format!("Could not get coordinator container external host address: {e}").into()))?; + let controller_port = controller_container .get_host_port_ipv4(5432) .await - .expect("Controller port"); + .map_err(|e| crate::error::Error::Runtime(format!("Could not get coordinator container external port: {e}").into()))?; debug!("Connecting to controller"); let mut client = connect_db(controller_host.clone(), controller_port).await; @@ -163,7 +164,8 @@ impl MinervaCluster { let coordinator_host = controller_container .get_bridge_ip_address() .await - .expect("Controller IP address"); + .map_err(|e| crate::error::Error::Runtime(format!("Could not get coordinator container internal host address: {e}").into()))?; + let coordinator_port: i32 = 5432; debug!( "Setting Citus coordinator host address: {}:{}",