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::Result;
15 use omry_service::tarpc::context;
16 use omry_service::{FloraServiceClient, SearchParameters, SearchResult};
17 use std::sync::Arc;
18 use tokio::time::{self, Duration};
19 use tracing::instrument;
20
21 #[derive(Debug, Clone)]
23 pub struct App {
24 client: FloraServiceClient,
26 }
27
28 impl App {
29 #[must_use]
31 pub fn new(client: FloraServiceClient) -> Self {
32 Self { client }
33 }
34
35 #[instrument]
41 pub async fn search(&self, query: String) -> Result<SearchResult> {
42 const QUERY_BY: &[&str] = &["title", "text-body"];
44
45 let query_by = QUERY_BY
46 .iter()
47 .map(std::string::ToString::to_string)
48 .collect::<Vec<_>>();
49
50 let params = SearchParameters {
51 query,
52 query_by,
53 num_typos: Some(2),
54 filter_by: None,
55 };
56
57 ServiceBridge::search(self, params).await
58 }
59 }
60
61 impl ServiceBridge for App {
62 fn client(&self) -> &FloraServiceClient {
63 &self.client
64 }
65 }
66
67 #[instrument]
70 pub(super) async fn init_app(flora_stack: Arc<FloraStack>) -> Result<App> {
71 const MAX_CONN_ATTEMPTS: usize = 5;
72 const BACKOFF_MULTIPLIER: u32 = 2;
73
74 tokio::spawn(async move {
75 let mut attempts_so_far = 0;
76 let mut backoff_interval = Duration::from_secs(1);
77
78 loop {
87 match flora_stack::flora_client(flora_stack.flora_container()).await {
88 Ok(client) => match client.ping(context::current()).await {
89 Ok(_) => break Ok(App::new(client)),
90 Err(error) => {
91 tracing::warn!("error while initializing the tarpc client: {error}");
92 }
93 },
94 Err(error) => {
95 tracing::warn!("error while creating the flora client: {error}");
96 }
97 }
98
99 if attempts_so_far == MAX_CONN_ATTEMPTS {
100 anyhow::bail!("couldn't succeed after {MAX_CONN_ATTEMPTS} attempts");
101 }
102
103 time::sleep(backoff_interval).await;
104 backoff_interval *= BACKOFF_MULTIPLIER;
105 attempts_so_far += 1;
106 }
107 })
108 .await?
109 }
110}
111
112#[derive(Debug)]
114pub struct OmryFullStack {
115 backend: Arc<FloraStack>,
117
118 app: App,
120}
121
122impl OmryFullStack {
123 #[instrument]
132 pub async fn new() -> Result<Self> {
133 let stack_options = FloraStackOptions {
134 search_sync_interval: Duration::from_secs(5),
135 ..Default::default()
136 };
137
138 let backend = Arc::new(FloraStack::new(Some(stack_options)).await?);
139 let app = test_app::init_app(Arc::clone(&backend)).await?;
140
141 tracing::info!("successfully initialized the test bridge");
142 Ok(Self { backend, app })
143 }
144
145 #[must_use]
147 pub fn app(&self) -> &App {
148 &self.app
149 }
150
151 pub async fn kill_flora_rpc(&mut self) -> Result<()> {
157 self.backend.stop().await?;
158 Ok(())
159 }
160}