From daba984def2a7bb8868767483cb85d5aac4bdd28 Mon Sep 17 00:00:00 2001 From: Siegfried Weber Date: Mon, 31 May 2021 13:34:06 +0200 Subject: [PATCH 1/3] Annotation "FeatureLogs" checked and assertions adapted --- tests/logs.rs | 54 ++++++++++++++++++++++++++++++----------- tests/test/kube.rs | 60 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/tests/logs.rs b/tests/logs.rs index 27c14e7..b56fb17 100644 --- a/tests/logs.rs +++ b/tests/logs.rs @@ -4,6 +4,7 @@ use test::prelude::*; struct EchoService<'a> { client: &'a TestKubeClient, pod: TemporaryResource<'a, Pod>, + pub logs_enabled: bool, } impl<'a> EchoService<'a> { @@ -44,9 +45,22 @@ impl<'a> EchoService<'a> { }), ); - client.verify_pod_condition(&pod, "Ready"); - - EchoService { client, pod } + const FEATURE_LOGS_KEY: &str = "featureLogs"; + let inner_pod: &Pod = &pod; + let logs_enabled = match client.get_annotation(inner_pod, FEATURE_LOGS_KEY).as_ref() { + "true" => true, + "false" => false, + value => panic!( + "Unknown value [{}] for pod annotation [{}]", + value, FEATURE_LOGS_KEY, + ), + }; + + EchoService { + client, + pod, + logs_enabled, + } } pub fn get_logs(&self, params: &LogParams) -> Vec { @@ -62,7 +76,12 @@ fn all_logs_should_be_retrievable() { let echo_service = EchoService::new(&client, &log_output); let logs = echo_service.get_logs(&LogParams::default()); - assert_equals(&["line 1", "line 2", "line 3"], &logs); + + if echo_service.logs_enabled { + assert_equals(&["line 1", "line 2", "line 3"], &logs); + } else { + assert_that(&logs).is_empty(); + } } #[test] @@ -80,28 +99,35 @@ fn the_tail_of_logs_should_be_retrievable() { let logs = echo_service.get_logs(&with_tail_lines(0)); assert_that(&logs).is_empty(); - let logs = echo_service.get_logs(&with_tail_lines(1)); - assert_equals(&["line 3"], &logs); + if echo_service.logs_enabled { + let logs = echo_service.get_logs(&with_tail_lines(1)); + assert_equals(&["line 3"], &logs); - let logs = echo_service.get_logs(&with_tail_lines(2)); - assert_equals(&["line 2", "line 3"], &logs); + let logs = echo_service.get_logs(&with_tail_lines(2)); + assert_equals(&["line 2", "line 3"], &logs); - let logs = echo_service.get_logs(&with_tail_lines(3)); - assert_equals(&["line 1", "line 2", "line 3"], &logs); + let logs = echo_service.get_logs(&with_tail_lines(3)); + assert_equals(&["line 1", "line 2", "line 3"], &logs); - let logs = echo_service.get_logs(&with_tail_lines(4)); - assert_equals(&["line 1", "line 2", "line 3"], &logs); + let logs = echo_service.get_logs(&with_tail_lines(4)); + assert_equals(&["line 1", "line 2", "line 3"], &logs); + } } #[test] -fn non_ascii_characters_should_be_handled_correctly() { +fn non_ascii_characters_should_be_handled_correctly_in_the_logs() { let client = TestKubeClient::new(); let log_output = vec!["Spade: ♠", "Heart: ♥", "Diamond: ♦", "Club: ♣"]; let echo_service = EchoService::new(&client, &log_output); let logs = echo_service.get_logs(&LogParams::default()); - assert_equals(&["Spade: ♠", "Heart: ♥", "Diamond: ♦", "Club: ♣"], &logs); + + if echo_service.logs_enabled { + assert_equals(&["Spade: ♠", "Heart: ♥", "Diamond: ♦", "Club: ♣"], &logs); + } else { + assert_that(&logs).is_empty(); + } } fn assert_equals(expected: &[&str], actual: &[String]) { diff --git a/tests/test/kube.rs b/tests/test/kube.rs index 2260b40..254e8e7 100644 --- a/tests/test/kube.rs +++ b/tests/test/kube.rs @@ -123,8 +123,20 @@ impl TestKubeClient { .expect("Resource could not be deleted") }) } + /// Returns the value of the annotation for the given resource. + pub fn get_annotation(&self, resource: &K, key: &str) -> String + where + K: Clone + DeserializeOwned + Meta, + { + self.runtime.block_on(async { + self.kube_client + .get_annotation(resource, key) + .await + .expect("Annotation could not be retrieved") + }) + } - /// Verifies that the given pod condition becomes true within 30 seconds. + /// Verifies that the given pod condition becomes true within the specified timeout. pub fn verify_pod_condition(&self, pod: &Pod, condition_type: &str) { self.runtime.block_on(async { self.kube_client @@ -161,6 +173,7 @@ pub struct Timeouts { pub apply_crd: Duration, pub create: Duration, pub delete: Duration, + pub get_annotation: Duration, pub verify_pod_condition: Duration, } @@ -170,6 +183,7 @@ impl Default for Timeouts { apply_crd: Duration::from_secs(30), create: Duration::from_secs(10), delete: Duration::from_secs(10), + get_annotation: Duration::from_secs(10), verify_pod_condition: Duration::from_secs(30), } } @@ -224,7 +238,6 @@ impl KubeClient { let mut stream = crds.watch(&lp, "0").await?.boxed(); while let Some(status) = stream.try_next().await? { - println!("{:?}", status); if let WatchEvent::Modified(crd) = status { if is_ready(&crd) { return Ok(()); @@ -325,7 +338,48 @@ impl KubeClient { )) } - /// Verifies that the given pod condition becomes true within 30 seconds. + /// Returns the value of the annotation for the given resource. + pub async fn get_annotation(&self, resource: &K, key: &str) -> Result + where + K: Clone + DeserializeOwned + Meta, + { + let get_value = |resource: &K| { + resource + .meta() + .annotations + .as_ref() + .and_then(|annotations| annotations.get(key).cloned()) + }; + + let timeout_secs = self.timeouts.get_annotation.as_secs() as u32; + let api: Api = Api::namespaced(self.client.clone(), &self.namespace); + + let lp = ListParams::default() + .fields(&format!("metadata.name={}", resource.name())) + .timeout(timeout_secs); + let mut stream = api.watch(&lp, "0").await?.boxed(); + + if let Some(value) = get_value(&resource) { + return Ok(value); + } + + while let Some(event) = stream.try_next().await? { + if let WatchEvent::Added(resource) = event { + if let Some(value) = get_value(&resource) { + return Ok(value); + } + } + } + + Err(anyhow!( + "Annotation [{}] could not be retrieved from [{}] within {} seconds", + key, + resource.name(), + timeout_secs + )) + } + + /// Verifies that the given pod condition becomes true within the specified timeout. pub async fn verify_pod_condition(&self, pod: &Pod, condition_type: &str) -> Result<()> { let is_condition_true = |pod: &Pod| { get_pod_conditions(pod) From 43a7c763da38465b42d305a7906aec0b40043865 Mon Sep 17 00:00:00 2001 From: Siegfried Weber Date: Tue, 1 Jun 2021 10:54:36 +0200 Subject: [PATCH 2/3] Code improved --- tests/logs.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/logs.rs b/tests/logs.rs index b56fb17..a8d9c5d 100644 --- a/tests/logs.rs +++ b/tests/logs.rs @@ -45,14 +45,20 @@ impl<'a> EchoService<'a> { }), ); - const FEATURE_LOGS_KEY: &str = "featureLogs"; - let inner_pod: &Pod = &pod; - let logs_enabled = match client.get_annotation(inner_pod, FEATURE_LOGS_KEY).as_ref() { + client.verify_pod_condition(&pod, "Ready"); + + const ANNOTATION_KEY_FEATURE_LOGS: &str = "featureLogs"; + + let logs_enabled = match client + .get_annotation::(&pod, ANNOTATION_KEY_FEATURE_LOGS) + .as_ref() + { "true" => true, "false" => false, value => panic!( - "Unknown value [{}] for pod annotation [{}]", - value, FEATURE_LOGS_KEY, + "Pod annotation [{}] contains unknown value [{}]; \ + expected [true] or [false]", + ANNOTATION_KEY_FEATURE_LOGS, value, ), }; From 23716e9cecdff6338742b624083ea8a7a61cfc10 Mon Sep 17 00:00:00 2001 From: Siegfried Weber Date: Tue, 1 Jun 2021 11:01:10 +0200 Subject: [PATCH 3/3] Code improved --- tests/test/kube.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test/kube.rs b/tests/test/kube.rs index 254e8e7..211a440 100644 --- a/tests/test/kube.rs +++ b/tests/test/kube.rs @@ -123,7 +123,8 @@ impl TestKubeClient { .expect("Resource could not be deleted") }) } - /// Returns the value of the annotation for the given resource. + + /// Returns the value of an annotation for the given resource. pub fn get_annotation(&self, resource: &K, key: &str) -> String where K: Clone + DeserializeOwned + Meta, @@ -338,7 +339,7 @@ impl KubeClient { )) } - /// Returns the value of the annotation for the given resource. + /// Returns the value of an annotation for the given resource. pub async fn get_annotation(&self, resource: &K, key: &str) -> Result where K: Clone + DeserializeOwned + Meta,