feat: capture stderr as well

This commit is contained in:
Aravinth Manivannan 2023-10-05 00:37:42 +05:30
parent 36c64878e0
commit 86c63f75ab
Signed by: realaravinth
GPG key ID: F8F50389936984FF
6 changed files with 62 additions and 17 deletions

View file

@ -5,6 +5,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::process::{Command, Stdio}; 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,6 +16,12 @@ impl Docker {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct Log {
pub stdout: String,
pub stderr: String,
}
impl Docker { impl Docker {
pub fn version(&self) -> String { pub fn version(&self) -> String {
let version = Command::new("docker") let version = Command::new("docker")
@ -74,12 +82,15 @@ impl Docker {
let out = out.trim(); let out = out.trim();
out.parse::<isize>().unwrap() out.parse::<isize>().unwrap()
} }
pub 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(),
}
} }
pub async fn block_till_container_exists(&self, name: &str, mut timeout: usize) -> bool { pub async fn block_till_container_exists(&self, name: &str, mut timeout: usize) -> bool {
@ -153,10 +164,10 @@ mod tests {
} }
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);
} }

View file

@ -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::Docker; 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 {
@ -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());

View file

@ -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);
} }
} }

View file

@ -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,

View file

@ -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)));
} }
} }

View file

@ -22,7 +22,11 @@
<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 %}
@ -40,7 +44,10 @@
<h3 class="test__name">[FAILED] {{init.container.name}}</h3> <h3 class="test__name">[FAILED] {{init.container.name}}</h3>
</summary> </summary>
{% endif %} {% endif %}
<code>{{ init.container.logs | linebreaksbr }}</code> <h4>STDOUT</h4>
<code>{{ init.container.logs.stdout | linebreaksbr }}</code>
<h4>STDERR</h4>
<code>{{ init.container.logs.stderr | linebreaksbr }}</code>
</details> </details>
{% endfor %} {% endif %} {% endfor %} {% endif %}
</body> </body>