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 .capability(Capability::configuration(
180 "fuchsia.pkgcache.UseDriverBlobPaging",
181 ))
182 .capability(Capability::configuration(
183 "fuchsia.fshost.StartupProfilingSeconds",
184 ))
185 .from(Ref::void())
186 .to(&pkg_cache),
187 )
188 .await
189 .unwrap();
190 let system_update_committer = realm_builder
191 .add_child(
192 "system-update-committer",
193 "#meta/fake-system-update-committer.cm",
194 ChildOptions::new(),
195 )
196 .await
197 .unwrap();
198
199 realm_builder
200 .add_route(
201 Route::new()
202 .capability(
203 Capability::directory("blob-exec")
204 .path("/blob")
205 .rights(fio::RW_STAR_DIR | fio::Operations::EXECUTE),
206 )
207 .from(&local_mocks)
208 .to(&pkg_cache),
209 )
210 .await
211 .unwrap();
212
213 realm_builder
214 .add_route(
215 Route::new()
216 .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
217 .from(Ref::parent())
218 .to(&pkg_cache),
219 )
220 .await
221 .unwrap();
222
223 realm_builder
224 .add_route(
225 Route::new()
226 .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobCreator"))
227 .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobReader"))
228 .from(&local_mocks)
229 .to(&pkg_cache),
230 )
231 .await
232 .unwrap();
233
234 realm_builder
235 .add_route(
236 Route::new()
237 .capability(Capability::protocol_by_name("fuchsia.pkg.PackageCache"))
238 .capability(Capability::protocol_by_name("fuchsia.pkg.PackageResolver-ota"))
239 .capability(Capability::protocol_by_name("fuchsia.pkg.RetainedPackages"))
240 .capability(Capability::protocol_by_name(
241 "fuchsia.pkg.garbagecollector.Manager",
242 ))
243 .from(&pkg_cache)
244 .to(Ref::parent()),
245 )
246 .await
247 .unwrap();
248
249 realm_builder
250 .add_route(
251 Route::new()
252 .capability(Capability::protocol_by_name(
253 "fuchsia.update.CommitStatusProvider",
254 ))
255 .from(&system_update_committer)
256 .to(&pkg_cache),
257 )
258 .await
259 .unwrap();
260
261 realm_builder
262 .add_route(
263 Route::new()
264 .capability(
265 Capability::protocol::<fmetrics::MetricEventLoggerFactoryMarker>(),
266 )
267 .from(&local_mocks)
268 .to(&pkg_cache),
269 )
270 .await
271 .unwrap();
272 Ok(pkg_cache)
273 }
274
275 pub async fn new(
276 realm_instance: &RealmInstance,
277 blobfs: BlobfsRamdisk,
278 ) -> Result<Self, Error> {
279 let pkg_cache_proxy = realm_instance
280 .root
281 .connect_to_protocol_at_exposed_dir()
282 .expect("connect to pkg cache");
283
284 let cache = Cache::new_with_proxies(pkg_cache_proxy).unwrap();
285
286 Ok(CacheForTest { blobfs, cache: Arc::new(cache) })
287 }
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use super::for_tests::CacheForTest;
294 use fuchsia_component_test::RealmBuilder;
295
296 #[fuchsia::test]
297 pub async fn test_cache_handles_sync() {
298 let realm_builder = RealmBuilder::new().await.unwrap();
299 let blobfs = blobfs_ramdisk::BlobfsRamdisk::start().await.expect("starting blobfs");
300
301 let _cache_ref =
302 CacheForTest::realm_setup(&realm_builder, &blobfs).await.expect("setting up realm");
303 let realm_instance = realm_builder.build().await.unwrap();
304 let cache = CacheForTest::new(&realm_instance, blobfs).await.expect("launching cache");
305 let proxy = cache.cache.package_cache_proxy().unwrap();
306
307 assert_eq!(proxy.sync().await.unwrap(), Ok(()));
308 }
309}