Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/adapter/graphql/tests/tests/test_accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async fn test_account_by_name() {
"#,
"unknown",
))
.data(cat),
.data(cat.clone()),
)
.await;

Expand All @@ -89,6 +89,36 @@ async fn test_account_by_name() {
}
})
);

let res = schema
.execute(
async_graphql::Request::new(format!(
r#"
query {{
accounts {{
byName (name: "{}") {{
accountName
}}
}}
}}
"#,
DEFAULT_ACCOUNT_NAME.to_ascii_uppercase(),
Comment thread
sergiimk marked this conversation as resolved.
))
.data(cat),
)
.await;

assert!(res.is_ok(), "{res:?}");
assert_eq!(
res.data,
value!({
"accounts": {
"byName": {
"accountName": DEFAULT_ACCOUNT_NAME
}
}
})
);
}

////////////////////////////////////////////////////////////////////////////////////////
59 changes: 59 additions & 0 deletions src/adapter/graphql/tests/tests/test_gql_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,65 @@ async fn test_dataset_schema_local_fs() {

/////////////////////////////////////////////////////////////////////////////////////////

#[test_group::group(engine, datafusion)]
#[test_log::test(tokio::test)]
async fn test_dataset_case_insensetive_schema_local_fs() {
Comment thread
zaychenko-sergei marked this conversation as resolved.
Outdated
let tempdir = tempfile::tempdir().unwrap();
let catalog = create_catalog_with_local_workspace(tempdir.path());
create_test_dataset(&catalog, tempdir.path()).await;

let schema = kamu_adapter_graphql::schema_quiet();
let res = schema
.execute(
async_graphql::Request::new(indoc::indoc!(
r#"
{
datasets {
byOwnerAndName(accountName: "kAmU", datasetName: "FOo") {
name
data {
tail(limit: 1, schemaFormat: PARQUET_JSON, dataFormat: JSON) {
... on DataQueryResultSuccess {
schema { content }
}
}
}
}
}
}
"#
))
.data(catalog),
)
.await;
assert!(res.is_ok(), "{res:?}");
let json = serde_json::to_string(&res.data).unwrap();
let json = serde_json::from_str::<serde_json::Value>(&json).unwrap();
let data_schema = &json["datasets"]["byOwnerAndName"]["data"]["tail"]["schema"]["content"];
let data_schema =
serde_json::from_str::<serde_json::Value>(data_schema.as_str().unwrap()).unwrap();
assert_eq!(
data_schema,
serde_json::json!({
"name": "arrow_schema",
"type": "struct",
"fields": [{
"name": "offset",
"repetition": "REQUIRED",
"type": "INT64",
"logicalType": "INTEGER(64,false)"
}, {
"name": "blah",
"repetition": "REQUIRED",
"type": "BYTE_ARRAY",
"logicalType": "STRING"
}]
})
);
}

/////////////////////////////////////////////////////////////////////////////////////////

#[test_group::group(engine, datafusion)]
#[test_log::test(tokio::test)]
async fn test_dataset_tail_local_fs() {
Expand Down
26 changes: 26 additions & 0 deletions src/adapter/http/tests/tests/test_routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,32 @@ async fn test_routing_dataset_name() {
await_client_server_flow!(server, client);
}

#[test_log::test(tokio::test)]
async fn test_routing_dataset_name_case_insensetive() {
let repo = setup_repo().await;

let server = setup_server(
repo.catalog,
"/:dataset_name",
|Path(p): Path<DatasetByName>| DatasetAlias::new(None, p.dataset_name).into_local_ref(),
);

let dataset_url = url::Url::parse(&format!(
"http://{}/{}/",
server.local_addr(),
repo.created_dataset
.dataset_handle
.alias
.dataset_name
.to_ascii_uppercase()
))
.unwrap();

let client = setup_client(dataset_url, repo.created_dataset.head);

await_client_server_flow!(server, client);
}

/////////////////////////////////////////////////////////////////////////////////////////

#[allow(dead_code)]
Expand Down
11 changes: 7 additions & 4 deletions src/app/cli/src/services/accounts/account_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,20 @@ impl AccountService {
RelatedAccountIndication::new(target_account)
}

fn find_account_info_impl(&self, account_name: &String) -> Option<AccountInfo> {
fn find_account_info_impl(&self, account_name: &AccountName) -> Option<AccountInfo> {
// The account might be predefined in the configuration
self.predefined_accounts.get(account_name).cloned()
self.predefined_accounts.get(account_name.as_str()).cloned()
Comment thread
sergiimk marked this conversation as resolved.
Outdated
}

fn get_account_info_impl(
&self,
account_name: &String,
) -> Result<AccountInfo, auth::RejectedCredentialsError> {
// The account might be predefined in the configuration
match self.predefined_accounts.get(account_name) {
match self
.predefined_accounts
.get(&account_name.to_ascii_lowercase())
{
// Use the predefined record
Some(account_info) => Ok(account_info.clone()),

Expand Down Expand Up @@ -226,7 +229,7 @@ impl auth::AuthenticationProvider for AccountService {
&'a self,
account_name: &'a AccountName,
) -> Result<Option<AccountInfo>, InternalError> {
Ok(self.find_account_info_impl(&account_name.into()))
Ok(self.find_account_info_impl(account_name))
}
}

Expand Down
35 changes: 23 additions & 12 deletions src/domain/opendatafabric/src/identity/dataset_identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

use std::borrow::Cow;
use std::convert::{AsRef, TryFrom};
use std::hash::Hash;
use std::sync::Arc;
use std::{cmp, fmt, ops};

Expand Down Expand Up @@ -104,18 +106,18 @@ macro_rules! impl_serde {
}

pub(crate) use impl_serde;
use like::Like;
use like::ILike;

////////////////////////////////////////////////////////////////////////////////

macro_rules! newtype_str {
macro_rules! newtype_istr {
($typ:ident, $parse:expr, $visitor:ident) => {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $typ(Arc<str>);

impl $typ {
pub fn new_unchecked<S: AsRef<str> + ?Sized>(s: &S) -> Self {
Self(Arc::from(s.as_ref()))
Self(Arc::from(Self::into_lowercase(s.as_ref())))
Comment thread
sergiimk marked this conversation as resolved.
Outdated
}

pub fn as_str(&self) -> &str {
Expand All @@ -129,6 +131,15 @@ macro_rules! newtype_str {
pub fn from_inner_unchecked(s: Arc<str>) -> Self {
Self(s)
}

pub fn into_lowercase(s: &str) -> Cow<'_, str> {
let bytes = s.as_bytes();
if !bytes.iter().any(u8::is_ascii_uppercase) {
Cow::Borrowed(s)
} else {
Cow::Owned(s.to_ascii_lowercase())
}
}
}

impl From<$typ> for String {
Expand All @@ -152,7 +163,7 @@ macro_rules! newtype_str {
impl std::str::FromStr for $typ {
type Err = ::multiformats::ParseError<$typ>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match $parse(s) {
match $parse(&$typ::into_lowercase(s)) {
Some((_, "")) => Ok(Self::new_unchecked(s)),
_ => Err(ParseError::new(s)),
}
Expand Down Expand Up @@ -207,7 +218,7 @@ macro_rules! newtype_str {

////////////////////////////////////////////////////////////////////////////////

newtype_str!(
newtype_istr!(
DatasetName,
Grammar::match_dataset_name,
DatasetNameSerdeVisitor
Expand All @@ -225,15 +236,15 @@ impl DatasetName {

///////////////////////////////////////////////////////////////////////////////

newtype_str!(
newtype_istr!(
DatasetNamePattern,
Grammar::match_dataset_name_pattern,
DatasetNamePatternSerdeVisitor
);

impl DatasetNamePattern {
pub fn matches(&self, dataset_name: &DatasetName) -> bool {
Like::<false>::like(dataset_name.as_str(), self).unwrap()
ILike::<false>::ilike(dataset_name.as_str(), self).unwrap()
}
}

Expand All @@ -257,7 +268,7 @@ impl DatasetAliasPattern {
}

pub fn matches(&self, dataset_handle: &DatasetHandle) -> bool {
(self.account_name.is_none() || self.account_name == dataset_handle.alias.account_name)
self.account_name == dataset_handle.alias.account_name
Comment thread
zaychenko-sergei marked this conversation as resolved.
Outdated
&& self
.dataset_name_pattern
.matches(&dataset_handle.alias.dataset_name)
Expand Down Expand Up @@ -299,15 +310,15 @@ pub const FAKE_ACCOUNT_ID: &str = "12345";

////////////////////////////////////////////////////////////////////////////////

newtype_str!(
newtype_istr!(
AccountName,
Grammar::match_account_name,
AccountNameSerdeVisitor
);

////////////////////////////////////////////////////////////////////////////////

newtype_str!(RepoName, Grammar::match_repo_name, RepoNameSerdeVisitor);
newtype_istr!(RepoName, Grammar::match_repo_name, RepoNameSerdeVisitor);

////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -361,7 +372,7 @@ impl DatasetAlias {
impl std::str::FromStr for DatasetAlias {
type Err = ParseError<Self>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match Grammar::match_dataset_alias(s) {
match Grammar::match_dataset_alias(&s.to_ascii_lowercase()) {
Some((acc, ds, "")) => Ok(Self::new(
acc.map(AccountName::new_unchecked),
DatasetName::new_unchecked(ds),
Expand Down Expand Up @@ -440,7 +451,7 @@ impl DatasetAliasRemote {
impl std::str::FromStr for DatasetAliasRemote {
type Err = ParseError<Self>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match Grammar::match_dataset_alias_remote(s) {
match Grammar::match_dataset_alias_remote(&s.to_ascii_lowercase()) {
Some((repo, acc, ds, "")) => Ok(Self::new(
RepoName::new_unchecked(repo),
acc.map(AccountName::new_unchecked),
Expand Down
1 change: 1 addition & 0 deletions src/domain/opendatafabric/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// by the Apache License, Version 2.0.

#![feature(error_generic_member_access)]
#![feature(let_chains)]

pub mod dtos;
pub use dtos::*;
Expand Down
52 changes: 52 additions & 0 deletions src/domain/opendatafabric/tests/tests/test_dataset_identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,55 @@ fn test_dataset_refs_conversions() {
alias: DatasetAlias::try_from("bar").unwrap(),
});
}

#[test]
fn test_dataset_alias_eq() {
assert_eq!(
DatasetAlias::from_str("account/net.example.com").unwrap(),
DatasetAlias::from_str("aCCouNt/net.ExaMplE.coM").unwrap(),
);
assert_eq!(
DatasetAlias::from_str("account/net.example.com").unwrap(),
DatasetAlias::from_str("account/net.example.com").unwrap(),
);
assert_eq!(
DatasetAlias::from_str("net.example.com").unwrap(),
DatasetAlias::from_str("net.ExaMplE.coM").unwrap(),
);
assert_ne!(
DatasetAlias::from_str("account/net.example.com").unwrap(),
DatasetAlias::from_str("aCCouNt1/net.eXamPle.cOm").unwrap(),
);
assert_ne!(
DatasetAlias::from_str("account1/net.example.com").unwrap(),
DatasetAlias::from_str("account/net.example.com").unwrap(),
);
assert_ne!(
DatasetAlias::from_str("net.example.com").unwrap(),
DatasetAlias::from_str("account/net.example.com").unwrap(),
);
}

#[test]
fn test_dataset_remote_alias_eq() {
assert_eq!(
DatasetAliasRemote::from_str("repository/net.example.com").unwrap(),
DatasetAliasRemote::from_str("repository/net.ExaMplE.coM").unwrap(),
);
assert_eq!(
DatasetAliasRemote::from_str("repository/net.example.com").unwrap(),
DatasetAliasRemote::from_str("repository/net.example.com").unwrap(),
);
assert_eq!(
DatasetAliasRemote::from_str("repository/account/net.example.com").unwrap(),
DatasetAliasRemote::from_str("repository/AccOuNt/net.ExaMplE.coM").unwrap(),
);
assert_eq!(
DatasetAliasRemote::from_str("repository/net.example.com").unwrap(),
DatasetAliasRemote::from_str("rEpoSitOry/net.ExaMplE.coM").unwrap(),
);
assert_ne!(
DatasetAliasRemote::from_str("repository/account/net.example.com").unwrap(),
DatasetAliasRemote::from_str("repository/net.example.com").unwrap(),
);
}
14 changes: 13 additions & 1 deletion src/domain/opendatafabric/tests/tests/test_dataset_refs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn test_dataset_ref_pattern_match() {
},
};

assert!(pattern.matches(&dataset_handle));
assert!(!pattern.matches(&dataset_handle));

let dataset_account = "account1";
let dataset_name_pattern = "net%";
Expand Down Expand Up @@ -169,6 +169,18 @@ fn test_dataset_ref_pattern_match() {
},
};
assert!(pattern.matches(&dataset_handle));

let expression = "nEt.eXample%";
let dataset_name = "net.example.com";
let pattern = DatasetRefPattern::from_str(expression).unwrap();
let dataset_handle = DatasetHandle {
id: default_dataset_id.clone(),
alias: DatasetAlias {
account_name: None,
dataset_name: DatasetName::from_str(dataset_name).unwrap(),
},
};
assert!(pattern.matches(&dataset_handle));
}

#[test]
Expand Down
Loading