summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud.bailly@iohk.io>2024-10-07 09:59:03 +0200
committerArnaud Bailly <arnaud.bailly@iohk.io>2024-10-07 09:59:03 +0200
commit1ef156ca34078a89d2955b52f5df18254bd9c095 (patch)
treef24a03b9c8f1ccfbe76af249d5394ec44bc54142
parenta2220cd6ca103b636567b557d21ab345c6ab99e0 (diff)
downloadlambda-nantes-1ef156ca34078a89d2955b52f5df18254bd9c095.tar.gz
Change delay on test success/failure
-rw-r--r--rust/src/web.rs166
1 files changed, 117 insertions, 49 deletions
diff --git a/rust/src/web.rs b/rust/src/web.rs
index 5729083..62dea22 100644
--- a/rust/src/web.rs
+++ b/rust/src/web.rs
@@ -1,23 +1,12 @@
-use actix_web::{
- get, http::header::ContentType, middleware::Logger, post, web, App, HttpResponse, HttpServer,
- Responder,
-};
+use actix_web::{middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder};
use clap::Parser;
-use futures::try_join;
-use futures::{future::join_all, lock::Mutex};
-use lambda::ast::Value;
+use futures::lock::Mutex;
use log::info;
use proptest::test_runner::TestRunner;
-use rand::rngs::SmallRng;
-use rand::{Rng, SeedableRng};
+use rand::Rng;
use serde::{Deserialize, Serialize};
-use std::{
- collections::HashMap,
- env::args,
- io::{stdin, stdout, IsTerminal},
- sync::Arc,
-};
-use tokio;
+use std::time::Duration;
+use std::{collections::HashMap, sync::Arc};
use tokio::task;
use uuid::Uuid;
@@ -46,8 +35,11 @@ struct Client {
grade: u8,
runner: TestRunner,
seed: u64,
+ results: Vec<TestResult>,
+ delay: std::time::Duration,
}
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
enum TestResult {
TestFailed(String),
ErrorSendingTest(String),
@@ -55,8 +47,20 @@ enum TestResult {
}
impl Client {
- fn time_to_next_test(&self) -> std::time::Duration {
- std::time::Duration::from_secs(1)
+ fn new(url: String) -> Self {
+ Self {
+ id: Uuid::new_v4(),
+ url,
+ grade: 1,
+ runner: TestRunner::deterministic(),
+ seed: 42,
+ results: Vec::new(),
+ delay: Duration::from_secs(10),
+ }
+ }
+
+ fn time_to_next_test(&self) -> Duration {
+ self.delay
}
fn generate_expr(&mut self) -> (String, String) {
@@ -67,26 +71,33 @@ impl Client {
fn check_result(
&mut self,
- expected: String,
- response: Result<String, TestResult>,
+ expected: &String,
+ response: &Result<String, TestResult>,
) -> TestResult {
- match response {
+ let result = match response {
Ok(expr) => {
- let vals = parse(&expr);
+ let vals = parse(expr);
let actual = eval_all(&vals)
.iter()
.map(|v| format!("{}", v))
.collect::<Vec<_>>()
.join("\n");
- if actual == expected {
+ if actual == *expected {
self.grade += 1;
+ self.delay = Duration::from_secs_f64(self.delay.as_secs_f64() * 0.8);
TestResult::TestSucceeded
} else {
+ self.delay = Duration::from_secs_f64(self.delay.as_secs_f64() * 1.2);
+ if self.delay.as_secs() > 30 {
+ self.delay = Duration::from_secs(30);
+ }
TestResult::TestFailed(actual)
}
}
- Err(res) => res,
- }
+ Err(res) => res.clone(),
+ };
+ self.results.push(result.clone());
+ result
}
}
@@ -105,29 +116,22 @@ impl State {
impl AppState for State {
fn register(&mut self, registration: &Registration) -> RegistrationResult {
- let mut rng = rand::thread_rng();
if self.clients.contains_key(&registration.url) {
RegistrationResult::UrlAlreadyRegistered {
url: registration.url.clone(),
}
} else {
- let id = Uuid::new_v4();
- let seed = rng.gen();
- let client = Arc::new(Mutex::new(Client {
- id,
- url: registration.url.clone(),
- grade: 1,
- seed,
- runner: TestRunner::deterministic(),
- }));
- let client_s = client.clone();
- self.clients.insert(registration.url.clone(), client);
+ let client = Client::new(registration.url.clone());
+ let id = client.id.to_string();
+ let client_ref = Arc::new(Mutex::new(client));
+ let client_s = client_ref.clone();
+ self.clients.insert(registration.url.clone(), client_ref);
// let it run in the background
// FIXME: should find a way to handle graceful termination
task::spawn(async move { send_tests(client_s).await });
RegistrationResult::RegistrationSuccess {
- id: id.to_string(),
+ id,
url: registration.url.clone(),
}
}
@@ -191,13 +195,12 @@ async fn main() -> std::io::Result<()> {
async fn send_tests(client_m: Arc<Mutex<Client>>) {
loop {
let mut client = client_m.lock().await;
- let time_to_next_test = client.time_to_next_test();
- let (input, expected) = client.generate_expr();
+ tokio::time::sleep(client.time_to_next_test()).await;
- tokio::time::sleep(time_to_next_test).await;
+ let (input, expected) = client.generate_expr();
let response = send_test(&input, &client.url).await;
- client.check_result(expected, response);
+ client.check_result(&expected, &response);
}
}
@@ -228,6 +231,7 @@ mod app_tests {
use actix_web::http::header::TryIntoHeaderValue;
use actix_web::{body, http::header::ContentType, middleware::Logger, test, App};
+ use lambda::ast::Value;
use super::*;
@@ -357,13 +361,7 @@ mod app_tests {
}
fn client() -> Client {
- Client {
- id: Uuid::new_v4(),
- url: "http://1.2.3.4".to_string(),
- grade: 1,
- seed: 42,
- runner: TestRunner::deterministic(),
- }
+ Client::new("http://1.2.3.4".to_string())
}
#[test]
@@ -401,4 +399,74 @@ mod app_tests {
_ => panic!("Expected symbol, got {:?}", parsed),
}
}
+
+ #[test]
+ async fn client_increases_grade_on_successful_test() {
+ let mut client = client();
+ let expected = "1".to_string();
+ let response = Ok("1".to_string());
+
+ let result = client.check_result(&expected, &response);
+
+ assert_eq!(TestResult::TestSucceeded, result);
+ assert_eq!(2, client.grade);
+ }
+
+ #[test]
+ async fn client_does_not_increase_grade_on_failed_test() {
+ let mut client = client();
+ let expected = "1".to_string();
+ let response = Ok("2".to_string());
+
+ let result = client.check_result(&expected, &response);
+
+ assert_eq!(TestResult::TestFailed("2".to_string()), result);
+ assert_eq!(1, client.grade);
+ }
+
+ #[test]
+ async fn client_starts_delay_to_next_test_at_10s() {
+ let client = client();
+
+ let delay = client.time_to_next_test();
+
+ assert_eq!(std::time::Duration::from_secs(10), delay);
+ }
+
+ #[test]
+ async fn client_increases_delay_to_next_upon_failed_test() {
+ let mut client = client();
+ let expected = "1".to_string();
+ let response = Ok("2".to_string());
+ let delay_before = client.time_to_next_test();
+
+ client.check_result(&expected, &response);
+
+ assert!(delay_before < client.time_to_next_test());
+ }
+
+ #[test]
+ async fn client_increases_delay_to_maximum_of_30s() {
+ let mut client = client();
+ let expected = "1".to_string();
+ let response = Ok("2".to_string());
+
+ for _ in 0..100 {
+ client.check_result(&expected, &response);
+ }
+
+ assert_eq!(Duration::from_secs(30), client.time_to_next_test());
+ }
+
+ #[test]
+ async fn client_decreases_delay_to_next_upon_successful_test() {
+ let mut client = client();
+ let expected = "1".to_string();
+ let response = Ok("1".to_string());
+ let delay_before = client.time_to_next_test();
+
+ client.check_result(&expected, &response);
+
+ assert!(delay_before > client.time_to_next_test());
+ }
}