use super::intent::VtaReply;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DiagCheck {
ResolveDid,
EnumerateServices,
AuthenticateTSP,
AuthenticateDIDComm,
AuthenticateREST,
VerifyAuthorization,
ListWebvhServers,
ProvisionIntegration,
}
impl DiagCheck {
pub fn label(&self) -> &'static str {
match self {
Self::ResolveDid => "Resolve VTA DID",
Self::EnumerateServices => "Enumerate service endpoints",
Self::AuthenticateTSP => "Open TSP session",
Self::AuthenticateDIDComm => "Open DIDComm session",
Self::AuthenticateREST => "Authenticate via REST",
Self::VerifyAuthorization => "Verify authorization with the VTA",
Self::ListWebvhServers => "List webvh hosting servers",
Self::ProvisionIntegration => "Provision integration DID + admin credential",
}
}
pub fn all() -> &'static [DiagCheck] {
&[
Self::ResolveDid,
Self::EnumerateServices,
Self::AuthenticateTSP,
Self::AuthenticateDIDComm,
Self::AuthenticateREST,
Self::VerifyAuthorization,
Self::ListWebvhServers,
Self::ProvisionIntegration,
]
}
}
#[derive(Clone, Debug)]
pub enum DiagStatus {
Pending,
Running,
Ok(String),
Skipped(String),
Failed(String),
}
#[derive(Clone, Debug)]
pub struct DiagEntry {
pub check: DiagCheck,
pub status: DiagStatus,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Protocol {
Tsp,
DidComm,
Rest,
}
impl Protocol {
pub fn label(&self) -> &'static str {
match self {
Self::Tsp => "TSP",
Self::DidComm => "DIDComm",
Self::Rest => "REST",
}
}
}
#[derive(Clone, Debug)]
pub struct ConnectedInfo {
pub protocol: Protocol,
pub rest_url: Option<String>,
pub mediator_did: Option<String>,
pub reply: VtaReply,
}
pub fn pending_list() -> Vec<DiagEntry> {
DiagCheck::all()
.iter()
.map(|c| DiagEntry {
check: *c,
status: DiagStatus::Pending,
})
.collect()
}
pub fn apply_update(list: &mut [DiagEntry], check: DiagCheck, status: DiagStatus) {
for entry in list.iter_mut() {
if entry.check == check {
entry.status = status;
return;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pending_list_has_all_checks() {
let list = pending_list();
assert_eq!(list.len(), DiagCheck::all().len());
assert!(list.iter().all(|e| matches!(e.status, DiagStatus::Pending)));
}
#[test]
fn apply_update_sets_status_on_matching_check() {
let mut list = pending_list();
apply_update(
&mut list,
DiagCheck::ResolveDid,
DiagStatus::Ok("did:webvh:...".into()),
);
let resolved = &list[0];
assert_eq!(resolved.check, DiagCheck::ResolveDid);
assert!(matches!(resolved.status, DiagStatus::Ok(_)));
}
#[test]
fn all_lists_split_authenticate_rows_in_order() {
let all = DiagCheck::all();
assert_eq!(
all,
&[
DiagCheck::ResolveDid,
DiagCheck::EnumerateServices,
DiagCheck::AuthenticateTSP,
DiagCheck::AuthenticateDIDComm,
DiagCheck::AuthenticateREST,
DiagCheck::VerifyAuthorization,
DiagCheck::ListWebvhServers,
DiagCheck::ProvisionIntegration,
]
);
}
#[test]
fn authenticate_rows_have_distinct_labels() {
assert_eq!(DiagCheck::AuthenticateTSP.label(), "Open TSP session");
assert_eq!(
DiagCheck::AuthenticateDIDComm.label(),
"Open DIDComm session"
);
assert_eq!(DiagCheck::AuthenticateREST.label(), "Authenticate via REST");
}
#[test]
fn only_the_rest_leg_claims_to_authenticate() {
for check in DiagCheck::all() {
if matches!(
check,
DiagCheck::AuthenticateTSP | DiagCheck::AuthenticateDIDComm
) {
assert!(
!check.label().to_lowercase().contains("authenticate"),
"{} opens a transport; it does not authenticate against the VTA",
check.label()
);
}
}
assert!(
DiagCheck::AuthenticateREST
.label()
.to_lowercase()
.contains("authenticate")
);
}
#[test]
fn authorization_is_verified_before_anything_is_minted() {
let all = DiagCheck::all();
let pos = |c: DiagCheck| all.iter().position(|x| *x == c).expect("row present");
assert!(pos(DiagCheck::VerifyAuthorization) > pos(DiagCheck::AuthenticateREST));
assert!(pos(DiagCheck::VerifyAuthorization) < pos(DiagCheck::ListWebvhServers));
assert!(pos(DiagCheck::VerifyAuthorization) < pos(DiagCheck::ProvisionIntegration));
}
#[test]
fn protocol_labels_are_distinct() {
assert_eq!(Protocol::Tsp.label(), "TSP");
assert_eq!(Protocol::DidComm.label(), "DIDComm");
assert_eq!(Protocol::Rest.label(), "REST");
}
#[test]
fn provision_label_is_template_agnostic() {
let label = DiagCheck::ProvisionIntegration.label();
assert!(!label.to_lowercase().contains("mediator"));
assert!(!label.to_lowercase().contains("webvh"));
assert!(label.contains("integration"));
}
}