1use anyhow::Error;
6
7pub struct Cache {
9 _pkg_cache_proxy: fidl_fuchsia_pkg::PackageCacheProxy,
10}
11
12impl Cache {
13 pub fn new_with_proxies(
16 pkg_cache_proxy: fidl_fuchsia_pkg::PackageCacheProxy,
17 ) -> Result<Self, Error> {
18 Ok(Self { _pkg_cache_proxy: pkg_cache_proxy })
19 }
20
21 pub fn new() -> Result<Self, Error> {
25 Ok(Self {
26 _pkg_cache_proxy: fuchsia_component::client::connect_to_protocol::<
27 fidl_fuchsia_pkg::PackageCacheMarker,
28 >()?,
29 })
30 }
31
32 #[cfg(test)]
34 pub fn package_cache_proxy(&self) -> Result<fidl_fuchsia_pkg::PackageCacheProxy, Error> {
35 Ok(self._pkg_cache_proxy.clone())
36 }
37}
38
39#[cfg(test)]
40pub(crate) mod for_tests {
41 use super::*;
42 use blobfs_ramdisk::BlobfsRamdisk;
43 use fidl::endpoints::{ServerEnd, SynchronousProxy};
44 use fidl_fuchsia_fxfs as ffxfs;
45 use fidl_fuchsia_io as fio;
46 use fidl_fuchsia_metrics as fmetrics;
47 use fuchsia_async as fasync;
48 use fuchsia_component_test::{
49 Capability, ChildOptions, ChildRef, RealmBuilder, RealmInstance, Ref, Route,
50 };
51 use futures::prelude::*;
52 use std::sync::Arc;
53
54 pub struct CacheForTest {
55 pub blobfs: blobfs_ramdisk::BlobfsRamdisk,
56 pub cache: Arc<Cache>,
57 }
58
59 impl CacheForTest {
60 pub async fn realm_setup(
61 realm_builder: &RealmBuilder,
62 blobfs: &BlobfsRamdisk,
63 ) -> Result<ChildRef, Error> {
64 let blobfs_proxy = blobfs.root_dir_proxy().expect("getting root dir proxy");
65 let svc_dir = blobfs.svc_dir().expect("getting service dir proxy");
66
67 let local_mocks = realm_builder
68 .add_local_child(
69 "pkg_cache_service_reflector",
70 move |handles| {
71 let mut fs = fuchsia_component::server::ServiceFs::new();
72 let (creator_dir, server_end) =
73 fidl::endpoints::create_sync_proxy::<fio::DirectoryMarker>();
74 svc_dir
75 .open(
76 ".",
77 fio::PERM_READABLE,
78 &fio::Options::default(),
79 server_end.into_channel(),
80 )
81 .unwrap();
82 let (reader_dir, server_end) =
83 fidl::endpoints::create_sync_proxy::<fio::DirectoryMarker>();
84 svc_dir
85 .open(
86 ".",
87 fio::PERM_READABLE,
88 &fio::Options::default(),
89 server_end.into_channel(),
90 )
91 .unwrap();
92 fs.dir("svc")
94 .add_fidl_service(move |stream| {
95 fasync::Task::spawn(
96 Arc::new(mock_metrics::MockMetricEventLoggerFactory::new())
97 .run_logger_factory(stream),
98 )
99 .detach()
100 })
101 .add_service_connector(
102 move |server_end: ServerEnd<ffxfs::BlobCreatorMarker>| {
103 fdio::service_connect_at(
104 creator_dir.as_channel(),
105 "fuchsia.fxfs.BlobCreator",
106 server_end.into_channel(),
107 )
108 .unwrap();
109 },
110 )
111 .add_service_connector(
112 move |server_end: ServerEnd<ffxfs::BlobReaderMarker>| {
113 fdio::service_connect_at(
114 reader_dir.as_channel(),
115 "fuchsia.fxfs.BlobReader",
116 server_end.into_channel(),
117 )
118 .unwrap();
119 },
120 );
121 fs.add_remote("blob", Clone::clone(&blobfs_proxy));
122 async move {
123 fs.serve_connection(handles.outgoing_dir).unwrap();
124 let () = fs.collect().await;
125 Ok(())
126 }
127 .boxed()
128 },
129 ChildOptions::new(),
130 )
131 .await
132 .unwrap();
133
134 let pkg_cache = realm_builder
135 .add_child("pkg_cache", "#meta/pkg-cache.cm", ChildOptions::new())
136 .await
137 .unwrap();
138
139 let system_image_package = fuchsia_pkg_testing::SystemImageBuilder::new().build().await;
140 system_image_package.write_to_blobfs(blobfs).await;
141
142 for (name, value) in [
143 ("fuchsia.zircon.system.pkgfs.cmd", system_image_package.hash().to_string().into()),
144 ("fuchsia.pkgcache.AllPackagesExecutable", false.into()),
145 ("fuchsia.pkgcache.RequireSystemImage", false.into()),
146 ("fuchsia.pkgcache.EnableUpgradablePackages", false.into()),
147 ] {
148 realm_builder
149 .add_capability(
150 cm_rust::ConfigurationDecl { name: name.parse().unwrap(), value }.into(),
151 )
152 .await
153 .unwrap();
154 realm_builder
155 .add_route(
156 Route::new()
157 .capability(Capability::configuration(name))
158 .from(Ref::self_())
159 .to(&pkg_cache),
160 )
161 .await
162 .unwrap();
163 }
164 realm_builder
165 .add_route(
166 Route::new()
167 .capability(Capability::configuration(
168 "fuchsia.pkgcache.BlobFetchConcurrencyLimit",
169 ))
170 .capability(Capability::configuration(
171 "fuchsia.pkgcache.BlobNetworkHeaderTimeoutSeconds",
172 ))
173 .capability(Capability::configuration(
174 "fuchsia.pkgcache.BlobNetworkBodyTimeoutSeconds",
175 ))
176 .capability(Capability::configuration(
177 "fuchsia.pkgcache.BlobDownloadResumptionAttemptsLimit",
178 ))
179 .from(Ref::void())
180 .to(&pkg_cache),
181 )
182 .await
183 .unwrap();
184 let system_update_committer = realm_builder
185 .add_child(
186 "system-update-committer",
187 "#meta/fake-system-update-committer.cm",
188 ChildOptions::new(),
189 )
190 .await
191 .unwrap();
192
193 realm_builder
194 .add_route(
195 Route::new()
196 .capability(
197 Capability::directory("blob-exec")
198 .path("/blob")
199 .rights(fio::RW_STAR_DIR | fio::Operations::EXECUTE),
200 )
201 .from(&local_mocks)
202 .to(&pkg_cache),
203 )
204 .await
205 .unwrap();
206
207 realm_builder
208 .add_route(
209 Route::new()
210 .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
211 .from(Ref::parent())
212 .to(&pkg_cache),
213 )
214 .await
215 .unwrap();
216
217 realm_builder
218 .add_route(
219 Route::new()
220 .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobCreator"))
221 .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobReader"))
222 .from(&local_mocks)
223 .to(&pkg_cache),
224 )
225 .await
226 .unwrap();
227
228 realm_builder
229 .add_route(
230 Route::new()
231 .capability(Capability::protocol_by_name("fuchsia.pkg.PackageCache"))
232 .capability(Capability::protocol_by_name("fuchsia.pkg.RetainedPackages"))
233 .capability(Capability::protocol_by_name(
234 "fuchsia.pkg.garbagecollector.Manager",
235 ))
236 .from(&pkg_cache)
237 .to(Ref::parent()),
238 )
239 .await
240 .unwrap();
241
242 realm_builder
243 .add_route(
244 Route::new()
245 .capability(Capability::protocol_by_name(
246 "fuchsia.update.CommitStatusProvider",
247 ))
248 .from(&system_update_committer)
249 .to(&pkg_cache),
250 )
251 .await
252 .unwrap();
253
254 realm_builder
255 .add_route(
256 Route::new()
257 .capability(
258 Capability::protocol::<fmetrics::MetricEventLoggerFactoryMarker>(),
259 )
260 .from(&local_mocks)
261 .to(&pkg_cache),
262 )
263 .await
264 .unwrap();
265 Ok(pkg_cache)
266 }
267
268 pub async fn new(
269 realm_instance: &RealmInstance,
270 blobfs: BlobfsRamdisk,
271 ) -> Result<Self, Error> {
272 let pkg_cache_proxy = realm_instance
273 .root
274 .connect_to_protocol_at_exposed_dir()
275 .expect("connect to pkg cache");
276
277 let cache = Cache::new_with_proxies(pkg_cache_proxy).unwrap();
278
279 Ok(CacheForTest { blobfs, cache: Arc::new(cache) })
280 }
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::for_tests::CacheForTest;
287 use fuchsia_component_test::RealmBuilder;
288
289 #[fuchsia::test]
290 pub async fn test_cache_handles_sync() {
291 let realm_builder = RealmBuilder::new().await.unwrap();
292 let blobfs = blobfs_ramdisk::BlobfsRamdisk::start().await.expect("starting blobfs");
293
294 let _cache_ref =
295 CacheForTest::realm_setup(&realm_builder, &blobfs).await.expect("setting up realm");
296 let realm_instance = realm_builder.build().await.unwrap();
297 let cache = CacheForTest::new(&realm_instance, blobfs).await.expect("launching cache");
298 let proxy = cache.cache.package_cache_proxy().unwrap();
299
300 assert_eq!(proxy.sync().await.unwrap(), Ok(()));
301 }
302}