1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    anyhow::{anyhow, Error},
    fidl_fuchsia_space::ErrorCode,
    fuchsia_async as fasync,
    futures::prelude::*,
    std::sync::Arc,
};

type CallHook = Box<dyn Fn() -> Result<(), ErrorCode> + Send + Sync>;

pub struct MockSpaceService {
    call_hook: CallHook,
}

impl MockSpaceService {
    pub fn new(call_hook: CallHook) -> Self {
        Self { call_hook }
    }

    pub fn spawn_space_service(self: &Arc<Self>) -> fidl_fuchsia_space::ManagerProxy {
        let (proxy, stream) =
            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_space::ManagerMarker>()
                .unwrap();

        fasync::Task::spawn(
            Arc::clone(self)
                .run_space_service(stream)
                .unwrap_or_else(|e| panic!("error running space service: {:#}", anyhow!(e))),
        )
        .detach();

        proxy
    }

    pub async fn run_space_service(
        self: Arc<Self>,
        mut stream: fidl_fuchsia_space::ManagerRequestStream,
    ) -> Result<(), Error> {
        while let Some(event) = stream.try_next().await.expect("received request") {
            let fidl_fuchsia_space::ManagerRequest::Gc { responder } = event;
            responder.send((self.call_hook)())?;
        }

        Ok(())
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::atomic::{AtomicU32, Ordering};

    #[fasync::run_singlethreaded(test)]
    async fn test_mock_space() {
        let called = Arc::new(AtomicU32::new(0));
        let called_clone = Arc::clone(&called);
        let mock = Arc::new(MockSpaceService::new(Box::new(move || {
            called_clone.fetch_add(1, Ordering::SeqCst);
            Ok(())
        })));
        let proxy = mock.spawn_space_service();

        assert_eq!(called.load(Ordering::SeqCst), 0);

        let gc_result = proxy.gc().await.expect("made fidl call");
        assert_eq!(gc_result, Ok(()));
        assert_eq!(called.load(Ordering::SeqCst), 1);

        let gc_result = proxy.gc().await.expect("made fidl call");
        assert_eq!(gc_result, Ok(()));

        let gc_result = proxy.gc().await.expect("made fidl call");
        assert_eq!(gc_result, Ok(()));

        assert_eq!(called.load(Ordering::SeqCst), 3);
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_mock_error() {
        let called = Arc::new(AtomicU32::new(0));
        let called_clone = Arc::clone(&called);
        let mock = Arc::new(MockSpaceService::new(Box::new(move || {
            called_clone.fetch_add(1, Ordering::SeqCst);
            Err(ErrorCode::Internal)
        })));
        let proxy = mock.spawn_space_service();

        let gc_result = proxy.gc().await.expect("made fidl call");
        assert_eq!(gc_result, Err(ErrorCode::Internal));

        assert_eq!(called.load(Ordering::SeqCst), 1);
    }
}