Compare commits
5 commits
9461b858fb
...
639527744b
Author | SHA1 | Date | |
---|---|---|---|
Aravinth Manivannan | 639527744b | ||
Aravinth Manivannan | 86c63f75ab | ||
Aravinth Manivannan | 36c64878e0 | ||
Aravinth Manivannan | bca4c795b2 | ||
Aravinth Manivannan | b5682ccfae |
|
@ -45,7 +45,7 @@ uuid = { version = "1.4.1", features = ["v4", "serde"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
semver = { version = "1.0.18", features = ["serde"] }
|
semver = { version = "1.0.18", features = ["serde"] }
|
||||||
toml = "0.7.6"
|
toml = "0.7.6"
|
||||||
tokio = { version = "1.32.0", features = ["sync", "time"] }
|
tokio = { version = "1.32.0", features = ["sync", "time", "process"] }
|
||||||
clap = { version = "4.4.6", features = ["derive"] }
|
clap = { version = "4.4.6", features = ["derive"] }
|
||||||
actix-rt = "2.7.0"
|
actix-rt = "2.7.0"
|
||||||
tera = { version = "1.19.1", default-features = false }
|
tera = { version = "1.19.1", default-features = false }
|
||||||
|
|
18
src/ctx.rs
18
src/ctx.rs
|
@ -10,7 +10,7 @@ use tokio::sync::mpsc::Sender;
|
||||||
|
|
||||||
use crate::db::*;
|
use crate::db::*;
|
||||||
use crate::docker::Docker;
|
use crate::docker::Docker;
|
||||||
use crate::docker::DockerLike;
|
//use crate::docker::DockerLike;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
use super::complaince::result::Result as CResult;
|
use super::complaince::result::Result as CResult;
|
||||||
|
@ -21,7 +21,7 @@ pub type ArcMinCtx = Arc<dyn MinAppContext>;
|
||||||
pub trait FullAppContext: std::marker::Send + std::marker::Sync + CloneFullAppCtx {
|
pub trait FullAppContext: std::marker::Send + std::marker::Sync + CloneFullAppCtx {
|
||||||
fn settings(&self) -> &Settings;
|
fn settings(&self) -> &Settings;
|
||||||
fn db(&self) -> &Database;
|
fn db(&self) -> &Database;
|
||||||
fn docker(&self) -> Arc<dyn DockerLike>;
|
fn docker(&self) -> Arc<Docker>;
|
||||||
fn results(&self) -> &ResultStore;
|
fn results(&self) -> &ResultStore;
|
||||||
fn port(&self) -> u32;
|
fn port(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
@ -46,13 +46,13 @@ impl Clone for Box<dyn FullAppContext> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MinAppContext: std::marker::Send + std::marker::Sync {
|
pub trait MinAppContext: std::marker::Send + std::marker::Sync {
|
||||||
fn docker_(&self) -> Arc<dyn DockerLike>;
|
fn docker_(&self) -> Arc<Docker>;
|
||||||
fn results_(&self) -> &ResultStore;
|
fn results_(&self) -> &ResultStore;
|
||||||
fn port_(&self) -> u32;
|
fn port_(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinAppContext for Arc<dyn FullAppContext> {
|
impl MinAppContext for Arc<dyn FullAppContext> {
|
||||||
fn docker_(&self) -> Arc<dyn DockerLike> {
|
fn docker_(&self) -> Arc<Docker> {
|
||||||
self.docker()
|
self.docker()
|
||||||
}
|
}
|
||||||
fn results_(&self) -> &ResultStore {
|
fn results_(&self) -> &ResultStore {
|
||||||
|
@ -68,7 +68,7 @@ pub struct DaemonCtx {
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
db: Database,
|
db: Database,
|
||||||
results: ResultStore,
|
results: ResultStore,
|
||||||
docker: Arc<dyn DockerLike>,
|
docker: Arc<Docker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FullAppContext for DaemonCtx {
|
impl FullAppContext for DaemonCtx {
|
||||||
|
@ -78,7 +78,7 @@ impl FullAppContext for DaemonCtx {
|
||||||
fn db(&self) -> &Database {
|
fn db(&self) -> &Database {
|
||||||
&self.db
|
&self.db
|
||||||
}
|
}
|
||||||
fn docker(&self) -> Arc<dyn DockerLike> {
|
fn docker(&self) -> Arc<Docker> {
|
||||||
self.docker.clone()
|
self.docker.clone()
|
||||||
}
|
}
|
||||||
fn results(&self) -> &ResultStore {
|
fn results(&self) -> &ResultStore {
|
||||||
|
@ -90,7 +90,7 @@ impl FullAppContext for DaemonCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinAppContext for DaemonCtx {
|
impl MinAppContext for DaemonCtx {
|
||||||
fn docker_(&self) -> Arc<dyn DockerLike> {
|
fn docker_(&self) -> Arc<Docker> {
|
||||||
self.docker()
|
self.docker()
|
||||||
}
|
}
|
||||||
fn results_(&self) -> &ResultStore {
|
fn results_(&self) -> &ResultStore {
|
||||||
|
@ -120,11 +120,11 @@ impl DaemonCtx {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CliCtx {
|
pub struct CliCtx {
|
||||||
results: ResultStore,
|
results: ResultStore,
|
||||||
docker: Arc<dyn DockerLike>,
|
docker: Arc<Docker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinAppContext for CliCtx {
|
impl MinAppContext for CliCtx {
|
||||||
fn docker_(&self) -> Arc<dyn DockerLike> {
|
fn docker_(&self) -> Arc<Docker> {
|
||||||
self.docker.clone()
|
self.docker.clone()
|
||||||
}
|
}
|
||||||
fn results_(&self) -> &ResultStore {
|
fn results_(&self) -> &ResultStore {
|
||||||
|
|
103
src/docker.rs
103
src/docker.rs
|
@ -3,7 +3,9 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::Command;
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Default, Clone, Eq, PartialEq)]
|
#[derive(Default, Clone, Eq, PartialEq)]
|
||||||
pub struct Docker;
|
pub struct Docker;
|
||||||
|
@ -14,24 +16,14 @@ impl Docker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DockerLike: std::marker::Send + std::marker::Sync + CloneDockerLike {
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
fn version(&self) -> String;
|
pub struct Log {
|
||||||
fn run_container(
|
pub stdout: String,
|
||||||
&self,
|
pub stderr: String,
|
||||||
name: &str,
|
|
||||||
img: &str,
|
|
||||||
detached: bool,
|
|
||||||
env: &HashMap<String, String>,
|
|
||||||
network: Option<String>,
|
|
||||||
pull: bool,
|
|
||||||
);
|
|
||||||
fn get_exit_status(&self, name: &str) -> isize;
|
|
||||||
fn get_logs(&self, name: &str) -> String;
|
|
||||||
fn rm_container(&self, name: &str, force: bool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DockerLike for Docker {
|
impl Docker {
|
||||||
fn version(&self) -> String {
|
pub fn version(&self) -> String {
|
||||||
let version = Command::new("docker")
|
let version = Command::new("docker")
|
||||||
.arg("--version")
|
.arg("--version")
|
||||||
.output()
|
.output()
|
||||||
|
@ -41,7 +33,7 @@ impl DockerLike for Docker {
|
||||||
x.get(1).unwrap().trim().to_string()
|
x.get(1).unwrap().trim().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_container(
|
pub fn run_container(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
img: &str,
|
img: &str,
|
||||||
|
@ -74,12 +66,14 @@ impl DockerLike for Docker {
|
||||||
env_args.push(img.to_string());
|
env_args.push(img.to_string());
|
||||||
let mut child = Command::new("docker")
|
let mut child = Command::new("docker")
|
||||||
.args(&env_args)
|
.args(&env_args)
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("unable to obtain Docker version");
|
.expect("unable to obtain Docker version");
|
||||||
child.wait().unwrap();
|
child.wait().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_exit_status(&self, name: &str) -> isize {
|
pub fn get_exit_status(&self, name: &str) -> isize {
|
||||||
let output = Command::new("docker")
|
let output = Command::new("docker")
|
||||||
.args(["inspect", name, "--format={{.State.ExitCode}}"])
|
.args(["inspect", name, "--format={{.State.ExitCode}}"])
|
||||||
.output()
|
.output()
|
||||||
|
@ -88,15 +82,40 @@ impl DockerLike for Docker {
|
||||||
let out = out.trim();
|
let out = out.trim();
|
||||||
out.parse::<isize>().unwrap()
|
out.parse::<isize>().unwrap()
|
||||||
}
|
}
|
||||||
fn get_logs(&self, name: &str) -> String {
|
pub fn get_logs(&self, name: &str) -> Log {
|
||||||
let output = Command::new("docker")
|
let output = Command::new("docker")
|
||||||
.args(["logs", name])
|
.args(["logs", name])
|
||||||
.output()
|
.output()
|
||||||
.expect("unable to get logs");
|
.expect("unable to get logs");
|
||||||
String::from_utf8(output.stdout).unwrap()
|
Log {
|
||||||
|
stderr: String::from_utf8(output.stderr).unwrap(),
|
||||||
|
stdout: String::from_utf8(output.stdout).unwrap(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rm_container(&self, name: &str, force: bool) {
|
pub async fn block_till_container_exists(&self, name: &str, mut timeout: usize) -> bool {
|
||||||
|
let args = ["container", "inspect", name, "--format={{.State.Status}}"];
|
||||||
|
loop {
|
||||||
|
let out = tokio::process::Command::new("docker")
|
||||||
|
.args(args)
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|_| panic!("unable to run docker command on container {name}"));
|
||||||
|
let out = String::from_utf8(out.stdout).unwrap();
|
||||||
|
let out = out.trim();
|
||||||
|
if out == "exited" {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeout == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tokio::time::sleep(std::time::Duration::new(1, 0)).await;
|
||||||
|
timeout -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rm_container(&self, name: &str, force: bool) {
|
||||||
let args = if force {
|
let args = if force {
|
||||||
vec!["rm", "--force", name]
|
vec!["rm", "--force", name]
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,34 +128,14 @@ impl DockerLike for Docker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CloneDockerLike {
|
|
||||||
/// clone DB
|
|
||||||
fn clone_docker_like(&self) -> Box<dyn DockerLike>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> CloneDockerLike for T
|
|
||||||
where
|
|
||||||
T: DockerLike + Clone + 'static,
|
|
||||||
{
|
|
||||||
fn clone_docker_like(&self) -> Box<dyn DockerLike> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for Box<dyn DockerLike> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
(**self).clone_docker_like()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::utils::get_random;
|
use crate::utils::get_random;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[actix_rt::test]
|
||||||
fn test_docker_util() {
|
async fn test_docker_util() {
|
||||||
let d = Docker::new();
|
let d = Docker::new();
|
||||||
d.version();
|
d.version();
|
||||||
let name = format!("test_sleep__{}", get_random(4));
|
let name = format!("test_sleep__{}", get_random(4));
|
||||||
|
@ -157,12 +156,18 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let out = String::from_utf8(out.stdout).unwrap();
|
let out = String::from_utf8(out.stdout).unwrap();
|
||||||
assert!(out.contains("true"));
|
assert!(out.contains("true"));
|
||||||
std::thread::sleep(std::time::Duration::new(10, 0));
|
|
||||||
|
loop {
|
||||||
|
if d.block_till_container_exists(&name, 13).await {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let logs = d.get_logs(&name);
|
let logs = d.get_logs(&name);
|
||||||
println!("{logs}");
|
println!("{:?}", logs);
|
||||||
assert!(logs.contains("running"));
|
assert!(logs.stdout.contains("running"));
|
||||||
assert!(logs.contains("FOO=BAR"));
|
assert!(logs.stdout.contains("FOO=BAR"));
|
||||||
assert!(logs.contains("BAZ=BOO"));
|
assert!(logs.stdout.contains("BAZ=BOO"));
|
||||||
assert_eq!(d.get_exit_status(&name), 0);
|
assert_eq!(d.get_exit_status(&name), 0);
|
||||||
d.rm_container(&name, true);
|
d.rm_container(&name, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::sync::Arc;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value as JValue;
|
use serde_json::Value as JValue;
|
||||||
|
|
||||||
use crate::docker::DockerLike;
|
use crate::docker::{Docker, Log};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
pub struct Container {
|
pub struct Container {
|
||||||
|
@ -20,11 +20,11 @@ pub struct Container {
|
||||||
|
|
||||||
pub struct DockerCompose {
|
pub struct DockerCompose {
|
||||||
base_dir: PathBuf,
|
base_dir: PathBuf,
|
||||||
docker: Arc<dyn DockerLike>,
|
docker: Arc<Docker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DockerCompose {
|
impl DockerCompose {
|
||||||
pub fn new(base_dir: PathBuf, docker: Arc<dyn DockerLike>) -> Self {
|
pub fn new(base_dir: PathBuf, docker: Arc<Docker>) -> Self {
|
||||||
Self { base_dir, docker }
|
Self { base_dir, docker }
|
||||||
}
|
}
|
||||||
pub fn version() -> String {
|
pub fn version() -> String {
|
||||||
|
@ -72,7 +72,7 @@ impl DockerCompose {
|
||||||
child.wait().unwrap();
|
child.wait().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logs(&self, service: &str) -> String {
|
pub fn logs(&self, service: &str) -> Log {
|
||||||
self.docker.get_logs(service)
|
self.docker.get_logs(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ mod tests {
|
||||||
assert_eq!(services.len(), 2);
|
assert_eq!(services.len(), 2);
|
||||||
for service in services.iter() {
|
for service in services.iter() {
|
||||||
let logs = cmp.logs(&service.name);
|
let logs = cmp.logs(&service.name);
|
||||||
assert!(logs.contains(&format!("NAME={}", service.name)));
|
assert!(logs.stdout.contains(&format!("NAME={}", service.name)));
|
||||||
}
|
}
|
||||||
cmp.down(true, true);
|
cmp.down(true, true);
|
||||||
assert!(cmp.services().is_empty());
|
assert!(cmp.services().is_empty());
|
||||||
|
|
|
@ -108,12 +108,13 @@ async fn main() -> std::io::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::runner::suite::SuiteRunnerState::run_proxy(ctx.as_ref());
|
crate::runner::suite::SuiteRunnerState::run_proxy(ctx.as_ref());
|
||||||
let (suite_results, init_containers) =
|
let (suite_results, init_containers, specimen_logs) =
|
||||||
crate::runner::target::run_target(ctx.as_ref(), path.clone()).await;
|
crate::runner::target::run_target(ctx.as_ref(), path.clone()).await;
|
||||||
let content = crate::runner::results::ArchivableResult {
|
let content = crate::runner::results::ArchivableResult {
|
||||||
commit: "".into(),
|
commit: "".into(),
|
||||||
suites: suite_results,
|
suites: suite_results,
|
||||||
init_containers,
|
init_containers,
|
||||||
|
specimen_logs,
|
||||||
};
|
};
|
||||||
let results_file = path.join("results.json");
|
let results_file = path.join("results.json");
|
||||||
println!("Writing results to: {:?}", path.canonicalize());
|
println!("Writing results to: {:?}", path.canonicalize());
|
||||||
|
|
|
@ -104,7 +104,10 @@ mod tests {
|
||||||
let init = init.get(0).unwrap();
|
let init = init.get(0).unwrap();
|
||||||
assert!(init.success);
|
assert!(init.success);
|
||||||
assert_eq!(init.exit_code, 0);
|
assert_eq!(init.exit_code, 0);
|
||||||
assert!(init.container.logs.contains("All Good"));
|
assert!(
|
||||||
|
init.container.logs.stdout.contains("All Good")
|
||||||
|
|| init.container.logs.stderr.contains("All Good")
|
||||||
|
);
|
||||||
compose.down(true, true);
|
compose.down(true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,13 @@ pub async fn run(ctx: AppFullCtx, commit: &str) {
|
||||||
Git::checkout_commit(commit, &control);
|
Git::checkout_commit(commit, &control);
|
||||||
|
|
||||||
for entry in crate::runner::target::get_targets(&control).iter() {
|
for entry in crate::runner::target::get_targets(&control).iter() {
|
||||||
let (suite_results, init_containers) =
|
let (suite_results, init_containers, target_logs) =
|
||||||
crate::runner::target::run_target(ctx.as_ref(), entry.into()).await;
|
crate::runner::target::run_target(ctx.as_ref(), entry.into()).await;
|
||||||
let content = ArchivableResult {
|
let content = ArchivableResult {
|
||||||
commit: commit.to_string(),
|
commit: commit.to_string(),
|
||||||
suites: suite_results,
|
suites: suite_results,
|
||||||
init_containers,
|
init_containers,
|
||||||
|
specimen_logs : target_logs,
|
||||||
};
|
};
|
||||||
|
|
||||||
let results_repo = base_dir.join("results");
|
let results_repo = base_dir.join("results");
|
||||||
|
|
|
@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::complaince::suite::Suite;
|
use crate::complaince::suite::Suite;
|
||||||
|
use crate::docker::Log;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct ArchivableInitResult {
|
pub struct ArchivableInitResult {
|
||||||
|
@ -27,9 +28,10 @@ pub struct ArchivableTestResult {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct ArchivableContainer {
|
pub struct ArchivableContainer {
|
||||||
pub logs: String,
|
pub logs: Log,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct ArchivableTest {
|
pub struct ArchivableTest {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -52,6 +54,7 @@ pub struct ArchivableResult {
|
||||||
pub commit: String,
|
pub commit: String,
|
||||||
pub suites: Vec<ArchivableSuiteResult>,
|
pub suites: Vec<ArchivableSuiteResult>,
|
||||||
pub init_containers: Option<Vec<ArchivableInitResult>>,
|
pub init_containers: Option<Vec<ArchivableInitResult>>,
|
||||||
|
pub specimen_logs: Vec<ArchivableContainer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
|
|
@ -59,7 +59,7 @@ impl SuiteRunnerState {
|
||||||
"run",
|
"run",
|
||||||
"-d",
|
"-d",
|
||||||
"-p",
|
"-p",
|
||||||
"9080:9000",
|
"9080:80",
|
||||||
"--name",
|
"--name",
|
||||||
FTEST_NGINX_PROXY,
|
FTEST_NGINX_PROXY,
|
||||||
"--network",
|
"--network",
|
||||||
|
@ -132,9 +132,14 @@ impl SuiteRunnerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn collect_results(mut self, ctx: &dyn MinAppContext) -> ArchivableSuiteResult {
|
async fn collect_results(mut self, ctx: &dyn MinAppContext) -> ArchivableSuiteResult {
|
||||||
|
const TIMEOUT: usize = 40;
|
||||||
|
|
||||||
let mut tests = Vec::with_capacity(self.tests.len());
|
let mut tests = Vec::with_capacity(self.tests.len());
|
||||||
for (_auth, mut r) in self.tests.drain() {
|
for (_auth, mut r) in self.tests.drain() {
|
||||||
let result = r.rx.recv().await.unwrap();
|
let result = r.rx.recv().await.unwrap();
|
||||||
|
ctx.docker_()
|
||||||
|
.block_till_container_exists(&r.container_name, TIMEOUT)
|
||||||
|
.await;
|
||||||
let log = ctx.docker_().get_logs(&r.container_name);
|
let log = ctx.docker_().get_logs(&r.container_name);
|
||||||
ctx.docker_().rm_container(&r.container_name, true);
|
ctx.docker_().rm_container(&r.container_name, true);
|
||||||
let container = ArchivableContainer {
|
let container = ArchivableContainer {
|
||||||
|
@ -307,19 +312,36 @@ mod tests {
|
||||||
archivable_test.result.logs,
|
archivable_test.result.logs,
|
||||||
format!("{}{LOGS}", archivable_test.result.container.name)
|
format!("{}{LOGS}", archivable_test.result.container.name)
|
||||||
);
|
);
|
||||||
println!("{}", archivable_test.result.container.logs);
|
println!("{:?}", archivable_test.result.container.logs);
|
||||||
assert!(archivable_test.result.container.logs.contains("FTEST_AUTH"));
|
|
||||||
assert!(archivable_test.result.container.logs.contains("FTEST_HOST"));
|
|
||||||
assert!(archivable_test
|
assert!(archivable_test
|
||||||
.result
|
.result
|
||||||
.container
|
.container
|
||||||
.logs
|
.logs
|
||||||
|
.stdout
|
||||||
|
.contains("FTEST_AUTH"));
|
||||||
|
assert!(archivable_test
|
||||||
|
.result
|
||||||
|
.container
|
||||||
|
.logs
|
||||||
|
.stdout
|
||||||
|
.contains("FTEST_HOST"));
|
||||||
|
assert!(archivable_test
|
||||||
|
.result
|
||||||
|
.container
|
||||||
|
.logs
|
||||||
|
.stdout
|
||||||
.contains("FTEST_TARGET_HOST"));
|
.contains("FTEST_TARGET_HOST"));
|
||||||
assert!(archivable_test.result.container.logs.contains("FTEST_USER"));
|
|
||||||
assert!(archivable_test
|
assert!(archivable_test
|
||||||
.result
|
.result
|
||||||
.container
|
.container
|
||||||
.logs
|
.logs
|
||||||
|
.stdout
|
||||||
|
.contains("FTEST_USER"));
|
||||||
|
assert!(archivable_test
|
||||||
|
.result
|
||||||
|
.container
|
||||||
|
.logs
|
||||||
|
.stdout
|
||||||
.contains(&format!("TEST_NAME={}", t.name)));
|
.contains(&format!("TEST_NAME={}", t.name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,11 @@ pub async fn run_target(
|
||||||
) -> (
|
) -> (
|
||||||
Vec<ArchivableSuiteResult>,
|
Vec<ArchivableSuiteResult>,
|
||||||
Option<Vec<ArchivableInitResult>>,
|
Option<Vec<ArchivableInitResult>>,
|
||||||
|
Vec<ArchivableContainer>,
|
||||||
) {
|
) {
|
||||||
let compose = DockerCompose::new(target.canonicalize().unwrap(), ctx.docker_().clone());
|
let compose = DockerCompose::new(target.canonicalize().unwrap(), ctx.docker_().clone());
|
||||||
compose.up();
|
compose.up();
|
||||||
let services = compose.services();
|
let mut services = compose.services();
|
||||||
|
|
||||||
// Read test suite
|
// Read test suite
|
||||||
let ftest_path = target.join(FTEST_TARGET_FILE);
|
let ftest_path = target.join(FTEST_TARGET_FILE);
|
||||||
|
@ -43,13 +44,17 @@ pub async fn run_target(
|
||||||
|
|
||||||
// shut down target instance
|
// shut down target instance
|
||||||
let mut target_logs = Vec::with_capacity(services.len());
|
let mut target_logs = Vec::with_capacity(services.len());
|
||||||
for s in services.iter() {
|
for s in services.drain(0..) {
|
||||||
target_logs.push(compose.logs(&s.service));
|
let logs = compose.logs(&s.service);
|
||||||
|
target_logs.push(ArchivableContainer {
|
||||||
|
logs,
|
||||||
|
name: s.service,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
compose.down(true, true);
|
compose.down(true, true);
|
||||||
|
|
||||||
(suite_results, init_containers)
|
(suite_results, init_containers, target_logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_targets(control: &Path) -> Vec<PathBuf> {
|
pub fn get_targets(control: &Path) -> Vec<PathBuf> {
|
||||||
|
|
|
@ -22,27 +22,48 @@
|
||||||
<h4>Logs</h4>
|
<h4>Logs</h4>
|
||||||
<code>{{ test.result.logs | linebreaksbr }}</code>
|
<code>{{ test.result.logs | linebreaksbr }}</code>
|
||||||
<h4>Container Logs: {{ test.result.container.name }}</h4>
|
<h4>Container Logs: {{ test.result.container.name }}</h4>
|
||||||
<code>{{ test.result.container.logs | linebreaksbr }}</code>
|
<h5>STDOUT</h5>
|
||||||
|
<code>{{ test.result.container.logs.stdout | linebreaksbr }}</code>
|
||||||
|
<h5>STDERR</h5>
|
||||||
|
<code>{{ test.result.container.logs.stderr | linebreaksbr }}</code>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
{% endfor %} {% endfor %} {% if payload.results.init_containers %}
|
{% endfor %} {% endfor %} {% if payload.results.init_containers %}
|
||||||
|
|
||||||
<h2>Initialization Workflow</h2>
|
<h2>Initialization Workflow</h2>
|
||||||
|
|
||||||
{% for init in payload.results.init_containers %}
|
{% for init in payload.results.init_containers %}
|
||||||
|
<details>
|
||||||
<details>
|
{% if init.success %}
|
||||||
{% if init.success %}
|
<summary>
|
||||||
<summary>
|
<h3 class="test__name">[OK] {{init.container.name}}</h3>
|
||||||
<h3 class="test__name">[OK] {{init.container.name}}</h3>
|
</summary>
|
||||||
</summary>
|
{% else %}
|
||||||
{% else %}
|
<summary>
|
||||||
<summary>
|
<h3 class="test__name">[FAILED] {{init.container.name}}</h3>
|
||||||
<h3 class="test__name">[FAILED] {{init.container.name}}</h3>
|
</summary>
|
||||||
</summary>
|
{% endif %}
|
||||||
{% endif %}
|
<h4>STDOUT</h4>
|
||||||
<code>{{ init.container.logs | linebreaksbr }}</code>
|
<code>{{ init.container.logs.stdout | linebreaksbr }}</code>
|
||||||
</details>
|
<h4>STDERR</h4>
|
||||||
|
<code>{{ init.container.logs.stderr | linebreaksbr }}</code>
|
||||||
|
</details>
|
||||||
{% endfor %} {% endif %}
|
{% endfor %} {% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Specimen Logs</h2>
|
||||||
|
{% for specimen in payload.results.specimen_logs %}
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<h3 class="test__name">{{specimen.name}}</h3>
|
||||||
|
</summary>
|
||||||
|
<h4>STDOUT</h4>
|
||||||
|
<code>{{ specimen.logs.stdout | linebreaksbr }}</code>
|
||||||
|
<h4>STDERR</h4>
|
||||||
|
<code>{{ specimen.logs.stderr | linebreaksbr }}</code>
|
||||||
|
</details>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
<style>
|
<style>
|
||||||
.test__name {
|
.test__name {
|
||||||
|
|
Loading…
Reference in a new issue