use sdk_storage::{StorageService, unix_to_system_time, create_app}; use tempfile::TempDir; use surf::Client; #[async_std::test] async fn store_and_retrieve_hex_in_tempdir() { let td = TempDir::new().unwrap(); let dir_path = td.path().to_string_lossy().to_string(); let svc = StorageService::new(dir_path); let key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let value = b"hello"; let expires = Some(unix_to_system_time(60 + sdk_storage::system_time_to_unix(std::time::SystemTime::now()))); svc.store_data(key, value, expires).await.unwrap(); let got = svc.retrieve_data(key).await.unwrap(); assert_eq!(got, value); } #[async_std::test] async fn conflict_on_duplicate_key() { let td = TempDir::new().unwrap(); let dir_path = td.path().to_string_lossy().to_string(); let svc = StorageService::new(dir_path); let key = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; let value = b"data"; svc.store_data(key, value, None).await.unwrap(); let err = svc.store_data(key, value, None).await.err().expect("should error"); assert_eq!(err.status(), tide::StatusCode::Conflict); } #[async_std::test] async fn cleanup_removes_expired() { let td = TempDir::new().unwrap(); let dir_path = td.path().to_string_lossy().to_string(); let svc = StorageService::new(dir_path.clone()); let key = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"; let value = b"x"; // expiration très proche: maintenant - 1s let past = sdk_storage::system_time_to_unix(std::time::SystemTime::now()).saturating_sub(1); let expires = Some(unix_to_system_time(past)); svc.store_data(key, value, expires).await.unwrap(); // cleanup one-shot svc.cleanup_expired_files_once().await.unwrap(); let res = svc.retrieve_data(key).await; assert!(res.is_err(), "expired key should be removed"); } #[async_std::test] async fn http_store_success_and_conflicts_and_invalids() { // app with permanent=false so default TTL applies when missing let td = TempDir::new().unwrap(); let storage = td.path().to_string_lossy().to_string(); let mut app = create_app(false, storage); let listener = async_std::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); async_std::task::spawn(async move { app.listen(listener).await.unwrap() }); let client = Client::new(); let base = format!("http://{}", addr); // success let key = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; let body = serde_json::json!({"key": key, "value": "01aa", "ttl": 120}); let res = client.post(format!("{}/store", base)).body_json(&body).unwrap().await.unwrap(); assert!(res.status().is_success()); // conflict let res2 = client.post(format!("{}/store", base)).body_json(&body).unwrap().await.unwrap(); assert_eq!(res2.status(), 409); // invalid key let bad = serde_json::json!({"key": "xyz", "value": "01"}); let res3 = client.post(format!("{}/store", base)).body_json(&bad).unwrap().await.unwrap(); assert_eq!(res3.status(), 400); // invalid value let badv = serde_json::json!({"key": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "value": "zz"}); let res4 = client.post(format!("{}/store", base)).body_json(&badv).unwrap().await.unwrap(); assert_eq!(res4.status(), 400); } #[async_std::test] async fn http_retrieve_success_and_invalid_and_notfound() { let td = TempDir::new().unwrap(); let storage = td.path().to_string_lossy().to_string(); let mut app = create_app(true, storage.clone()); let listener = async_std::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); async_std::task::spawn(async move { app.listen(listener).await.unwrap() }); let client = Client::new(); let base = format!("http://{}", addr); // prepare stored value (permanent mode) let svc = StorageService::new(storage); let key = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; svc.store_data(key, b"hi", None).await.unwrap(); // success let mut res = client.get(format!("{}/retrieve/{}", base, key)).await.unwrap(); assert!(res.status().is_success()); let v: serde_json::Value = res.body_json().await.unwrap(); assert_eq!(v["value"].as_str().unwrap(), hex::encode("hi")); // invalid key let res2 = client.get(format!("{}/retrieve/{}", base, "bad")).await.unwrap(); assert_eq!(res2.status(), 400); // not found let k2 = "1111111111111111111111111111111111111111111111111111111111111111"; let res3 = client.get(format!("{}/retrieve/{}", base, k2)).await.unwrap(); assert_eq!(res3.status(), 404); } #[async_std::test] async fn http_health_ok() { let td = TempDir::new().unwrap(); let storage = td.path().to_string_lossy().to_string(); let mut app = create_app(true, storage); let listener = async_std::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); async_std::task::spawn(async move { app.listen(listener).await.unwrap() }); let client = Client::new(); let base = format!("http://{}", addr); let mut res = client.get(format!("{}/health", base)).await.unwrap(); assert!(res.status().is_success()); let v: serde_json::Value = res.body_json().await.unwrap(); assert_eq!(v["message"].as_str().unwrap(), "ok"); }