omry_integration/
full_stack.rs1use crate::flora_stack::{FloraStack, FloraStackOptions};
4use anyhow::Result;
5use std::sync::Arc;
6use std::time::Duration;
7pub use test_app::App;
8use tracing::instrument;
9
10mod test_app {
12 use crate::bridge::ServiceBridge;
13 use crate::flora_stack::{self, FloraStack};
14 use anyhow::{Context, Result};
15 use omry_service::FloraServiceClient;
16 use omry_service::search::{SearchParameters, SearchResponse};
17 use omry_service::tarpc::context;
18 use std::sync::Arc;
19 use tokio::time::{self, Duration};
20 use tracing::instrument;
21
22 #[derive(Debug, Clone)]
24 pub struct App {
25 client: FloraServiceClient,
27 }
28
29 impl App {
30 #[must_use]
32 pub fn new(client: FloraServiceClient) -> Self {
33 Self { client }
34 }
35
36 #[instrument]
42 pub async fn search(&self, query: String) -> Result<SearchResponse> {
43 const QUERY_BY: &[&str] = &["title", "text-body"];
45
46 let query_by = QUERY_BY
47 .iter()
48 .map(std::string::ToString::to_string)
49 .collect::<Vec<_>>();
50
51 let params = SearchParameters {
52 query,
53 query_by,
54 num_typos: Some(2),
55 filter_by: None,
56 };
57
58 ServiceBridge::search(self, params.into())
59 .await
60 .context("Couldn't call search")
61 }
62 }
63
64 impl ServiceBridge for App {
65 fn client(&self) -> &FloraServiceClient {
66 &self.client
67 }
68 }
69
70 #[instrument]
73 pub(super) async fn init_app(flora_stack: Arc<FloraStack>) -> Result<App> {
74 const MAX_CONN_ATTEMPTS: usize = 5;
75 const BACKOFF_MULTIPLIER: u32 = 2;
76
77 tokio::spawn(async move {
78 let mut attempts_so_far = 0;
79 let mut backoff_interval = Duration::from_secs(1);
80
81 loop {
90 match flora_stack::flora_client(flora_stack.flora_container()).await {
91 Ok(client) => match client.ping(context::current()).await {
92 Ok(_) => break Ok(App::new(client)),
93 Err(error) => {
94 tracing::warn!("error while initializing the tarpc client: {error}");
95 }
96 },
97 Err(error) => {
98 tracing::warn!("error while creating the flora client: {error}");
99 }
100 }
101
102 if attempts_so_far == MAX_CONN_ATTEMPTS {
103 anyhow::bail!("couldn't succeed after {MAX_CONN_ATTEMPTS} attempts");
104 }
105
106 time::sleep(backoff_interval).await;
107 backoff_interval *= BACKOFF_MULTIPLIER;
108 attempts_so_far += 1;
109 }
110 })
111 .await?
112 }
113}
114
115#[derive(Debug)]
117pub struct OmryFullStack {
118 backend: Arc<FloraStack>,
120
121 app: App,
123}
124
125impl OmryFullStack {
126 #[instrument]
135 pub async fn new() -> Result<Self> {
136 let stack_options = FloraStackOptions {
137 search_sync_interval: Duration::from_secs(5),
138 ..Default::default()
139 };
140
141 let backend = Arc::new(FloraStack::new(Some(stack_options)).await?);
142 let app = test_app::init_app(Arc::clone(&backend)).await?;
143
144 tracing::info!("successfully initialized the test bridge");
145 Ok(Self { backend, app })
146 }
147
148 #[must_use]
150 pub fn app(&self) -> &App {
151 &self.app
152 }
153
154 pub async fn kill_flora_rpc(&mut self) -> Result<()> {
160 self.backend.stop().await?;
161 Ok(())
162 }
163}