Create basic fuzz tests.

Create a mock adaptation to send mock JNICommand to lower level without
triggering HAL. Only SessionInit command is implemented now. More commands are to be added.

Test: adb shell /data/fuzz/$(get_build_var
TARGET_ARCH)/uwb_uci_rust_fuzzer/uwb_uci_rust_fuzzer
Bug: 202531943

Change-Id: I446aec2318869073444cb36ecae085a9153531f9
diff --git a/src/Android.bp b/src/Android.bp
index 1c1c1c0..a81f53e 100755
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -27,6 +27,9 @@
         "libuwb_uci_packets",
 	"libbinder_tokio_rs",
     ],
+    rlibs: [
+        "libarbitrary",
+    ],
     proc_macros: [
         "libasync_trait",
     ],
@@ -163,3 +166,26 @@
         "libenv_logger",
     ],
 }
+
+rust_fuzz {
+    name: "uwb_uci_rust_fuzzer",
+    srcs: [
+        "fuzz/fuzzer.rs",
+    ],
+    rustlibs: [
+        "libarbitrary",
+        "liblog_rust",
+        "libnum_traits",
+        "libtokio",
+        "libuwb_uci_packets",
+        "libuwb_uci_rust",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-uwb-team@google.com",
+        ],
+        componentid: 1042770,
+        fuzz_on_haiku_device: true,
+        fuzz_on_haiku_host: true,
+    },
+}
diff --git a/src/fuzz/fuzzer.rs b/src/fuzz/fuzzer.rs
new file mode 100644
index 0000000..f56739f
--- /dev/null
+++ b/src/fuzz/fuzzer.rs
@@ -0,0 +1,74 @@
+#![no_main]
+#![allow(missing_docs)]
+
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
+use log::{error, info};
+use num_traits::cast::FromPrimitive;
+use std::sync::Arc;
+use tokio::sync::mpsc;
+use uwb_uci_packets::{SessionInitRspBuilder, StatusCode};
+use uwb_uci_rust::adaptation::MockUwbAdaptation;
+use uwb_uci_rust::error::UwbErr;
+use uwb_uci_rust::event_manager::MockEventManager;
+use uwb_uci_rust::uci::{
+    uci_hmsgs, Dispatcher, DispatcherImpl, HalCallback, JNICommand, SyncUwbAdaptation,
+};
+
+fn create_dispatcher_with_mock_adaptation(msgs: Vec<JNICommand>) -> Result<DispatcherImpl, UwbErr> {
+    let (rsp_sender, rsp_receiver) = mpsc::unbounded_channel::<HalCallback>();
+    let mut mock_adaptation = Arc::new(MockUwbAdaptation::new(rsp_sender));
+    let mut mock_event_manager = MockEventManager::new();
+    for msg in &msgs {
+        match msg {
+            JNICommand::Enable => {
+                mock_adaptation.expect_hal_open(Ok(()));
+                mock_adaptation.expect_core_initialization(Ok(()));
+            }
+            JNICommand::Disable(_graceful) => {
+                mock_adaptation.expect_hal_close(Ok(()));
+            }
+            _ => {
+                let (cmd, rsp) = generate_fake_cmd_rsp(msg)?;
+                mock_adaptation.expect_send_uci_message(cmd, Some(rsp), None, Ok(()));
+            }
+        }
+    }
+    DispatcherImpl::new_for_testing(
+        mock_event_manager,
+        mock_adaptation as SyncUwbAdaptation,
+        rsp_receiver,
+    )
+}
+
+fn generate_fake_cmd_rsp(msg: &JNICommand) -> Result<(Vec<u8>, Vec<u8>), UwbErr> {
+    match msg {
+        JNICommand::UciSessionInit(session_id, session_type) => Ok((
+            uci_hmsgs::build_session_init_cmd(*session_id, *session_type)?.build().into(),
+            SessionInitRspBuilder { status: StatusCode::UciStatusOk }.build().into(),
+        )),
+        _ => Err(UwbErr::Undefined),
+    }
+}
+
+fn consume_command(msgs: Vec<JNICommand>) -> Result<(), UwbErr> {
+    let mut mock_dispatcher = create_dispatcher_with_mock_adaptation(msgs.clone())?;
+    for msg in msgs {
+        match msg {
+            JNICommand::Enable => {
+                mock_dispatcher.send_jni_command(JNICommand::Enable)?;
+            }
+            _ => {
+                mock_dispatcher.block_on_jni_command(msg)?;
+            }
+        }
+    }
+    mock_dispatcher.exit();
+    Ok(())
+}
+
+fuzz_target!(|msgs: Vec<JNICommand>| {
+    match consume_command(msgs) {
+        Ok(()) => info!("fuzzing success"),
+        Err(e) => error!("fuzzing failed: {:?}", e),
+    };
+});
diff --git a/src/rust/adaptation/mod.rs b/src/rust/adaptation/mod.rs
index 58405be..5f6f1c3 100644
--- a/src/rust/adaptation/mod.rs
+++ b/src/rust/adaptation/mod.rs
@@ -2,6 +2,7 @@
 
 use crate::error::UwbErr;
 use crate::uci::uci_hrcv;
+use crate::uci::uci_logger::MockUciLogger;
 use crate::uci::uci_logger::{UciLogMode, UciLogger, UciLoggerImpl};
 use crate::uci::HalCallback;
 use android_hardware_uwb::aidl::android::hardware::uwb::{
@@ -19,7 +20,9 @@
 use binder_tokio::{Tokio, TokioRuntime};
 use log::{error, warn};
 use rustutils::system_properties;
+use std::collections::VecDeque;
 use std::sync::Arc;
+use std::sync::Mutex as StdMutex;
 use tokio::runtime::Handle;
 use tokio::sync::{mpsc, Mutex};
 use uwb_uci_packets::{
@@ -195,283 +198,81 @@
     }
 }
 
-#[cfg(test)]
-pub mod tests {
-    #![allow(non_snake_case)]
-    use super::*;
-    use crate::uci::uci_logger::MockUciLogger;
-    use android_hardware_uwb::aidl::android::hardware::uwb::{
-        IUwbChip::IUwbChipAsync, IUwbClientCallback::IUwbClientCallback,
-    };
-    use android_hardware_uwb::binder::{DeathRecipient, Result as BinderResult};
-    use binder::{SpIBinder, StatusCode};
-    use bytes::Bytes;
-    use log::warn;
-    use std::collections::VecDeque;
-    use std::sync::Mutex as StdMutex;
-    use uwb_uci_packets::{
-        GetDeviceInfoCmdBuilder, UciPacketHalPacket, UciPacketPacket, UciVendor_9_CommandBuilder,
-    };
+enum ExpectedCall {
+    Finalize {
+        expected_exit_status: bool,
+    },
+    HalOpen {
+        out: Result<()>,
+    },
+    HalClose {
+        out: Result<()>,
+    },
+    CoreInitialization {
+        out: Result<()>,
+    },
+    SessionInitialization {
+        expected_session_id: i32,
+        out: Result<()>,
+    },
+    SendUciMessage {
+        expected_data: Vec<u8>,
+        rsp_data: Option<Vec<u8>>,
+        notf_data: Option<Vec<u8>>,
+        out: Result<()>,
+    },
+}
 
-    enum ExpectedCall {
-        Finalize {
-            expected_exit_status: bool,
-        },
-        HalOpen {
-            out: Result<()>,
-        },
-        HalClose {
-            out: Result<()>,
-        },
-        CoreInitialization {
-            out: Result<()>,
-        },
-        SessionInitialization {
-            expected_session_id: i32,
-            out: Result<()>,
-        },
-        SendUciMessage {
-            expected_data: Vec<u8>,
-            rsp_data: Option<Vec<u8>>,
-            notf_data: Option<Vec<u8>>,
-            out: Result<()>,
-        },
+pub struct MockUwbAdaptation {
+    rsp_sender: mpsc::UnboundedSender<HalCallback>,
+    expected_calls: StdMutex<VecDeque<ExpectedCall>>,
+}
+
+impl MockUwbAdaptation {
+    pub fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self {
+        Self { rsp_sender, expected_calls: StdMutex::new(VecDeque::new()) }
     }
 
-    pub struct MockUwbAdaptation {
-        rsp_sender: mpsc::UnboundedSender<HalCallback>,
-        expected_calls: StdMutex<VecDeque<ExpectedCall>>,
+    #[allow(dead_code)]
+    pub fn expect_finalize(&self, expected_exit_status: bool) {
+        self.expected_calls
+            .lock()
+            .unwrap()
+            .push_back(ExpectedCall::Finalize { expected_exit_status });
     }
-
-    impl MockUwbAdaptation {
-        pub fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self {
-            Self { rsp_sender, expected_calls: StdMutex::new(VecDeque::new()) }
-        }
-
-        #[allow(dead_code)]
-        pub fn expect_finalize(&self, expected_exit_status: bool) {
-            self.expected_calls
-                .lock()
-                .unwrap()
-                .push_back(ExpectedCall::Finalize { expected_exit_status });
-        }
-        #[allow(dead_code)]
-        pub fn expect_hal_open(&self, out: Result<()>) {
-            self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalOpen { out });
-        }
-        #[allow(dead_code)]
-        pub fn expect_hal_close(&self, out: Result<()>) {
-            self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalClose { out });
-        }
-        #[allow(dead_code)]
-        pub fn expect_core_initialization(&self, out: Result<()>) {
-            self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreInitialization { out });
-        }
-        #[allow(dead_code)]
-        pub fn expect_session_initialization(&self, expected_session_id: i32, out: Result<()>) {
-            self.expected_calls
-                .lock()
-                .unwrap()
-                .push_back(ExpectedCall::SessionInitialization { expected_session_id, out });
-        }
-        #[allow(dead_code)]
-        pub fn expect_send_uci_message(
-            &self,
-            expected_data: Vec<u8>,
-            rsp_data: Option<Vec<u8>>,
-            notf_data: Option<Vec<u8>>,
-            out: Result<()>,
-        ) {
-            self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendUciMessage {
-                expected_data,
-                rsp_data,
-                notf_data,
-                out,
-            });
-        }
-
-        fn create_uwb_client_callback(
-            rsp_sender: mpsc::UnboundedSender<HalCallback>,
-        ) -> UwbClientCallback {
-            // Add tests for the mock logger.
-            UwbClientCallback::new(rsp_sender, Arc::new(MockUciLogger::new()))
-        }
-
-        async fn send_client_event(&self, event: UwbEvent, status: UwbStatus) {
-            let uwb_client_callback =
-                MockUwbAdaptation::create_uwb_client_callback(self.rsp_sender.clone());
-            let _ = uwb_client_callback.onHalEvent(event, status).await;
-        }
-
-        async fn send_client_message(&self, rsp_data: Vec<u8>) {
-            let uwb_client_callback =
-                MockUwbAdaptation::create_uwb_client_callback(self.rsp_sender.clone());
-            let _ = uwb_client_callback.onUciMessage(&rsp_data).await;
-        }
+    #[allow(dead_code)]
+    pub fn expect_hal_open(&self, out: Result<()>) {
+        self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalOpen { out });
     }
-
-    impl Drop for MockUwbAdaptation {
-        fn drop(&mut self) {
-            assert!(self.expected_calls.lock().unwrap().is_empty());
-        }
+    #[allow(dead_code)]
+    pub fn expect_hal_close(&self, out: Result<()>) {
+        self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalClose { out });
     }
-
-    #[async_trait]
-    impl UwbAdaptation for MockUwbAdaptation {
-        async fn finalize(&mut self, exit_status: bool) {
-            let mut expected_calls = self.expected_calls.lock().unwrap();
-            match expected_calls.pop_front() {
-                Some(ExpectedCall::Finalize { expected_exit_status })
-                    if expected_exit_status == exit_status =>
-                {
-                    return;
-                }
-                Some(call) => {
-                    expected_calls.push_front(call);
-                }
-                None => {}
-            }
-            warn!("unpected finalize() called");
-        }
-
-        async fn hal_open(&self) -> Result<()> {
-            let expected_out = {
-                let mut expected_calls = self.expected_calls.lock().unwrap();
-                match expected_calls.pop_front() {
-                    Some(ExpectedCall::HalOpen { out }) => Some(out),
-                    Some(call) => {
-                        expected_calls.push_front(call);
-                        None
-                    }
-                    None => None,
-                }
-            };
-
-            match expected_out {
-                Some(out) => {
-                    let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
-                    self.send_client_event(UwbEvent::OPEN_CPLT, status).await;
-                    out
-                }
-                None => {
-                    warn!("unpected hal_open() called");
-                    Err(UwbErr::Undefined)
-                }
-            }
-        }
-
-        async fn hal_close(&self) -> Result<()> {
-            let expected_out = {
-                let mut expected_calls = self.expected_calls.lock().unwrap();
-                match expected_calls.pop_front() {
-                    Some(ExpectedCall::HalClose { out }) => Some(out),
-                    Some(call) => {
-                        expected_calls.push_front(call);
-                        None
-                    }
-                    None => None,
-                }
-            };
-
-            match expected_out {
-                Some(out) => {
-                    let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
-                    self.send_client_event(UwbEvent::CLOSE_CPLT, status).await;
-                    out
-                }
-                None => {
-                    warn!("unpected hal_close() called");
-                    Err(UwbErr::Undefined)
-                }
-            }
-        }
-
-        async fn core_initialization(&self) -> Result<()> {
-            let expected_out = {
-                let mut expected_calls = self.expected_calls.lock().unwrap();
-                match expected_calls.pop_front() {
-                    Some(ExpectedCall::CoreInitialization { out }) => Some(out),
-                    Some(call) => {
-                        expected_calls.push_front(call);
-                        None
-                    }
-                    None => None,
-                }
-            };
-
-            match expected_out {
-                Some(out) => {
-                    let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
-                    self.send_client_event(UwbEvent::POST_INIT_CPLT, status).await;
-                    out
-                }
-                None => {
-                    warn!("unpected core_initialization() called");
-                    Err(UwbErr::Undefined)
-                }
-            }
-        }
-
-        async fn session_initialization(&self, session_id: i32) -> Result<()> {
-            let expected_out = {
-                let mut expected_calls = self.expected_calls.lock().unwrap();
-                match expected_calls.pop_front() {
-                    Some(ExpectedCall::SessionInitialization { expected_session_id, out })
-                        if expected_session_id == session_id =>
-                    {
-                        Some(out)
-                    }
-                    Some(call) => {
-                        expected_calls.push_front(call);
-                        None
-                    }
-                    None => None,
-                }
-            };
-
-            match expected_out {
-                Some(out) => out,
-                None => {
-                    warn!("unpected session_initialization() called");
-                    Err(UwbErr::Undefined)
-                }
-            }
-        }
-
-        async fn send_uci_message(&self, cmd: UciCommandPacket) -> Result<()> {
-            let expected_out = {
-                let mut expected_calls = self.expected_calls.lock().unwrap();
-                match expected_calls.pop_front() {
-                    Some(ExpectedCall::SendUciMessage {
-                        expected_data,
-                        rsp_data,
-                        notf_data,
-                        out,
-                    }) if expected_data == cmd.to_vec() => Some((rsp_data, notf_data, out)),
-                    Some(call) => {
-                        expected_calls.push_front(call);
-                        None
-                    }
-                    None => None,
-                }
-            };
-
-            match expected_out {
-                Some((rsp_data, notf_data, out)) => {
-                    if let Some(rsp) = rsp_data {
-                        self.send_client_message(rsp).await;
-                    }
-                    if let Some(notf) = notf_data {
-                        self.send_client_message(notf).await;
-                    }
-                    out
-                }
-                None => {
-                    warn!("unpected send_uci_message() called");
-                    Err(UwbErr::Undefined)
-                }
-            }
-        }
+    #[allow(dead_code)]
+    pub fn expect_core_initialization(&self, out: Result<()>) {
+        self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreInitialization { out });
+    }
+    #[allow(dead_code)]
+    pub fn expect_session_initialization(&self, expected_session_id: i32, out: Result<()>) {
+        self.expected_calls
+            .lock()
+            .unwrap()
+            .push_back(ExpectedCall::SessionInitialization { expected_session_id, out });
+    }
+    #[allow(dead_code)]
+    pub fn expect_send_uci_message(
+        &self,
+        expected_data: Vec<u8>,
+        rsp_data: Option<Vec<u8>>,
+        notf_data: Option<Vec<u8>>,
+        out: Result<()>,
+    ) {
+        self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendUciMessage {
+            expected_data,
+            rsp_data,
+            notf_data,
+            out,
+        });
     }
 
     fn create_uwb_client_callback(
@@ -481,6 +282,196 @@
         UwbClientCallback::new(rsp_sender, Arc::new(MockUciLogger::new()))
     }
 
+    async fn send_client_event(&self, event: UwbEvent, status: UwbStatus) {
+        let uwb_client_callback =
+            MockUwbAdaptation::create_uwb_client_callback(self.rsp_sender.clone());
+        let _ = uwb_client_callback.onHalEvent(event, status).await;
+    }
+
+    async fn send_client_message(&self, rsp_data: Vec<u8>) {
+        let uwb_client_callback =
+            MockUwbAdaptation::create_uwb_client_callback(self.rsp_sender.clone());
+        let _ = uwb_client_callback.onUciMessage(&rsp_data).await;
+    }
+}
+
+impl Drop for MockUwbAdaptation {
+    fn drop(&mut self) {
+        assert!(self.expected_calls.lock().unwrap().is_empty());
+    }
+}
+
+#[async_trait]
+impl UwbAdaptation for MockUwbAdaptation {
+    async fn finalize(&mut self, exit_status: bool) {
+        let mut expected_calls = self.expected_calls.lock().unwrap();
+        match expected_calls.pop_front() {
+            Some(ExpectedCall::Finalize { expected_exit_status })
+                if expected_exit_status == exit_status =>
+            {
+                return;
+            }
+            Some(call) => {
+                expected_calls.push_front(call);
+            }
+            None => {}
+        }
+        warn!("unpected finalize() called");
+    }
+
+    async fn hal_open(&self) -> Result<()> {
+        let expected_out = {
+            let mut expected_calls = self.expected_calls.lock().unwrap();
+            match expected_calls.pop_front() {
+                Some(ExpectedCall::HalOpen { out }) => Some(out),
+                Some(call) => {
+                    expected_calls.push_front(call);
+                    None
+                }
+                None => None,
+            }
+        };
+
+        match expected_out {
+            Some(out) => {
+                let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
+                self.send_client_event(UwbEvent::OPEN_CPLT, status).await;
+                out
+            }
+            None => {
+                warn!("unpected hal_open() called");
+                Err(UwbErr::Undefined)
+            }
+        }
+    }
+
+    async fn hal_close(&self) -> Result<()> {
+        let expected_out = {
+            let mut expected_calls = self.expected_calls.lock().unwrap();
+            match expected_calls.pop_front() {
+                Some(ExpectedCall::HalClose { out }) => Some(out),
+                Some(call) => {
+                    expected_calls.push_front(call);
+                    None
+                }
+                None => None,
+            }
+        };
+
+        match expected_out {
+            Some(out) => {
+                let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
+                self.send_client_event(UwbEvent::CLOSE_CPLT, status).await;
+                out
+            }
+            None => {
+                warn!("unpected hal_close() called");
+                Err(UwbErr::Undefined)
+            }
+        }
+    }
+
+    async fn core_initialization(&self) -> Result<()> {
+        let expected_out = {
+            let mut expected_calls = self.expected_calls.lock().unwrap();
+            match expected_calls.pop_front() {
+                Some(ExpectedCall::CoreInitialization { out }) => Some(out),
+                Some(call) => {
+                    expected_calls.push_front(call);
+                    None
+                }
+                None => None,
+            }
+        };
+
+        match expected_out {
+            Some(out) => {
+                let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
+                self.send_client_event(UwbEvent::POST_INIT_CPLT, status).await;
+                out
+            }
+            None => {
+                warn!("unpected core_initialization() called");
+                Err(UwbErr::Undefined)
+            }
+        }
+    }
+
+    async fn session_initialization(&self, session_id: i32) -> Result<()> {
+        let expected_out = {
+            let mut expected_calls = self.expected_calls.lock().unwrap();
+            match expected_calls.pop_front() {
+                Some(ExpectedCall::SessionInitialization { expected_session_id, out })
+                    if expected_session_id == session_id =>
+                {
+                    Some(out)
+                }
+                Some(call) => {
+                    expected_calls.push_front(call);
+                    None
+                }
+                None => None,
+            }
+        };
+
+        match expected_out {
+            Some(out) => out,
+            None => {
+                warn!("unpected session_initialization() called");
+                Err(UwbErr::Undefined)
+            }
+        }
+    }
+
+    async fn send_uci_message(&self, cmd: UciCommandPacket) -> Result<()> {
+        let expected_out = {
+            let mut expected_calls = self.expected_calls.lock().unwrap();
+            match expected_calls.pop_front() {
+                Some(ExpectedCall::SendUciMessage { expected_data, rsp_data, notf_data, out })
+                    if expected_data == cmd.to_vec() =>
+                {
+                    Some((rsp_data, notf_data, out))
+                }
+                Some(call) => {
+                    expected_calls.push_front(call);
+                    None
+                }
+                None => None,
+            }
+        };
+
+        match expected_out {
+            Some((rsp_data, notf_data, out)) => {
+                if let Some(rsp) = rsp_data {
+                    self.send_client_message(rsp).await;
+                }
+                if let Some(notf) = notf_data {
+                    self.send_client_message(notf).await;
+                }
+                out
+            }
+            None => {
+                warn!("unpected send_uci_message() called");
+                Err(UwbErr::Undefined)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+fn create_uwb_client_callback(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> UwbClientCallback {
+    // Add tests for the mock logger.
+    UwbClientCallback::new(rsp_sender, Arc::new(MockUciLogger::new()))
+}
+
+#[cfg(test)]
+pub mod tests {
+    #![allow(non_snake_case)]
+    use super::*;
+    use android_hardware_uwb::aidl::android::hardware::uwb::IUwbClientCallback::IUwbClientCallback;
+    use binder::{SpIBinder, StatusCode};
+    use bytes::Bytes;
+    use uwb_uci_packets::{GetDeviceInfoCmdBuilder, UciVendor_9_CommandBuilder};
     enum ExpectedHalCall {
         Open { out: BinderResult<()> },
         Close { out: BinderResult<()> },
@@ -531,6 +522,11 @@
             assert!(self.expected_calls.lock().unwrap().is_empty());
         }
     }
+    impl Default for MockHal {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
 
     impl binder::Interface for MockHal {}
 
@@ -649,7 +645,6 @@
                     None => None,
                 }
             };
-
             match expected_out {
                 Some(out) => Box::pin(std::future::ready(out)),
                 None => Box::pin(std::future::ready(Err(StatusCode::UNKNOWN_ERROR.into()))),
diff --git a/src/rust/event_manager/mod.rs b/src/rust/event_manager/mod.rs
index f3abd7b..c8e5f65 100644
--- a/src/rust/event_manager/mod.rs
+++ b/src/rust/event_manager/mod.rs
@@ -712,14 +712,10 @@
     }
 }
 
-#[cfg(test)]
 use log::warn;
-#[cfg(test)]
 use std::collections::VecDeque;
-#[cfg(test)]
 use std::sync::Mutex;
 
-#[cfg(test)]
 enum ExpectedCall {
     DeviceStatus { out: Result<()> },
     CoreGenericError { out: Result<()> },
@@ -730,13 +726,11 @@
     VendorUci { out: Result<()> },
 }
 
-#[cfg(test)]
 #[derive(Default)]
 pub struct MockEventManager {
     expected_calls: Mutex<VecDeque<ExpectedCall>>,
 }
 
-#[cfg(test)]
 impl MockEventManager {
     pub fn new() -> Self {
         Default::default()
@@ -792,14 +786,11 @@
     }
 }
 
-#[cfg(test)]
 impl Drop for MockEventManager {
     fn drop(&mut self) {
         assert!(self.expected_calls.lock().unwrap().is_empty());
     }
 }
-
-#[cfg(test)]
 impl EventManager for MockEventManager {
     fn device_status_notification_received(&self, _data: DeviceStatusNtfPacket) -> Result<()> {
         let out = {
diff --git a/src/rust/lib.rs b/src/rust/lib.rs
index f9a18ab..d42e060 100644
--- a/src/rust/lib.rs
+++ b/src/rust/lib.rs
@@ -17,7 +17,7 @@
 // moves into packages/modules/Uwb
 #![allow(missing_docs)]
 
-mod adaptation;
+pub mod adaptation;
 pub mod error;
 pub mod event_manager;
 pub mod uci;
diff --git a/src/rust/uci/mod.rs b/src/rust/uci/mod.rs
index b6c38bd..3b60478 100644
--- a/src/rust/uci/mod.rs
+++ b/src/rust/uci/mod.rs
@@ -25,6 +25,7 @@
 use android_hardware_uwb::aidl::android::hardware::uwb::{
     UwbEvent::UwbEvent, UwbStatus::UwbStatus,
 };
+use arbitrary::Arbitrary;
 use log::{debug, error, info, warn};
 use std::future::Future;
 use std::option::Option;
@@ -41,10 +42,10 @@
 
 pub type Result<T> = std::result::Result<T, UwbErr>;
 pub type UciResponseHandle = oneshot::Sender<UciResponse>;
-type SyncUwbAdaptation = Arc<dyn UwbAdaptation + Send + Sync>;
+pub type SyncUwbAdaptation = Arc<dyn UwbAdaptation + Send + Sync>;
 
 // Commands sent from JNI.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Arbitrary, Clone, Debug, PartialEq, Eq)]
 pub enum JNICommand {
     // Blocking UCI commands
     UciGetCapsInfo,
@@ -488,7 +489,6 @@
         Self::new_with_args(event_manager, adaptation, rsp_receiver)
     }
 
-    #[cfg(test)]
     pub fn new_for_testing<T: 'static + EventManager + Send + Sync>(
         event_manager: T,
         adaptation: SyncUwbAdaptation,
@@ -557,7 +557,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::adaptation::tests::MockUwbAdaptation;
+    use crate::adaptation::MockUwbAdaptation;
     use crate::event_manager::MockEventManager;
     use android_hardware_uwb::aidl::android::hardware::uwb::{
         UwbEvent::UwbEvent, UwbStatus::UwbStatus,
diff --git a/src/rust/uci/uci_logger.rs b/src/rust/uci/uci_logger.rs
index 1277032..79a11f4 100644
--- a/src/rust/uci/uci_logger.rs
+++ b/src/rust/uci/uci_logger.rs
@@ -331,24 +331,20 @@
     }
 }
 
-#[cfg(test)]
 pub struct MockUciLogger {}
 
-#[cfg(test)]
 impl MockUciLogger {
     pub fn new() -> Self {
         MockUciLogger {}
     }
 }
 
-#[cfg(test)]
 impl Default for MockUciLogger {
     fn default() -> Self {
         Self::new()
     }
 }
 
-#[cfg(test)]
 #[async_trait]
 impl UciLogger for MockUciLogger {
     async fn log_uci_command(&self, _cmd: UciCommandPacket) {}