107 lines
3.1 KiB
Rust
107 lines
3.1 KiB
Rust
|
|
use vapora_channels::ChannelRegistry;
|
||
|
|
use vapora_workflow_engine::config::WorkflowsConfig;
|
||
|
|
|
||
|
|
/// Full TOML round-trip: channels section + per-workflow notification targets.
|
||
|
|
const TOML_WITH_CHANNELS: &str = r#"
|
||
|
|
[engine]
|
||
|
|
max_parallel_tasks = 4
|
||
|
|
workflow_timeout = 3600
|
||
|
|
approval_gates_enabled = false
|
||
|
|
|
||
|
|
[channels.team-slack]
|
||
|
|
type = "slack"
|
||
|
|
webhook_url = "https://hooks.slack.com/services/TEST/TEST/TEST"
|
||
|
|
|
||
|
|
[channels.ops-telegram]
|
||
|
|
type = "telegram"
|
||
|
|
bot_token = "123:TEST"
|
||
|
|
chat_id = "-100999"
|
||
|
|
|
||
|
|
[[workflows]]
|
||
|
|
name = "deploy-prod"
|
||
|
|
trigger = "manual"
|
||
|
|
|
||
|
|
[workflows.notifications]
|
||
|
|
on_completed = ["team-slack"]
|
||
|
|
on_failed = ["team-slack", "ops-telegram"]
|
||
|
|
on_approval_required = ["team-slack"]
|
||
|
|
|
||
|
|
[[workflows.stages]]
|
||
|
|
name = "build"
|
||
|
|
agents = ["developer"]
|
||
|
|
|
||
|
|
[[workflows.stages]]
|
||
|
|
name = "deploy"
|
||
|
|
agents = ["deployer"]
|
||
|
|
approval_required = true
|
||
|
|
"#;
|
||
|
|
|
||
|
|
/// Workflow with no [channels] section — should parse without error and leave
|
||
|
|
/// the channel map empty (registry skipped by orchestrator).
|
||
|
|
const TOML_WITHOUT_CHANNELS: &str = r#"
|
||
|
|
[engine]
|
||
|
|
max_parallel_tasks = 4
|
||
|
|
workflow_timeout = 3600
|
||
|
|
approval_gates_enabled = false
|
||
|
|
|
||
|
|
[[workflows]]
|
||
|
|
name = "ci-pipeline"
|
||
|
|
trigger = "manual"
|
||
|
|
|
||
|
|
[[workflows.stages]]
|
||
|
|
name = "test"
|
||
|
|
agents = ["developer"]
|
||
|
|
"#;
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn channels_section_parses_into_config() {
|
||
|
|
let config: WorkflowsConfig = toml::from_str(TOML_WITH_CHANNELS).expect("must parse");
|
||
|
|
|
||
|
|
assert_eq!(config.channels.len(), 2);
|
||
|
|
assert!(config.channels.contains_key("team-slack"));
|
||
|
|
assert!(config.channels.contains_key("ops-telegram"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn notification_targets_parse_per_workflow() {
|
||
|
|
let config: WorkflowsConfig = toml::from_str(TOML_WITH_CHANNELS).expect("must parse");
|
||
|
|
|
||
|
|
let wf = config.get_workflow("deploy-prod").expect("workflow exists");
|
||
|
|
assert_eq!(wf.notifications.on_completed, ["team-slack"]);
|
||
|
|
assert_eq!(wf.notifications.on_failed, ["team-slack", "ops-telegram"]);
|
||
|
|
assert_eq!(wf.notifications.on_approval_required, ["team-slack"]);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn missing_channels_section_defaults_to_empty() {
|
||
|
|
let config: WorkflowsConfig = toml::from_str(TOML_WITHOUT_CHANNELS).expect("must parse");
|
||
|
|
|
||
|
|
assert!(config.channels.is_empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn missing_notifications_block_defaults_to_empty_vecs() {
|
||
|
|
let config: WorkflowsConfig = toml::from_str(TOML_WITHOUT_CHANNELS).expect("must parse");
|
||
|
|
|
||
|
|
let wf = config.get_workflow("ci-pipeline").expect("workflow exists");
|
||
|
|
assert!(wf.notifications.on_completed.is_empty());
|
||
|
|
assert!(wf.notifications.on_failed.is_empty());
|
||
|
|
assert!(wf.notifications.on_approval_required.is_empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn channel_registry_builds_from_config() {
|
||
|
|
let config: WorkflowsConfig = toml::from_str(TOML_WITH_CHANNELS).expect("must parse");
|
||
|
|
let registry = ChannelRegistry::from_map(config.channels).expect("registry must build");
|
||
|
|
|
||
|
|
let mut names = registry.channel_names();
|
||
|
|
names.sort_unstable();
|
||
|
|
assert_eq!(names, ["ops-telegram", "team-slack"]);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn validation_passes_with_channels_and_notifications() {
|
||
|
|
let config: WorkflowsConfig = toml::from_str(TOML_WITH_CHANNELS).expect("must parse");
|
||
|
|
config.validate().expect("validation must pass");
|
||
|
|
}
|