use std::sync::Arc;
use faucet_core::{AuthProvider, AuthReference, AuthSpec, Credential, FaucetError, Source};
use faucet_source_snowflake::{SnowflakeAuth, SnowflakeSource, SnowflakeSourceConfig};
use serde_json::json;
use wiremock::matchers::{header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[derive(Debug)]
struct FixedBearer(&'static str);
#[async_trait::async_trait]
impl AuthProvider for FixedBearer {
async fn credential(&self) -> Result<Credential, FaucetError> {
Ok(Credential::Bearer(self.0.to_string()))
}
fn provider_name(&self) -> &'static str {
"fixed-bearer"
}
}
fn minimal_response() -> serde_json::Value {
json!({
"code": "090001",
"statementHandle": "h",
"resultSetMetaData": {
"rowType": [{"name": "ID", "type": "fixed"}],
"partitionInfo": [{"rowCount": 1}]
},
"data": [["42"]]
})
}
fn base_cfg() -> SnowflakeSourceConfig {
SnowflakeSourceConfig::new(
"xy12345",
"WH",
"DB",
"PUBLIC",
SnowflakeAuth::OAuth {
token: "INLINE-TOKEN".into(),
},
"SELECT 1",
)
}
#[tokio::test]
async fn injected_provider_supplies_oauth_token() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/api/v2/statements"))
.and(header("Authorization", "Snowflake Token=\"INJECTED\""))
.and(header("X-Snowflake-Authorization-Token-Type", "OAUTH"))
.respond_with(ResponseTemplate::new(200).set_body_json(minimal_response()))
.mount(&server)
.await;
let provider = Arc::new(FixedBearer("INJECTED"));
let src = SnowflakeSource::new(base_cfg())
.unwrap()
.with_endpoint_base(server.uri())
.with_auth_provider(provider);
let rows = src.fetch_all().await.unwrap();
assert_eq!(rows.len(), 1);
assert_eq!(rows[0]["ID"], 42);
}
#[tokio::test]
async fn token_credential_maps_to_oauth() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/api/v2/statements"))
.and(header("Authorization", "Snowflake Token=\"TOKEN-CRED\""))
.respond_with(ResponseTemplate::new(200).set_body_json(minimal_response()))
.mount(&server)
.await;
#[derive(Debug)]
struct FixedToken(&'static str);
#[async_trait::async_trait]
impl AuthProvider for FixedToken {
async fn credential(&self) -> Result<Credential, FaucetError> {
Ok(Credential::Token(self.0.to_string()))
}
fn provider_name(&self) -> &'static str {
"fixed-token"
}
}
let src = SnowflakeSource::new(base_cfg())
.unwrap()
.with_endpoint_base(server.uri())
.with_auth_provider(Arc::new(FixedToken("TOKEN-CRED")));
let rows = src.fetch_all().await.unwrap();
assert_eq!(rows.len(), 1);
}
#[tokio::test]
async fn unresolved_auth_reference_errors() {
let server = MockServer::start().await;
let mut config = base_cfg();
config.auth = AuthSpec::Reference(AuthReference {
name: "missing-provider".into(),
});
let src = SnowflakeSource::new(config)
.unwrap()
.with_endpoint_base(server.uri());
let err = src.fetch_all().await.unwrap_err();
assert!(
matches!(err, FaucetError::Auth(_)),
"expected Auth error, got {err:?}"
);
}
#[test]
fn credential_to_auth_rejects_basic() {
let cred = Credential::Basic {
username: "u".into(),
password: "p".into(),
};
let err = faucet_common_snowflake::credential_to_auth(cred).unwrap_err();
assert!(
matches!(err, FaucetError::Auth(_)),
"expected Auth error, got {err:?}"
);
}
#[tokio::test]
async fn one_provider_shared_across_two_sources() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(header("Authorization", "Snowflake Token=\"SHARED\""))
.respond_with(ResponseTemplate::new(200).set_body_json(minimal_response()))
.mount(&server)
.await;
let provider = Arc::new(FixedBearer("SHARED"));
let a = SnowflakeSource::new(base_cfg())
.unwrap()
.with_endpoint_base(server.uri())
.with_auth_provider(provider.clone());
let b = SnowflakeSource::new(base_cfg())
.unwrap()
.with_endpoint_base(server.uri())
.with_auth_provider(provider.clone());
assert_eq!(a.fetch_all().await.unwrap().len(), 1);
assert_eq!(b.fetch_all().await.unwrap().len(), 1);
}