1use fidl_fuchsia_fxfs::{BlobCreatorMarker, BlobReaderMarker};
6use fuchsia_component_test::{Capability, ChildOptions, ChildRef, RealmBuilder, Ref, Route};
7use std::collections::HashMap;
8
9use {
10 fidl_fuchsia_fshost as ffshost, fidl_fuchsia_fxfs as ffxfs, fidl_fuchsia_io as fio,
11 fidl_fuchsia_logger as flogger, fidl_fuchsia_process as fprocess,
12 fidl_fuchsia_storage_partitions as fpartitions, fidl_fuchsia_update_verify as ffuv,
13};
14
15pub trait IntoValueSpec {
16 fn into_value_spec(self) -> cm_rust::ConfigValueSpec;
17}
18
19impl IntoValueSpec for bool {
20 fn into_value_spec(self) -> cm_rust::ConfigValueSpec {
21 cm_rust::ConfigValueSpec {
22 value: cm_rust::ConfigValue::Single(cm_rust::ConfigSingleValue::Bool(self)),
23 }
24 }
25}
26
27impl IntoValueSpec for u64 {
28 fn into_value_spec(self) -> cm_rust::ConfigValueSpec {
29 cm_rust::ConfigValueSpec {
30 value: cm_rust::ConfigValue::Single(cm_rust::ConfigSingleValue::Uint64(self)),
31 }
32 }
33}
34
35impl IntoValueSpec for String {
36 fn into_value_spec(self) -> cm_rust::ConfigValueSpec {
37 cm_rust::ConfigValueSpec {
38 value: cm_rust::ConfigValue::Single(cm_rust::ConfigSingleValue::String(self)),
39 }
40 }
41}
42
43impl<'a> IntoValueSpec for &'a str {
44 fn into_value_spec(self) -> cm_rust::ConfigValueSpec {
45 self.to_string().into_value_spec()
46 }
47}
48
49#[derive(Debug, Clone)]
57pub struct FshostBuilder {
58 component_name: &'static str,
59 config_values: HashMap<&'static str, cm_rust::ConfigValueSpec>,
60 create_starnix_volume_crypt: bool,
61}
62
63impl FshostBuilder {
64 pub fn new(component_name: &'static str) -> FshostBuilder {
65 FshostBuilder {
66 component_name,
67 config_values: HashMap::new(),
68 create_starnix_volume_crypt: false,
69 }
70 }
71
72 pub fn create_starnix_volume_crypt(&mut self) -> &mut Self {
73 self.create_starnix_volume_crypt = true;
74 self
75 }
76
77 pub fn set_config_value(&mut self, key: &'static str, value: impl IntoValueSpec) -> &mut Self {
78 assert!(
79 self.config_values.insert(key, value.into_value_spec()).is_none(),
80 "Attempted to insert duplicate config value '{}'!",
81 key
82 );
83 self
84 }
85
86 pub(crate) async fn build(mut self, realm_builder: &RealmBuilder) -> ChildRef {
87 let fshost_url = format!("#meta/{}.cm", self.component_name);
88 log::info!(fshost_url:%; "building test fshost instance");
89 let fshost = realm_builder
90 .add_child("test-fshost", fshost_url, ChildOptions::new().eager())
91 .await
92 .unwrap();
93
94 let mut map = HashMap::from([
96 ("no_zxcrypt", "fuchsia.fshost.NoZxcrypt"),
97 ("ramdisk_image", "fuchsia.fshost.RamdiskImage"),
98 ("gpt_all", "fuchsia.fshost.GptAll"),
99 ("check_filesystems", "fuchsia.fshost.CheckFilesystems"),
100 ("blobfs_max_bytes", "fuchsia.fshost.BlobfsMaxBytes"),
101 ("data_max_bytes", "fuchsia.fshost.DataMaxBytes"),
102 ("format_data_on_corruption", "fuchsia.fshost.FormatDataOnCorruption"),
103 ("data_filesystem_format", "fuchsia.fshost.DataFilesystemFormat"),
104 ("nand", "fuchsia.fshost.Nand"),
105 ("blobfs", "fuchsia.fshost.Blobfs"),
106 ("bootpart", "fuchsia.fshost.BootPart"),
107 ("factory", "fuchsia.fshost.Factory"),
108 ("fvm", "fuchsia.fshost.Fvm"),
109 ("gpt", "fuchsia.fshost.Gpt"),
110 ("mbr", "fuchsia.fshost.Mbr"),
111 ("data", "fuchsia.fshost.Data"),
112 ("netboot", "fuchsia.fshost.Netboot"),
113 ("use_disk_migration", "fuchsia.fshost.UseDiskMigration"),
114 ("disable_block_watcher", "fuchsia.fshost.DisableBlockWatcher"),
115 ("fvm_slice_size", "fuchsia.fshost.FvmSliceSize"),
116 ("blobfs_initial_inodes", "fuchsia.fshost.BlobfsInitialInodes"),
117 (
118 "blobfs_use_deprecated_padded_format",
119 "fuchsia.fshost.BlobfsUseDeprecatedPaddedFormat",
120 ),
121 ("fxfs_blob", "fuchsia.fshost.FxfsBlob"),
122 ("fxfs_crypt_url", "fuchsia.fshost.FxfsCryptUrl"),
123 ("storage_host", "fuchsia.fshost.StorageHost"),
124 ("disable_automount", "fuchsia.fshost.DisableAutomount"),
125 ("starnix_volume_name", "fuchsia.fshost.StarnixVolumeName"),
126 ("blobfs_write_compression_algorithm", "fuchsia.blobfs.WriteCompressionAlgorithm"),
127 ("blobfs_cache_eviction_policy", "fuchsia.blobfs.CacheEvictionPolicy"),
128 ]);
129
130 if self.create_starnix_volume_crypt {
131 let user_fxfs_crypt = realm_builder
132 .add_child("user_fxfs_crypt", "#meta/fxfs-crypt.cm", ChildOptions::new().eager())
133 .await
134 .unwrap();
135 realm_builder
136 .add_route(
137 Route::new()
138 .capability(Capability::protocol::<ffxfs::CryptMarker>())
139 .capability(Capability::protocol::<ffxfs::CryptManagementMarker>())
140 .from(&user_fxfs_crypt)
141 .to(Ref::parent()),
142 )
143 .await
144 .unwrap();
145 }
146
147 self.config_values.insert("fxfs_crypt_url", "#meta/fxfs-crypt.cm".into_value_spec());
149 for (key, value) in self.config_values {
150 let cap_name = map[key];
151 realm_builder
152 .add_capability(cm_rust::CapabilityDecl::Config(cm_rust::ConfigurationDecl {
153 name: cap_name.parse().unwrap(),
154 value: value.value,
155 }))
156 .await
157 .unwrap();
158 realm_builder
159 .add_route(
160 Route::new()
161 .capability(Capability::configuration(cap_name))
162 .from(Ref::self_())
163 .to(&fshost),
164 )
165 .await
166 .unwrap();
167 map.remove(key);
168 }
169
170 let fshost_config_url = format!("#meta/{}_config.cm", self.component_name);
172 let fshost_config = realm_builder
173 .add_child("test-fshost-config", fshost_config_url, ChildOptions::new().eager())
174 .await
175 .unwrap();
176 for (_, value) in map.iter() {
177 realm_builder
178 .add_route(
179 Route::new()
180 .capability(Capability::configuration(*value))
181 .from(&fshost_config)
182 .to(&fshost),
183 )
184 .await
185 .unwrap();
186 }
187
188 realm_builder
189 .add_route(
190 Route::new()
191 .capability(Capability::protocol::<ffshost::AdminMarker>())
192 .capability(Capability::protocol::<ffshost::RecoveryMarker>())
193 .capability(Capability::protocol::<ffuv::ComponentOtaHealthCheckMarker>())
194 .capability(Capability::protocol::<ffshost::StarnixVolumeProviderMarker>())
195 .capability(Capability::protocol::<fpartitions::PartitionsManagerMarker>())
196 .capability(Capability::protocol::<BlobCreatorMarker>())
197 .capability(Capability::protocol::<BlobReaderMarker>())
198 .capability(Capability::directory("blob").rights(fio::RW_STAR_DIR))
199 .capability(Capability::directory("block").rights(fio::R_STAR_DIR))
200 .capability(Capability::directory("debug_block").rights(fio::R_STAR_DIR))
201 .capability(Capability::directory("data").rights(fio::RW_STAR_DIR))
202 .capability(Capability::directory("tmp").rights(fio::RW_STAR_DIR))
203 .capability(Capability::directory("volumes").rights(fio::RW_STAR_DIR))
204 .capability(Capability::service::<fpartitions::PartitionServiceMarker>())
205 .from(&fshost)
206 .to(Ref::parent()),
207 )
208 .await
209 .unwrap();
210
211 realm_builder
212 .add_route(
213 Route::new()
214 .capability(Capability::protocol::<flogger::LogSinkMarker>())
215 .capability(Capability::protocol::<fprocess::LauncherMarker>())
216 .from(Ref::parent())
217 .to(&fshost),
218 )
219 .await
220 .unwrap();
221
222 realm_builder
223 .add_route(
224 Route::new()
225 .capability(
226 Capability::protocol_by_name("fuchsia.scheduler.RoleManager").optional(),
227 )
228 .capability(
229 Capability::protocol_by_name("fuchsia.tracing.provider.Registry")
230 .optional(),
231 )
232 .capability(
233 Capability::protocol_by_name("fuchsia.kernel.VmexResource").optional(),
234 )
235 .capability(
236 Capability::protocol_by_name("fuchsia.memorypressure.Provider").optional(),
237 )
238 .from(Ref::void())
239 .to(&fshost),
240 )
241 .await
242 .unwrap();
243
244 fshost
245 }
246}