summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud.bailly@iohk.io>2024-10-04 17:17:10 +0200
committerArnaud Bailly <arnaud.bailly@iohk.io>2024-10-04 17:17:10 +0200
commitc7ecec3f7e64bfbc8dc0231d538599716e1ccf88 (patch)
treeb1c9ba512bb5d6df532417bafa66b824f5248773
parent47533afd36990b486f1a5d66851f886510c04c20 (diff)
downloadlambda-nantes-c7ecec3f7e64bfbc8dc0231d538599716e1ccf88.tar.gz
Spawn thread to start sending requests to clients
-rw-r--r--rust/Cargo.lock362
-rw-r--r--rust/Cargo.toml13
-rw-r--r--rust/src/web.rs167
3 files changed, 480 insertions, 62 deletions
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index cd32246..90dc032 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -253,6 +253,125 @@ dependencies = [
]
[[package]]
+name = "async-channel"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
+dependencies = [
+ "concurrent-queue",
+ "event-listener 2.5.3",
+ "futures-core",
+]
+
+[[package]]
+name = "async-channel"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
+dependencies = [
+ "concurrent-queue",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
+dependencies = [
+ "async-task",
+ "concurrent-queue",
+ "fastrand",
+ "futures-lite",
+ "slab",
+]
+
+[[package]]
+name = "async-global-executor"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
+dependencies = [
+ "async-channel 2.3.1",
+ "async-executor",
+ "async-io",
+ "async-lock",
+ "blocking",
+ "futures-lite",
+ "once_cell",
+]
+
+[[package]]
+name = "async-io"
+version = "2.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
+dependencies = [
+ "async-lock",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-io",
+ "futures-lite",
+ "parking",
+ "polling",
+ "rustix",
+ "slab",
+ "tracing",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "async-lock"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
+dependencies = [
+ "event-listener 5.3.1",
+ "event-listener-strategy",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-std"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615"
+dependencies = [
+ "async-channel 1.9.0",
+ "async-global-executor",
+ "async-io",
+ "async-lock",
+ "crossbeam-utils",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-lite",
+ "gloo-timers",
+ "kv-log-macro",
+ "log",
+ "memchr",
+ "once_cell",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "async-task"
+version = "4.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -321,6 +440,19 @@ dependencies = [
]
[[package]]
+name = "blocking"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
+dependencies = [
+ "async-channel 2.3.1",
+ "async-task",
+ "futures-io",
+ "futures-lite",
+ "piper",
+]
+
+[[package]]
name = "brotli"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -401,6 +533,15 @@ dependencies = [
]
[[package]]
+name = "concurrent-queue"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
name = "convert_case"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -442,6 +583,12 @@ dependencies = [
]
[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -522,6 +669,33 @@ dependencies = [
]
[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
+[[package]]
+name = "event-listener"
+version = "5.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+dependencies = [
+ "event-listener 5.3.1",
+ "pin-project-lite",
+]
+
+[[package]]
name = "fastrand"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -553,12 +727,78 @@ dependencies = [
]
[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
+name = "futures-executor"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-lite"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
+dependencies = [
+ "fastrand",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -576,10 +816,16 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
+ "futures-channel",
"futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
"futures-task",
+ "memchr",
"pin-project-lite",
"pin-utils",
+ "slab",
]
[[package]]
@@ -610,6 +856,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
[[package]]
+name = "gloo-timers"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
name = "h2"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -650,6 +908,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
+name = "hermit-abi"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
+
+[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -752,6 +1016,15 @@ dependencies = [
]
[[package]]
+name = "kv-log-macro"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
+dependencies = [
+ "log",
+]
+
+[[package]]
name = "language-tags"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -813,6 +1086,9 @@ name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+dependencies = [
+ "value-bag",
+]
[[package]]
name = "memchr"
@@ -880,6 +1156,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
+name = "parking"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+
+[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -927,12 +1209,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
+name = "piper"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
+dependencies = [
+ "atomic-waker",
+ "fastrand",
+ "futures-io",
+]
+
+[[package]]
name = "pkg-config"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
+name = "polling"
+version = "3.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
+dependencies = [
+ "cfg-if",
+ "concurrent-queue",
+ "hermit-abi 0.4.0",
+ "pin-project-lite",
+ "rustix",
+ "tracing",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1079,13 +1387,16 @@ name = "rust"
version = "0.1.0"
dependencies = [
"actix-web",
+ "async-std",
"chrono",
"env_logger",
+ "futures",
"log",
"proptest",
"rand",
"serde",
"serde_json",
+ "uuid",
]
[[package]]
@@ -1415,6 +1726,35 @@ dependencies = [
]
[[package]]
+name = "uuid"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
+dependencies = [
+ "getrandom",
+ "rand",
+ "serde",
+ "uuid-macro-internal",
+]
+
+[[package]]
+name = "uuid-macro-internal"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee1cd046f83ea2c4e920d6ee9f7c3537ef928d75dce5d84a87c2c5d6b3999a3a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "value-bag"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
+
+[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1462,6 +1802,18 @@ dependencies = [
]
[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1491,6 +1843,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 4deb7ec..8e75422 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -8,9 +8,20 @@ rand = "0.8.5"
serde = { version = "1.0", features = ["derive"] }
chrono = { version= "0.4.38", features = ["serde"]}
serde_json = "1.0.128"
-actix-web = "4"
+actix-web = "4.9.0"
env_logger = "0.8"
log = "0.4"
+futures = "0.3.30"
+async-std = "1.13.0"
+
+[dependencies.uuid]
+version = "1.10.0"
+features = [
+ "v4", # Lets you generate random UUIDs
+ "fast-rng", # Use a faster (but still sufficiently random) RNG
+ "macro-diagnostics", # Enable better diagnostics for compile-time UUIDs
+ "serde"
+]
[dev-dependencies]
proptest = "1.0.0"
diff --git a/rust/src/web.rs b/rust/src/web.rs
index 257817d..45540e4 100644
--- a/rust/src/web.rs
+++ b/rust/src/web.rs
@@ -1,20 +1,25 @@
+use actix_web::{
+ get, http::header::ContentType, middleware::Logger, post, web, App, HttpResponse, HttpServer,
+ Responder,
+};
+use async_std::task;
+use futures::future::join_all;
+use futures::try_join;
+use serde::{Deserialize, Serialize};
use std::{
+ collections::HashMap,
env::args,
io::{stdin, stdout, IsTerminal},
- sync::Mutex,
+ sync::{Arc, Mutex},
};
-
-use actix_web::{
- get, http::header::ContentType, post, web, App, HttpResponse, HttpServer, Responder,
-};
-use serde::{Deserialize, Serialize};
+use uuid::Uuid;
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
struct Registration {
url: String,
}
-trait AppState {
+trait AppState: Send + Sync {
fn register(&mut self, registration: &Registration) -> RegistrationResult;
}
@@ -29,9 +34,51 @@ enum RegistrationFailure {
UrlAlreadyRegistered { url: String },
}
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+struct Client {
+ id: Uuid,
+ url: String,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+struct State {
+ clients: HashMap<String, Client>,
+}
+
+impl State {
+ fn new() -> Self {
+ Self {
+ clients: HashMap::new(),
+ }
+ }
+}
+
+impl AppState for State {
+ fn register(&mut self, registration: &Registration) -> RegistrationResult {
+ if self.clients.contains_key(&registration.url) {
+ RegistrationResult::UrlAlreadyRegistered {
+ url: registration.url.clone(),
+ }
+ } else {
+ let id = Uuid::new_v4();
+ self.clients.insert(
+ registration.url.clone(),
+ Client {
+ id,
+ url: registration.url.clone(),
+ },
+ );
+ RegistrationResult::RegistrationSuccess {
+ id: id.to_string(),
+ url: registration.url.clone(),
+ }
+ }
+ }
+}
+
#[post("/register")]
async fn register(
- app_state: web::Data<Mutex<dyn AppState>>,
+ app_state: web::Data<Arc<Mutex<dyn AppState>>>,
registration: web::Json<Registration>,
) -> impl Responder {
let result = app_state.lock().unwrap().register(&registration);
@@ -43,16 +90,43 @@ async fn register(
#[actix_web::main]
async fn main() -> std::io::Result<()> {
- HttpServer::new(|| App::new().service(register))
- .bind(("127.0.0.1", 8080))?
- .run()
- .await
+ let app_state = Arc::new(Mutex::new(State::new()));
+ let send_state: Arc<Mutex<State>> = app_state.clone();
+ let http_state: Arc<Mutex<dyn AppState>> = app_state.clone();
+ env_logger::init();
+ // let it run in the background
+ task::spawn(async move { send_tests(send_state).await });
+ HttpServer::new(move || {
+ App::new()
+ .wrap(Logger::default())
+ .app_data(web::Data::new(http_state.clone()))
+ .service(register)
+ })
+ .bind(("127.0.0.1", 8080))?
+ .run()
+ .await
+}
+
+async fn send_tests(clients: Arc<Mutex<State>>) -> ! {
+ loop {
+ task::sleep(std::time::Duration::from_secs(1)).await;
+ let clients = clients.lock().unwrap();
+ for client in clients.clients.values() {
+ send_test(client);
+ }
+ }
+}
+
+fn send_test(client: &Client) -> Result<(), String> {
+ println!("Sending test to {}", client.url);
+ Ok(())
}
#[cfg(test)]
mod app_tests {
use std::sync::Arc;
+ use actix_web::http::header::TryIntoHeaderValue;
use actix_web::{body, http::header::ContentType, middleware::Logger, test, App};
use super::*;
@@ -70,9 +144,9 @@ mod app_tests {
impl AppState for DummyAppState {
fn register(&mut self, registration: &Registration) -> RegistrationResult {
if self.id == "" {
- return RegistrationResult::UrlAlreadyRegistered {
+ RegistrationResult::UrlAlreadyRegistered {
url: registration.url.clone(),
- };
+ }
} else {
RegistrationResult::RegistrationSuccess {
id: self.id.clone(),
@@ -88,12 +162,12 @@ mod app_tests {
let dummy_state: Arc<Mutex<dyn AppState>> =
Arc::new(Mutex::new(DummyAppState::new(id.clone())));
// FIXME should only be called once, move to setup
- // env_logger::init();
+ env_logger::init();
let app = test::init_service(
App::new()
.wrap(Logger::default())
- .app_data(web::Data::from(dummy_state))
+ .app_data(web::Data::new(dummy_state))
.service(register),
)
.await;
@@ -117,25 +191,19 @@ mod app_tests {
}
#[actix_web::test]
- async fn post_registration_fails_given_url_is_already_registered() {
+ async fn post_registration_returns_400_when_register_fails() {
let dummy_state: Arc<Mutex<dyn AppState>> =
Arc::new(Mutex::new(DummyAppState::new("".to_string())));
let app = test::init_service(
App::new()
.wrap(Logger::default())
- .app_data(web::Data::from(dummy_state))
+ .app_data(web::Data::new(dummy_state))
.service(register),
)
.await;
let url = "http://192.168.1.1".to_string();
- let _ = test::TestRequest::post()
- .uri("/register")
- .set_json(Registration { url: url.clone() })
- .insert_header(ContentType::json())
- .to_request();
- // second request with the same URL
let req = test::TestRequest::post()
.uri("/register")
.set_json(Registration { url: url.clone() })
@@ -145,50 +213,27 @@ mod app_tests {
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_client_error());
-
- let body = resp.into_body();
- let bytes = body::to_bytes(body).await;
assert_eq!(
- RegistrationResult::UrlAlreadyRegistered { url },
- serde_json::from_slice(&bytes.unwrap()).unwrap()
+ ContentType::json().try_into_value().unwrap(),
+ resp.headers().get("content-type").unwrap()
);
}
- #[actix_web::test]
- async fn post_registration_fails_given_url_is_already_registered() {
- let id = "0123456789abcdef0123456789abcdef".to_string();
- let id_generator: Arc<dyn IdGenerator> = Arc::new(ConstantIdGenerator::new(id.clone()));
+ #[test]
+ async fn app_does_not_register_same_url_twice() {
+ let mut app_state = State::new();
+ let registration = Registration {
+ url: "http://1.2.3.4".to_string(),
+ };
- let app = test::init_service(
- App::new()
- .wrap(Logger::default())
- .app_data(web::Data::from(id_generator))
- .service(register),
- )
- .await;
- let url = "http://192.168.1.1".to_string();
- let _ = test::TestRequest::post()
- .uri("/register")
- .set_json(Registration { url: url.clone() })
- .insert_header(ContentType::json())
- .to_request();
-
- // second request with the same URL
- let req = test::TestRequest::post()
- .uri("/register")
- .set_json(Registration { url: url.clone() })
- .insert_header(ContentType::json())
- .to_request();
-
- let resp = test::call_service(&app, req).await;
-
- assert!(resp.status().is_client_error());
+ app_state.register(&registration);
+ let result = app_state.register(&registration);
- let body = resp.into_body();
- let bytes = body::to_bytes(body).await;
assert_eq!(
- RegistrationResult::Failure(RegistrationFailure::UrlAlreadyRegistered { url }),
- serde_json::from_slice(&bytes.unwrap()).unwrap()
+ RegistrationResult::UrlAlreadyRegistered {
+ url: "http://1.2.3.4".to_string()
+ },
+ result
);
}
}