onlyne_client/backend/
fake.rs1use super::*;
2use std::collections::{HashMap, HashSet};
3use std::sync::{Arc, Mutex};
4
5#[derive(Clone, Default)]
6pub struct FakeBackend {
7 state: Arc<Mutex<HashMap<String, SessionRef>>>,
8 failed_probes: Arc<Mutex<HashSet<String>>>,
9 pub fail_available: bool,
10}
11
12impl FakeBackend {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 fn guard<'a, T>(
18 mutex: &'a Mutex<T>,
19 task_id: &str,
20 what: &str,
21 ) -> Result<std::sync::MutexGuard<'a, T>> {
22 mutex
23 .lock()
24 .map_err(|_| anyhow::anyhow!("fake {what} lock poisoned for task {task_id}"))
25 }
26
27 pub fn sessions(&self) -> HashMap<String, SessionRef> {
28 Self::guard(&self.state, "<sessions>", "state")
29 .unwrap_or_else(|err| panic!("{err}"))
30 .clone()
31 }
32
33 pub fn fail_probe(&self, task_id: &str) {
35 Self::guard(&self.failed_probes, task_id, "failed_probes")
36 .unwrap_or_else(|err| panic!("{err}"))
37 .insert(task_id.to_owned());
38 }
39
40 pub fn clear_probe_failure(&self, task_id: &str) {
42 Self::guard(&self.failed_probes, task_id, "failed_probes")
43 .unwrap_or_else(|err| panic!("{err}"))
44 .remove(task_id);
45 }
46}
47
48impl SessionBackend for FakeBackend {
49 fn name(&self) -> &'static str {
50 "fake"
51 }
52 fn capabilities(&self) -> Capabilities {
53 Capabilities {
54 spawn: true,
55 attach: true,
56 probe: true,
57 close: true,
58 focus: true,
59 rename: true,
60 }
61 }
62 fn available(&self) -> Result<bool> {
63 Ok(!self.fail_available)
64 }
65 fn spawn(&self, spec: SpawnSpec) -> Result<SessionRef> {
66 let session = SessionRef {
67 task_id: spec.task_id.clone(),
68 backend: self.name().into(),
69 backend_ref: serde_json::json!({"id": spec.task_id}),
70 generation: 1,
71 };
72 Self::guard(&self.state, &session.task_id, "state")?.insert(spec.task_id, session.clone());
73 Ok(session)
74 }
75 fn attach(&self, session: &SessionRef) -> Result<SessionRef> {
76 if Self::guard(&self.state, &session.task_id, "state")?.contains_key(&session.task_id) {
77 Ok(session.clone())
78 } else {
79 anyhow::bail!("fake session not found: {}", session.task_id)
80 }
81 }
82 fn probe(&self, session: &SessionRef) -> Result<ResourceProbe> {
83 let failed = Self::guard(&self.failed_probes, &session.task_id, "failed_probes")?
84 .contains(&session.task_id);
85 Ok(ResourceProbe {
86 alive: !failed
87 && Self::guard(&self.state, &session.task_id, "state")?
88 .contains_key(&session.task_id),
89 attached: !failed,
90 detail: failed.then(|| serde_json::json!({"forced": "probe_failure"})),
91 })
92 }
93 fn close(&self, session: &SessionRef, _reason: CloseReason, _force: bool) -> Result<()> {
94 Self::guard(&self.state, &session.task_id, "state")?.remove(&session.task_id);
95 Ok(())
96 }
97}