mkv

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

integration.rs (6323B)


      1 use reqwest::StatusCode;
      2 use std::sync::atomic::{AtomicU32, Ordering};
      3 
      4 static TEST_COUNTER: AtomicU32 = AtomicU32::new(0);
      5 
      6 async fn start_server() -> String {
      7     let id = TEST_COUNTER.fetch_add(1, Ordering::Relaxed);
      8     let db_path = format!("/tmp/mkv-test/index-{id}.db");
      9 
     10     let _ = std::fs::remove_file(&db_path);
     11     let _ = std::fs::remove_file(format!("{db_path}-wal"));
     12     let _ = std::fs::remove_file(format!("{db_path}-shm"));
     13 
     14     let args = mkv::Args {
     15         db_path,
     16         volumes: vec![
     17             "http://localhost:3101".into(),
     18             "http://localhost:3102".into(),
     19             "http://localhost:3103".into(),
     20         ],
     21         replicas: 2,
     22         voltimeout: std::time::Duration::from_secs(1),
     23     };
     24 
     25     let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
     26     let port = listener.local_addr().unwrap().port();
     27     let app = mkv::build_app(&args);
     28 
     29     tokio::spawn(async move {
     30         axum::serve(listener, app).await.unwrap();
     31     });
     32 
     33     tokio::time::sleep(std::time::Duration::from_millis(50)).await;
     34     format!("http://127.0.0.1:{port}")
     35 }
     36 
     37 fn client() -> reqwest::Client {
     38     reqwest::Client::builder()
     39         .redirect(reqwest::redirect::Policy::none())
     40         .build()
     41         .unwrap()
     42 }
     43 
     44 #[tokio::test]
     45 async fn test_put_and_head() {
     46     let base = start_server().await;
     47     let c = client();
     48 
     49     let resp = c
     50         .put(format!("{base}/hello"))
     51         .body("world")
     52         .send()
     53         .await
     54         .unwrap();
     55     assert_eq!(resp.status(), StatusCode::CREATED);
     56 
     57     let resp = c.head(format!("{base}/hello")).send().await.unwrap();
     58     assert_eq!(resp.status(), StatusCode::OK);
     59     assert_eq!(
     60         resp.headers()
     61             .get("content-length")
     62             .unwrap()
     63             .to_str()
     64             .unwrap(),
     65         "5"
     66     );
     67 }
     68 
     69 #[tokio::test]
     70 async fn test_put_and_get_redirect() {
     71     let base = start_server().await;
     72     let c = client();
     73 
     74     let resp = c
     75         .put(format!("{base}/redirect-test"))
     76         .body("some data")
     77         .send()
     78         .await
     79         .unwrap();
     80     assert_eq!(resp.status(), StatusCode::CREATED);
     81 
     82     let resp = c.get(format!("{base}/redirect-test")).send().await.unwrap();
     83     assert_eq!(resp.status(), StatusCode::FOUND);
     84 
     85     let location = resp.headers().get("location").unwrap().to_str().unwrap();
     86     assert!(
     87         location.starts_with("http://localhost:310"),
     88         "got: {location}"
     89     );
     90 
     91     let blob_resp = reqwest::get(location).await.unwrap();
     92     assert_eq!(blob_resp.status(), StatusCode::OK);
     93     assert_eq!(blob_resp.text().await.unwrap(), "some data");
     94 }
     95 
     96 #[tokio::test]
     97 async fn test_get_nonexistent_returns_404() {
     98     let base = start_server().await;
     99     let c = client();
    100     let resp = c
    101         .get(format!("{base}/does-not-exist"))
    102         .send()
    103         .await
    104         .unwrap();
    105     assert_eq!(resp.status(), StatusCode::NOT_FOUND);
    106 }
    107 
    108 #[tokio::test]
    109 async fn test_put_get_delete_get() {
    110     let base = start_server().await;
    111     let c = client();
    112 
    113     let resp = c
    114         .put(format!("{base}/delete-me"))
    115         .body("temporary")
    116         .send()
    117         .await
    118         .unwrap();
    119     assert_eq!(resp.status(), StatusCode::CREATED);
    120 
    121     let resp = c.get(format!("{base}/delete-me")).send().await.unwrap();
    122     assert_eq!(resp.status(), StatusCode::FOUND);
    123 
    124     let resp = c.delete(format!("{base}/delete-me")).send().await.unwrap();
    125     assert_eq!(resp.status(), StatusCode::NO_CONTENT);
    126 
    127     let resp = c.get(format!("{base}/delete-me")).send().await.unwrap();
    128     assert_eq!(resp.status(), StatusCode::NOT_FOUND);
    129 }
    130 
    131 #[tokio::test]
    132 async fn test_delete_nonexistent_returns_404() {
    133     let base = start_server().await;
    134     let c = client();
    135     let resp = c
    136         .delete(format!("{base}/never-existed"))
    137         .send()
    138         .await
    139         .unwrap();
    140     assert_eq!(resp.status(), StatusCode::NOT_FOUND);
    141 }
    142 
    143 #[tokio::test]
    144 async fn test_list_keys() {
    145     let base = start_server().await;
    146     let c = client();
    147 
    148     for name in ["docs/a", "docs/b", "docs/c", "other/x"] {
    149         c.put(format!("{base}/{name}"))
    150             .body("data")
    151             .send()
    152             .await
    153             .unwrap();
    154     }
    155 
    156     let resp = c.get(format!("{base}/")).send().await.unwrap();
    157     assert_eq!(resp.status(), StatusCode::OK);
    158     let body = resp.text().await.unwrap();
    159     assert!(body.contains("docs/a"));
    160     assert!(body.contains("other/x"));
    161 
    162     let resp = c.get(format!("{base}/?prefix=docs/")).send().await.unwrap();
    163     assert_eq!(resp.status(), StatusCode::OK);
    164     let body = resp.text().await.unwrap();
    165     let lines: Vec<&str> = body.lines().collect();
    166     assert_eq!(lines.len(), 3);
    167     assert!(!body.contains("other/x"));
    168 }
    169 
    170 #[tokio::test]
    171 async fn test_put_overwrite() {
    172     let base = start_server().await;
    173     let c = client();
    174 
    175     c.put(format!("{base}/overwrite"))
    176         .body("version1")
    177         .send()
    178         .await
    179         .unwrap();
    180 
    181     let resp = c
    182         .put(format!("{base}/overwrite"))
    183         .body("version2")
    184         .send()
    185         .await
    186         .unwrap();
    187     assert_eq!(resp.status(), StatusCode::CREATED);
    188 
    189     let resp = c.head(format!("{base}/overwrite")).send().await.unwrap();
    190     assert_eq!(
    191         resp.headers()
    192             .get("content-length")
    193             .unwrap()
    194             .to_str()
    195             .unwrap(),
    196         "8"
    197     );
    198 
    199     let resp = c.get(format!("{base}/overwrite")).send().await.unwrap();
    200     let location = resp.headers().get("location").unwrap().to_str().unwrap();
    201     let body = reqwest::get(location).await.unwrap().text().await.unwrap();
    202     assert_eq!(body, "version2");
    203 }
    204 
    205 #[tokio::test]
    206 async fn test_replication_writes_to_multiple_volumes() {
    207     let base = start_server().await;
    208     let c = client();
    209 
    210     c.put(format!("{base}/replicated"))
    211         .body("replica-data")
    212         .send()
    213         .await
    214         .unwrap();
    215 
    216     let resp = c.head(format!("{base}/replicated")).send().await.unwrap();
    217     assert_eq!(resp.status(), StatusCode::OK);
    218 
    219     let resp = c.get(format!("{base}/replicated")).send().await.unwrap();
    220     assert_eq!(resp.status(), StatusCode::FOUND);
    221     let location = resp.headers().get("location").unwrap().to_str().unwrap();
    222     let body = reqwest::get(location).await.unwrap().text().await.unwrap();
    223     assert_eq!(body, "replica-data");
    224 }