summaryrefslogtreecommitdiffstats
path: root/crates/common/tedge_config/tests/test_tedge_config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/common/tedge_config/tests/test_tedge_config.rs')
-rw-r--r--crates/common/tedge_config/tests/test_tedge_config.rs867
1 files changed, 867 insertions, 0 deletions
diff --git a/crates/common/tedge_config/tests/test_tedge_config.rs b/crates/common/tedge_config/tests/test_tedge_config.rs
new file mode 100644
index 00000000..0cf4c396
--- /dev/null
+++ b/crates/common/tedge_config/tests/test_tedge_config.rs
@@ -0,0 +1,867 @@
+use assert_matches::assert_matches;
+use std::convert::TryFrom;
+use std::io::Write;
+use tedge_config::*;
+use tempfile::TempDir;
+
+#[test]
+fn test_parse_config_with_all_values() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+key_path = "/path/to/key"
+cert_path = "/path/to/cert"
+
+[c8y]
+url = "your-tenant.cumulocity.com"
+root_cert_path = "/path/to/c8y/root/cert"
+connect = "true"
+
+[az]
+url = "MyAzure.azure-devices.net"
+root_cert_path = "/path/to/azure/root/cert"
+connect = "false"
+mapper_timestamp = true
+
+[mqtt]
+port = 1234
+external_port = 2345
+external_bind_address = "0.0.0.0"
+external_bind_interface = "wlan0"
+external_capath = "ca.pem"
+external_certfile = "cert.pem"
+external_keyfile = "key.pem"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config_defaults = dummy_tedge_config_defaults();
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/path/to/key")
+ );
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/path/to/cert")
+ );
+
+ assert_eq!(
+ config.query(C8yUrlSetting)?.as_str(),
+ "your-tenant.cumulocity.com"
+ );
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/path/to/c8y/root/cert")
+ );
+
+ assert_eq!(
+ config.query(AzureUrlSetting)?.as_str(),
+ "MyAzure.azure-devices.net"
+ );
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/path/to/azure/root/cert")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1234));
+
+ assert_eq!(config.query(MqttExternalPortSetting)?, Port(2345));
+
+ assert_eq!(
+ config.query(MqttExternalBindAddressSetting)?.as_str(),
+ "0.0.0.0"
+ );
+
+ assert_eq!(
+ config.query(MqttExternalBindInterfaceSetting)?.as_str(),
+ "wlan0"
+ );
+
+ assert_eq!(
+ config.query(MqttExternalCAPathSetting)?,
+ FilePath::from("ca.pem")
+ );
+
+ assert_eq!(
+ config.query(MqttExternalCertfileSetting)?,
+ FilePath::from("cert.pem")
+ );
+
+ assert_eq!(
+ config.query(MqttExternalKeyfileSetting)?,
+ FilePath::from("key.pem")
+ );
+
+ Ok(())
+}
+
+#[test]
+fn test_store_config_with_all_values() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+key_path = "/path/to/key"
+cert_path = "/path/to/cert"
+
+[c8y]
+url = "your-tenant.cumulocity.com"
+root_cert_path = "/path/to/c8y/root/cert"
+
+[az]
+url = "MyAzure.azure-devices.net"
+root_cert_path = "/path/to/azure/root/cert"
+mapper_timestamp = false
+
+[mqtt]
+port = 1883
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config_defaults = TEdgeConfigDefaults {
+ default_c8y_root_cert_path: FilePath::from("default_c8y_root_cert_path"),
+ default_azure_root_cert_path: FilePath::from("default_azure_root_cert_path"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let config_repo = TEdgeConfigRepository::new_with_defaults(config_location, config_defaults);
+
+ let updated_c8y_url = "other-tenant.cumulocity.com";
+ let updated_azure_url = "OtherAzure.azure-devices.net";
+ let updated_mqtt_port = Port(2345);
+ let updated_mqtt_external_port = Port(3456);
+ let updated_mqtt_external_bind_address = "localhost";
+ let updated_mqtt_external_bind_interface = "eth0";
+ let updated_mqtt_external_capath = "/some/path";
+ let updated_mqtt_external_certfile = "cert.pem";
+ let updated_mqtt_external_keyfile = "key.pem";
+
+ {
+ let mut config = config_repo.load()?;
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/path/to/key")
+ );
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/path/to/cert")
+ );
+
+ assert_eq!(
+ config.query(C8yUrlSetting)?.as_str(),
+ "your-tenant.cumulocity.com"
+ );
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/path/to/c8y/root/cert")
+ );
+
+ assert_eq!(
+ config.query(AzureUrlSetting)?.as_str(),
+ "MyAzure.azure-devices.net"
+ );
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/path/to/azure/root/cert")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(false));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1883));
+
+ config.update(C8yUrlSetting, ConnectUrl::try_from(updated_c8y_url)?)?;
+ config.unset(C8yRootCertPathSetting)?;
+ config.update(AzureUrlSetting, ConnectUrl::try_from(updated_azure_url)?)?;
+ config.unset(AzureRootCertPathSetting)?;
+ config.unset(AzureMapperTimestamp)?;
+ config.update(MqttPortSetting, updated_mqtt_port)?;
+ config.update(MqttExternalPortSetting, updated_mqtt_external_port)?;
+ config.update(
+ MqttExternalBindAddressSetting,
+ updated_mqtt_external_bind_address.to_string(),
+ )?;
+ config.update(
+ MqttExternalBindInterfaceSetting,
+ updated_mqtt_external_bind_interface.to_string(),
+ )?;
+ config.update(
+ MqttExternalCAPathSetting,
+ FilePath::from(updated_mqtt_external_capath),
+ )?;
+ config.update(
+ MqttExternalCertfileSetting,
+ FilePath::from(updated_mqtt_external_certfile),
+ )?;
+ config.update(
+ MqttExternalKeyfileSetting,
+ FilePath::from(updated_mqtt_external_keyfile),
+ )?;
+ config_repo.store(&config)?;
+ }
+
+ {
+ let config = config_repo.load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/path/to/key")
+ );
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/path/to/cert")
+ );
+
+ assert_eq!(config.query(C8yUrlSetting)?.as_str(), updated_c8y_url);
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("default_c8y_root_cert_path")
+ );
+
+ assert_eq!(config.query(AzureUrlSetting)?.as_str(), updated_azure_url);
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("default_azure_root_cert_path")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, updated_mqtt_port);
+ assert_eq!(
+ config.query(MqttExternalPortSetting)?,
+ updated_mqtt_external_port
+ );
+ assert_eq!(
+ config.query(MqttExternalBindAddressSetting)?.as_str(),
+ updated_mqtt_external_bind_address
+ );
+ assert_eq!(
+ config.query(MqttExternalBindInterfaceSetting)?.as_str(),
+ updated_mqtt_external_bind_interface
+ );
+ assert_eq!(
+ config.query(MqttExternalCAPathSetting)?,
+ FilePath::from(updated_mqtt_external_capath)
+ );
+ assert_eq!(
+ config.query(MqttExternalCertfileSetting)?,
+ FilePath::from(updated_mqtt_external_certfile)
+ );
+ assert_eq!(
+ config.query(MqttExternalKeyfileSetting)?,
+ FilePath::from(updated_mqtt_external_keyfile)
+ );
+ }
+
+ Ok(())
+}
+
+#[test]
+fn test_parse_config_with_only_device_configuration() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config_defaults = TEdgeConfigDefaults {
+ default_device_cert_path: FilePath::from("/etc/ssl/certs/tedge-certificate.pem"),
+ default_device_key_path: FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ default_c8y_root_cert_path: FilePath::from("/etc/ssl/certs"),
+ default_azure_root_cert_path: FilePath::from("/etc/ssl/certs"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-certificate.pem")
+ );
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-private-key.pem")
+ );
+
+ assert!(config.query_optional(C8yUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+
+ assert!(config.query_optional(AzureUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1883));
+ Ok(())
+}
+
+#[test]
+fn test_parse_config_with_only_c8y_configuration() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[c8y]
+url = "your-tenant.cumulocity.com"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+
+ let config_defaults = TEdgeConfigDefaults {
+ default_device_cert_path: FilePath::from("/etc/ssl/certs/tedge-certificate.pem"),
+ default_device_key_path: FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-certificate.pem")
+ );
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ );
+
+ assert_eq!(
+ config.query(C8yUrlSetting)?.as_str(),
+ "your-tenant.cumulocity.com"
+ );
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/dev/null")
+ );
+
+ assert!(config.query_optional(AzureUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/dev/null")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1883));
+ Ok(())
+}
+
+#[test]
+fn test_parse_config_with_only_az_configuration() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[az]
+url = "MyAzure.azure-devices.net"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+
+ let config_defaults = TEdgeConfigDefaults {
+ default_device_cert_path: FilePath::from("/etc/ssl/certs/tedge-certificate.pem"),
+ default_device_key_path: FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-certificate.pem")
+ );
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ );
+
+ assert!(config.query_optional(C8yUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/dev/null")
+ );
+
+ assert_eq!(
+ config.query(AzureUrlSetting)?.as_str(),
+ "MyAzure.azure-devices.net"
+ );
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/dev/null")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1883));
+ Ok(())
+}
+
+#[test]
+fn test_parse_config_with_only_mqtt_configuration() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[mqtt]
+port = 2222
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+
+ let config_defaults = TEdgeConfigDefaults {
+ default_device_cert_path: FilePath::from("/etc/ssl/certs/tedge-certificate.pem"),
+ default_device_key_path: FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-certificate.pem")
+ );
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ );
+
+ assert!(config.query_optional(C8yUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/dev/null")
+ );
+
+ assert!(config.query_optional(AzureUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/dev/null")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(2222));
+ Ok(())
+}
+
+#[test]
+fn read_az_keys_from_old_version_config() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[azure]
+url = "MyAzure.azure-devices.net"
+root_cert_path = "/path/to/azure/root/cert"
+mapper_timestamp = true
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config_defaults = dummy_tedge_config_defaults();
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert_eq!(
+ config.query(AzureUrlSetting)?.as_str(),
+ "MyAzure.azure-devices.net"
+ );
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/path/to/azure/root/cert")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ Ok(())
+}
+
+#[test]
+fn set_az_keys_from_old_version_config() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[azure]
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config_defaults = TEdgeConfigDefaults {
+ default_azure_root_cert_path: FilePath::from("default_azure_root_cert_path"),
+ ..dummy_tedge_config_defaults()
+ };
+ let config_repo = TEdgeConfigRepository::new_with_defaults(config_location, config_defaults);
+ let updated_azure_url = "OtherAzure.azure-devices.net";
+
+ {
+ let mut config = config_repo.load()?;
+
+ assert!(config.query_optional(AzureUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("default_azure_root_cert_path")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ config.update(AzureUrlSetting, ConnectUrl::try_from(updated_azure_url)?)?;
+ config.unset(AzureRootCertPathSetting)?;
+ config.unset(AzureMapperTimestamp)?;
+ config_repo.store(&config)?;
+ }
+
+ {
+ let config = config_repo.load()?;
+
+ assert_eq!(config.query(AzureUrlSetting)?.as_str(), updated_azure_url);
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("default_azure_root_cert_path")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+ }
+
+ Ok(())
+}
+
+#[test]
+fn test_parse_config_empty_file() -> Result<(), TEdgeConfigError> {
+ let toml_conf = "";
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+
+ let config_defaults = TEdgeConfigDefaults {
+ default_device_cert_path: FilePath::from("/etc/ssl/certs/tedge-certificate.pem"),
+ default_device_key_path: FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ default_c8y_root_cert_path: FilePath::from("/etc/ssl/certs"),
+ default_azure_root_cert_path: FilePath::from("/etc/ssl/certs"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-certificate.pem")
+ );
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/etc/ssl/certs/tedge-private-key.pem"),
+ );
+
+ assert!(config.query_optional(C8yUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+
+ assert!(config.query_optional(AzureUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1883));
+ Ok(())
+}
+
+#[test]
+fn test_parse_config_no_config_file() -> Result<(), TEdgeConfigError> {
+ let config_location = TEdgeConfigLocation::from_custom_root("/non/existent/path");
+ let config = TEdgeConfigRepository::new(config_location).load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ FilePath::from("/non/existent/path/device-certs/tedge-certificate.pem")
+ );
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ FilePath::from("/non/existent/path/device-certs/tedge-private-key.pem"),
+ );
+
+ assert!(config.query_optional(C8yUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+
+ assert!(config.query_optional(AzureUrlSetting)?.is_none());
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1883));
+ Ok(())
+}
+
+#[test]
+fn test_parse_unsupported_keys() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+hey="tedge"
+[c8y]
+hello="tedge"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let result = TEdgeConfigRepository::new(config_location).load();
+
+ assert_matches!(
+ result,
+ Err(TEdgeConfigError::FromTOMLParse(_)),
+ "Expected the parsing to fail with TOMLParseError"
+ );
+ Ok(())
+}
+
+#[test]
+fn test_invalid_mqtt_port() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[mqtt]
+port = "1883"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let result = TEdgeConfigRepository::new(config_location).load();
+
+ let expected_err =
+ "invalid type: string \"1883\", expected u16 for key `mqtt.port` at line 3 column 8";
+
+ match result {
+ Err(TEdgeConfigError::FromTOMLParse(err)) => assert_eq!(err.to_string(), expected_err),
+
+ _ => assert!(false, "Expected the parsing to fail with TOMLParseError"),
+ }
+
+ Ok(())
+}
+
+#[test]
+fn test_parse_invalid_toml_file() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+ <abcde>
+ "#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let result = TEdgeConfigRepository::new(config_location).load();
+
+ assert_matches!(
+ result,
+ Err(TEdgeConfigError::FromTOMLParse(_)),
+ "Expected the parsing to fail with TOMLParseError"
+ );
+ Ok(())
+}
+
+#[test]
+fn test_crud_config_value() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+key_path = "/path/to/key"
+cert_path = "/path/to/cert"
+
+[c8y]
+url = "your-tenant.cumulocity.com"
+root_cert_path = "/path/to/c8y/root/cert"
+
+[az]
+url = "MyAzure.azure-devices.net"
+root_cert_path = "/path/to/azure/root/cert"
+mapper_timestamp = false
+
+[mqtt]
+port = 1024
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+
+ let config_defaults = TEdgeConfigDefaults {
+ default_c8y_root_cert_path: FilePath::from("/etc/ssl/certs"),
+ default_azure_root_cert_path: FilePath::from("/etc/ssl/certs"),
+ ..dummy_tedge_config_defaults()
+ };
+
+ let mut config =
+ TEdgeConfigRepository::new_with_defaults(config_location, config_defaults).load()?;
+
+ let original_device_key_path = FilePath::from("/path/to/key");
+ let original_device_cert_path = FilePath::from("/path/to/cert");
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ original_device_key_path
+ );
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ original_device_cert_path
+ );
+
+ let original_c8y_url = ConnectUrl::try_from("your-tenant.cumulocity.com")?;
+ let original_c8y_root_cert_path = FilePath::from("/path/to/c8y/root/cert");
+ assert_eq!(config.query(C8yUrlSetting)?, original_c8y_url);
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ original_c8y_root_cert_path
+ );
+
+ let original_azure_url = ConnectUrl::try_from("MyAzure.azure-devices.net")?;
+ let original_azure_root_cert_path = FilePath::from("/path/to/azure/root/cert");
+ assert_eq!(config.query(AzureUrlSetting)?, original_azure_url);
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ original_azure_root_cert_path
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(false));
+
+ assert_eq!(config.query(MqttPortSetting)?, Port(1024));
+
+ let updated_c8y_url = ConnectUrl::try_from("other-tenant.cumulocity.com")?;
+ config.update(C8yUrlSetting, updated_c8y_url.clone())?;
+ config.unset(C8yRootCertPathSetting)?;
+
+ let updated_azure_url = ConnectUrl::try_from("OtherAzure.azure-devices.net")?;
+ config.update(AzureUrlSetting, updated_azure_url.clone())?;
+ config.unset(AzureRootCertPathSetting)?;
+ config.unset(AzureMapperTimestamp)?;
+
+ let updated_mqtt_port = Port(2048);
+ config.update(MqttPortSetting, updated_mqtt_port)?;
+
+ assert_eq!(
+ config.query(DeviceKeyPathSetting)?,
+ original_device_key_path
+ );
+ assert_eq!(
+ config.query(DeviceCertPathSetting)?,
+ original_device_cert_path
+ );
+
+ assert_eq!(config.query(C8yUrlSetting)?, updated_c8y_url);
+ assert_eq!(
+ config.query(C8yRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+
+ assert_eq!(config.query(AzureUrlSetting)?, updated_azure_url);
+ assert_eq!(
+ config.query(AzureRootCertPathSetting)?,
+ FilePath::from("/etc/ssl/certs")
+ );
+ assert_eq!(config.query(AzureMapperTimestamp)?, Flag(true));
+
+ assert_eq!(config.query(MqttPortSetting)?, updated_mqtt_port);
+ Ok(())
+}
+
+#[test]
+fn test_any_device_id_provided_by_the_configuration_is_ignored() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+id = "ABCD1234" # ignored for backward compatibility
+cert_path = "/path/to/cert"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, dummy_tedge_config_defaults())
+ .load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ Ok(())
+}
+
+#[test]
+fn test_device_id_is_none_when_there_is_no_certificate() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+cert_path = "/path/to/cert"
+"#;
+
+ let (_tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let config =
+ TEdgeConfigRepository::new_with_defaults(config_location, dummy_tedge_config_defaults())
+ .load()?;
+
+ assert!(config.query_optional(DeviceIdSetting).is_err());
+ Ok(())
+}
+
+#[test]
+fn test_device_id_is_err_when_cert_path_is_not_a_certificate() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+cert_path = "/path/to/cert"
+"#;
+
+ let (tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let mut config =
+ TEdgeConfigRepository::new_with_defaults(config_location, dummy_tedge_config_defaults())
+ .load()?;
+
+ let cert_path = tempdir.path().join("not-a-certificate.pem");
+ std::fs::File::create(cert_path.clone()).expect("fail to create a fake certificate");
+ config.update(DeviceCertPathSetting, cert_path.into())?;
+
+ match config.query(DeviceIdSetting) {
+ Err(ConfigSettingError::DerivationFailed { key, cause }) => {
+ assert_eq!(key, "device.id");
+ assert_eq!(cause, "PEM file format error");
+ }
+ Err(_) => assert!(false, "unexpected error"),
+ Ok(_) => assert!(false, "unexpected ok result"),
+ }
+ Ok(())
+}
+
+#[test]
+fn test_device_id_is_extracted_from_device_certificate() -> Result<(), TEdgeConfigError> {
+ let toml_conf = r#"
+[device]
+cert_path = "/path/to/cert"
+"#;
+ let device_id = "device-serial-number";
+
+ let (tempdir, config_location) = create_temp_tedge_config(toml_conf)?;
+ let mut config =
+ TEdgeConfigRepository::new_with_defaults(config_location, dummy_tedge_config_defaults())
+ .load()?;
+
+ let cert_path = tempdir.path().join("certificate.pem");
+ create_certificate(cert_path.clone(), device_id).expect("fail to create a certificate");
+ config.update(DeviceCertPathSetting, cert_path.into())?;
+
+ assert_eq!(config.query(DeviceIdSetting)?, device_id);
+
+ Ok(())
+}
+
+fn create_temp_tedge_config(content: &str) -> std::io::Result<(TempDir, TEdgeConfigLocation)> {
+ let dir = TempDir::new()?;
+ let config_location = TEdgeConfigLocation::from_custom_root(dir.path());
+ let mut file = std::fs::File::create(config_location.tedge_config_file_path())?;
+ file.write_all(content.as_bytes())?;
+ Ok((dir, config_location))
+}
+
+fn dummy_tedge_config_defaults() -> TEdgeConfigDefaults {
+ TEdgeConfigDefaults {
+ default_device_cert_path: FilePath::from("/dev/null"),
+ default_device_key_path: FilePath::from("/dev/null"),
+ default_c8y_root_cert_path: FilePath::from("/dev/null"),
+ default_azure_root_cert_path: FilePath::from("/dev/null"),
+ default_mapper_timestamp: Flag(true),
+ default_mqtt_port: Port(1883),
+ }
+}
+
+fn create_certificate(
+ path: std::path::PathBuf,
+ device_id: &str,
+) -> Result<(), certificate::CertificateError> {
+ let keypair = certificate::KeyCertPair::new_selfsigned_certificate(
+ &certificate::NewCertificateConfig::default(),
+ device_id,
+ )?;
+ let pem = keypair.certificate_pem_string()?;
+ let mut file = std::fs::File::create(path)?;
+ file.write_all(pem.as_bytes())?;
+ Ok(())
+}