[channel] Move channel.rs to its own crate
This is necessary for use in both bin/omaha-client and build scripts.
Bug: 103263
Change-Id: I593f57bf2e24fbcd9b3abd7ee2015ed4ba6e9638
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693782
Reviewed-by: Sen Jiang <senj@google.com>
Commit-Queue: James Buckland <jbuckland@google.com>
diff --git a/src/sys/pkg/bin/omaha-client/BUILD.gn b/src/sys/pkg/bin/omaha-client/BUILD.gn
index 0610a00..e9daa40 100644
--- a/src/sys/pkg/bin/omaha-client/BUILD.gn
+++ b/src/sys/pkg/bin/omaha-client/BUILD.gn
@@ -53,6 +53,7 @@
"//src/sys/lib/fidl-connector",
"//src/sys/pkg/fidl/fuchsia.update.installer:fuchsia.update.installer-rustc",
"//src/sys/pkg/lib/bounded-node",
+ "//src/sys/pkg/lib/channel-config",
"//src/sys/pkg/lib/event-queue",
"//src/sys/pkg/lib/fidl-fuchsia-update-ext",
"//src/sys/pkg/lib/fidl-fuchsia-update-installer-ext",
diff --git a/src/sys/pkg/bin/omaha-client/src/app_set.rs b/src/sys/pkg/bin/omaha-client/src/app_set.rs
index 8a5b1dd8..b651ee5 100644
--- a/src/sys/pkg/bin/omaha-client/src/app_set.rs
+++ b/src/sys/pkg/bin/omaha-client/src/app_set.rs
@@ -3,7 +3,7 @@
// found in the LICENSE file.
use {
- crate::channel::ChannelConfigs,
+ channel_config::ChannelConfigs,
omaha_client::{app_set::AppSet, common::App},
};
diff --git a/src/sys/pkg/bin/omaha-client/src/channel.rs b/src/sys/pkg/bin/omaha-client/src/channel.rs
index b1cb793..9cd162c 100644
--- a/src/sys/pkg/bin/omaha-client/src/channel.rs
+++ b/src/sys/pkg/bin/omaha-client/src/channel.rs
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use omaha_client::protocol::Cohort;
-use serde::{Deserialize, Serialize};
+use channel_config::ChannelConfigs;
+use serde::Deserialize;
use std::fs;
use std::io;
@@ -20,101 +20,6 @@
Version1(ChannelConfigs),
}
-/// Wrapper for deserializing repository configs to the on-disk JSON format.
-#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
-pub struct ChannelConfigs {
- pub default_channel: Option<String>,
- #[serde(rename = "channels")]
- pub known_channels: Vec<ChannelConfig>,
-}
-
-impl ChannelConfigs {
- pub fn validate(&self) -> Result<(), io::Error> {
- let names: Vec<&str> = self.known_channels.iter().map(|c| c.name.as_str()).collect();
- if !names.iter().all(|n| Cohort::validate_name(n)) {
- return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid channel name"));
- }
- if let Some(default) = &self.default_channel {
- if !names.contains(&default.as_str()) {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "default channel not a known channel",
- ));
- }
- }
- Ok(())
- }
-
- pub fn get_default_channel(&self) -> Option<ChannelConfig> {
- self.default_channel.as_ref().and_then(|default| self.get_channel(&default))
- }
-
- pub fn get_channel(&self, name: &str) -> Option<ChannelConfig> {
- self.known_channels
- .iter()
- .find(|channel_config| channel_config.name == name)
- .map(|c| c.clone())
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
-pub struct ChannelConfig {
- pub name: String,
- pub repo: String,
- pub appid: Option<String>,
- pub check_interval_secs: Option<u64>,
-}
-
-#[cfg(test)]
-impl ChannelConfig {
- pub fn new(name: &str) -> Self {
- ChannelConfigBuilder::new(name, name.to_owned() + "-repo").build()
- }
-
- pub fn with_appid(name: &str, appid: &str) -> Self {
- ChannelConfigBuilder::new(name, name.to_owned() + "-repo").appid(appid).build()
- }
-}
-
-#[cfg(test)]
-#[derive(Debug, Default)]
-pub struct ChannelConfigBuilder {
- name: String,
- repo: String,
- appid: Option<String>,
- check_interval_secs: Option<u64>,
-}
-
-#[cfg(test)]
-impl ChannelConfigBuilder {
- pub fn new(name: impl Into<String>, repo: impl Into<String>) -> Self {
- ChannelConfigBuilder {
- name: name.into(),
- repo: repo.into(),
- ..ChannelConfigBuilder::default()
- }
- }
-
- pub fn appid(mut self, appid: impl Into<String>) -> Self {
- self.appid = Some(appid.into());
- self
- }
-
- pub fn check_interval_secs(mut self, check_interval_secs: u64) -> Self {
- self.check_interval_secs = Some(check_interval_secs);
- self
- }
-
- pub fn build(self) -> ChannelConfig {
- ChannelConfig {
- name: self.name,
- repo: self.repo,
- appid: self.appid,
- check_interval_secs: self.check_interval_secs,
- }
- }
-}
-
/// This method retrieves the channel configuation from the file in config data
pub fn get_configs() -> Result<ChannelConfigs, io::Error> {
get_configs_from_path(CHANNEL_CONFIG_PATH)
@@ -214,77 +119,8 @@
}
#[test]
- fn test_channel_configs_get_default() {
- let configs = ChannelConfigs {
- default_channel: Some("default_channel".to_string()),
- known_channels: vec![
- ChannelConfig::new("some_channel"),
- ChannelConfig::new("default_channel"),
- ChannelConfig::new("other"),
- ],
- };
- assert_eq!(configs.get_default_channel().unwrap(), configs.known_channels[1]);
- }
-
- #[test]
- fn test_channel_configs_get_default_none() {
- let configs = ChannelConfigs {
- default_channel: None,
- known_channels: vec![ChannelConfig::new("some_channel")],
- };
- assert_eq!(configs.get_default_channel(), None);
- }
-
- #[test]
- fn test_channel_configs_get_channel() {
- let configs = ChannelConfigs {
- default_channel: Some("default_channel".to_string()),
- known_channels: vec![
- ChannelConfig::new("some_channel"),
- ChannelConfig::new("default_channel"),
- ChannelConfig::new("other"),
- ],
- };
- assert_eq!(configs.get_channel("other").unwrap(), configs.known_channels[2]);
- }
-
- #[test]
- fn test_channel_configs_get_channel_missing() {
- let configs = ChannelConfigs {
- default_channel: Some("default_channel".to_string()),
- known_channels: vec![
- ChannelConfig::new("some_channel"),
- ChannelConfig::new("default_channel"),
- ChannelConfig::new("other"),
- ],
- };
- assert_eq!(configs.get_channel("missing"), None);
- }
-
- #[test]
fn test_missing_channel_configs_file_behavior() {
let config = get_configs_from_path("/config/data/invalid.path");
assert!(config.is_err());
}
-
- #[test]
- fn test_channel_cfg_builder_app_id() {
- let config = ChannelConfigBuilder::new("name", "repo").appid("appid").build();
- assert_eq!("name", config.name);
- assert_eq!("repo", config.repo);
- assert_eq!(Some("appid".to_owned()), config.appid);
- assert_eq!(None, config.check_interval_secs);
- }
-
- #[test]
- fn test_channel_cfg_builder_check_interval() {
- let config = ChannelConfigBuilder::new("name", "repo")
- .appid("appid")
- .check_interval_secs(3600)
- .build();
- assert_eq!("name", config.name);
- assert_eq!("repo", config.repo);
- assert_eq!(Some("appid".to_owned()), config.appid);
- assert_eq!(Some(3600), config.check_interval_secs);
- }
}
diff --git a/src/sys/pkg/bin/omaha-client/src/configuration.rs b/src/sys/pkg/bin/omaha-client/src/configuration.rs
index 66fc5cb..a0fe8fe 100644
--- a/src/sys/pkg/bin/omaha-client/src/configuration.rs
+++ b/src/sys/pkg/bin/omaha-client/src/configuration.rs
@@ -4,10 +4,10 @@
use crate::{
app_set::{EagerPackage, FuchsiaAppSet},
- channel::{ChannelConfig, ChannelConfigs},
eager_package_config::{EagerPackageConfig, EagerPackageConfigs},
};
use anyhow::{anyhow, Error};
+use channel_config::{ChannelConfig, ChannelConfigs};
use fidl_fuchsia_boot::{ArgumentsMarker, ArgumentsProxy};
use fidl_fuchsia_pkg::{self as fpkg, CupMarker, CupProxy, GetInfoError};
use log::{error, info, warn};
@@ -389,7 +389,7 @@
#[fasync::run_singlethreaded(test)]
async fn test_channel_data_configured() {
- let channel_config = ChannelConfig::with_appid("some-channel", "some-appid");
+ let channel_config = ChannelConfig::with_appid_for_test("some-channel", "some-appid");
let channel_configs = ChannelConfigs {
default_channel: Some(channel_config.name.clone()),
known_channels: vec![channel_config.clone()],
@@ -415,10 +415,10 @@
Some(&ChannelConfigs {
default_channel: Some("some-channel".to_string()),
known_channels: vec![
- ChannelConfig::new("no-appid-channel"),
- ChannelConfig::with_appid("wrong-channel", "wrong-appid"),
- ChannelConfig::with_appid("some-channel", "some-appid"),
- ChannelConfig::with_appid("some-other-channel", "some-other-appid"),
+ ChannelConfig::new_for_test("no-appid-channel"),
+ ChannelConfig::with_appid_for_test("wrong-channel", "wrong-appid"),
+ ChannelConfig::with_appid_for_test("some-channel", "some-appid"),
+ ChannelConfig::with_appid_for_test("some-other-channel", "some-other-appid"),
],
}),
VbMetaData::default(),
@@ -448,7 +448,10 @@
"1.2.3.4",
Some(&ChannelConfigs {
default_channel: Some("wrong-channel".to_string()),
- known_channels: vec![ChannelConfig::with_appid("wrong-channel", "wrong-appid")],
+ known_channels: vec![ChannelConfig::with_appid_for_test(
+ "wrong-channel",
+ "wrong-appid",
+ )],
}),
VbMetaData {
appid: Some("vbmeta-appid".to_string()),
diff --git a/src/sys/pkg/bin/omaha-client/src/eager_package_config.rs b/src/sys/pkg/bin/omaha-client/src/eager_package_config.rs
index 19dfb08..a14cb58 100644
--- a/src/sys/pkg/bin/omaha-client/src/eager_package_config.rs
+++ b/src/sys/pkg/bin/omaha-client/src/eager_package_config.rs
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::channel::ChannelConfigs;
use anyhow::{Context as _, Error};
+use channel_config::ChannelConfigs;
use fuchsia_url::UnpinnedAbsolutePackageUrl;
use omaha_client::cup_ecdsa::PublicKeys;
use serde::Deserialize;
@@ -72,8 +72,8 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::channel::ChannelConfig;
use assert_matches::assert_matches;
+ use channel_config::ChannelConfig;
use omaha_client::cup_ecdsa::{
test_support::{
make_default_json_public_keys_for_test, make_default_public_key_for_test,
diff --git a/src/sys/pkg/bin/omaha-client/src/fidl.rs b/src/sys/pkg/bin/omaha-client/src/fidl.rs
index ac68bba..5d6c019 100644
--- a/src/sys/pkg/bin/omaha-client/src/fidl.rs
+++ b/src/sys/pkg/bin/omaha-client/src/fidl.rs
@@ -5,10 +5,10 @@
use crate::{
api_metrics::{ApiEvent, ApiMetricsReporter},
app_set::FuchsiaAppSet,
- channel::ChannelConfigs,
inspect::{AppsNode, StateNode},
};
use anyhow::{anyhow, Context as _, Error};
+use channel_config::ChannelConfigs;
use event_queue::{ClosedClient, ControlHandle, Event, EventQueue, Notify};
use fidl::endpoints::ClientEnd;
use fidl_fuchsia_hardware_power_statecontrol::RebootReason;
@@ -962,8 +962,8 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::channel::ChannelConfig;
use assert_matches::assert_matches;
+ use channel_config::ChannelConfig;
use fidl::endpoints::{create_proxy_and_stream, create_request_stream};
use fidl_fuchsia_update::{
self as update, AttemptsMonitorRequest, ManagerMarker, MonitorMarker, MonitorRequest,
@@ -1371,8 +1371,8 @@
.with_channel_configs(ChannelConfigs {
default_channel: None,
known_channels: vec![
- ChannelConfig::new("some-channel"),
- ChannelConfig::with_appid("target-channel", "target-id"),
+ ChannelConfig::new_for_test("some-channel"),
+ ChannelConfig::with_appid_for_test("target-channel", "target-id"),
],
})
.build()
@@ -1399,7 +1399,10 @@
let fidl = FidlServerBuilder::new()
.with_channel_configs(ChannelConfigs {
default_channel: "default-channel".to_string().into(),
- known_channels: vec![ChannelConfig::with_appid("default-channel", "default-app")],
+ known_channels: vec![ChannelConfig::with_appid_for_test(
+ "default-channel",
+ "default-app",
+ )],
})
.build()
.await;
@@ -1452,8 +1455,8 @@
.with_channel_configs(ChannelConfigs {
default_channel: None,
known_channels: vec![
- ChannelConfig::new("some-channel"),
- ChannelConfig::new("some-other-channel"),
+ ChannelConfig::new_for_test("some-channel"),
+ ChannelConfig::new_for_test("some-other-channel"),
],
})
.build()
@@ -1508,7 +1511,7 @@
.with_apps_node(apps_node)
.with_channel_configs(ChannelConfigs {
default_channel: None,
- known_channels: vec![ChannelConfig::new("target-channel")],
+ known_channels: vec![ChannelConfig::new_for_test("target-channel")],
})
.build()
.await;
diff --git a/src/sys/pkg/lib/BUILD.gn b/src/sys/pkg/lib/BUILD.gn
index 1a35e98..392f642 100644
--- a/src/sys/pkg/lib/BUILD.gn
+++ b/src/sys/pkg/lib/BUILD.gn
@@ -8,6 +8,7 @@
"async-generator",
"blobfs",
"bounded-node",
+ "channel-config",
"epoch",
"event-queue",
"far:lib",
@@ -36,6 +37,7 @@
"async-generator:tests",
"blobfs:tests",
"bounded-node:tests",
+ "channel-config:tests",
"epoch:tests",
"event-queue:tests",
"far:tests",
diff --git a/src/sys/pkg/lib/channel-config/BUILD.gn b/src/sys/pkg/lib/channel-config/BUILD.gn
new file mode 100644
index 0000000..32d7981
--- /dev/null
+++ b/src/sys/pkg/lib/channel-config/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright 2022 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+import("//build/config.gni")
+import("//build/rust/rustc_library.gni")
+
+rustc_library("channel-config") {
+ version = "0.0.1"
+ edition = "2021"
+ with_unit_tests = true
+
+ deps = [
+ "//src/sys/pkg/lib/omaha-client",
+ "//src/sys/pkg/lib/version",
+ "//third_party/rust_crates:serde",
+ "//third_party/rust_crates:serde_json",
+ ]
+
+ test_deps = [ "//third_party/rust_crates:pretty_assertions" ]
+
+ sources = [ "src/lib.rs" ]
+}
+
+fuchsia_unittest_package("channel-config-lib-tests") {
+ deps = [ ":channel-config_test" ]
+}
+
+group("tests") {
+ testonly = true
+ deps = [ ":channel-config-lib-tests" ]
+}
diff --git a/src/sys/pkg/lib/channel-config/OWNERS b/src/sys/pkg/lib/channel-config/OWNERS
new file mode 100644
index 0000000..f29ac69
--- /dev/null
+++ b/src/sys/pkg/lib/channel-config/OWNERS
@@ -0,0 +1,4 @@
+senj@google.com
+jbuckland@google.com
+
+# COMPONENT: Packages>OMCL
diff --git a/src/sys/pkg/lib/channel-config/README.md b/src/sys/pkg/lib/channel-config/README.md
new file mode 100644
index 0000000..02295f7
--- /dev/null
+++ b/src/sys/pkg/lib/channel-config/README.md
@@ -0,0 +1,6 @@
+# Channel library
+
+Updated: 2022-06
+
+This crate contains the implementation for reading the `channel_config.json`
+configuration file.
diff --git a/src/sys/pkg/lib/channel-config/src/lib.rs b/src/sys/pkg/lib/channel-config/src/lib.rs
new file mode 100644
index 0000000..22b2029
--- /dev/null
+++ b/src/sys/pkg/lib/channel-config/src/lib.rs
@@ -0,0 +1,177 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use omaha_client::protocol::Cohort;
+use serde::{Deserialize, Serialize};
+use std::io;
+
+/// Wrapper for deserializing repository configs to the on-disk JSON format.
+#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
+pub struct ChannelConfigs {
+ pub default_channel: Option<String>,
+ #[serde(rename = "channels")]
+ pub known_channels: Vec<ChannelConfig>,
+}
+
+impl ChannelConfigs {
+ pub fn validate(&self) -> Result<(), io::Error> {
+ let names: Vec<&str> = self.known_channels.iter().map(|c| c.name.as_str()).collect();
+ if !names.iter().all(|n| Cohort::validate_name(n)) {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid channel name"));
+ }
+ if let Some(default) = &self.default_channel {
+ if !names.contains(&default.as_str()) {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidData,
+ "default channel not a known channel",
+ ));
+ }
+ }
+ Ok(())
+ }
+
+ pub fn get_default_channel(&self) -> Option<ChannelConfig> {
+ self.default_channel.as_ref().and_then(|default| self.get_channel(&default))
+ }
+
+ pub fn get_channel(&self, name: &str) -> Option<ChannelConfig> {
+ self.known_channels
+ .iter()
+ .find(|channel_config| channel_config.name == name)
+ .map(|c| c.clone())
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
+pub struct ChannelConfig {
+ pub name: String,
+ pub repo: String,
+ pub appid: Option<String>,
+ pub check_interval_secs: Option<u64>,
+}
+
+impl ChannelConfig {
+ pub fn new_for_test(name: &str) -> Self {
+ testing::ChannelConfigBuilder::new(name, name.to_owned() + "-repo").build()
+ }
+
+ pub fn with_appid_for_test(name: &str, appid: &str) -> Self {
+ testing::ChannelConfigBuilder::new(name, name.to_owned() + "-repo").appid(appid).build()
+ }
+}
+
+pub mod testing {
+ use super::*;
+ #[derive(Debug, Default)]
+ pub struct ChannelConfigBuilder {
+ name: String,
+ repo: String,
+ appid: Option<String>,
+ check_interval_secs: Option<u64>,
+ }
+
+ impl ChannelConfigBuilder {
+ pub fn new(name: impl Into<String>, repo: impl Into<String>) -> Self {
+ ChannelConfigBuilder {
+ name: name.into(),
+ repo: repo.into(),
+ ..ChannelConfigBuilder::default()
+ }
+ }
+
+ pub fn appid(mut self, appid: impl Into<String>) -> Self {
+ self.appid = Some(appid.into());
+ self
+ }
+
+ pub fn check_interval_secs(mut self, check_interval_secs: u64) -> Self {
+ self.check_interval_secs = Some(check_interval_secs);
+ self
+ }
+
+ pub fn build(self) -> ChannelConfig {
+ ChannelConfig {
+ name: self.name,
+ repo: self.repo,
+ appid: self.appid,
+ check_interval_secs: self.check_interval_secs,
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use pretty_assertions::assert_eq;
+
+ #[test]
+ fn test_channel_configs_get_default() {
+ let configs = ChannelConfigs {
+ default_channel: Some("default_channel".to_string()),
+ known_channels: vec![
+ ChannelConfig::new_for_test("some_channel"),
+ ChannelConfig::new_for_test("default_channel"),
+ ChannelConfig::new_for_test("other"),
+ ],
+ };
+ assert_eq!(configs.get_default_channel().unwrap(), configs.known_channels[1]);
+ }
+
+ #[test]
+ fn test_channel_configs_get_default_none() {
+ let configs = ChannelConfigs {
+ default_channel: None,
+ known_channels: vec![ChannelConfig::new_for_test("some_channel")],
+ };
+ assert_eq!(configs.get_default_channel(), None);
+ }
+
+ #[test]
+ fn test_channel_configs_get_channel() {
+ let configs = ChannelConfigs {
+ default_channel: Some("default_channel".to_string()),
+ known_channels: vec![
+ ChannelConfig::new_for_test("some_channel"),
+ ChannelConfig::new_for_test("default_channel"),
+ ChannelConfig::new_for_test("other"),
+ ],
+ };
+ assert_eq!(configs.get_channel("other").unwrap(), configs.known_channels[2]);
+ }
+
+ #[test]
+ fn test_channel_configs_get_channel_missing() {
+ let configs = ChannelConfigs {
+ default_channel: Some("default_channel".to_string()),
+ known_channels: vec![
+ ChannelConfig::new_for_test("some_channel"),
+ ChannelConfig::new_for_test("default_channel"),
+ ChannelConfig::new_for_test("other"),
+ ],
+ };
+ assert_eq!(configs.get_channel("missing"), None);
+ }
+
+ #[test]
+ fn test_channel_cfg_builder_app_id() {
+ let config = testing::ChannelConfigBuilder::new("name", "repo").appid("appid").build();
+ assert_eq!("name", config.name);
+ assert_eq!("repo", config.repo);
+ assert_eq!(Some("appid".to_owned()), config.appid);
+ assert_eq!(None, config.check_interval_secs);
+ }
+
+ #[test]
+ fn test_channel_cfg_builder_check_interval() {
+ let config = testing::ChannelConfigBuilder::new("name", "repo")
+ .appid("appid")
+ .check_interval_secs(3600)
+ .build();
+ assert_eq!("name", config.name);
+ assert_eq!("repo", config.repo);
+ assert_eq!(Some("appid".to_owned()), config.appid);
+ assert_eq!(Some(3600), config.check_interval_secs);
+ }
+}