tests/app_send_tests.rs 3.8 K raw
1
//! End-to-end: TUI action → async send task → response/token state update.
2
3
use std::path::PathBuf;
4
5
use cielago::app::App;
6
use cielago::model::{Collection, KeyValueRow, Method, OAuthConfig, SavedRequest};
7
use cielago::store::AppConfig;
8
use wiremock::matchers::{method, path};
9
use wiremock::{Mock, MockServer, ResponseTemplate};
10
11
fn app_with(base_url: String) -> App {
12
    let mut c = Collection::new("test");
13
    c.servers = vec![base_url];
14
    let mut req = SavedRequest::blank("get thing");
15
    req.method = Method::Get;
16
    req.path = "/things/1".into();
17
    req.headers
18
        .push(KeyValueRow::new("X-Request-Id", "{{uuid}}", true));
19
    c.requests = vec![req];
20
    App::new(
21
        c,
22
        PathBuf::from("/tmp/cielago-test.json"),
23
        AppConfig::default(),
24
    )
25
}
26
27
#[tokio::test]
28
async fn send_from_app_updates_response_pane() {
29
    let server = MockServer::start().await;
30
    Mock::given(method("GET"))
31
        .and(path("/things/1"))
32
        .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({"id": 1})))
33
        .mount(&server)
34
        .await;
35
36
    let mut app = app_with(server.uri());
37
    assert!(app.response.is_none());
38
39
    app.send_selected();
40
    assert!(app.sending);
41
42
    let outcome = app.rx.recv().await.expect("send outcome");
43
    app.handle_outcome(outcome);
44
45
    assert!(!app.sending);
46
    let resp = app.response.as_ref().expect("response recorded");
47
    assert_eq!(resp.status, 200);
48
    assert!(resp.body.contains("\"id\": 1"));
49
    assert!(app.status.contains("200"));
50
51
    // {{uuid}} was substituted in the outgoing header.
52
    let received = server.received_requests().await.unwrap();
53
    let id = received[0]
54
        .headers
55
        .get("x-request-id")
56
        .unwrap()
57
        .to_str()
58
        .unwrap();
59
    assert!(uuid::Uuid::parse_str(id).is_ok(), "got {id}");
60
}
61
62
#[tokio::test]
63
async fn send_with_oauth_fetches_and_caches_token() {
64
    let server = MockServer::start().await;
65
    Mock::given(method("POST"))
66
        .and(path("/token"))
67
        .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
68
            "access_token": "cached-tok",
69
            "expires_in": 3600
70
        })))
71
        .expect(1) // fetched once, then cached
72
        .mount(&server)
73
        .await;
74
    Mock::given(method("GET"))
75
        .and(path("/things/1"))
76
        .respond_with(ResponseTemplate::new(200))
77
        .expect(2)
78
        .mount(&server)
79
        .await;
80
81
    let mut app = app_with(server.uri());
82
    app.collection.auth = Some(OAuthConfig {
83
        token_url: format!("{}/token", server.uri()),
84
        client_id: "id".into(),
85
        client_secret: "secret".into(),
86
        scopes: vec![],
87
        auth_style: cielago::model::AuthStyle::Basic,
88
    });
89
90
    // First send: fetches a token.
91
    app.send_selected();
92
    let outcome = app.rx.recv().await.unwrap();
93
    app.handle_outcome(outcome);
94
    assert_eq!(app.response.as_ref().unwrap().status, 200);
95
    assert!(app.token.is_some());
96
97
    // Second send: reuses the cached token (token endpoint expect(1)).
98
    app.send_selected();
99
    let outcome = app.rx.recv().await.unwrap();
100
    app.handle_outcome(outcome);
101
    assert_eq!(app.response.as_ref().unwrap().status, 200);
102
103
    // Both API calls carried the bearer token.
104
    let received = server.received_requests().await.unwrap();
105
    let api_calls: Vec<_> = received
106
        .iter()
107
        .filter(|r| r.url.path() == "/things/1")
108
        .collect();
109
    assert_eq!(api_calls.len(), 2);
110
    for r in api_calls {
111
        assert_eq!(
112
            r.headers.get("authorization").unwrap().to_str().unwrap(),
113
            "Bearer cached-tok"
114
        );
115
    }
116
}
117
118
#[tokio::test]
119
async fn send_without_server_shows_status_error() {
120
    let mut app = app_with("".into());
121
    app.collection.servers.clear();
122
    app.send_selected();
123
    assert!(!app.sending);
124
    assert!(app.status.contains("No server configured"));
125
}