summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud.bailly@iohk.io>2024-10-10 18:23:02 +0200
committerArnaud Bailly <arnaud.bailly@iohk.io>2024-10-10 18:23:02 +0200
commit653c7d93e9f8ecae78bdd2d884cce59041b11202 (patch)
tree2b26c78932d97a1f7619a925614fd5efcabf9dd3
parentc511c31fe25045b46a57b11201704ff55207e808 (diff)
downloadlambda-nantes-653c7d93e9f8ecae78bdd2d884cce59041b11202.tar.gz
Improve leaderboard to add timestamp and result
-rw-r--r--rust/src/lambda.rs5
-rw-r--r--rust/src/web.rs62
-rw-r--r--rust/templates/leaderboard.html38
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>