From 82696eb56895f905320dd4e37f55838b4bbe588a Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Thu, 5 Sep 2024 10:49:22 +0200 Subject: [PATCH] test Productstore::load --- rust/agama-lib/src/base_http_client.rs | 1 + rust/agama-lib/src/product/settings.rs | 2 +- rust/agama-lib/src/product/store.rs | 77 +++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/rust/agama-lib/src/base_http_client.rs b/rust/agama-lib/src/base_http_client.rs index a080ac4420..8838a6e434 100644 --- a/rust/agama-lib/src/base_http_client.rs +++ b/rust/agama-lib/src/base_http_client.rs @@ -20,6 +20,7 @@ use crate::{auth::AuthToken, error::ServiceError}; /// client.get("/questions").await /// } /// ``` +#[derive(Clone)] pub struct BaseHTTPClient { client: reqwest::Client, pub base_url: String, diff --git a/rust/agama-lib/src/product/settings.rs b/rust/agama-lib/src/product/settings.rs index b4674a3d9c..701444fe72 100644 --- a/rust/agama-lib/src/product/settings.rs +++ b/rust/agama-lib/src/product/settings.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; /// Software settings for installation -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ProductSettings { /// ID of the product to install (e.g., "ALP", "Tumbleweed", etc.) diff --git a/rust/agama-lib/src/product/store.rs b/rust/agama-lib/src/product/store.rs index 1f99dd6c6b..fdebe53088 100644 --- a/rust/agama-lib/src/product/store.rs +++ b/rust/agama-lib/src/product/store.rs @@ -17,6 +17,14 @@ impl ProductStore { }) } + fn non_empty_string(s: String) -> Option { + if s.is_empty() { + None + } else { + Some(s) + } + } + pub async fn load(&self) -> Result { let product = self.product_client.product().await?; let registration_code = self.product_client.registration_code().await?; @@ -24,8 +32,8 @@ impl ProductStore { Ok(ProductSettings { id: Some(product), - registration_code: Some(registration_code), - registration_email: Some(email), + registration_code: Self::non_empty_string(registration_code), + registration_email: Self::non_empty_string(email), }) } @@ -61,3 +69,68 @@ impl ProductStore { Ok(()) } } + +#[cfg(test)] +mod test { + use super::*; + use crate::base_http_client::BaseHTTPClient; + use httpmock::prelude::*; + use std::error::Error; + use tokio::test; // without this, "error: async functions cannot be used for tests" + + fn product_store(mock_server_url: String) -> ProductStore { + let mut bhc = BaseHTTPClient::default(); + bhc.base_url = mock_server_url; + let p_client = ProductHTTPClient::new_with_base(bhc.clone()); + let m_client = ManagerHTTPClient::new_with_base(bhc); + ProductStore { + product_client: p_client, + manager_client: m_client, + } + } + + #[test] + async fn test_getting_product() -> Result<(), Box> { + let server = MockServer::start(); + let software_mock = server.mock(|when, then| { + when.method(GET).path("/api/software/config"); + then.status(200) + .header("content-type", "application/json") + .body( + r#"{ + "patterns": {"xfce":true}, + "product": "Tumbleweed" + }"#, + ); + }); + let registration_mock = server.mock(|when, then| { + when.method(GET).path("/api/software/registration"); + then.status(200) + .header("content-type", "application/json") + .body( + r#"{ + "key": "", + "email": "", + "requirement": "NotRequired" + }"#, + ); + }); + let url = server.url("/api"); + + let store = product_store(url); + let settings = store.load().await?; + + let expected = ProductSettings { + id: Some("Tumbleweed".to_owned()), + registration_code: None, + registration_email: None, + }; + // main assertion + assert_eq!(settings, expected); + + // Ensure the specified mock was called exactly one time (or fail with a detailed error description). + software_mock.assert(); + registration_mock.assert_hits(2); + Ok(()) + } +}