OXYGENHUB
# a0a1601eb5a5 oxygenhub / crates / hub / tests / shutdown.rs
2.5 KiB · Rust · last changed Restarts drain: SIGTERM stops taking connections and lets requests finish 20 days ago source blame history raw
1
//! Stopping drains (oxygenhub#233): its own test binary, as stopping is
2
//! for the whole process.
3
4
use oxygenhub::config::Config;
5
use oxygenhub::db;
6
use tokio::io::{AsyncReadExt, AsyncWriteExt};
7
8
/// A live event stream ends when the hub begins stopping, so it cannot
9
/// hold the drain open, and `serve` returns well within the drain's bound.
10
#[tokio::test(flavor = "multi_thread")]
11
async fn stopping_ends_event_streams_and_serve_returns() {
12
    let home = tempfile::tempdir().unwrap();
13
    std::env::set_var("OXY_HOME", home.path());
14
    let dir = tempfile::tempdir().unwrap();
15
    let mut config = Config::load(dir.path()).unwrap();
16
    let port = std::net::TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap().port();
17
    config.server.bind = format!("127.0.0.1:{port}");
18
    config.server.base_url = format!("http://127.0.0.1:{port}");
19
    let app = oxygenhub::build(config).await.unwrap();
20
    let repo = db::repos::create(&app.db, "andy", "demo", "", hub_api::Visibility::Public).await.unwrap();
21
    let server = tokio::spawn(oxygenhub::serve(app.clone()));
22
23
    // An open event stream, as a browser on a live page holds.
24
    let mut stream = None;
25
    for _ in 0..50 {
26
        if let Ok(s) = tokio::net::TcpStream::connect(("127.0.0.1", port)).await {
27
            stream = Some(s);
28
            break;
29
        }
30
        tokio::time::sleep(std::time::Duration::from_millis(50)).await;
31
    }
32
    let mut stream = stream.expect("the hub listens");
33
    let request = format!("GET /live?topics=repo:{} HTTP/1.1\r\nHost: 127.0.0.1\r\nAccept: text/event-stream\r\n\r\n", repo.id);
34
    stream.write_all(request.as_bytes()).await.unwrap();
35
    let mut head = vec![0u8; 512];
36
    let n = stream.read(&mut head).await.unwrap();
37
    let head = String::from_utf8_lossy(&head[..n]).to_string();
38
    assert!(head.starts_with("HTTP/1.1 200") && head.contains("text/event-stream"), "{head}");
39
40
    let started = std::time::Instant::now();
41
    oxygenhub::shutdown::begin();
42
    // The stream ends (the server closes it) rather than staying open.
43
    let mut rest = Vec::new();
44
    tokio::time::timeout(std::time::Duration::from_secs(10), stream.read_to_end(&mut rest))
45
        .await
46
        .expect("the event stream ends when stopping begins")
47
        .unwrap();
48
    tokio::time::timeout(std::time::Duration::from_secs(10), server).await.expect("serve returns once drained").unwrap().unwrap();
49
    assert!(started.elapsed() < oxygenhub::shutdown::DRAIN, "drained in {:?}", started.elapsed());
50
    assert!(oxygenhub::shutdown::is_stopping());
51
}