diff options
| author | Arnaud Bailly <arnaud.bailly@iohk.io> | 2024-10-10 18:23:02 +0200 |
|---|---|---|
| committer | Arnaud Bailly <arnaud.bailly@iohk.io> | 2024-10-10 18:23:02 +0200 |
| commit | 653c7d93e9f8ecae78bdd2d884cce59041b11202 (patch) | |
| tree | 2b26c78932d97a1f7619a925614fd5efcabf9dd3 | |
| parent | c511c31fe25045b46a57b11201704ff55207e808 (diff) | |
| download | lambda-nantes-653c7d93e9f8ecae78bdd2d884cce59041b11202.tar.gz | |
Improve leaderboard to add timestamp and result
| -rw-r--r-- | rust/src/lambda.rs | 5 | ||||
| -rw-r--r-- | rust/src/web.rs | 62 | ||||
| -rw-r--r-- | rust/templates/leaderboard.html | 38 |
3 files changed, 69 insertions, 36 deletions
diff --git a/rust/src/lambda.rs b/rust/src/lambda.rs index 4027a62..30f9f43 100644 --- a/rust/src/lambda.rs +++ b/rust/src/lambda.rs @@ -1,11 +1,10 @@ use proptest::{ - arbitrary::{any, any_with, arbitrary_with}, + arbitrary::any, prelude::*, strategy::{Strategy, ValueTree}, test_runner::TestRunner, }; -use rand::{rngs::SmallRng, Rng, RngCore, SeedableRng}; -use serde::{Deserialize, Serialize}; +use rand::Rng; use std::collections::HashMap; use crate::ast::*; diff --git a/rust/src/web.rs b/rust/src/web.rs index 291801a..0bf36a5 100644 --- a/rust/src/web.rs +++ b/rust/src/web.rs @@ -1,13 +1,10 @@ -use actix_web::{ - get, middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder, - Result as ActixResult, -}; +use actix_web::{get, middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder}; +use chrono::{DateTime, Utc}; use clap::Parser; use futures::lock::Mutex; use handlebars::{DirectorySourceOptions, Handlebars}; use log::info; use proptest::test_runner::{Config, RngAlgorithm, TestRng, TestRunner}; -use rand::Rng; use serde::{Deserialize, Serialize}; use std::time::Duration; use std::{collections::HashMap, sync::Arc}; @@ -27,6 +24,8 @@ struct Registration { struct ClientData { name: String, grade: u8, + last_query: DateTime<Utc>, + success: bool, } impl ClientData { @@ -34,6 +33,14 @@ impl ClientData { ClientData { name: client.name.clone(), grade: client.grade, + last_query: client + .results + .last() + .map_or(chrono::offset::Utc::now(), |q| q.timestamp), + success: client + .results + .last() + .map_or(false, |q| matches!(q.result, TestResult::TestSucceeded)), } } } @@ -47,17 +54,6 @@ trait AppState: Send + Sync { fn register(&mut self, registration: &Registration) -> RegistrationResult; } -fn make_leaderboard(clients: Vec<Client>) -> Leaderboard { - let clients = clients - .iter() - .map(|c| ClientData { - name: c.name.clone(), - grade: c.grade, - }) - .collect(); - Leaderboard { clients } -} - #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] enum RegistrationResult { RegistrationSuccess { id: String, url: String }, @@ -71,11 +67,17 @@ struct Client { url: String, grade: u8, runner: TestRunner, - results: Vec<TestResult>, + results: Vec<Test>, delay: std::time::Duration, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +struct Test { + timestamp: DateTime<Utc>, + result: TestResult, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] enum TestResult { TestFailed(String), ErrorSendingTest(String), @@ -132,11 +134,8 @@ impl Client { ) } - fn check_result( - &mut self, - expected: &String, - response: &Result<String, TestResult>, - ) -> TestResult { + fn check_result(&mut self, expected: &String, response: &Result<String, TestResult>) -> Test { + let timestamp = chrono::offset::Utc::now(); let result = match response { Ok(expr) => { let vals = parse(expr); @@ -162,8 +161,9 @@ impl Client { } Err(res) => res.clone(), }; - self.results.push(result.clone()); - result + let test = Test { result, timestamp }; + self.results.push(test.clone()); + test } } @@ -226,9 +226,9 @@ async fn eval(input: String) -> impl Responder { .map(|v| format!("{}", v)) .collect::<Vec<_>>() .join("\n"); - HttpResponse::Ok().body(format!("{}", output)) + HttpResponse::Ok().body(output.to_string()) } - Err(e) => HttpResponse::BadRequest().body(format!("{}", e)), + Err(e) => HttpResponse::BadRequest().body(e.to_string()), } } @@ -243,6 +243,7 @@ async fn leaderboard( let client = client.lock().await; client_data.push(ClientData::from(&client)); } + client_data.sort_by(|a, b| b.grade.cmp(&a.grade)); let body = hb .render( @@ -357,7 +358,6 @@ mod app_tests { #[actix_web::test] async fn post_registration_returns_success_with_unique_id() { - let id = "0123456789abcdef0123456789abcdef".to_string(); let state = Arc::new(Mutex::new(State::new())); // FIXME should only be called once, move to setup env_logger::init(); @@ -679,9 +679,9 @@ mod app_tests { let expected = "1".to_string(); let response = Ok("1".to_string()); - let result = client.check_result(&expected, &response); + let test = client.check_result(&expected, &response); - assert_eq!(TestResult::TestSucceeded, result); + assert_eq!(TestResult::TestSucceeded, test.result); assert_eq!(2, client.grade); } @@ -691,9 +691,9 @@ mod app_tests { let expected = "1".to_string(); let response = Ok("2".to_string()); - let result = client.check_result(&expected, &response); + let test = client.check_result(&expected, &response); - assert_eq!(TestResult::TestFailed("2".to_string()), result); + assert_eq!(TestResult::TestFailed("2".to_string()), test.result); assert_eq!(1, client.grade); } diff --git a/rust/templates/leaderboard.html b/rust/templates/leaderboard.html index f062323..82992d1 100644 --- a/rust/templates/leaderboard.html +++ b/rust/templates/leaderboard.html @@ -2,14 +2,48 @@ <html> <head> + <meta charset="utf-8"> <title>Leaderboard</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <style> + table { + width: 80%; + border-collapse: collapse; + } + + table, th, td { + border: 1px solid black; + } + + th, td { + padding: 15px; + text-align: left; + } + + th { + background-color: #f2f2f2; + } + + tr:nth-child(even) { + background-color: #f2f2f2; + } + + .success { + background-color: green; + } + + .fail { + background-color: red; + } + </style> </head> <body> + <h1>Leaderboard</h1> <table> - <tr><th>Name</th><th>Grade</th></tr> + <tr><th>Name</th><th>Grade</th><th>Last test</th></tr> {{#each this.clients}} - <tr><td>{{this.name}}</td><td>{{this.grade}}</td></tr> + <tr><td>{{this.name}}</td><td>{{this.grade}}</td><td class="{{#if this.success}}success{{else}}fail{{/if}}">{{this.last_query}}</td></tr> {{/each}} </table> </body> |
