greentic-setup 0.4.21

End-to-end bundle setup engine for the Greentic platform — pack discovery, QA-driven configuration, secrets persistence, and bundle lifecycle management
Documentation
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use greentic_setup::qa::shared_questions::merge_shared_with_provider_answers;
use greentic_setup::{ProviderFormSpec, collect_shared_questions};
use qa_spec::{FormSpec, QuestionSpec, QuestionType};
use serde_json::{Map as JsonMap, Value, json};

fn make_question(id: &str, required: bool, secret: bool) -> QuestionSpec {
    QuestionSpec {
        id: id.to_string(),
        kind: QuestionType::String,
        title: id.to_string(),
        title_i18n: None,
        description: None,
        description_i18n: None,
        required,
        choices: None,
        default_value: None,
        secret,
        visible_if: None,
        constraint: None,
        list: None,
        computed: None,
        policy: Default::default(),
        computed_overridable: false,
    }
}

fn make_provider_form_spec(provider_id: &str, question_ids: &[String]) -> ProviderFormSpec {
    let questions = question_ids
        .iter()
        .map(|id| make_question(id, true, id.contains("token") || id.contains("secret")))
        .collect();
    ProviderFormSpec {
        provider_id: provider_id.to_string(),
        form_spec: FormSpec {
            id: format!("{provider_id}-setup"),
            title: format!("{provider_id} Setup"),
            version: "1.0.0".to_string(),
            description: None,
            presentation: None,
            progress_policy: None,
            secrets_policy: None,
            store: vec![],
            validations: vec![],
            includes: vec![],
            questions,
        },
    }
}

fn synth_provider_specs(provider_count: usize, unique_questions: usize) -> Vec<ProviderFormSpec> {
    let mut providers = Vec::with_capacity(provider_count);
    let mut ids: Vec<String> = vec!["public_base_url".to_string()];
    for i in 0..unique_questions {
        ids.push(format!("q_{i}"));
    }
    ids.push("bot_token".to_string());

    for p in 0..provider_count {
        let mut provider_qs = ids.clone();
        provider_qs.push(format!("provider_{p}_only"));
        providers.push(make_provider_form_spec(
            &format!("messaging-provider-{p}"),
            &provider_qs,
        ));
    }
    providers
}

fn synth_answers(shared_keys: usize, provider_keys: usize) -> (Value, Value) {
    let mut shared = JsonMap::new();
    let mut provider = JsonMap::new();

    for i in 0..shared_keys {
        shared.insert(format!("shared_{i}"), json!(format!("value_{i}")));
    }
    shared.insert("public_base_url".into(), json!("https://example.com"));

    for i in 0..provider_keys {
        provider.insert(format!("provider_{i}"), json!(i));
    }
    provider.insert("shared_1".into(), json!("override-should-not-win"));

    (Value::Object(shared), Value::Object(provider))
}

fn bench_collect_shared_questions(c: &mut Criterion) {
    let mut group = c.benchmark_group("shared_questions");
    for (providers, questions) in [(25usize, 40usize), (100usize, 80usize)] {
        let dataset = synth_provider_specs(providers, questions);
        group.throughput(Throughput::Elements(providers as u64));
        group.bench_with_input(
            BenchmarkId::new(
                "collect_shared_questions",
                format!("p{providers}_q{questions}"),
            ),
            &dataset,
            |b, data| b.iter(|| collect_shared_questions(data)),
        );
    }
    group.finish();
}

fn bench_merge_shared_with_provider_answers(c: &mut Criterion) {
    let mut group = c.benchmark_group("answers_merge");
    for (shared_keys, provider_keys) in [(250usize, 250usize), (1000usize, 1000usize)] {
        let (shared, provider) = synth_answers(shared_keys, provider_keys);
        group.throughput(Throughput::Elements((shared_keys + provider_keys) as u64));
        group.bench_with_input(
            BenchmarkId::new(
                "merge_shared_with_provider_answers",
                format!("s{shared_keys}_p{provider_keys}"),
            ),
            &(shared, provider),
            |b, (shared, provider)| {
                b.iter(|| merge_shared_with_provider_answers(shared, Some(provider)))
            },
        );
    }
    group.finish();
}

criterion_group!(
    benches,
    bench_collect_shared_questions,
    bench_merge_shared_with_provider_answers
);
criterion_main!(benches);