obeli_sk_wasm_workers/
lib.rs

1use concepts::StrVariant;
2use std::{error::Error, fmt::Debug};
3use utils::wasm_tools::{self};
4
5pub mod activity;
6mod component_logger;
7pub mod engines;
8pub mod epoch_ticker;
9pub mod std_output_stream;
10pub mod webhook;
11pub mod workflow;
12
13#[derive(thiserror::Error, Debug)]
14pub enum WasmFileError {
15    #[error("cannot read WASM file: {0}")]
16    CannotReadComponent(wasmtime::Error),
17    #[error("cannot decode: {0}")]
18    DecodeError(#[from] wasm_tools::DecodeError),
19    #[error("linking error - {context}, details: {err}")]
20    LinkingError {
21        context: StrVariant,
22        err: Box<dyn Error + Send + Sync>,
23    },
24}
25
26pub mod envvar {
27    #[derive(Clone, derive_more::Debug)]
28    pub struct EnvVar {
29        pub key: String,
30        #[debug(skip)]
31        pub val: String,
32    }
33}
34
35#[cfg(test)]
36pub(crate) mod tests {
37    use std::{sync::Arc, time::Duration};
38
39    use async_trait::async_trait;
40    use concepts::{
41        ComponentId, ComponentRetryConfig, FnName, FunctionFqn, FunctionMetadata, FunctionRegistry,
42        IfcFqnName, PackageIfcFns, ParameterTypes,
43    };
44    use indexmap::IndexMap;
45    use utils::wasm_tools::WasmComponent;
46
47    pub(crate) struct TestingFnRegistry {
48        ffqn_to_fn_details:
49            hashbrown::HashMap<FunctionFqn, (FunctionMetadata, ComponentId, ComponentRetryConfig)>,
50        export_hierarchy: Vec<PackageIfcFns>,
51    }
52
53    impl TestingFnRegistry {
54        pub(crate) fn new_from_components(
55            wasm_components: Vec<(WasmComponent, ComponentId)>,
56        ) -> Arc<dyn FunctionRegistry> {
57            let mut ffqn_to_fn_details = hashbrown::HashMap::new();
58            let mut export_hierarchy: hashbrown::HashMap<
59                IfcFqnName,
60                IndexMap<FnName, FunctionMetadata>,
61            > = hashbrown::HashMap::new();
62            for (wasm_component, component_id) in wasm_components {
63                for exported_function in wasm_component.exim.get_exports(true) {
64                    let ffqn = exported_function.ffqn.clone();
65                    ffqn_to_fn_details.insert(
66                        ffqn.clone(),
67                        (
68                            exported_function.clone(),
69                            component_id.clone(),
70                            ComponentRetryConfig {
71                                max_retries: 0,
72                                retry_exp_backoff: Duration::ZERO,
73                            },
74                        ),
75                    );
76
77                    let index_map = export_hierarchy.entry(ffqn.ifc_fqn.clone()).or_default();
78                    index_map.insert(ffqn.function_name.clone(), exported_function.clone());
79                }
80            }
81            let export_hierarchy = export_hierarchy
82                .into_iter()
83                .map(|(ifc_fqn, fns)| PackageIfcFns {
84                    extension: ifc_fqn.is_extension(),
85                    ifc_fqn,
86                    fns,
87                })
88                .collect();
89            Arc::from(TestingFnRegistry {
90                ffqn_to_fn_details,
91                export_hierarchy,
92            })
93        }
94    }
95
96    #[async_trait]
97    impl FunctionRegistry for TestingFnRegistry {
98        async fn get_by_exported_function(
99            &self,
100            ffqn: &FunctionFqn,
101        ) -> Option<(FunctionMetadata, ComponentId, ComponentRetryConfig)> {
102            self.ffqn_to_fn_details.get(ffqn).cloned()
103        }
104
105        fn all_exports(&self) -> &[PackageIfcFns] {
106            &self.export_hierarchy
107        }
108    }
109
110    pub(crate) fn fn_registry_dummy(ffqns: &[FunctionFqn]) -> Arc<dyn FunctionRegistry> {
111        let component_id = ComponentId::dummy_activity();
112        let mut ffqn_to_fn_details = hashbrown::HashMap::new();
113        let mut export_hierarchy: hashbrown::HashMap<
114            IfcFqnName,
115            IndexMap<FnName, FunctionMetadata>,
116        > = hashbrown::HashMap::new();
117        for ffqn in ffqns {
118            let fn_metadata = FunctionMetadata {
119                ffqn: ffqn.clone(),
120                parameter_types: ParameterTypes::default(),
121                return_type: None,
122                extension: None,
123                submittable: true,
124            };
125            ffqn_to_fn_details.insert(
126                ffqn.clone(),
127                (
128                    fn_metadata.clone(),
129                    component_id.clone(),
130                    ComponentRetryConfig {
131                        max_retries: 0,
132                        retry_exp_backoff: Duration::ZERO,
133                    },
134                ),
135            );
136            let index_map = export_hierarchy.entry(ffqn.ifc_fqn.clone()).or_default();
137            index_map.insert(ffqn.function_name.clone(), fn_metadata);
138        }
139        let export_hierarchy = export_hierarchy
140            .into_iter()
141            .map(|(ifc_fqn, fns)| PackageIfcFns {
142                extension: ifc_fqn.is_extension(),
143                ifc_fqn,
144                fns,
145            })
146            .collect();
147        Arc::new(TestingFnRegistry {
148            ffqn_to_fn_details,
149            export_hierarchy,
150        })
151    }
152
153    mod populate_codegen_cache {
154        use crate::{
155            activity::activity_worker::tests::compile_activity,
156            workflow::workflow_worker::tests::compile_workflow,
157        };
158
159        #[rstest::rstest(wasm_path => [
160            test_programs_fibo_activity_builder::TEST_PROGRAMS_FIBO_ACTIVITY,
161            test_programs_http_get_activity_builder::TEST_PROGRAMS_HTTP_GET_ACTIVITY,
162            test_programs_sleep_activity_builder::TEST_PROGRAMS_SLEEP_ACTIVITY,
163            ])]
164        #[tokio::test]
165        async fn fibo(wasm_path: &str) {
166            compile_activity(wasm_path).await;
167        }
168
169        #[rstest::rstest(wasm_path => [
170            test_programs_fibo_workflow_builder::TEST_PROGRAMS_FIBO_WORKFLOW,
171            test_programs_http_get_workflow_builder::TEST_PROGRAMS_HTTP_GET_WORKFLOW,
172            test_programs_sleep_workflow_builder::TEST_PROGRAMS_SLEEP_WORKFLOW,
173            ])]
174        #[tokio::test]
175        async fn workflow(wasm_path: &str) {
176            compile_workflow(wasm_path).await;
177        }
178
179        #[cfg(not(madsim))]
180        #[rstest::rstest(wasm_path => [
181            test_programs_fibo_webhook_builder::TEST_PROGRAMS_FIBO_WEBHOOK
182            ])]
183        #[tokio::test]
184        async fn webhook(wasm_path: &str) {
185            crate::webhook::webhook_trigger::tests::nosim::compile_webhook(wasm_path).await;
186        }
187    }
188}