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