Skip to main content

hashtree_cli/
cashu_helper.rs

1pub use cashu_service::{
2    base_helper_args, helper_binary_name, helper_binary_path, run_helper_status, CashuHelperClient,
3    CashuMintBalance, CashuPaymentClient, CashuReceivedPayment, CashuSentPayment, CARGO_HELPER_ENV,
4    CASHU_HELPER_ENV,
5};
6
7#[cfg(test)]
8mod tests {
9    use super::*;
10    use crate::test_support::test_env_lock;
11    use serde_json::json;
12    use std::env;
13    #[cfg(unix)]
14    use std::os::unix::fs::PermissionsExt;
15    use std::path::Path;
16
17    #[test]
18    fn test_helper_binary_path_prefers_env_override() {
19        let _guard = test_env_lock()
20            .lock()
21            .unwrap_or_else(|err| err.into_inner());
22        let temp_dir = tempfile::tempdir().unwrap();
23        let override_path = temp_dir.path().join("custom-helper");
24        std::fs::write(&override_path, b"").unwrap();
25
26        env::set_var(CASHU_HELPER_ENV, &override_path);
27        env::remove_var(CARGO_HELPER_ENV);
28
29        let resolved = helper_binary_path(Path::new("/tmp/htree")).unwrap();
30        assert_eq!(resolved, override_path);
31
32        env::remove_var(CASHU_HELPER_ENV);
33    }
34
35    #[test]
36    fn test_helper_binary_path_falls_back_to_sibling_binary() {
37        let _guard = test_env_lock()
38            .lock()
39            .unwrap_or_else(|err| err.into_inner());
40        env::remove_var(CASHU_HELPER_ENV);
41        env::remove_var(CARGO_HELPER_ENV);
42
43        let temp_dir = tempfile::tempdir().unwrap();
44        let current_exe = temp_dir.path().join("htree");
45        std::fs::write(&current_exe, b"").unwrap();
46        let sibling = temp_dir.path().join(helper_binary_name());
47        std::fs::write(&sibling, b"").unwrap();
48
49        let resolved = helper_binary_path(&current_exe).unwrap();
50        assert_eq!(resolved, sibling);
51    }
52
53    #[cfg(unix)]
54    #[tokio::test]
55    #[allow(clippy::await_holding_lock)]
56    async fn test_cashu_helper_client_send_and_receive_json() {
57        let _guard = test_env_lock()
58            .lock()
59            .unwrap_or_else(|err| err.into_inner());
60        env::remove_var(CARGO_HELPER_ENV);
61
62        let temp_dir = tempfile::tempdir().unwrap();
63        let helper_path = temp_dir.path().join("htree-cashu-stub");
64        let script = format!(
65            "#!/bin/sh\nif [ \"$3\" = \"internal\" ] && [ \"$4\" = \"send\" ]; then\n  printf '%s' '{}'\nelif [ \"$3\" = \"internal\" ] && [ \"$4\" = \"receive\" ]; then\n  cat >/dev/null\n  printf '%s' '{}'\nelse\n  printf '%s' '{}'\nfi\n",
66            json!({
67                "mint_url": "https://mint.example",
68                "unit": "sat",
69                "amount_sat": 3,
70                "send_fee_sat": 1,
71                "operation_id": "op-123",
72                "token": "cashuBtoken"
73            }),
74            json!({
75                "mint_url": "https://mint.example",
76                "unit": "sat",
77                "amount_sat": 3
78            }),
79            json!({"ok": true}),
80        );
81        std::fs::write(&helper_path, script).unwrap();
82        let mut perms = std::fs::metadata(&helper_path).unwrap().permissions();
83        perms.set_mode(0o755);
84        std::fs::set_permissions(&helper_path, perms).unwrap();
85
86        env::set_var(CASHU_HELPER_ENV, &helper_path);
87        let client = CashuHelperClient::discover(temp_dir.path()).unwrap();
88
89        let sent = client
90            .send_payment("https://mint.example", 3)
91            .await
92            .unwrap();
93        assert_eq!(sent.amount_sat, 3);
94        assert_eq!(sent.send_fee_sat, 1);
95        assert_eq!(sent.operation_id, "op-123");
96
97        let received = client.receive_payment("cashuBtoken").await.unwrap();
98        assert_eq!(received.amount_sat, 3);
99        assert_eq!(received.mint_url, "https://mint.example");
100
101        client
102            .revoke_payment("https://mint.example", "op-123")
103            .await
104            .unwrap();
105
106        env::remove_var(CASHU_HELPER_ENV);
107    }
108
109    #[cfg(unix)]
110    #[tokio::test]
111    #[allow(clippy::await_holding_lock)]
112    async fn test_cashu_helper_client_queries_mint_balance_json() {
113        let _guard = test_env_lock()
114            .lock()
115            .unwrap_or_else(|err| err.into_inner());
116        env::remove_var(CARGO_HELPER_ENV);
117
118        let temp_dir = tempfile::tempdir().unwrap();
119        let helper_path = temp_dir.path().join("htree-cashu-stub");
120        let script = format!(
121            "#!/bin/sh\nif [ \"$3\" = \"internal\" ] && [ \"$4\" = \"balance\" ]; then\n  printf '%s' '{}'\nelse\n  printf '%s' '{}'\nfi\n",
122            json!({
123                "mint_url": "https://mint.example",
124                "unit": "sat",
125                "balance_sat": 21
126            }),
127            json!({"ok": true}),
128        );
129        std::fs::write(&helper_path, script).unwrap();
130        let mut perms = std::fs::metadata(&helper_path).unwrap().permissions();
131        perms.set_mode(0o755);
132        std::fs::set_permissions(&helper_path, perms).unwrap();
133
134        env::set_var(CASHU_HELPER_ENV, &helper_path);
135        let client = CashuHelperClient::discover(temp_dir.path()).unwrap();
136        let balance = client.mint_balance("https://mint.example").await.unwrap();
137        assert_eq!(balance.mint_url, "https://mint.example");
138        assert_eq!(balance.unit, "sat");
139        assert_eq!(balance.balance_sat, 21);
140
141        env::remove_var(CASHU_HELPER_ENV);
142    }
143}