engenho_diff/observe.rs
1//! The response half of the harness — a typed [`Observation`] captured
2//! from a [`DiffTarget`](crate::target::DiffTarget), plus the [`HttpMethod`]
3//! verb and the [`DiffError`] failure taxonomy.
4
5use serde_json::Value;
6use thiserror::Error;
7
8/// The HTTP verb of an [`Operation`](crate::op::Operation) — typed, so the
9/// harness never string-matches a method.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum HttpMethod {
12 Get,
13 Post,
14 Put,
15 Patch,
16 Delete,
17}
18
19impl HttpMethod {
20 /// The `reqwest::Method` this verb maps to.
21 #[must_use]
22 pub fn as_reqwest(self) -> reqwest::Method {
23 match self {
24 Self::Get => reqwest::Method::GET,
25 Self::Post => reqwest::Method::POST,
26 Self::Put => reqwest::Method::PUT,
27 Self::Patch => reqwest::Method::PATCH,
28 Self::Delete => reqwest::Method::DELETE,
29 }
30 }
31
32 /// A stable label for reports + signatures.
33 #[must_use]
34 pub fn label(self) -> &'static str {
35 match self {
36 Self::Get => "GET",
37 Self::Post => "POST",
38 Self::Put => "PUT",
39 Self::Patch => "PATCH",
40 Self::Delete => "DELETE",
41 }
42 }
43}
44
45/// One observed response from a target: the wire status, the content-type,
46/// and the parsed body.
47#[derive(Clone, Debug)]
48pub struct Observation {
49 /// HTTP status code.
50 pub status: u16,
51 /// `Content-Type` header, if present.
52 pub content_type: Option<String>,
53 /// The parsed response body. `Value::Null` when the body was empty;
54 /// a non-JSON body is wrapped as `Value::String` (never silently
55 /// dropped).
56 pub json: Value,
57}
58
59impl Observation {
60 /// `true` iff the status is in the 2xx range.
61 #[must_use]
62 pub fn is_success(&self) -> bool {
63 (200..300).contains(&self.status)
64 }
65}
66
67/// Failure taxonomy for target execution. A transport failure against the
68/// k3s reference is what the runner turns into
69/// [`Verdict::ReferenceUnreachable`](crate::verdict::Verdict::ReferenceUnreachable)
70/// — a fail-loud signal, never a silent skip.
71#[derive(Debug, Error)]
72pub enum DiffError {
73 /// The HTTP request itself failed (connection refused, TLS, DNS).
74 #[error("transport error against {side}: {source}")]
75 Transport {
76 side: &'static str,
77 #[source]
78 source: reqwest::Error,
79 },
80 /// A kube-client / kubeconfig error (auth, parse).
81 #[error("kube error: {0}")]
82 Kube(String),
83 /// Booting the in-process engenho failed.
84 #[error("engenho boot error: {0}")]
85 Boot(String),
86}