Skip to content

Commit 3cc284e

Browse files
committed
test: improve test helper & add auth tests
1 parent aa5f20a commit 3cc284e

2 files changed

Lines changed: 225 additions & 4 deletions

File tree

rust/operator-binary/src/controller/build/properties/config_properties.rs

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,75 @@ pub fn build(
250250
mod tests {
251251
use super::*;
252252
use crate::controller::build::properties::test_support::{
253-
MINIMAL_TRINO_YAML, validated_cluster_from_yaml,
253+
MINIMAL_TRINO_YAML, file_auth_class, validated_cluster_from_yaml,
254+
validated_cluster_from_yaml_with_auth,
254255
};
255256

257+
const SERVER_TLS_ONLY_YAML: &str = r#"
258+
apiVersion: trino.stackable.tech/v1alpha1
259+
kind: TrinoCluster
260+
metadata:
261+
name: simple-trino
262+
namespace: default
263+
uid: "e6ac237d-a6d4-43a1-8135-f36506110912"
264+
spec:
265+
image:
266+
productVersion: "479"
267+
clusterConfig:
268+
catalogLabelSelector: {}
269+
tls:
270+
internalSecretClass: null
271+
coordinators:
272+
roleGroups:
273+
default:
274+
replicas: 1
275+
workers:
276+
roleGroups:
277+
default:
278+
replicas: 1
279+
"#;
280+
281+
const INTERNAL_TLS_ONLY_YAML: &str = r#"
282+
apiVersion: trino.stackable.tech/v1alpha1
283+
kind: TrinoCluster
284+
metadata:
285+
name: simple-trino
286+
namespace: default
287+
uid: "e6ac237d-a6d4-43a1-8135-f36506110912"
288+
spec:
289+
image:
290+
productVersion: "479"
291+
clusterConfig:
292+
catalogLabelSelector: {}
293+
tls:
294+
serverSecretClass: null
295+
coordinators:
296+
roleGroups:
297+
default:
298+
replicas: 1
299+
workers:
300+
roleGroups:
301+
default:
302+
replicas: 1
303+
"#;
304+
305+
fn cluster_info() -> stackable_operator::utils::cluster_info::KubernetesClusterInfo {
306+
stackable_operator::utils::cluster_info::KubernetesClusterInfo {
307+
cluster_domain: stackable_operator::commons::networking::DomainName::try_from(
308+
"cluster.local",
309+
)
310+
.unwrap(),
311+
}
312+
}
313+
314+
fn rg(cluster: &ValidatedCluster, role: &TrinoRole) -> TrinoRoleGroupConfig {
315+
cluster.role_group_configs[role]
316+
.values()
317+
.next()
318+
.expect("the fixture defines a role group")
319+
.clone()
320+
}
321+
256322
#[test]
257323
fn default_renders_includes_coordinator_default_and_query_max_memory_default() {
258324
let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML);
@@ -280,4 +346,125 @@ mod tests {
280346
Some("50GB")
281347
);
282348
}
349+
350+
#[test]
351+
fn server_tls_only_uses_server_keystore_dir_and_http_discovery() {
352+
let cluster = validated_cluster_from_yaml(SERVER_TLS_ONLY_YAML);
353+
let props = build(
354+
&cluster,
355+
TrinoRole::Coordinator,
356+
&rg(&cluster, &TrinoRole::Coordinator),
357+
&cluster_info(),
358+
)
359+
.unwrap();
360+
361+
assert_eq!(
362+
props.get("http-server.https.enabled").map(String::as_str),
363+
Some("true")
364+
);
365+
assert_eq!(
366+
props.get("http-server.https.port").map(String::as_str),
367+
Some("8443")
368+
);
369+
assert_eq!(
370+
props
371+
.get("http-server.https.keystore.path")
372+
.map(String::as_str),
373+
Some("/stackable/server_tls/keystore.p12"),
374+
);
375+
// Server TLS is on, so insecure HTTP access must not be allowed.
376+
assert_eq!(
377+
props.get("http-server.authentication.allow-insecure-over-http"),
378+
None
379+
);
380+
// Internal TLS is off: no internal-communication keystore or FQDN address source.
381+
assert_eq!(
382+
props.get("internal-communication.https.keystore.path"),
383+
None
384+
);
385+
assert_eq!(props.get("node.internal-address-source"), None);
386+
// Discovery uses http when internal TLS is disabled.
387+
assert!(props.get("discovery.uri").unwrap().starts_with("http://"));
388+
}
389+
390+
#[test]
391+
fn internal_tls_only_allows_insecure_http_and_uses_internal_keystore_dir() {
392+
let cluster = validated_cluster_from_yaml(INTERNAL_TLS_ONLY_YAML);
393+
let props = build(
394+
&cluster,
395+
TrinoRole::Coordinator,
396+
&rg(&cluster, &TrinoRole::Coordinator),
397+
&cluster_info(),
398+
)
399+
.unwrap();
400+
401+
assert_eq!(
402+
props.get("http-server.https.enabled").map(String::as_str),
403+
Some("true")
404+
);
405+
assert_eq!(
406+
props
407+
.get("http-server.authentication.allow-insecure-over-http")
408+
.map(String::as_str),
409+
Some("true"),
410+
);
411+
assert_eq!(
412+
props.get("http-server.http.port").map(String::as_str),
413+
Some("8080")
414+
);
415+
assert_eq!(
416+
props
417+
.get("http-server.https.keystore.path")
418+
.map(String::as_str),
419+
Some("/stackable/internal_tls/keystore.p12"),
420+
);
421+
// Internal TLS block is present.
422+
assert_eq!(
423+
props
424+
.get("internal-communication.https.keystore.path")
425+
.map(String::as_str),
426+
Some("/stackable/internal_tls/keystore.p12"),
427+
);
428+
assert_eq!(
429+
props
430+
.get("node.internal-address-source")
431+
.map(String::as_str),
432+
Some("FQDN")
433+
);
434+
// Discovery uses https when internal TLS is enabled.
435+
assert!(props.get("discovery.uri").unwrap().starts_with("https://"));
436+
}
437+
438+
#[test]
439+
fn worker_omits_include_coordinator() {
440+
let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML);
441+
let props = build(
442+
&cluster,
443+
TrinoRole::Worker,
444+
&rg(&cluster, &TrinoRole::Worker),
445+
&cluster_info(),
446+
)
447+
.unwrap();
448+
449+
assert_eq!(props.get("coordinator").map(String::as_str), Some("false"));
450+
assert_eq!(props.get("node-scheduler.include-coordinator"), None);
451+
}
452+
453+
#[test]
454+
fn authentication_without_server_tls_errors() {
455+
// Server TLS off (only internal) plus an enabled authenticator must be rejected.
456+
let cluster = validated_cluster_from_yaml_with_auth(
457+
INTERNAL_TLS_ONLY_YAML,
458+
vec![file_auth_class("file-auth")],
459+
);
460+
let err = build(
461+
&cluster,
462+
TrinoRole::Coordinator,
463+
&rg(&cluster, &TrinoRole::Coordinator),
464+
&cluster_info(),
465+
)
466+
.unwrap_err();
467+
468+
assert!(matches!(err, Error::AuthenticationRequiresTls));
469+
}
283470
}

rust/operator-binary/src/controller/build/properties/mod.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,22 @@ pub(crate) mod test_support {
3939

4040
use crate::{
4141
controller::{ValidatedCluster, dereference::DereferencedObjects},
42-
crd::v1alpha1,
42+
crd::{authentication::ResolvedAuthenticationClassRef, v1alpha1},
4343
};
4444

4545
pub fn validated_cluster_from_yaml(yaml: &str) -> ValidatedCluster {
46+
validated_cluster_from_yaml_with_auth(yaml, Vec::new())
47+
}
48+
49+
/// Like [`validated_cluster_from_yaml`], but injects already-resolved AuthenticationClasses so
50+
/// tests can exercise authentication-dependent branches.
51+
pub fn validated_cluster_from_yaml_with_auth(
52+
yaml: &str,
53+
resolved_authentication_classes: Vec<ResolvedAuthenticationClassRef>,
54+
) -> ValidatedCluster {
4655
let trino: v1alpha1::TrinoCluster = serde_yaml::from_str(yaml).expect("invalid test YAML");
4756
let derefs = DereferencedObjects {
48-
resolved_authentication_classes: Vec::new(),
57+
resolved_authentication_classes,
4958
catalog_definitions: Vec::new(),
5059
catalogs: Vec::new(),
5160
trino_opa_config: None,
@@ -58,7 +67,32 @@ pub(crate) mod test_support {
5867
image_repository: "oci.example.org".to_string(),
5968
};
6069
crate::controller::validate::validate(&trino, &derefs, &operator_env)
61-
.expect("validate should succeed for the minimal fixture")
70+
.expect("validate should succeed for the test fixture")
71+
}
72+
73+
/// A resolved `static` (file) AuthenticationClass, enough to make
74+
/// [`ValidatedClusterConfig::authentication_enabled`](crate::controller::ValidatedClusterConfig)
75+
/// return `true`.
76+
pub fn file_auth_class(name: &str) -> ResolvedAuthenticationClassRef {
77+
let yaml = format!(
78+
r#"
79+
metadata:
80+
name: {name}
81+
spec:
82+
provider:
83+
static:
84+
userCredentialsSecret:
85+
name: {name}
86+
"#
87+
);
88+
let deserializer = serde_yaml::Deserializer::from_str(&yaml);
89+
let authentication_class =
90+
serde_yaml::with::singleton_map_recursive::deserialize(deserializer)
91+
.expect("invalid test AuthenticationClass");
92+
ResolvedAuthenticationClassRef {
93+
authentication_class,
94+
client_auth_options: None,
95+
}
6296
}
6397

6498
pub const MINIMAL_TRINO_YAML: &str = r#"

0 commit comments

Comments
 (0)