This commit is contained in:
AsafMah 2023-02-23 15:01:39 +02:00
Родитель ce336b6091
Коммит 5c5272211f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: AD0D1680EEE7A4FF
3 изменённых файлов: 196 добавлений и 7 удалений

Просмотреть файл

@ -37,8 +37,9 @@ static DEFAULT_USER: Lazy<String> = Lazy::new(|| {
static DEFAULT_APPLICATION: Lazy<String> = Lazy::new(|| {
std::env::current_exe()
.map(|x| x.to_string_lossy().to_string())
.unwrap_or_else(|_| UNKNOWN.to_string())
.ok()
.and_then(|x| x.file_name().map(|x| x.to_string_lossy().to_string()))
.unwrap_or_else(|| UNKNOWN.to_string())
});
static DEFAULT_VERSION: Lazy<String> = Lazy::new(|| {
@ -120,3 +121,184 @@ pub struct ConnectorDetails<'a> {
/// Additional fields to add to the header.
additional_fields: Vec<(&'a str, &'a str)>,
}
#[cfg(test)]
mod tests {
use super::*;
// Write extensive tests
#[test]
fn test_escape_value() {
assert_eq!(escape_value("".into()), "{}");
assert_eq!(escape_value("abc".into()), "{abc}");
assert_eq!(escape_value("ab c".into()), "{ab_c}");
assert_eq!(escape_value("ab_c".into()), "{ab_c}");
assert_eq!(escape_value("ab|c".into()), "{ab_c}");
assert_eq!(escape_value("ab{}c".into()), "{ab_c}");
}
#[test]
fn test_format_header() {
assert_eq!(
format_header(vec![("a".into(), "b".into())]),
"a:{b}"
);
assert_eq!(
format_header(vec![("a".into(), "b".into()), ("c".into(), "d".into())]),
"a:{b}|c:{d}"
);
}
#[test]
fn test_client_details_new() {
let client_details = ClientDetails::new(None, None);
assert_eq!(
client_details,
ClientDetails {
application: DEFAULT_APPLICATION.clone(),
user: DEFAULT_USER.clone(),
version: DEFAULT_VERSION.clone()
}
);
let client_details = ClientDetails::new(Some("my_app".to_string()), None);
assert_eq!(
client_details,
ClientDetails {
application: "my_app".to_string(),
user: DEFAULT_USER.clone(),
version: DEFAULT_VERSION.clone()
}
);
let client_details = ClientDetails::new(None, Some("my_user".to_string()));
assert_eq!(
client_details,
ClientDetails {
application: DEFAULT_APPLICATION.clone(),
user: "my_user".to_string(),
version: DEFAULT_VERSION.clone()
}
);
let client_details = ClientDetails::new(
Some("my_app".to_string()),
Some("my_user".to_string()),
);
assert_eq!(
client_details,
ClientDetails {
application: "my_app".to_string(),
user: "my_user".to_string(),
version: DEFAULT_VERSION.clone()
}
);
}
#[test]
fn test_set_connector_details_user() {
let details = ConnectorDetailsBuilder::default()
.with_name("MyConnector")
.with_version("1.0")
.with_send_user(true)
.with_override_user("user1")
.with_app_name("MyApp")
.with_app_version("1.0.1")
.with_additional_fields(vec![("key1", "value1"), ("key2", "value2")])
.build()
.unwrap();
let (header, user) = set_connector_details(details);
let expected_header = "Kusto.MyConnector:{1.0}|App.{MyApp}:{1.0.1}|key1:{value1}|key2:{value2}".to_string();
assert_eq!(header, expected_header);
assert_eq!(user, "user1");
let details = ConnectorDetailsBuilder::default()
.with_name("MyConnector")
.with_version("1.0")
.with_send_user(false)
.with_app_name("MyApp")
.with_app_version("1.0.1")
.with_additional_fields(vec![("key1", "value1"), ("key2", "value2")])
.build()
.unwrap();
let (header, user) = set_connector_details(details);
let expected_header = "Kusto.MyConnector:{1.0}|App.{MyApp}:{1.0.1}|key1:{value1}|key2:{value2}".to_string();
assert_eq!(header, expected_header);
assert_eq!(user, "[none]");
let details = ConnectorDetailsBuilder::default()
.with_name("MyConnector")
.with_version("1.0")
.with_send_user(true)
.with_app_name("MyApp")
.with_app_version("1.0.1")
.with_additional_fields(vec![("key1", "value1"), ("key2", "value2")])
.build()
.unwrap();
let (header, user) = set_connector_details(details);
let expected_header = "Kusto.MyConnector:{1.0}|App.{MyApp}:{1.0.1}|key1:{value1}|key2:{value2}".to_string();
// We don't know the actual user that will be returned, but we can at least check
// that it's not an empty string.
assert_ne!(user, "", "user should not be an empty string, but it is");
assert_eq!(header, expected_header);
}
#[test]
fn test_set_connector_details_no_app_name() {
let details = ConnectorDetailsBuilder::default()
.with_name("MyConnector")
.with_version("1.0")
.build()
.unwrap();
let (header, user) = set_connector_details(details);
assert!(header.contains("Kusto.MyConnector:{1.0}"));
assert_eq!(user, "[none]");
}
#[test]
fn test_set_connector_details_no_app_version() {
let details = ConnectorDetailsBuilder::default()
.with_name("MyConnector")
.with_version("1.0")
.with_app_name("MyApp")
.build()
.unwrap();
let (header, user) = set_connector_details(details);
assert!(header.contains("Kusto.MyConnector:{1.0}"));
assert!(header.contains("App.{MyApp}:{unknown}"));
assert_eq!(user, "[none]");
}
#[test]
fn test_set_connector_details_no_additional_fields() {
let details = ConnectorDetailsBuilder::default()
.with_name("MyConnector")
.with_version("1.0")
.with_app_name("MyApp")
.with_app_version("1.0.1")
.build()
.unwrap();
let (header, user) = set_connector_details(details);
assert!(header.contains("Kusto.MyConnector:{1.0}"));
assert!(header.contains("App.{MyApp}:{1.0.1}"));
assert_eq!(user, "[none]");
}
}

Просмотреть файл

@ -15,12 +15,19 @@ static CLOUDINFO_CACHE: Lazy<Mutex<HashMap<String, CloudInfo>>> =
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
#[serde(rename_all = "PascalCase")]
/// Represents the information from the metadata endpoint about a cloud.
pub struct CloudInfo {
/// Whether the cloud requires MFA for login.
pub login_mfa_required: bool,
/// The login endpoint for the cloud.
pub login_endpoint: Cow<'static, str>,
/// The client app id for kusto for the cloud.
pub kusto_client_app_id: Cow<'static, str>,
/// The client redirect uri for kusto for the cloud.
pub kusto_client_redirect_uri: Cow<'static, str>,
/// The service resource id for kusto for the cloud.
pub kusto_service_resource_id: Cow<'static, str>,
/// The first party authority url for the cloud.
pub first_party_authority_url: Cow<'static, str>,
}

Просмотреть файл

@ -1062,17 +1062,17 @@ impl ConnectionString {
(self.data_source, self.auth)
}
/// Extracts the client details from the connection string.
pub(crate) fn client_details(&self) -> ClientDetails {
ClientDetails::new(self.application.clone(), self.user.clone())
}
/// Sets the application and user for a connector.
pub fn set_connector_details(&mut self, details: ConnectorDetails) {
let (app, user) = client_details::set_connector_details(details);
self.application = app.into();
self.user = user.into();
}
/// Extracts the client details from the connection string.
pub fn client_details(&self) -> ClientDetails {
ClientDetails::new(self.application.clone(), self.user.clone())
}
}
fn parse_boolean(term: &str, name: &str) -> Result<bool, ConnectionStringError> {