1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use anyhow::{bail, Context as _, Result};
6use fidl::endpoints::{create_proxy, ProtocolMarker};
7use url::Url;
8use {fidl_fuchsia_fuzzer as fuzz, zx_status as zx};
910/// Represents the FIDL connection from the `ffx fuzz` plugin to the `fuzz-manager` component on a
11/// target device.
12pub struct Manager {
13 proxy: fuzz::ManagerProxy,
14}
1516impl Manager {
17/// Creates a new `Manager`.
18 ///
19 /// The created object maintains a FIDL `proxy` to the `fuzz-manager` component on a target
20 /// device. Any output produced by this object will be written using the given `writer`.
21pub fn new(proxy: fuzz::ManagerProxy) -> Self {
22Self { proxy }
23 }
2425/// Requests that the `fuzz-manager` connect to a fuzzer instance.
26 ///
27 /// This will create and connect a `fuchsia.fuzzer.Controller` to the fuzzer on the target
28 /// device given by the `url`. Any artifacts produced by the fuzzer will be saved to the
29 /// `artifact_dir`, and outputs such as logs can optionally be saved to the `output_dir`.
30 ///
31 /// Returns an object representing the connected fuzzer, or an error.
32pub async fn connect(&self, url: &Url) -> Result<fuzz::ControllerProxy> {
33let (proxy, server_end) = create_proxy::<fuzz::ControllerMarker>();
34let result = self
35.proxy
36 .connect(url.as_str(), server_end)
37 .await
38.context("fuchsia.fuzzer/Manager.Connect")?;
39if let Err(e) = result {
40bail!("fuchsia.fuzzer/Manager.Connect returned ZX_ERR_{}", zx::Status::from_raw(e));
41 }
42Ok(proxy)
43 }
4445/// Returns a socket that provides the given type of fuzzer output.
46pub async fn get_output(&self, url: &Url, output: fuzz::TestOutput) -> Result<fidl::Socket> {
47let (rx, tx) = fidl::Socket::create_stream();
48let result = self
49.proxy
50 .get_output(url.as_str(), output, tx)
51 .await
52.context("failed to get output")?;
53if let Err(e) = result {
54bail!("fuchsia.fuzzer/Manager.GetOutput returned ZX_ERR_{}", zx::Status::from_raw(e));
55 }
56Ok(rx)
57 }
5859/// Requests that the `fuzz-manager` stop a running fuzzer instance.
60 ///
61 /// As a result of this call, the fuzzer component will cease an ongoing workflow and exit.
62 ///
63 /// Returns whether a fuzzer was stopped.
64pub async fn stop(&self, url: &Url) -> Result<bool> {
65let result = self.proxy.stop(url.as_str()).await.context(fidl_name("Stop"))?;
66match result {
67Ok(()) => Ok(true),
68Err(e) if e == zx::Status::NOT_FOUND.into_raw() => Ok(false),
69Err(e) => {
70bail!("fuchsia.fuzzer/Manager.Stop returned ZX_ERR_{}", zx::Status::from_raw(e))
71 }
72 }
73 }
74}
7576fn fidl_name(method: &str) -> String {
77format!("{}/{}", fuzz::ManagerMarker::DEBUG_NAME, method)
78}
7980#[cfg(test)]
81mod tests {
82use super::Manager;
83use anyhow::Result;
84use fidl::endpoints::create_proxy;
85use fidl_fuchsia_fuzzer as fuzz;
86use fuchsia_fuzzctl_test::{create_task, serve_manager, Test, TEST_URL};
87use url::Url;
8889#[fuchsia::test]
90async fn test_connect() -> Result<()> {
91let test = Test::try_new()?;
92let (proxy, server_end) = create_proxy::<fuzz::ManagerMarker>();
93let _task = create_task(serve_manager(server_end, test.clone()), test.writer());
94let manager = Manager::new(proxy);
9596let url = Url::parse(TEST_URL)?;
97 manager.connect(&url).await?;
9899let actual = test.url().borrow().as_ref().map(|url| url.to_string());
100let expected = Some(url.to_string());
101assert_eq!(actual, expected);
102Ok(())
103 }
104105#[fuchsia::test]
106async fn test_stop() -> Result<()> {
107let test = Test::try_new()?;
108let (proxy, server_end) = create_proxy::<fuzz::ManagerMarker>();
109let _task = create_task(serve_manager(server_end, test.clone()), test.writer());
110let manager = Manager::new(proxy);
111112let url = Url::parse(TEST_URL)?;
113 manager.stop(&url).await?;
114115let actual = test.url().borrow().as_ref().map(|url| url.to_string());
116let expected = Some(url.to_string());
117assert_eq!(actual, expected);
118Ok(())
119 }
120}