mcaptcha/pages/panel/
utils.rs1use actix_identity::Identity;
7use actix_web::{web, HttpResponse, Responder};
8use sailfish::TemplateOnce;
9
10use crate::api::v1::stats::{percentile_bench_runner, PercentileReq, PercentileResp};
11use crate::errors::PageResult;
12use crate::pages::auth::sudo::SudoPage;
13use crate::AppData;
14
15pub mod routes {
16 pub struct Utils {
17 pub percentile: &'static str,
18 }
19
20 impl Utils {
21 pub const fn new() -> Self {
22 Utils {
23 percentile: "/utils/percentile",
24 }
25 }
26
27 pub const fn get_sitemap() -> [&'static str; 1] {
28 const S: Utils = Utils::new();
29 [S.percentile]
30 }
31 }
32}
33
34pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
35 cfg.service(get_percentile);
36 cfg.service(post_percentile);
37}
38
39const PAGE: &str = "Difficulty factor statistics";
40
41#[derive(TemplateOnce, Clone)]
42#[template(path = "panel/utils/percentile/index.html")]
43pub struct PercentilePage {
44 time: Option<u32>,
45 percentile: Option<f64>,
46 difficulty_factor: Option<u32>,
47}
48
49#[my_codegen::get(
50 path = "crate::PAGES.panel.utils.percentile",
51 wrap = "crate::pages::get_middleware()"
52)]
53async fn get_percentile(id: Identity) -> PageResult<impl Responder> {
54 let data = PercentilePage {
55 time: None,
56 percentile: None,
57 difficulty_factor: None,
58 };
59
60 let body = data.render_once().unwrap();
61 Ok(HttpResponse::Ok()
62 .content_type("text/html; charset=utf-8")
63 .body(body))
64}
65
66#[my_codegen::post(
67 path = "crate::PAGES.panel.utils.percentile",
68 wrap = "crate::pages::get_middleware()"
69)]
70async fn post_percentile(
71 data: AppData,
72 id: Identity,
73 payload: web::Form<PercentileReq>,
74) -> PageResult<impl Responder> {
75 let resp = percentile_bench_runner(&data, &payload).await?;
76 let page = PercentilePage {
77 time: Some(payload.time),
78 percentile: Some(payload.percentile),
79 difficulty_factor: resp.difficulty_factor,
80 };
81
82 let body = page.render_once().unwrap();
83 Ok(HttpResponse::Ok()
84 .content_type("text/html; charset=utf-8")
85 .body(body))
86}
87
88#[cfg(test)]
89mod tests {
90 use actix_web::{http::StatusCode, test, web::Bytes, App};
91
92 use super::*;
93 use crate::api::v1::services;
94 use crate::*;
95
96 #[actix_rt::test]
97 async fn page_stats_bench_work_pg() {
98 let data = crate::tests::pg::get_data().await;
99 page_stats_bench_work(data).await;
100 }
101
102 #[actix_rt::test]
103 async fn page_stats_bench_work_maria() {
104 let data = crate::tests::maria::get_data().await;
105 page_stats_bench_work(data).await;
106 }
107
108 async fn page_stats_bench_work(data: ArcData) {
109 use crate::tests::*;
110
111 const NAME: &str = "pagebenchstatsuesr";
112 const EMAIL: &str = "pagebenchstatsuesr@testadminuser.com";
113 const PASSWORD: &str = "longpassword2";
114
115 const DEVICE_USER_PROVIDED: &str = "foo";
116 const DEVICE_SOFTWARE_RECOGNISED: &str = "Foobar.v2";
117 const THREADS: i32 = 4;
118
119 let data = &data;
120 {
121 delete_user(&data, NAME).await;
122 }
123
124 register_and_signin(data, NAME, EMAIL, PASSWORD).await;
125 let (_, signin_resp, key) = add_levels_util(data, NAME, PASSWORD).await;
127 let app = get_app!(data).await;
128 let cookies = get_cookie!(signin_resp);
129
130 let page = 1;
131 let tmp_id = uuid::Uuid::new_v4();
132 let download_rotue = V1_API_ROUTES
133 .survey
134 .get_download_route(&tmp_id.to_string(), page);
135
136 let download_req = test::call_service(
137 &app,
138 test::TestRequest::get().uri(&download_rotue).to_request(),
139 )
140 .await;
141 assert_eq!(download_req.status(), StatusCode::NOT_FOUND);
142
143 data.db
144 .analytics_create_psuedo_id_if_not_exists(&key.key)
145 .await
146 .unwrap();
147
148 let psuedo_id = data
149 .db
150 .analytics_get_psuedo_id_from_capmaign_id(&key.key)
151 .await
152 .unwrap();
153
154 for i in 1..6 {
155 println!("[{i}] Saving analytics");
156 let analytics = db_core::CreatePerformanceAnalytics {
157 time: i,
158 difficulty_factor: i,
159 worker_type: "wasm".into(),
160 };
161 data.db.analysis_save(&key.key, &analytics).await.unwrap();
162 }
163
164 let msg = PercentileReq {
165 time: 1,
166 percentile: 99.00,
167 };
168 let resp = test::call_service(
169 &app,
170 post_request!(&msg, V1_API_ROUTES.stats.percentile_benches).to_request(),
171 )
172 .await;
173 assert_eq!(resp.status(), StatusCode::OK);
174 let resp: PercentileResp = test::read_body_json(resp).await;
175
176 assert!(resp.difficulty_factor.is_none());
177
178 let msg = PercentileReq {
179 time: 1,
180 percentile: 100.00,
181 };
182
183 let resp = test::call_service(
184 &app,
185 post_request!(&msg, V1_API_ROUTES.stats.percentile_benches).to_request(),
186 )
187 .await;
188 assert_eq!(resp.status(), StatusCode::OK);
189 let resp: PercentileResp = test::read_body_json(resp).await;
190
191 let percentile_resp = test::call_service(
193 &app,
194 test::TestRequest::get()
195 .uri(&crate::PAGES.panel.utils.percentile)
196 .cookie(cookies.clone())
197 .to_request(),
198 )
199 .await;
200
201 assert_eq!(percentile_resp.status(), StatusCode::OK);
202
203 let body: Bytes = test::read_body(percentile_resp).await;
204 let body = String::from_utf8(body.to_vec()).unwrap();
205
206 assert!(body.contains("Maximum time taken"));
207
208 let percentile_resp = test::call_service(
209 &app,
210 test::TestRequest::get()
211 .uri(&crate::PAGES.panel.utils.percentile)
212 .cookie(cookies.clone())
213 .to_request(),
214 )
215 .await;
216
217 assert_eq!(percentile_resp.status(), StatusCode::OK);
218
219 let body: Bytes = test::read_body(percentile_resp).await;
220 let body = String::from_utf8(body.to_vec()).unwrap();
221
222 assert!(body.contains("Maximum time taken"));
223
224 let msg = PercentileReq {
228 time: 1,
229 percentile: 99.00,
230 };
231
232 let percentile_resp = test::call_service(
233 &app,
234 test::TestRequest::post()
235 .uri(&crate::PAGES.panel.utils.percentile)
236 .set_form(&msg)
237 .cookie(cookies.clone())
238 .to_request(),
239 )
240 .await;
241
242 assert_eq!(percentile_resp.status(), StatusCode::OK);
243
244 let body: Bytes = test::read_body(percentile_resp).await;
245 let body = String::from_utf8(body.to_vec()).unwrap();
246
247 assert!(body.contains(
248 "Not enough inputs to compute statistics. Please try again later"
249 ));
250 assert!(body.contains(&1.to_string()));
251 assert!(body.contains(&99.00.to_string()));
252 let msg = PercentileReq {
257 time: 2,
258 percentile: 100.00,
259 };
260
261 let percentile_resp = test::call_service(
262 &app,
263 test::TestRequest::post()
264 .uri(&crate::PAGES.panel.utils.percentile)
265 .set_form(&msg)
266 .cookie(cookies.clone())
267 .to_request(),
268 )
269 .await;
270
271 assert_eq!(percentile_resp.status(), StatusCode::OK);
272
273 let body: Bytes = test::read_body(percentile_resp).await;
274 let body = String::from_utf8(body.to_vec()).unwrap();
275
276 assert!(body.contains("Difficulty factor: 2"));
277 assert!(body.contains(&2.to_string()));
278 assert!(body.contains(&100.00.to_string()));
279 }
280}