summaryrefslogtreecommitdiffstats
path: root/mqtt-tester/src/main.rs
blob: 9a68848ed066b7bcc6f491245990ca01bc3afa19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//
//   This Source Code Form is subject to the terms of the Mozilla Public
//   License, v. 2.0. If a copy of the MPL was not distributed with this
//   file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

mod behaviour;
mod behaviour_test;
mod client_report;
mod command;
mod executable;
mod invariant;
mod packet_invariant;
mod report;

use std::{path::PathBuf, process::exit};

use clap::{Parser, Subcommand};
use client_report::create_client_report;
use miette::IntoDiagnostic;
use report::{print_report, ReportResult};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

#[derive(Parser, Debug)]
#[clap(author, version)]
struct Cli {
    #[clap(subcommand)]
    command: Commands,

    #[clap(long, default_value = "10")]
    parallelism: std::num::NonZeroUsize,
}

#[derive(Subcommand, Debug)]
enum Commands {
    TestClient {
        #[clap(value_parser)]
        executable: PathBuf,
    },
}

#[tokio::main]
async fn main() -> miette::Result<()> {
    let fmt_layer = tracing_subscriber::fmt::layer()
        .pretty()
        .with_timer(tracing_subscriber::fmt::time::uptime());

    let filter_layer = tracing_subscriber::EnvFilter::from_default_env();

    tracing_subscriber::registry()
        .with(fmt_layer)
        .with(filter_layer)
        .init();

    tracing::info!("Starting up");

    let args = Cli::parse();

    match args.command {
        Commands::TestClient { executable } => {
            let reports = create_client_report(executable, args.parallelism).await?;

            let mut stdout = std::io::stdout().lock();
            for report in &reports {
                print_report(report, &mut stdout).into_diagnostic()?;
            }

            if reports.iter().any(|r| r.result != ReportResult::Success) {
                struct ReportSummary {
                    successes: usize,
                    failures: usize,
                    inconclusive: usize,
                }

                let summary = reports.iter().fold(
                    ReportSummary {
                        successes: 0,
                        failures: 0,
                        inconclusive: 0,
                    },
                    |mut sum, rep| {
                        match rep.result {
                            ReportResult::Success => sum.successes += 1,
                            ReportResult::Failure => sum.failures += 1,
                            ReportResult::Inconclusive => sum.inconclusive += 1,
                        }

                        sum
                    },
                );

                println!();
                println!(
                    "{} tests total, {} success, {} failures, {} inconclusive",
                    reports.len(),
                    summary.successes,
                    summary.failures,
                    summary.inconclusive
                );
                exit(1);
            }
        }
    }

    Ok(())
}