1pub mod args;
2
3use std::{ops::Deref, sync::Arc};
4
5use base64::{engine::general_purpose, Engine};
6use futures_util::{
7 stream::{SplitSink, SplitStream},
8 SinkExt, StreamExt,
9};
10use reqwest::{
11 header::{HeaderValue, CONTENT_TYPE},
12 multipart::{Form, Part},
13 redirect::Policy,
14 StatusCode,
15};
16pub use shuttlings;
17use shuttlings::{SubmissionState, SubmissionUpdate};
18use tokio::{
19 net::TcpStream,
20 sync::mpsc::Sender,
21 time::{sleep, Duration},
22};
23use tokio_tungstenite::{tungstenite::Message, MaybeTlsStream, WebSocketStream};
24use tracing::info;
25use uuid::Uuid;
26
27pub const SUPPORTED_CHALLENGES: &[i32] =
28 &[-1, 1, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22];
29pub const SUBMISSION_TIMEOUT: u64 = 60;
30
31pub async fn run(url: String, id: Uuid, number: i32, tx: Sender<SubmissionUpdate>) {
32 info!(%id, %url, %number, "Starting submission");
33
34 tx.send(SubmissionState::Running.into()).await.unwrap();
35 tx.send(SubmissionUpdate::Save).await.unwrap();
36
37 tokio::select! {
38 _ = validate(url.as_str(), number, tx.clone()) => (),
39 _ = sleep(Duration::from_secs(SUBMISSION_TIMEOUT)) => {
40 info!(%id, %url, %number, "Submission timed out");
42 tx.send("Timed out".to_owned().into()).await.unwrap();
43 tx.send(SubmissionState::Done.into()).await.unwrap();
44 tx.send(SubmissionUpdate::Save).await.unwrap();
45 },
46 };
47 info!(%id, %url, %number, "Completed submission");
48}
49
50type TaskTest = (i32, i32);
52type ValidateResult = std::result::Result<(), TaskTest>;
54
55pub async fn validate(url: &str, number: i32, tx: Sender<SubmissionUpdate>) {
56 if !SUPPORTED_CHALLENGES.contains(&number) {
57 tx.send(
58 format!("Validating Challenge {number} is not supported yet! Check for updates.")
59 .into(),
60 )
61 .await
62 .unwrap();
63 return;
64 }
65 let txc = tx.clone();
66 if let Err((task, test)) = match number {
67 -1 => validate_minus1(url, txc).await,
68 1 => validate_1(url, txc).await,
69 4 => validate_4(url, txc).await,
70 5 => validate_5(url, txc).await,
71 6 => validate_6(url, txc).await,
72 7 => validate_7(url, txc).await,
73 8 => validate_8(url, txc).await,
74 11 => validate_11(url, txc).await,
75 12 => validate_12(url, txc).await,
76 13 => validate_13(url, txc).await,
77 14 => validate_14(url, txc).await,
78 15 => validate_15(url, txc).await,
79 18 => validate_18(url, txc).await,
80 19 => validate_19(url, txc).await,
81 20 => validate_20(url, txc).await,
82 21 => validate_21(url, txc).await,
83 22 => validate_22(url, txc).await,
84 _ => unreachable!(),
85 } {
86 info!(%url, %number, %task, %test, "Submission failed");
87 tx.send(format!("Task {task}: test #{test} failed 🟥").into())
88 .await
89 .unwrap();
90 }
91 tx.send(SubmissionState::Done.into()).await.unwrap();
92 tx.send(SubmissionUpdate::Save).await.unwrap();
93}
94
95fn new_client() -> reqwest::Client {
96 reqwest::ClientBuilder::new()
97 .http1_only()
98 .connect_timeout(Duration::from_secs(3))
99 .redirect(Policy::limited(3))
100 .referer(false)
101 .timeout(Duration::from_secs(60))
102 .build()
103 .unwrap()
104}
105
106async fn validate_minus1(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
107 let client = new_client();
108 let mut test: TaskTest;
109 test = (1, 1);
111 let url = &format!("{}/", base_url);
112 let res = client.get(url).send().await.map_err(|_| test)?;
113 if res.status() != StatusCode::OK {
114 return Err(test);
115 }
116 tx.send((true, 0).into()).await.unwrap();
118 tx.send(SubmissionUpdate::Save).await.unwrap();
119
120 test = (2, 1);
122 let url = &format!("{}/-1/error", base_url);
123 let res = client.get(url).send().await.map_err(|_| test)?;
124 if res.status() != StatusCode::INTERNAL_SERVER_ERROR {
125 return Err(test);
126 }
127 tx.send((false, 0).into()).await.unwrap();
129
130 Ok(())
131}
132
133async fn validate_1(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
134 let client = new_client();
135 let mut test: TaskTest;
136 test = (1, 1);
138 let url = &format!("{}/1/2/3", base_url);
139 let res = client.get(url).send().await.map_err(|_| test)?;
140 let text = res.text().await.map_err(|_| test)?;
141 if text != "1" {
142 return Err(test);
143 }
144 test = (1, 2);
145 let url = &format!("{}/1/12/16", base_url);
146 let res = client.get(url).send().await.map_err(|_| test)?;
147 let text = res.text().await.map_err(|_| test)?;
148 if text != "21952" {
149 return Err(test);
150 }
151 tx.send((true, 0).into()).await.unwrap();
153 tx.send(SubmissionUpdate::Save).await.unwrap();
154
155 test = (2, 1);
157 let url = &format!("{}/1/3/5/7/9", base_url);
158 let res = client.get(url).send().await.map_err(|_| test)?;
159 let text = res.text().await.map_err(|_| test)?;
160 if text != "512" {
161 return Err(test);
162 }
163 test = (2, 2);
164 let url = &format!("{}/1/0/0/0", base_url);
165 let res = client.get(url).send().await.map_err(|_| test)?;
166 let text = res.text().await.map_err(|_| test)?;
167 if text != "0" {
168 return Err(test);
169 }
170 test = (2, 3);
171 let url = &format!("{}/1/-3/1", base_url);
172 let res = client.get(url).send().await.map_err(|_| test)?;
173 let text = res.text().await.map_err(|_| test)?;
174 if text != "-64" {
175 return Err(test);
176 }
177 test = (2, 4);
178 let url = &format!("{}/1/3/5/7/9/2/13/12/16/18", base_url);
179 let res = client.get(url).send().await.map_err(|_| test)?;
180 let text = res.text().await.map_err(|_| test)?;
181 if text != "729" {
182 return Err(test);
183 }
184 tx.send((false, 100).into()).await.unwrap();
185
186 Ok(())
187}
188
189async fn validate_4(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
190 let client = new_client();
191 let mut test: TaskTest;
192 test = (1, 1);
194 let url = &format!("{}/4/strength", base_url);
195 let res = client
196 .post(url)
197 .json(&serde_json::json!([
198 {
199 "name": "Zeus",
200 "strength": 8
201 },
202 {
203 "name": "Oner",
204 "strength": 6
205 },
206 {
207 "name": "Faker",
208 "strength": 7
209 },
210 {
211 "name": "Gumayusi",
212 "strength": 6
213 },
214 {
215 "name": "Keria",
216 "strength": 6
217 }
218 ]))
219 .send()
220 .await
221 .map_err(|_| test)?;
222 let text = res.text().await.map_err(|_| test)?;
223 if text != "33" {
224 return Err(test);
225 }
226 tx.send((true, 0).into()).await.unwrap();
228 tx.send(SubmissionUpdate::Save).await.unwrap();
229
230 test = (2, 1);
232 let url = &format!("{}/4/contest", base_url);
233 let res = client
234 .post(url)
235 .json(&serde_json::json!([
236 {
237 "name": "Zeus",
238 "strength": 8,
239 "speed": 51.2,
240 "height": 81,
241 "antler_width": 31,
242 "snow_magic_power": 311,
243 "favorite_food": "pizza",
244 "cAnD13s_3ATeN-yesT3rdAy": 4
245 },
246 {
247 "name": "Oner",
248 "strength": 6,
249 "speed": 41.3,
250 "height": 51,
251 "antler_width": 30,
252 "snow_magic_power": 321,
253 "favorite_food": "burger",
254 "cAnD13s_3ATeN-yesT3rdAy": 1
255 },
256 {
257 "name": "Faker",
258 "strength": 7,
259 "speed": 50,
260 "height": 50,
261 "antler_width": 37,
262 "snow_magic_power": 6667,
263 "favorite_food": "broccoli",
264 "cAnD13s_3ATeN-yesT3rdAy": 1
265 },
266 {
267 "name": "Gumayusi",
268 "strength": 6,
269 "speed": 60.1,
270 "height": 50,
271 "antler_width": 34,
272 "snow_magic_power": 2323,
273 "favorite_food": "pizza",
274 "cAnD13s_3ATeN-yesT3rdAy": 1
275 },
276 {
277 "name": "Keria",
278 "strength": 6,
279 "speed": 48.2,
280 "height": 65,
281 "antler_width": 33,
282 "snow_magic_power": 5014,
283 "favorite_food": "wok",
284 "cAnD13s_3ATeN-yesT3rdAy": 5
285 }
286 ]))
287 .send()
288 .await
289 .map_err(|_| test)?;
290 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
291 if json
292 != serde_json::json!({
293 "fastest":"Speeding past the finish line with a strength of 6 is Gumayusi",
294 "tallest":"Zeus is standing tall with his 31 cm wide antlers",
295 "magician":"Faker could blast you away with a snow magic power of 6667",
296 "consumer":"Keria ate lots of candies, but also some wok"
297 })
298 {
299 return Err(test);
300 }
301 tx.send((false, 150).into()).await.unwrap();
302
303 Ok(())
304}
305
306async fn validate_5(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
307 let t = JSONTester::new(format!("{}/5?offset=0&limit=8", base_url));
309 t.test(
310 (1, 1),
311 &serde_json::json!(["Ava", "Caleb", "Mia", "Owen", "Lily", "Ethan", "Zoe", "Nolan"]),
312 StatusCode::OK,
313 &serde_json::json!(["Ava", "Caleb", "Mia", "Owen", "Lily", "Ethan", "Zoe", "Nolan"]),
314 )
315 .await?;
316 let t = JSONTester::new(format!("{}/5?offset=10&limit=4", base_url));
317 t.test(
318 (1, 2),
319 &serde_json::json!([
320 "Ava", "Caleb", "Mia", "Owen", "Lily", "Ethan", "Zoe", "Nolan", "Harper", "Lucas",
321 "Stella", "Mason", "Olivia", "Wyatt", "Isabella", "Logan",
322 ]),
323 StatusCode::OK,
324 &serde_json::json!(["Stella", "Mason", "Olivia", "Wyatt"]),
325 )
326 .await?;
327 tx.send((true, 0).into()).await.unwrap();
329 tx.send(SubmissionUpdate::Save).await.unwrap();
330
331 let t = JSONTester::new(format!("{}/5?offset=0&limit=5", base_url));
333 t.test(
334 (2, 1),
335 &serde_json::json!([]),
336 StatusCode::OK,
337 &serde_json::json!([]),
338 )
339 .await?;
340 let t = JSONTester::new(format!("{}/5", base_url));
341 t.test(
342 (2, 2),
343 &serde_json::json!(["Alice", "Bob", "Charlie", "David"]),
344 StatusCode::OK,
345 &serde_json::json!(["Alice", "Bob", "Charlie", "David"]),
346 )
347 .await?;
348 let t = JSONTester::new(format!("{}/5?offset=2", base_url));
349 t.test(
350 (2, 3),
351 &serde_json::json!(["Alice", "Bob", "Charlie", "David"]),
352 StatusCode::OK,
353 &serde_json::json!(["Charlie", "David"]),
354 )
355 .await?;
356 let t = JSONTester::new(format!("{}/5?offset=2&limit=0", base_url));
357 t.test(
358 (2, 4),
359 &serde_json::json!(["Alice", "Bob", "Charlie", "David"]),
360 StatusCode::OK,
361 &serde_json::json!([]),
362 )
363 .await?;
364 let t = JSONTester::new(format!("{}/5?split=6", base_url));
365 t.test(
366 (2, 5),
367 &serde_json::json!([
368 "Alice", "Bob", "Charlie", "David", "Eva", "Frank", "Grace", "Hank", "Ivy", "Jack",
369 "Katie", "Liam", "Mia", "Nathan", "Olivia", "Paul", "Quinn", "Rachel", "Samuel",
370 "Tara", "Aria", "Jackson"
371 ]),
372 StatusCode::OK,
373 &serde_json::json!([
374 ["Alice", "Bob", "Charlie", "David", "Eva", "Frank"],
375 ["Grace", "Hank", "Ivy", "Jack", "Katie", "Liam"],
376 ["Mia", "Nathan", "Olivia", "Paul", "Quinn", "Rachel"],
377 ["Samuel", "Tara", "Aria", "Jackson"]
378 ]),
379 )
380 .await?;
381 let t = JSONTester::new(format!("{}/5?offset=2&limit=4&split=1", base_url));
382 t.test(
383 (2, 6),
384 &serde_json::json!([
385 "Alice", "Bob", "Charlie", "David", "Alice", "Bob", "Charlie", "David"
386 ]),
387 StatusCode::OK,
388 &serde_json::json!([["Charlie"], ["David"], ["Alice"], ["Bob"],]),
389 )
390 .await?;
391 let t = JSONTester::new(format!("{}/5?limit=0", base_url));
392 t.test(
393 (2, 7),
394 &serde_json::json!(["Alice", "Bob", "Charlie", "David"]),
395 StatusCode::OK,
396 &serde_json::json!([]),
397 )
398 .await?;
399 let t = JSONTester::new(format!("{}/5?offset=0&limit=0", base_url));
400 t.test(
401 (2, 8),
402 &serde_json::json!(["Alice", "Bob", "Charlie", "David"]),
403 StatusCode::OK,
404 &serde_json::json!([]),
405 )
406 .await?;
407 tx.send((false, 150).into()).await.unwrap();
408
409 Ok(())
410}
411
412async fn validate_6(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
413 let client = new_client();
414 let mut test: TaskTest;
415 let url = &format!("{}/6", base_url);
416 test = (1, 1);
418 let res = client
419 .post(url)
420 .body("elf elf elf")
421 .send()
422 .await
423 .map_err(|_| test)?;
424 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
425 if json["elf"] != serde_json::Value::Number(3.into()) {
426 return Err(test);
427 }
428 test = (1, 2);
429 let res = client
430 .post(url)
431 .body("In the quirky town of Elf stood an enchanting shop named 'The Elf & Shelf.' Managed by Wally, a mischievous elf with a knack for crafting exquisite shelves, the shop was a bustling hub of elf after elf who wanter to see their dear elf in Belfast.")
432 .send()
433 .await
434 .map_err(|_| test)?;
435 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
436 if json["elf"] != serde_json::Value::Number(6.into()) {
437 return Err(test);
438 }
439 tx.send((true, 0).into()).await.unwrap();
441 tx.send(SubmissionUpdate::Save).await.unwrap();
442
443 test = (2, 1);
445 let res = client
446 .post(url)
447 .body("elf elf elf on a shelf")
448 .send()
449 .await
450 .map_err(|_| test)?;
451 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
452 if json
453 != serde_json::json!({
454 "elf":4,
455 "elf on a shelf":1,
456 "shelf with no elf on it":0
457 })
458 {
459 return Err(test);
460 }
461 test = (2, 2);
462 let res = client
463 .post(url)
464 .body("In Belfast I heard an elf on a shelf on a shelf on a ")
465 .send()
466 .await
467 .map_err(|_| test)?;
468 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
469 if json
470 != serde_json::json!({
471 "elf":4,
472 "elf on a shelf":2,
473 "shelf with no elf on it":0
474 })
475 {
476 return Err(test);
477 }
478 test = (2, 3);
479 let res = client
480 .post(url)
481 .body("Somewhere in Belfast under a shelf store but above the shelf realm there's an elf on a shelf on a shelf on a shelf on a elf on a shelf on a shelf on a shelf on a shelf on a elf on a elf on a elf on a shelf on a ")
482 .send()
483 .await
484 .map_err(|_| test)?;
485 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
486 if json
487 != serde_json::json!({
488 "elf":16,
489 "elf on a shelf":8,
490 "shelf with no elf on it":2
491 })
492 {
493 return Err(test);
494 }
495 tx.send((false, 200).into()).await.unwrap();
497
498 Ok(())
499}
500
501async fn validate_7(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
502 let client = new_client();
503 let mut test: TaskTest;
504 test = (1, 1);
506 let url = &format!("{}/7/decode", base_url);
507 let data = serde_json::json!({
508 "recipe": {
509 "flour": 4,
510 "sugar": 3,
511 "butter": 3,
512 "baking powder": 1,
513 "raisins": 50
514 },
515 });
516 let b64 = general_purpose::STANDARD.encode(serde_json::to_vec(&data).unwrap());
517 let res = client
518 .get(url)
519 .header("Cookie", format!("recipe={b64}"))
520 .send()
521 .await
522 .map_err(|_| test)?;
523 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
524 if json != data {
525 return Err(test);
526 }
527 test = (1, 2);
528 let data = serde_json::json!({
529 "recipe": {
530 "peanuts": 26,
531 "dough": 37,
532 "extra salt": 1,
533 "raisins": 50
534 },
535 });
536 let b64 = general_purpose::STANDARD.encode(serde_json::to_vec(&data).unwrap());
537 let res = client
538 .get(url)
539 .header("Cookie", format!("recipe={b64}"))
540 .send()
541 .await
542 .map_err(|_| test)?;
543 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
544 if json != data {
545 return Err(test);
546 }
547 tx.send((true, 0).into()).await.unwrap();
549 tx.send(SubmissionUpdate::Save).await.unwrap();
550
551 let url = &format!("{}/7/bake", base_url);
553 let test_bake = |test: (i32, i32), i: serde_json::Value, o: serde_json::Value| async move {
554 let client = new_client();
555 let b64 = general_purpose::STANDARD.encode(serde_json::to_vec(&i).unwrap());
556 let res = client
557 .get(url)
558 .header("Cookie", format!("recipe={b64}"))
559 .send()
560 .await
561 .map_err(|_| test)?;
562 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
563 if json != o {
564 return Err(test);
565 }
566 Ok(())
567 };
568 test = (2, 1);
569 test_bake(
570 test,
571 serde_json::json!({
572 "recipe": {
573 "flour": 35,
574 "sugar": 56,
575 "butter": 3,
576 "baking powder": 1001,
577 "chocolate chips": 55
578 },
579 "pantry": {
580 "flour": 4045,
581 "sugar": 9606,
582 "butter": 99, "baking powder": 8655432,
584 "chocolate chips": 4587
585 }
586 }),
587 serde_json::json!({
588 "cookies": 33,
589 "pantry": {
590 "flour": 2890,
591 "sugar": 7758,
592 "butter": 0,
593 "baking powder": 8622399,
594 "chocolate chips": 2772
595 }
596 }),
597 )
598 .await?;
599 test = (2, 2);
600 test_bake(
601 test,
602 serde_json::json!({
603 "recipe": {
604 "flour": 35,
605 "sugar": 56,
606 "butter": 3,
607 "baking powder": 1001,
608 "chocolate chips": 55
609 },
610 "pantry": {
611 "flour": 4045,
612 "sugar": 7606,
613 "butter": 100,
614 "baking powder": 865543211516164409i64,
615 "chocolate chips": 4587
616 }
617 }),
618 serde_json::json!({
619 "cookies": 33,
620 "pantry": {
621 "flour": 2890,
622 "sugar": 5758,
623 "butter": 1,
624 "baking powder": 865543211516131376i64,
625 "chocolate chips": 2772
626 }
627 }),
628 )
629 .await?;
630 tx.send((false, 120).into()).await.unwrap();
632 tx.send(SubmissionUpdate::Save).await.unwrap();
633
634 test = (3, 1);
636 test_bake(
637 test,
638 serde_json::json!({
639 "recipe": {
640 "chicken": 1,
641 },
642 "pantry": {
643 "chicken": 0,
644 }
645 }),
646 serde_json::json!({
647 "cookies": 0,
648 "pantry": {
649 "chicken": 0,
650 }
651 }),
652 )
653 .await?;
654 test = (3, 2);
655 test_bake(
656 test,
657 serde_json::json!({
658 "recipe": {
659 "cocoa bean": 1,
660 "chicken": 0,
661 },
662 "pantry": {
663 "cocoa bean": 5,
664 "corn": 5,
665 "cucumber": 0,
666 }
667 }),
668 serde_json::json!({
669 "cookies": 5,
670 "pantry": {
671 "cocoa bean": 0,
672 "corn": 5,
673 "cucumber": 0,
674 }
675 }),
676 )
677 .await?;
678 test = (3, 3);
679 test_bake(
680 test,
681 serde_json::json!({
682 "recipe": {
683 "cocoa bean": 1,
684 "chicken": 0,
685 },
686 "pantry": {
687 "cocoa bean": 5,
688 "chicken": 0,
689 }
690 }),
691 serde_json::json!({
692 "cookies": 5,
693 "pantry": {
694 "cocoa bean": 0,
695 "chicken": 0,
696 }
697 }),
698 )
699 .await?;
700 test = (3, 4);
701 test_bake(
702 test,
703 serde_json::json!({
704 "recipe": {
705 "cocoa bean": 1,
706 "chicken": 0,
707 },
708 "pantry": {
709 "cocoa bean": 5,
710 }
711 }),
712 serde_json::json!({
713 "cookies": 5,
714 "pantry": {
715 "cocoa bean": 0,
716 }
717 }),
718 )
719 .await?;
720 tx.send((false, 100).into()).await.unwrap();
722
723 Ok(())
724}
725
726async fn validate_8(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
727 let client = new_client();
728 let mut test: TaskTest;
729 let tol = 0.001f64;
730 test = (1, 1);
732 let url = &format!("{}/8/weight/225", base_url);
733 let res = client.get(url).send().await.map_err(|_| test)?;
734 let text = res.text().await.map_err(|_| test)?;
735 let num: f64 = text.parse().map_err(|_| test)?;
736 if !(num.is_finite() && (num - 16f64).abs() < tol) {
737 return Err(test);
738 }
739 test = (1, 2);
740 let url = &format!("{}/8/weight/393", base_url);
741 let res = client.get(url).send().await.map_err(|_| test)?;
742 let text = res.text().await.map_err(|_| test)?;
743 let num: f64 = text.parse().map_err(|_| test)?;
744 if !(num.is_finite() && (num - 5.2f64).abs() < tol) {
745 return Err(test);
746 }
747 test = (1, 3);
748 let url = &format!("{}/8/weight/92", base_url);
749 let res = client.get(url).send().await.map_err(|_| test)?;
750 let text = res.text().await.map_err(|_| test)?;
751 let num: f64 = text.parse().map_err(|_| test)?;
752 if !(num.is_finite() && (num - 0.1f64).abs() < tol) {
753 return Err(test);
754 }
755 tx.send((true, 0).into()).await.unwrap();
757 tx.send(SubmissionUpdate::Save).await.unwrap();
758
759 test = (2, 1);
761 let url = &format!("{}/8/drop/383", base_url);
762 let res = client.get(url).send().await.map_err(|_| test)?;
763 let text = res.text().await.map_err(|_| test)?;
764 let num: f64 = text.parse().map_err(|_| test)?;
765 if !(num.is_finite() && (num - 13316.953480432378f64).abs() < tol) {
766 return Err(test);
767 }
768 test = (2, 2);
769 let url = &format!("{}/8/drop/16", base_url);
770 let res = client.get(url).send().await.map_err(|_| test)?;
771 let text = res.text().await.map_err(|_| test)?;
772 let num: f64 = text.parse().map_err(|_| test)?;
773 if !(num.is_finite() && (num - 25.23212238397714f64).abs() < tol) {
774 return Err(test);
775 }
776 test = (2, 3);
777 let url = &format!("{}/8/drop/143", base_url);
778 let res = client.get(url).send().await.map_err(|_| test)?;
779 let text = res.text().await.map_err(|_| test)?;
780 let num: f64 = text.parse().map_err(|_| test)?;
781 if !(num.is_finite() && (num - 6448.2090536830465f64).abs() < tol) {
782 return Err(test);
783 }
784 tx.send((false, 160).into()).await.unwrap();
786
787 Ok(())
788}
789
790async fn validate_11(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
791 let client = new_client();
792 let mut test: TaskTest;
793 test = (1, 1);
795 let url = &format!("{}/11/assets/decoration.png", base_url);
796 let res = client.get(url).send().await.map_err(|_| test)?;
797 let headers = res.headers();
798 if !headers
799 .get("content-type")
800 .is_some_and(|v| v == "image/png")
801 {
802 return Err(test);
803 }
804 if !headers.get("content-length").is_some_and(|v| v == "787297") {
805 return Err(test);
806 }
807 let bytes = res.bytes().await.map_err(|_| test)?;
808 const EXPECTED: &[u8] = include_bytes!("../assets/decoration.png");
809 if bytes.to_vec().as_slice() != EXPECTED {
810 return Err(test);
811 }
812 tx.send((true, 0).into()).await.unwrap();
814 tx.send(SubmissionUpdate::Save).await.unwrap();
815
816 test = (2, 1);
818 let url = &format!("{}/11/red_pixels", base_url);
819 let form = Form::new().part(
820 "image",
821 Part::bytes(include_bytes!("../assets/decoration2.png").as_slice())
822 .file_name("decoration2.png")
823 .mime_str("image/png")
824 .unwrap(),
825 );
826 let res = client
827 .post(url)
828 .multipart(form)
829 .send()
830 .await
831 .map_err(|_| test)?;
832 let text = res.text().await.map_err(|_| test)?;
833 if text != "152107" {
834 return Err(test);
835 }
836 test = (2, 2);
837 let form = Form::new().part(
838 "image",
839 Part::bytes(include_bytes!("../assets/decoration3.png").as_slice())
840 .file_name("decoration3.png")
841 .mime_str("image/png")
842 .unwrap(),
843 );
844 let res = client
845 .post(url)
846 .multipart(form)
847 .send()
848 .await
849 .map_err(|_| test)?;
850 let text = res.text().await.map_err(|_| test)?;
851 if text != "40263" {
852 return Err(test);
853 }
854 test = (2, 3);
855 let form = Form::new().part(
856 "image",
857 Part::bytes(include_bytes!("../assets/decoration4.png").as_slice())
858 .file_name("decoration4.png")
859 .mime_str("image/png")
860 .unwrap(),
861 );
862 let res = client
863 .post(url)
864 .multipart(form)
865 .send()
866 .await
867 .map_err(|_| test)?;
868 let text = res.text().await.map_err(|_| test)?;
869 if text != "86869" {
870 return Err(test);
871 }
872 tx.send((false, 200).into()).await.unwrap();
874
875 Ok(())
876}
877
878async fn validate_12(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
879 let client = new_client();
880 let mut test: TaskTest;
881 test = (1, 1);
883 let url = &format!("{}/12/save/cch23", base_url);
884 let res = client.post(url).send().await.map_err(|_| test)?;
885 if res.status() != StatusCode::OK {
886 return Err(test);
887 }
888 sleep(Duration::from_secs(2)).await;
889 let url = &format!("{}/12/load/cch23", base_url);
890 let res = client.get(url).send().await.map_err(|_| test)?;
891 let text = res.text().await.map_err(|_| test)?;
892 if text != "2" {
893 return Err(test);
894 }
895 sleep(Duration::from_secs(2)).await;
896 let url = &format!("{}/12/load/cch23", base_url);
897 let res = client.get(url).send().await.map_err(|_| test)?;
898 let text = res.text().await.map_err(|_| test)?;
899 if text != "4" {
900 return Err(test);
901 }
902 test = (1, 2);
903 let url = &format!("{}/12/save/alpha", base_url);
904 let res = client.post(url).send().await.map_err(|_| test)?;
905 if res.status() != StatusCode::OK {
906 return Err(test);
907 }
908 sleep(Duration::from_secs(2)).await;
909 let url = &format!("{}/12/save/omega", base_url);
910 let res = client.post(url).send().await.map_err(|_| test)?;
911 if res.status() != StatusCode::OK {
912 return Err(test);
913 }
914 sleep(Duration::from_secs(2)).await;
915 let url = &format!("{}/12/load/alpha", base_url);
916 let res = client.get(url).send().await.map_err(|_| test)?;
917 let text = res.text().await.map_err(|_| test)?;
918 if text != "4" {
919 return Err(test);
920 }
921 let url = &format!("{}/12/save/alpha", base_url);
922 let res = client.post(url).send().await.map_err(|_| test)?;
923 if res.status() != StatusCode::OK {
924 return Err(test);
925 }
926 sleep(Duration::from_secs(1)).await;
927 let url = &format!("{}/12/load/omega", base_url);
928 let res = client.get(url).send().await.map_err(|_| test)?;
929 let text = res.text().await.map_err(|_| test)?;
930 if text != "3" {
931 return Err(test);
932 }
933 let url = &format!("{}/12/load/alpha", base_url);
934 let res = client.get(url).send().await.map_err(|_| test)?;
935 let text = res.text().await.map_err(|_| test)?;
936 if text != "1" {
937 return Err(test);
938 }
939 tx.send((true, 0).into()).await.unwrap();
941 tx.send(SubmissionUpdate::Save).await.unwrap();
942
943 test = (2, 1);
945 let url = &format!("{}/12/ulids", base_url);
946 let res = client
947 .post(url)
948 .json(&serde_json::json!([
949 "01BJQ0E1C3Z56ABCD0E11HYX4M",
950 "01BJQ0E1C3Z56ABCD0E11HYX5N",
951 "01BJQ0E1C3Z56ABCD0E11HYX6Q",
952 "01BJQ0E1C3Z56ABCD0E11HYX7R",
953 "01BJQ0E1C3Z56ABCD0E11HYX8P"
954 ]))
955 .send()
956 .await
957 .map_err(|_| test)?;
958 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
959 if json
960 != serde_json::json!([
961 "015cae07-0583-f94c-a5b1-a070431f7516",
962 "015cae07-0583-f94c-a5b1-a070431f74f8",
963 "015cae07-0583-f94c-a5b1-a070431f74d7",
964 "015cae07-0583-f94c-a5b1-a070431f74b5",
965 "015cae07-0583-f94c-a5b1-a070431f7494"
966 ])
967 {
968 return Err(test);
969 }
970 test = (2, 2);
971 let res = client
972 .post(url)
973 .json(&serde_json::json!([]))
974 .send()
975 .await
976 .map_err(|_| test)?;
977 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
978 if json != serde_json::json!([]) {
979 return Err(test);
980 }
981 tx.send((false, 100).into()).await.unwrap();
983 tx.send(SubmissionUpdate::Save).await.unwrap();
984
985 test = (3, 1);
987 let ids = serde_json::json!([
988 "00WEGGF0G0J5HEYXS3D7RWZGV8",
989 "76EP4G39R8JD1N8AQNYDVJBRCF",
990 "018CJ7KMG0051CDCS3B7BFJ3AK",
991 "00Y986KPG0AMGB78RD45E9109K",
992 "010451HTG0NYWMPWCEXG6AJ8F2",
993 "01HH9SJEG0KY16H81S3N1BMXM4",
994 "01HH9SJEG0P9M22Z9VGHH9C8CX",
995 "017F8YY0G0NQA16HHC2QT5JD6X",
996 "03QCPC7P003V1NND3B3QJW72QJ"
997 ]);
998 let url = &format!("{}/12/ulids/5", base_url);
999 let res = client.post(url).json(&ids).send().await.map_err(|_| test)?;
1000 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1001 if json
1002 != serde_json::json!({
1003 "christmas eve": 3,
1004 "weekday": 1,
1005 "in the future": 2,
1006 "LSB is 1": 5
1007 })
1008 {
1009 return Err(test);
1010 }
1011 test = (3, 2);
1012 let url = &format!("{}/12/ulids/0", base_url);
1013 let res = client.post(url).json(&ids).send().await.map_err(|_| test)?;
1014 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1015 if json
1016 != serde_json::json!({
1017 "christmas eve": 3,
1018 "weekday": 0,
1019 "in the future": 2,
1020 "LSB is 1": 5
1021 })
1022 {
1023 return Err(test);
1024 }
1025 test = (3, 3);
1026 let url = &format!("{}/12/ulids/2", base_url);
1027 let res = client
1028 .post(url)
1029 .json(&serde_json::json!(["04BJK8N300BAMR9SQQWPWHVYKZ"]))
1030 .send()
1031 .await
1032 .map_err(|_| test)?;
1033 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1034 if json
1035 != serde_json::json!({
1036 "christmas eve": 1,
1037 "weekday": 1,
1038 "in the future": 1,
1039 "LSB is 1": 1
1040 })
1041 {
1042 return Err(test);
1043 }
1044 tx.send((false, 200).into()).await.unwrap();
1046
1047 Ok(())
1048}
1049
1050async fn validate_13(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1051 let client = new_client();
1052 let mut test: TaskTest;
1053 test = (1, 1);
1055 let url = &format!("{}/13/sql", base_url);
1056 let res = client.get(url).send().await.map_err(|_| test)?;
1057 let text = res.text().await.map_err(|_| test)?;
1058 if text != "20231213" {
1059 return Err(test);
1060 }
1061 tx.send((false, 0).into()).await.unwrap();
1063 tx.send(SubmissionUpdate::Save).await.unwrap();
1064
1065 test = (2, 1);
1067 let reset_url = &format!("{}/13/reset", base_url);
1068 let order_url = &format!("{}/13/orders", base_url);
1069 let total_url = &format!("{}/13/orders/total", base_url);
1070 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1071 if res.status() != StatusCode::OK {
1072 return Err(test);
1073 }
1074 let res = client
1075 .post(order_url)
1076 .json(&serde_json::json!([
1077 {"id":1,"region_id":2,"gift_name":"Toy Train","quantity":5},
1078 {"id":2,"region_id":2,"gift_name":"Doll","quantity":8},
1079 {"id":3,"region_id":3,"gift_name":"Action Figure","quantity":12},
1080 {"id":4,"region_id":4,"gift_name":"Board Game","quantity":10},
1081 {"id":5,"region_id":2,"gift_name":"Teddy Bear","quantity":6},
1082 {"id":6,"region_id":3,"gift_name":"Toy Train","quantity":3},
1083 ]))
1084 .send()
1085 .await
1086 .map_err(|_| test)?;
1087 if res.status() != StatusCode::OK {
1088 return Err(test);
1089 }
1090 let res = client.get(total_url).send().await.map_err(|_| test)?;
1091 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1092 if json != serde_json::json!({"total": 44}) {
1093 return Err(test);
1094 }
1095 test = (2, 2);
1096 let res = client
1097 .post(order_url)
1098 .json(&serde_json::json!([
1099 {"id":123,"region_id":6,"gift_name":"Unknown","quantity":333},
1100 ]))
1101 .send()
1102 .await
1103 .map_err(|_| test)?;
1104 if res.status() != StatusCode::OK {
1105 return Err(test);
1106 }
1107 let res = client.get(total_url).send().await.map_err(|_| test)?;
1108 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1109 if json != serde_json::json!({"total": 377}) {
1110 return Err(test);
1111 }
1112 tx.send((true, 0).into()).await.unwrap();
1114 tx.send(SubmissionUpdate::Save).await.unwrap();
1115
1116 test = (3, 1);
1118 let popular_url = &format!("{}/13/orders/popular", base_url);
1119 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1120 if res.status() != StatusCode::OK {
1121 return Err(test);
1122 }
1123 let res = client.get(popular_url).send().await.map_err(|_| test)?;
1124 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1125 if json != serde_json::json!({"popular": null}) {
1126 return Err(test);
1127 }
1128 test = (3, 2);
1129 let res = client
1130 .post(order_url)
1131 .json(&serde_json::json!([
1132 {"id":1,"region_id":2,"gift_name":"Lego Rocket","quantity":12},
1133 {"id":2,"region_id":2,"gift_name":"Action Figure","quantity":18},
1134 {"id":3,"region_id":5,"gift_name":"Toy Train","quantity":19},
1135 {"id":4,"region_id":5,"gift_name":"Lego Rocket","quantity":12},
1136 {"id":5,"region_id":4,"gift_name":"Toy Train","quantity":15},
1137 {"id":6,"region_id":2,"gift_name":"Toy Train","quantity":7},
1138 {"id":7,"region_id":3,"gift_name":"Toy Train","quantity":19},
1139 {"id":8,"region_id":4,"gift_name":"Action Figure","quantity":8},
1140 {"id":9,"region_id":2,"gift_name":"Toy Axe","quantity":15},
1141 {"id":10,"region_id":4,"gift_name":"Toy Axe","quantity":1},
1142 {"id":11,"region_id":2,"gift_name":"Toy Train","quantity":17},
1143 {"id":12,"region_id":4,"gift_name":"Toy Train","quantity":5},
1144 {"id":13,"region_id":4,"gift_name":"Sweater","quantity":20},
1145 {"id":14,"region_id":4,"gift_name":"Action Figure","quantity":7},
1146 {"id":15,"region_id":2,"gift_name":"Toy Train","quantity":16},
1147 {"id":16,"region_id":3,"gift_name":"Action Figure","quantity":12},
1148 {"id":17,"region_id":4,"gift_name":"Toy Axe","quantity":2},
1149 {"id":18,"region_id":3,"gift_name":"Toy Train","quantity":9},
1150 {"id":19,"region_id":2,"gift_name":"Sweater","quantity":9},
1151 {"id":20,"region_id":5,"gift_name":"Toy Train","quantity":9},
1152 {"id":21,"region_id":4,"gift_name":"Action Figure","quantity":11},
1153 {"id":22,"region_id":3,"gift_name":"Toy Train","quantity":7},
1154 {"id":23,"region_id":2,"gift_name":"Action Figure","quantity":5},
1155 {"id":24,"region_id":4,"gift_name":"Action Figure","quantity":17},
1156 {"id":25,"region_id":5,"gift_name":"Lego Rocket","quantity":6},
1157 {"id":26,"region_id":2,"gift_name":"Sweater","quantity":5},
1158 {"id":27,"region_id":5,"gift_name":"Toy Train","quantity":4},
1159 {"id":28,"region_id":4,"gift_name":"Lego Rocket","quantity":8},
1160 {"id":29,"region_id":2,"gift_name":"Toy Train","quantity":3},
1161 {"id":30,"region_id":4,"gift_name":"Toy Axe","quantity":20},
1162 {"id":31,"region_id":2,"gift_name":"Action Figure","quantity":5},
1163 {"id":32,"region_id":2,"gift_name":"Lego Rocket","quantity":10},
1164 {"id":33,"region_id":5,"gift_name":"Toy Train","quantity":4},
1165 {"id":34,"region_id":2,"gift_name":"Toy Axe","quantity":14},
1166 {"id":35,"region_id":3,"gift_name":"Action Figure","quantity":18},
1167 {"id":36,"region_id":5,"gift_name":"Toy Axe","quantity":10},
1168 {"id":37,"region_id":4,"gift_name":"Lego Rocket","quantity":6},
1169 {"id":38,"region_id":4,"gift_name":"Action Figure","quantity":16},
1170 {"id":39,"region_id":4,"gift_name":"Toy Axe","quantity":15},
1171 {"id":40,"region_id":5,"gift_name":"Lego Rocket","quantity":15},
1172 {"id":41,"region_id":5,"gift_name":"Action Figure","quantity":7},
1173 {"id":42,"region_id":3,"gift_name":"Action Figure","quantity":16},
1174 {"id":43,"region_id":3,"gift_name":"Toy Train","quantity":8},
1175 {"id":44,"region_id":4,"gift_name":"Action Figure","quantity":13},
1176 {"id":45,"region_id":3,"gift_name":"Lego Rocket","quantity":12},
1177 {"id":46,"region_id":3,"gift_name":"Toy Train","quantity":1},
1178 {"id":47,"region_id":2,"gift_name":"Toy Train","quantity":11},
1179 {"id":48,"region_id":5,"gift_name":"Action Figure","quantity":1},
1180 {"id":49,"region_id":4,"gift_name":"Toy Train","quantity":13},
1181 {"id":50,"region_id":5,"gift_name":"Action Figure","quantity":16},
1182 {"id":51,"region_id":4,"gift_name":"Toy Axe","quantity":19},
1183 {"id":52,"region_id":2,"gift_name":"Toy Train","quantity":14},
1184 {"id":53,"region_id":3,"gift_name":"Action Figure","quantity":16},
1185 ]))
1186 .send()
1187 .await
1188 .map_err(|_| test)?;
1189 if res.status() != StatusCode::OK {
1190 return Err(test);
1191 }
1192 let res = client.get(popular_url).send().await.map_err(|_| test)?;
1193 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1194 if json != serde_json::json!({"popular": "Action Figure"}) {
1195 return Err(test);
1196 }
1197 tx.send((false, 100).into()).await.unwrap();
1199
1200 Ok(())
1201}
1202
1203async fn validate_14(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1204 let client = new_client();
1205 let mut test: TaskTest;
1206 test = (1, 1);
1208 let url = &format!("{}/14/unsafe", base_url);
1209 let res = client
1210 .post(url)
1211 .json(&serde_json::json!({"content": "Bing Chilling 🥶🍦"}))
1212 .send()
1213 .await
1214 .map_err(|_| test)?;
1215 let text = res.text().await.map_err(|_| test)?;
1216 if text
1217 != "\
1218<html>
1219 <head>
1220 <title>CCH23 Day 14</title>
1221 </head>
1222 <body>
1223 Bing Chilling 🥶🍦
1224 </body>
1225</html>"
1226 {
1227 return Err(test);
1228 }
1229 test = (1, 2);
1230 let res = client
1231 .post(url)
1232 .json(&serde_json::json!({"content": r#"<script>alert("XSS Attack Success!")</script>"#}))
1233 .send()
1234 .await
1235 .map_err(|_| test)?;
1236 let text = res.text().await.map_err(|_| test)?;
1237 if text
1238 != "\
1239<html>
1240 <head>
1241 <title>CCH23 Day 14</title>
1242 </head>
1243 <body>
1244 <script>alert(\"XSS Attack Success!\")</script>
1245 </body>
1246</html>"
1247 {
1248 return Err(test);
1249 }
1250 tx.send((true, 0).into()).await.unwrap();
1252 tx.send(SubmissionUpdate::Save).await.unwrap();
1253
1254 test = (2, 1);
1256 let url = &format!("{}/14/safe", base_url);
1257 let res = client
1258 .post(url)
1259 .json(&serde_json::json!({"content": r#"<script>alert("XSS Attack Failed!")</script>"#}))
1260 .send()
1261 .await
1262 .map_err(|_| test)?;
1263 let text = res.text().await.map_err(|_| test)?;
1264 if text
1265 != "\
1266<html>
1267 <head>
1268 <title>CCH23 Day 14</title>
1269 </head>
1270 <body>
1271 <script>alert("XSS Attack Failed!")</script>
1272 </body>
1273</html>"
1274 {
1275 return Err(test);
1276 }
1277 tx.send((false, 100).into()).await.unwrap();
1279
1280 Ok(())
1281}
1282
1283struct JSONTester {
1284 client: reqwest::Client,
1285 url: String,
1286}
1287
1288impl JSONTester {
1289 fn new(url: String) -> Self {
1290 Self {
1291 client: new_client(),
1292 url,
1293 }
1294 }
1295 async fn test(
1296 &self,
1297 test: TaskTest,
1298 i: &serde_json::Value,
1299 code: StatusCode,
1300 o: &serde_json::Value,
1301 ) -> ValidateResult {
1302 let res = self
1303 .client
1304 .post(&self.url)
1305 .json(i)
1306 .send()
1307 .await
1308 .map_err(|_| test)?;
1309 if res.status() != code {
1310 return Err(test);
1311 }
1312 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1313 if json != *o {
1314 return Err(test);
1315 }
1316 Ok(())
1317 }
1318}
1319
1320async fn validate_15(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1321 let t = JSONTester::new(format!("{}/15/nice", base_url));
1323 t.test(
1324 (1, 1),
1325 &serde_json::json!({"input": "hello there"}),
1326 StatusCode::OK,
1327 &serde_json::json!({"result": "nice"}),
1328 )
1329 .await?;
1330 t.test(
1331 (1, 2),
1332 &serde_json::json!({"input": "he77o there"}),
1333 StatusCode::BAD_REQUEST,
1334 &serde_json::json!({"result": "naughty"}),
1335 )
1336 .await?;
1337 t.test(
1338 (1, 3),
1339 &serde_json::json!({"input": "hello"}),
1340 StatusCode::BAD_REQUEST,
1341 &serde_json::json!({"result": "naughty"}),
1342 )
1343 .await?;
1344 t.test(
1345 (1, 4),
1346 &serde_json::json!({"input": "hello xylophone"}),
1347 StatusCode::BAD_REQUEST,
1348 &serde_json::json!({"result": "naughty"}),
1349 )
1350 .await?;
1351 t.test(
1352 (1, 5),
1353 &serde_json::json!({"input": "password"}),
1354 StatusCode::BAD_REQUEST,
1355 &serde_json::json!({"result": "naughty"}),
1356 )
1357 .await?;
1358 let test = (1, 6);
1359 let res = new_client()
1360 .post(format!("{}/15/nice", base_url))
1361 .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
1362 .body("WooooOOOooOOOoooOO 👻")
1363 .send()
1364 .await
1365 .map_err(|_| test)?;
1366 if res.status() != StatusCode::BAD_REQUEST {
1367 return Err(test);
1368 }
1369 tx.send((true, 0).into()).await.unwrap();
1371 tx.send(SubmissionUpdate::Save).await.unwrap();
1372
1373 let t = JSONTester::new(format!("{}/15/game", base_url));
1375 t.test(
1376 (2, 1),
1377 &serde_json::json!({"input": "mario"}),
1378 StatusCode::BAD_REQUEST,
1379 &serde_json::json!({"result": "naughty", "reason": "8 chars"}),
1380 )
1381 .await?;
1382 t.test(
1383 (2, 2),
1384 &serde_json::json!({"input": "mariobro"}),
1385 StatusCode::BAD_REQUEST,
1386 &serde_json::json!({"result": "naughty", "reason": "more types of chars"}),
1387 )
1388 .await?;
1389 t.test(
1390 (2, 3),
1391 &serde_json::json!({"input": "EEEEEEEEEEE"}),
1392 StatusCode::BAD_REQUEST,
1393 &serde_json::json!({"result": "naughty", "reason": "more types of chars"}),
1394 )
1395 .await?;
1396 t.test(
1397 (2, 4),
1398 &serde_json::json!({"input": "E3E3E3E3E3E"}),
1399 StatusCode::BAD_REQUEST,
1400 &serde_json::json!({"result": "naughty", "reason": "more types of chars"}),
1401 )
1402 .await?;
1403 t.test(
1404 (2, 5),
1405 &serde_json::json!({"input": "e3E3e#eE#ee3#EeE3"}),
1406 StatusCode::BAD_REQUEST,
1407 &serde_json::json!({"result": "naughty", "reason": "55555"}),
1408 )
1409 .await?;
1410 t.test(
1411 (2, 6),
1412 &serde_json::json!({"input": "Password12345"}),
1413 StatusCode::BAD_REQUEST,
1414 &serde_json::json!({"result": "naughty", "reason": "math is hard"}),
1415 )
1416 .await?;
1417 t.test(
1418 (2, 7),
1419 &serde_json::json!({"input": "2 00 2 3 OOgaBooga"}),
1420 StatusCode::BAD_REQUEST,
1421 &serde_json::json!({"result": "naughty", "reason": "math is hard"}),
1422 )
1423 .await?;
1424 t.test(
1425 (2, 8),
1426 &serde_json::json!({"input": "2+2/2-8*8 = 1-2000 OOgaBooga"}),
1427 StatusCode::NOT_ACCEPTABLE,
1428 &serde_json::json!({"result": "naughty", "reason": "not joyful enough"}),
1429 )
1430 .await?;
1431 t.test(
1432 (2, 9),
1433 &serde_json::json!({"input": "2000.23.A yoyoj"}),
1434 StatusCode::NOT_ACCEPTABLE,
1435 &serde_json::json!({"result": "naughty", "reason": "not joyful enough"}),
1436 )
1437 .await?;
1438 t.test(
1439 (2, 10),
1440 &serde_json::json!({"input": "2000.23.A joy joy"}),
1441 StatusCode::NOT_ACCEPTABLE,
1442 &serde_json::json!({"result": "naughty", "reason": "not joyful enough"}),
1443 )
1444 .await?;
1445 t.test(
1446 (2, 11),
1447 &serde_json::json!({"input": "2000.23.A joyo"}),
1448 StatusCode::NOT_ACCEPTABLE,
1449 &serde_json::json!({"result": "naughty", "reason": "not joyful enough"}),
1450 )
1451 .await?;
1452 t.test(
1453 (2, 12),
1454 &serde_json::json!({"input": "2000.23.A j ;) o ;) y "}),
1455 StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
1456 &serde_json::json!({"result": "naughty", "reason": "illegal: no sandwich"}),
1457 )
1458 .await?;
1459 t.test(
1460 (2, 13),
1461 &serde_json::json!({"input": "2020.3.A j ;) o ;) y"}),
1462 StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
1463 &serde_json::json!({"result": "naughty", "reason": "illegal: no sandwich"}),
1464 )
1465 .await?;
1466 t.test(
1467 (2, 14),
1468 &serde_json::json!({"input": "2000.23.A j ;) o ;) y AzA"}),
1469 StatusCode::RANGE_NOT_SATISFIABLE,
1470 &serde_json::json!({"result": "naughty", "reason": "outranged"}),
1471 )
1472 .await?;
1473 t.test(
1474 (2, 15),
1475 &serde_json::json!({"input": "2000.23.A j ;) o ;) y⥿ AzA"}),
1476 StatusCode::RANGE_NOT_SATISFIABLE,
1477 &serde_json::json!({"result": "naughty", "reason": "outranged"}),
1478 )
1479 .await?;
1480 t.test(
1481 (2, 16),
1482 &serde_json::json!({"input": "2000.23.A j ;) o ;) y ⦄AzA"}),
1483 StatusCode::UPGRADE_REQUIRED,
1484 &serde_json::json!({"result": "naughty", "reason": "😳"}),
1485 )
1486 .await?;
1487 t.test(
1488 (2, 17),
1489 &serde_json::json!({"input": "2000.23.A j 🥶 o 🍦 y ⦄AzA"}),
1490 StatusCode::IM_A_TEAPOT,
1491 &serde_json::json!({"result": "naughty", "reason": "not a coffee brewer"}),
1492 )
1493 .await?;
1494 t.test(
1495 (2, 18),
1496 &serde_json::json!({"input": "2000.23.A j ⦖⦖⦖⦖⦖⦖⦖⦖ 🥶 o 🍦 y ⦄AzA"}),
1497 StatusCode::OK,
1498 &serde_json::json!({"result": "nice", "reason": "that's a nice password"}),
1499 )
1500 .await?;
1501 tx.send((false, 400).into()).await.unwrap();
1503
1504 Ok(())
1505}
1506
1507struct RegionGiftTester {
1508 client: reqwest::Client,
1509 reset_url: String,
1510 regions_url: String,
1511 orders_url: String,
1512 final_url: String,
1513}
1514
1515impl RegionGiftTester {
1516 async fn test(
1517 &self,
1518 test: TaskTest,
1519 i1: &serde_json::Value,
1520 i2: &serde_json::Value,
1521 o: &serde_json::Value,
1522 ) -> ValidateResult {
1523 let res = self
1524 .client
1525 .post(&self.reset_url)
1526 .send()
1527 .await
1528 .map_err(|_| test)?;
1529 if res.status() != StatusCode::OK {
1530 return Err(test);
1531 }
1532 let res = self
1533 .client
1534 .post(&self.regions_url)
1535 .json(i1)
1536 .send()
1537 .await
1538 .map_err(|_| test)?;
1539 if res.status() != StatusCode::OK {
1540 return Err(test);
1541 }
1542 let res = self
1543 .client
1544 .post(&self.orders_url)
1545 .json(i2)
1546 .send()
1547 .await
1548 .map_err(|_| test)?;
1549 if res.status() != StatusCode::OK {
1550 return Err(test);
1551 }
1552 let res = self
1553 .client
1554 .get(&self.final_url)
1555 .send()
1556 .await
1557 .map_err(|_| test)?;
1558 if res.status() != StatusCode::OK {
1559 return Err(test);
1560 }
1561 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1562 if json != *o {
1563 return Err(test);
1564 }
1565 Ok(())
1566 }
1567}
1568
1569async fn validate_18(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1570 let t = RegionGiftTester {
1572 client: new_client(),
1573 reset_url: format!("{}/18/reset", base_url),
1574 regions_url: format!("{}/18/regions", base_url),
1575 orders_url: format!("{}/18/orders", base_url),
1576 final_url: format!("{}/18/regions/total", base_url),
1577 };
1578 t.test(
1579 (1, 1),
1580 &serde_json::json!([{"id":1,"name":"North Pole"}]),
1581 &serde_json::json!([]),
1582 &serde_json::json!([]),
1583 )
1584 .await?;
1585 t.test(
1586 (1, 2),
1587 &serde_json::json!([]),
1588 &serde_json::json!([{"id":1,"region_id":2,"gift_name":"Board Game","quantity":5}]),
1589 &serde_json::json!([]),
1590 )
1591 .await?;
1592 t.test(
1593 (1, 3),
1594 &serde_json::json!([{"id":1,"name":"A"}]),
1595 &serde_json::json!([{"id":1,"region_id":1,"gift_name":"A","quantity":1}]),
1596 &serde_json::json!([{"region":"A","total":1}]),
1597 )
1598 .await?;
1599 t.test(
1600 (1, 4),
1601 &serde_json::json!([{"id":1,"name":"A"}]),
1602 &serde_json::json!([
1603 {"id":1,"region_id":1,"gift_name":"A","quantity":1},
1604 {"id":2,"region_id":1,"gift_name":"A","quantity":1},
1605 {"id":3,"region_id":1,"gift_name":"A","quantity":1}
1606 ]),
1607 &serde_json::json!([{"region":"A","total":3}]),
1608 )
1609 .await?;
1610 t.test(
1611 (1, 5),
1612 &serde_json::json!([
1613 {"id":1,"name":"A"},
1614 {"id":2,"name":"B"}
1615 ]),
1616 &serde_json::json!([
1617 {"id":1,"region_id":1,"gift_name":"A","quantity":1},
1618 {"id":2,"region_id":1,"gift_name":"A","quantity":1},
1619 {"id":3,"region_id":2,"gift_name":"B","quantity":1}
1620 ]),
1621 &serde_json::json!([
1622 {"region":"A","total":2},
1623 {"region":"B","total":1}
1624 ]),
1625 )
1626 .await?;
1627 t.test(
1628 (1, 6),
1629 &serde_json::json!([
1630 {"id":1,"name":"A"},
1631 {"id":2,"name":"B"}
1632 ]),
1633 &serde_json::json!([
1634 {"id":1,"region_id":1,"gift_name":"A","quantity":1},
1635 {"id":2,"region_id":1,"gift_name":"A","quantity":1},
1636 {"id":3,"region_id":3,"gift_name":"C","quantity":1}
1637 ]),
1638 &serde_json::json!([{"region":"A","total":2}]),
1639 )
1640 .await?;
1641 t.test(
1642 (1, 7),
1643 &serde_json::json!([{"id":1,"name":"A"}]),
1644 &serde_json::json!([{"id":1,"region_id":1,"gift_name":"A","quantity":555555555}]),
1645 &serde_json::json!([{"region":"A","total":555555555}]),
1646 )
1647 .await?;
1648 t.test(
1649 (1, 8),
1650 &serde_json::json!([{"id":-1,"name":"A"}]),
1651 &serde_json::json!([
1652 {"id":-1,"region_id":-1,"gift_name":"A","quantity":-1},
1653 {"id":0,"region_id":-1,"gift_name":"A","quantity":1}
1654 ]),
1655 &serde_json::json!([{"region":"A","total":0}]),
1656 )
1657 .await?;
1658 tx.send((true, 0).into()).await.unwrap();
1660 tx.send(SubmissionUpdate::Save).await.unwrap();
1661
1662 let t = RegionGiftTester {
1664 client: new_client(),
1665 reset_url: format!("{}/18/reset", base_url),
1666 regions_url: format!("{}/18/regions", base_url),
1667 orders_url: format!("{}/18/orders", base_url),
1668 final_url: format!("{}/18/regions/top_list/2", base_url),
1669 };
1670 t.test(
1671 (2, 1),
1672 &serde_json::json!([]),
1673 &serde_json::json!([]),
1674 &serde_json::json!([]),
1675 )
1676 .await?;
1677 t.test(
1678 (2, 2),
1679 &serde_json::json!([{"id":1,"name":"A"}]),
1680 &serde_json::json!([]),
1681 &serde_json::json!([{"region":"A","top_gifts":[]}]),
1682 )
1683 .await?;
1684 t.test(
1685 (2, 3),
1686 &serde_json::json!([]),
1687 &serde_json::json!([{"id":1,"region_id":2,"gift_name":"B","quantity":5}]),
1688 &serde_json::json!([]),
1689 )
1690 .await?;
1691 t.test(
1692 (2, 4),
1693 &serde_json::json!([{"id":1,"name":"A"}]),
1694 &serde_json::json!([{"id":1,"region_id":2,"gift_name":"B","quantity":5}]),
1695 &serde_json::json!([{"region":"A","top_gifts":[]}]),
1696 )
1697 .await?;
1698 t.test(
1699 (2, 5),
1700 &serde_json::json!([{"id":1,"name":"A"}]),
1701 &serde_json::json!([
1702 {"id":1,"region_id":1,"gift_name":"B","quantity":10},
1703 {"id":2,"region_id":1,"gift_name":"A","quantity":5},
1704 {"id":3,"region_id":1,"gift_name":"A","quantity":5},
1705 {"id":4,"region_id":1,"gift_name":"C","quantity":9}
1706 ]),
1707 &serde_json::json!([{"region":"A","top_gifts":["A","B"]}]),
1708 )
1709 .await?;
1710 let regions = serde_json::json!([
1711 {"id":1,"name":"North Pole"},
1712 {"id":2,"name":"Europe"},
1713 {"id":3,"name":"North America"},
1714 {"id":4,"name":"South America"},
1715 {"id":5,"name":"Africa"},
1716 {"id":6,"name":"Asia"},
1717 {"id":7,"name":"Oceania"}
1718 ]);
1719 t.test(
1720 (2, 6),
1721 ®ions,
1722 &serde_json::json!([
1723 {"id":1,"region_id":2,"gift_name":"Toy Train","quantity":5},
1724 {"id":2,"region_id":2,"gift_name":"Toy Train","quantity":3},
1725 {"id":3,"region_id":2,"gift_name":"Doll","quantity":8},
1726 {"id":4,"region_id":3,"gift_name":"Toy Train","quantity":3},
1727 {"id":5,"region_id":2,"gift_name":"Teddy Bear","quantity":6},
1728 {"id":6,"region_id":3,"gift_name":"Action Figure","quantity":12},
1729 {"id":7,"region_id":4,"gift_name":"Board Game","quantity":10},
1730 {"id":8,"region_id":3,"gift_name":"Teddy Bear","quantity":1},
1731 {"id":9,"region_id":3,"gift_name":"Teddy Bear","quantity":2}
1732 ]),
1733 &serde_json::json!([
1734 {"region":"Africa","top_gifts":[]},
1735 {"region":"Asia","top_gifts":[]},
1736 {"region":"Europe","top_gifts":["Doll","Toy Train"]},
1737 {"region":"North America","top_gifts":["Action Figure","Teddy Bear"]},
1738 {"region":"North Pole","top_gifts":[]},
1739 {"region":"Oceania","top_gifts":[]},
1740 {"region":"South America","top_gifts":["Board Game"]},
1741 ]),
1742 )
1743 .await?;
1744 let t = RegionGiftTester {
1745 client: new_client(),
1746 reset_url: format!("{}/18/reset", base_url),
1747 regions_url: format!("{}/18/regions", base_url),
1748 orders_url: format!("{}/18/orders", base_url),
1749 final_url: format!("{}/18/regions/top_list/3", base_url),
1750 };
1751 t.test(
1752 (2, 7),
1753 ®ions,
1754 &serde_json::json!([
1755 {"id":1,"region_id":2,"gift_name":"Toy Train","quantity":5},
1756 {"id":2,"region_id":2,"gift_name":"Toy Train","quantity":3},
1757 {"id":3,"region_id":2,"gift_name":"Doll","quantity":8},
1758 {"id":4,"region_id":3,"gift_name":"Toy Train","quantity":3},
1759 {"id":5,"region_id":2,"gift_name":"Teddy Bear","quantity":6},
1760 {"id":6,"region_id":3,"gift_name":"Action Figure","quantity":12},
1761 {"id":7,"region_id":4,"gift_name":"Board Game","quantity":10},
1762 {"id":8,"region_id":3,"gift_name":"Teddy Bear","quantity":1},
1763 {"id":9,"region_id":3,"gift_name":"Teddy Bear","quantity":2}
1764 ]),
1765 &serde_json::json!([
1766 {"region":"Africa","top_gifts":[]},
1767 {"region":"Asia","top_gifts":[]},
1768 {"region":"Europe","top_gifts":["Doll","Toy Train","Teddy Bear"]},
1769 {"region":"North America","top_gifts":["Action Figure","Teddy Bear","Toy Train"]},
1770 {"region":"North Pole","top_gifts":[]},
1771 {"region":"Oceania","top_gifts":[]},
1772 {"region":"South America","top_gifts":["Board Game"]},
1773 ]),
1774 )
1775 .await?;
1776 let t = RegionGiftTester {
1777 client: new_client(),
1778 reset_url: format!("{}/18/reset", base_url),
1779 regions_url: format!("{}/18/regions", base_url),
1780 orders_url: format!("{}/18/orders", base_url),
1781 final_url: format!("{}/18/regions/top_list/0", base_url),
1782 };
1783 t.test(
1784 (2, 8),
1785 &serde_json::json!([{"id":1,"name":"A"}]),
1786 &serde_json::json!([{"id":1,"region_id":1,"gift_name":"A","quantity":555555555}]),
1787 &serde_json::json!([{"region":"A","top_gifts":[]}]),
1788 )
1789 .await?;
1790 tx.send((false, 600).into()).await.unwrap();
1792
1793 Ok(())
1794}
1795
1796struct WS {
1797 test: TaskTest,
1798 w: SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>,
1799 r: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
1800}
1801
1802impl WS {
1803 async fn new(test: TaskTest, url: String) -> Result<Self, TaskTest> {
1804 let (s, _) = tokio_tungstenite::connect_async(url)
1805 .await
1806 .map_err(|_| test)?;
1807 let (w, r) = s.split();
1808
1809 Ok(Self { test, w, r })
1810 }
1811
1812 async fn send(&mut self, msg: impl Into<String>) -> ValidateResult {
1813 self.w
1814 .send(Message::Text(msg.into()))
1815 .await
1816 .map_err(|_| self.test)
1817 }
1818
1819 async fn send_tweet(&mut self, msg: impl Into<String>) -> ValidateResult {
1820 self.send(serde_json::to_string(&serde_json::json!({"message": msg.into()})).unwrap())
1821 .await
1822 }
1823
1824 async fn recv(&mut self) -> Result<String, TaskTest> {
1825 let Some(Ok(Message::Text(text))) = self.r.next().await else {
1826 return Err(self.test);
1827 };
1828
1829 Ok(text)
1830 }
1831
1832 async fn recv_str(&mut self, exp: &str) -> ValidateResult {
1833 let text = self.recv().await?;
1834 if text != exp {
1835 return Err(self.test);
1836 }
1837
1838 Ok(())
1839 }
1840
1841 async fn recv_json(&mut self, exp: &serde_json::Value) -> ValidateResult {
1842 let text = self.recv().await?;
1843 let json = serde_json::from_str::<serde_json::Value>(&text).map_err(|_| self.test)?;
1844 if &json != exp {
1845 return Err(self.test);
1846 }
1847
1848 Ok(())
1849 }
1850
1851 async fn close(mut self) -> ValidateResult {
1852 self.w.close().await.map_err(|_| self.test)?;
1853
1854 Ok(())
1855 }
1856}
1857
1858async fn validate_19(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1859 let mut test: TaskTest;
1860 let ws_base_url = format!(
1861 "ws{}",
1862 base_url
1863 .strip_prefix("http")
1864 .expect("url to begin with http")
1865 );
1866 test = (1, 1);
1868 let mut ws = WS::new(test, format!("{}/19/ws/ping", ws_base_url)).await?;
1869 ws.send("ping").await?;
1870 tokio::select! {
1871 _ = ws.recv() => {
1872 return Err(test);
1873 },
1874 _ = sleep(Duration::from_secs(1)) => (),
1875 };
1876 ws.send("serve").await?;
1877 ws.send("ping").await?;
1878 ws.recv_str("pong").await?;
1879 test = (1, 2);
1880 ws.test = test;
1881 ws.send("ding").await?;
1882 tokio::select! {
1883 _ = ws.recv() => {
1884 return Err(test);
1885 },
1886 _ = sleep(Duration::from_secs(1)) => (),
1887 };
1888 test = (1, 3);
1889 ws.test = test;
1890 ws.send("ping").await?;
1891 ws.send("ping").await?;
1892 ws.recv_str("pong").await?;
1893 ws.recv_str("pong").await?;
1894 tokio::select! {
1895 _ = ws.recv() => {
1896 return Err(test);
1897 },
1898 _ = sleep(Duration::from_millis(500)) => (),
1899 };
1900 ws.close().await?;
1901 tx.send((true, 0).into()).await.unwrap();
1903 tx.send(SubmissionUpdate::Save).await.unwrap();
1904
1905 let reset_url = &format!("{}/19/reset", base_url);
1907 let reset = || async move {
1908 let client = new_client();
1909 let res = client.post(reset_url).send().await.map_err(|_| ())?;
1910 if res.status() != StatusCode::OK {
1911 return Err(());
1912 }
1913 Ok(())
1914 };
1915 let views_url = &format!("{}/19/views", base_url);
1916 let ensure_views = |v: u32| async move {
1917 let client = new_client();
1918 let res = client.get(views_url).send().await.map_err(|_| ())?;
1919 let text = res.text().await.map_err(|_| ())?;
1920 if text != v.to_string() {
1921 return Err(());
1922 }
1923 Ok(())
1924 };
1925
1926 test = (2, 1);
1927 reset().await.map_err(|_| test)?;
1928 ensure_views(0).await.map_err(|_| test)?;
1929
1930 test = (2, 2);
1931 let mut elon = WS::new(test, format!("{}/19/ws/room/1/user/elonmusk", ws_base_url)).await?;
1932 let s = "Next I'm buying Coca-Cola to put the cocaine back in";
1933 elon.send_tweet(s).await?;
1934 elon.recv_json(&serde_json::json!({"user": "elonmusk", "message": s}))
1935 .await?;
1936 ensure_views(1).await.map_err(|_| test)?;
1937
1938 test = (2, 3);
1939 let s = "I've concocted a whimsical idea to bring a bit of the ol' history back to life by attempting to put the cocaine back in Coca-Cola, rekindling the rebellious spirit of its original formulation";
1940 elon.send_tweet(s).await?;
1941 tokio::select! {
1942 _ = elon.recv() => {
1943 return Err(test);
1944 },
1945 _ = sleep(Duration::from_secs(1)) => (),
1946 };
1947 ensure_views(1).await.map_err(|_| test)?;
1948 elon.close().await?;
1949 sleep(Duration::from_millis(10)).await;
1950
1951 test = (2, 4);
1952 reset().await.map_err(|_| test)?;
1953 ensure_views(0).await.map_err(|_| test)?;
1954 let mut a1 = WS::new(test, format!("{}/19/ws/room/44/user/annifrid", ws_base_url)).await?;
1955 let mut b1 = WS::new(test, format!("{}/19/ws/room/55/user/bjorn", ws_base_url)).await?;
1956 let mut b2 = WS::new(test, format!("{}/19/ws/room/55/user/benny", ws_base_url)).await?;
1957 let mut a2 = WS::new(test, format!("{}/19/ws/room/44/user/agnetha", ws_base_url)).await?;
1958 let l1 = "thank you for the music";
1959 let l2 = "the songs i'm singing";
1960 let l3 = "thanks for all";
1961 let l4 = "the joy they're bringing";
1962 let l5 = "who can live without it";
1963 let l6 = "i ask in all honesty";
1964 let x1 = "uhhhhhhhh?";
1965 let x2 = "wazzaaaaa?";
1966 a1.send_tweet(l1).await?;
1967 sleep(Duration::from_millis(10)).await;
1968 a2.send_tweet(l2).await?;
1969 sleep(Duration::from_millis(10)).await;
1970 a1.send_tweet(l3).await?;
1971 sleep(Duration::from_millis(10)).await;
1972 b1.send_tweet(x1).await?;
1973 sleep(Duration::from_millis(10)).await;
1974 a2.send_tweet(l4).await?;
1975 sleep(Duration::from_millis(10)).await;
1976 a1.send_tweet(l5).await?;
1977 sleep(Duration::from_millis(10)).await;
1978 a1.recv_json(&serde_json::json!({"user": "annifrid", "message": l1}))
1979 .await?;
1980 a2.recv_json(&serde_json::json!({"user": "annifrid", "message": l1}))
1981 .await?;
1982 a1.recv_json(&serde_json::json!({"user": "agnetha", "message": l2}))
1983 .await?;
1984 a2.recv_json(&serde_json::json!({"user": "agnetha", "message": l2}))
1985 .await?;
1986 a1.recv_json(&serde_json::json!({"user": "annifrid", "message": l3}))
1987 .await?;
1988 a2.recv_json(&serde_json::json!({"user": "annifrid", "message": l3}))
1989 .await?;
1990 a1.recv_json(&serde_json::json!({"user": "agnetha", "message": l4}))
1991 .await?;
1992 a2.recv_json(&serde_json::json!({"user": "agnetha", "message": l4}))
1993 .await?;
1994 a1.recv_json(&serde_json::json!({"user": "annifrid", "message": l5}))
1995 .await?;
1996 a2.recv_json(&serde_json::json!({"user": "annifrid", "message": l5}))
1997 .await?;
1998 sleep(Duration::from_millis(10)).await;
1999 ensure_views(12).await.map_err(|_| test)?;
2000
2001 test = (2, 5);
2002 a1.close().await?;
2003 sleep(Duration::from_millis(10)).await;
2004 a2.send_tweet(l6).await?;
2005 a2.recv_json(&serde_json::json!({"user": "agnetha", "message": l6}))
2006 .await?;
2007 sleep(Duration::from_millis(10)).await;
2008 ensure_views(13).await.map_err(|_| test)?;
2009
2010 test = (2, 6);
2011 let mut a1 = WS::new(test, format!("{}/19/ws/room/55/user/annifrid", ws_base_url)).await?;
2012 tokio::select! {
2013 _ = a1.recv() => {
2014 return Err(test);
2015 },
2016 _ = sleep(Duration::from_secs(1)) => (),
2017 };
2018 b1.recv_json(&serde_json::json!({"user": "bjorn", "message": x1}))
2019 .await?;
2020 b2.recv_json(&serde_json::json!({"user": "bjorn", "message": x1}))
2021 .await?;
2022 a1.send_tweet(x2).await?;
2023 sleep(Duration::from_millis(10)).await;
2024 b1.close().await?;
2025 a1.send_tweet(x2).await?;
2026 b2.recv_json(&serde_json::json!({"user": "annifrid", "message": x2}))
2027 .await?;
2028 b2.recv_json(&serde_json::json!({"user": "annifrid", "message": x2}))
2029 .await?;
2030 a1.recv_json(&serde_json::json!({"user": "annifrid", "message": x2}))
2031 .await?;
2032 a1.recv_json(&serde_json::json!({"user": "annifrid", "message": x2}))
2033 .await?;
2034 sleep(Duration::from_millis(10)).await;
2035 ensure_views(18).await.map_err(|_| test)?;
2036
2037 test = (2, 7);
2038 reset().await.map_err(|_| test)?;
2039 ensure_views(0).await.map_err(|_| test)?;
2040 let phrases = Arc::new([
2042 "Okilydokily Give me praise Shhh how high umm what now epic fail mine",
2043 "quite Wow Shhh driving wot exorbitant Church",
2044 "whatcha talkin' 'bout chaos look buddy husband good pow Shalom",
2045 "joking don't have a cow so let it be written you should be so lucky taxes wonderbread spirit",
2046 "radio dean scream slumin big fish begs the question unemployment red fang",
2047 "radio Is that your final answer how goes it where's the love unsung hero yep fool",
2048 "yeah ghetto pardon the french happy middle class what a mess Isn't that special",
2049 "incoming you better not husband hope driving Watch this thank you very much",
2050 "I didn't see that sex won't you be my neighbor What take your pick naughty delicious",
2051 "you're in big trouble hypocrite won't you be my neighbor not in kansas anymore angel joy look on the brightside",
2052 "money freak joyful bizarre ahh go ahead make my day HolySpirit",
2053 "Han shot first awesome CIA what's up king of mars what's the plan do you like it",
2054 "woot ridiculous in a perfect world in other words It's nice being God I was just thinking joker",
2055 "lying depressing gluttony thank you very much think you could do better charity rip off",
2056 "how come You da man gosh chaos what a mess frown vengeance",
2057 "when hell freezes over resume theft I had a crazy dream dude such a scoffer not good Wow",
2058 "in a perfect world rose colored glasses quite That's gonna leave a mark slumin That's my favorite I have an idea",
2059 "you don't say I'm not sure what a nightmare well I never be quiet bird fortitude when hell freezes over",
2060 "scum you're in big trouble you see the light I'm bored who are you to judge because I said so by the way",
2061 "nevada cheerful vermin threads boss Yes you are I planned that",
2062 "high mucky muck Isn't that special what a mess mine pet energy that's your opinion",
2063 "et tu who's to say tattle tale oh my I'm good you good you owe me yuck",
2064 "praying patience genius I'm in suspense how high Venus I didn't do it",
2065 "Terry the Mom rum bitty di do it Zap I veto that",
2066 "hotel I got your back on the otherhand not good chess chill out talk to my lawyer",
2067 "in a perfect world I'm on a roll Yawn rubbish boss hold on a minute sports",
2068 "Varoom it'd take a miracle ohh thank you naughty Terry make my day outrageous",
2069 "atrocious Icarus hate piety one small step phasors on stun take your pick",
2070 "whazza matter for you not a chance in hell ridiculous whoop there it is little fish hilarious close your eyes",
2071 "you'll see yep this might end badly news to me red fang that's for me to know you're nuts",
2072 "what part of God do you not understand what's it to you laziness I donno ha whale beam me up",
2073 "sess me yep joy hurts my head chaos be happy okay",
2074 "how about that Pullin the dragons tail prosperity mocking refreshing StephenHawking my bad",
2075 "boss quite beep beep study dang it population basket case",
2076 "hobnob no you cant employee jealousy one of the secret words are REMOTE lift uh huh are you deaf",
2077 "bickering skills thats laughable theres no place like home king of mars repeat after me go ahead make my day",
2078 "music you should be so lucky in theory no more tears do you know what time it is Angel it's hopeless",
2079 "couldnt possibly bad ol puddytat husband anger yep atheist et tu",
2080 "FBI energy lust well I never dance I'm the boss manufacturing",
2081 "think you could do better gluttony Shalom I didn't see that voodoo Han shot first how could you",
2082 "virtue experts just between us drama like like vengeance charity",
2083 "incredibly don't have a cow got the life Russia rufus! basically Is that so",
2084 "I planned that white trash failure to communicate check this out virtue crash and burn let's see",
2085 "check this out sloth news to me but of course NOT do it shucks",
2086 "It grieves me you're no fun cursing rufus! sess me rose colored glasses Church",
2087 "dance bizarre these cans are defective frown Knock you upside the head no more tears I am not amused",
2088 "manufacturing adjusted for inflation application Jedi mind trick do I have to praise Venus",
2089 "I'll let you know you're not all there are you I'm impressed talk to my lawyer abnormal This cant be william wallace frown",
2090 "Putin This cant be william wallace California rum bitty di end begs the question look buddy",
2091 "shist Greece failure to communicate you'll see rich left field Mom",
2092 "thats right you're wonderful you never know really that's your opinion what's up ice cream",
2093 "class class shutup tree hugger news to me just between us ROFLMAO not good not",
2094 "do it smile You fix it services liberal study I'm God and you're not",
2095 "chump change I'm feeling nice today thats just wrong you're fired it figures God smack Oy",
2096 "One finger salute ba ha won't you be my neighbor bring it on don't mention it talk to my lawyer exorbitant",
2097 "phasors on stun ohh thank you Yes you are how goes it nut job come and get me I got your back",
2098 "tattle tale you shouldn't have you're wonderful perfect Give me praise I veto that Is that so",
2099 "fabulous stuff pride Pope You know ordinarily ho ho ho",
2100 "ouch CIA study application phasors on stun not a chance in hell I'm not sure",
2101 "energy Isn't that special piety unsung hero guilty downer you owe me",
2102 "now you tell me no more hypocrite food one small step bad ol puddytat you're not all there are you",
2103 "depressing Ivy league I was just thinking umm I can't believe it ipod angel",
2104 "WooHoo place in theory strip African hello a flag on that play",
2105 "slumin grumble here now I'll get right on it frown If had my druthers over the top",
2106 "doh naughty joy NeilDeGrasseTyson sports nut job now you tell me",
2107 "commanded lust Yes you are don't worry recipe nope evolution",
2108 "manufacturing because I said so pride straighten up I'm on a roll quit it evolution",
2109 "Mom a likely story I'm off today Is that so don't mention it surprise surprise grumble",
2110 "arrogant won't you be my neighbor exports act yep Terry I have an idea",
2111 "reverse engineer I could be wrong news to me nope employee love foul",
2112 "conservative thank you very much commanded I'll let you know let me count the ways funny theres no place like home",
2113 "handyman yeah You get what you pray for whale gambling delightful sloth",
2114 "I'll think about it in theory awful Mom what a mess radio rum bitty di",
2115 "holy grail glam fortitude have fun depressing who are you to judge take your pick",
2116 "incoming in a galaxy far far away blessing spirit Pullin the dragons tail computers red fang",
2117 "beam me up Mom money boss fake prosperity scorning",
2118 "umm what now one more time nevada completely what's the plan rum bitty di no news is good news",
2119 "okay exorbitant hopefully mocking is it just me or I pity the fool that's your opinion",
2120 "because I said so kick back wot vote it's my world Pope charged",
2121 "money wazz up with that in other words I'm God who the hell are you tattle tale you're lucky don't count on it",
2122 "small talk genius lying here now mocking other smart",
2123 "you're lucky smurfs no way dude tree hugger abnormal You da man it's my world",
2124 "couldn't be better sloth look buddy we ve already got one holy grail take the day off ehheh that's all folks",
2125 "don't worry relax baffling whoop there it is phasors on stun lighten up I hate when that happens",
2126 "yeah illogical astrophysics not good busybody bye funny",
2127 "I hate when that happens food fancy it'd take a miracle shist pick me pick me sloth",
2128 "check this out wonderful ba ha Moses It's nice being God I don't care abnormal",
2129 "ipod here now one small step Ivy league that's your opinion you think I'm joking programming",
2130 "super computer happy GarryKasparov I be like smile God after a break",
2131 "Oh really it'd take a miracle nut job you owe me Pope holy grail dude such a scoffer",
2132 "genius humility California holier than thou persistence Isn't that special absetively posilutely",
2133 "desert break some woopass on you rufus! super computer stuff I'm thrilled the",
2134 "yep not too shabby voodoo you should be so lucky You da man boss Knock you upside the head",
2135 "joyful boss you're fired yada yada yada close your eyes look out you'll see",
2136 "Varoom food don't have a cow run away got the life You know stuff",
2137 "play is it just me or tiffanies vermin God is not mocked bad what luck",
2138 "by the way hotel pow study courage I can't believe it I pity the fool",
2139 "failure is not an option how hard could it be ridiculous what do you want nerd bring it on Dad",
2140 "spirit king of mars I'm off today threads oh oh what's the plan so he sess",
2141 "are you feeling lucky do not disturb here now bring it on Bam Dad red fang",
2142 ]);
2143 let mut joins = tokio::task::JoinSet::<ValidateResult>::new();
2144 let mut tasks = vec![];
2145 let views_url = Arc::new(views_url.clone());
2146 for i in 0..5 {
2147 let u = ws_base_url.clone();
2148 let ps = phrases.clone();
2149 let views_url = views_url.clone();
2150 let mut user = WS::new(test, format!("{}/19/ws/room/1/user/{}", u, i)).await?;
2151 tasks.push(async move {
2152 for (ii, p) in ps.iter().enumerate() {
2153 user.send_tweet(*p).await?;
2154 sleep(Duration::from_millis(150)).await;
2155 if i == 0 && ii == 50 {
2156 let client = new_client();
2157 client
2158 .get(views_url.deref())
2159 .send()
2160 .await
2161 .map_err(|_| test)?;
2162 }
2163 }
2164 sleep(Duration::from_secs(2)).await;
2165 user.close().await?;
2166
2167 Ok(())
2168 });
2169 }
2170 for t in tasks.into_iter() {
2171 joins.spawn(t);
2172 }
2173 while let Some(Ok(r)) = joins.join_next().await {
2174 r?;
2175 }
2176 sleep(Duration::from_millis(100)).await;
2177 ensure_views(2500).await.map_err(|_| test)?;
2178 tx.send((false, 500).into()).await.unwrap();
2180
2181 Ok(())
2182}
2183
2184async fn validate_20(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
2185 let client = new_client();
2186 let mut test: TaskTest;
2187 test = (1, 1);
2189 let url = &format!("{}/20/archive_files", base_url);
2190 let res = client
2191 .post(url)
2192 .body(include_bytes!("../assets/northpole20231220.tar").to_vec())
2193 .send()
2194 .await
2195 .map_err(|_| test)?;
2196 let text = res.text().await.map_err(|_| test)?;
2197 if text != "6" {
2198 return Err(test);
2199 }
2200 test = (1, 2);
2201 let url = &format!("{}/20/archive_files_size", base_url);
2202 let res = client
2203 .post(url)
2204 .body(include_bytes!("../assets/northpole20231220.tar").to_vec())
2205 .send()
2206 .await
2207 .map_err(|_| test)?;
2208 let text = res.text().await.map_err(|_| test)?;
2209 if text != "1196282" {
2210 return Err(test);
2211 }
2212 tx.send((true, 0).into()).await.unwrap();
2214 tx.send(SubmissionUpdate::Save).await.unwrap();
2215
2216 test = (2, 1);
2218 let url = &format!("{}/20/cookie", base_url);
2219 let res = client
2220 .post(url)
2221 .body(include_bytes!("../assets/cookiejar.tar").to_vec())
2222 .send()
2223 .await
2224 .map_err(|_| test)?;
2225 let text = res.text().await.map_err(|_| test)?;
2226 if text != "Grinch 71dfab551a1958b35b7436c54b7455dcec99a12c" {
2227 return Err(test);
2228 }
2229 test = (2, 2);
2230 let url = &format!("{}/20/cookie", base_url);
2231 let res = client
2232 .post(url)
2233 .body(include_bytes!("../assets/lottery.tar").to_vec())
2234 .send()
2235 .await
2236 .map_err(|_| test)?;
2237 let text = res.text().await.map_err(|_| test)?;
2238 if text != "elf-27221 6342c1dbdb560f0d5dcaac7566fca51454866664" {
2239 return Err(test);
2240 }
2241 tx.send((false, 350).into()).await.unwrap();
2243
2244 Ok(())
2245}
2246
2247async fn validate_21(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
2248 let client = new_client();
2249 let mut test: TaskTest;
2250 test = (1, 1);
2252 let url = &format!(
2253 "{}/21/coords/0100111110010011000110011001010101011111000010100011110001011011",
2254 base_url
2255 );
2256 let res = client.get(url).send().await.map_err(|_| test)?;
2257 let text = res.text().await.map_err(|_| test)?;
2258 if text != "83°39'54.324''N 30°37'40.584''W" {
2259 return Err(test);
2260 }
2261 test = (1, 2);
2262 let url = &format!(
2263 "{}/21/coords/0010000111110000011111100000111010111100000100111101111011000101",
2264 base_url
2265 );
2266 let res = client.get(url).send().await.map_err(|_| test)?;
2267 let text = res.text().await.map_err(|_| test)?;
2268 if text != "18°54'55.944''S 47°31'17.976''E" {
2269 return Err(test);
2270 }
2271 test = (1, 3);
2272 let url = &format!(
2273 "{}/21/coords/0101110100010001110001111100100111000111100010111100111101110001",
2274 base_url
2275 );
2276 let res = client.get(url).send().await.map_err(|_| test)?;
2277 let text = res.text().await.map_err(|_| test)?;
2278 if text != "51°26'57.804''N 99°28'33.204''E" {
2279 return Err(test);
2280 }
2281 tx.send((true, 0).into()).await.unwrap();
2283 tx.send(SubmissionUpdate::Save).await.unwrap();
2284
2285 test = (2, 1);
2287 let url = &format!(
2288 "{}/21/country/0010000111110000011111100000111010111100000100111101111011000101",
2289 base_url
2290 );
2291 let res = client.get(url).send().await.map_err(|_| test)?;
2292 let text = res.text().await.map_err(|_| test)?;
2293 if text != "Madagascar" {
2294 return Err(test);
2295 }
2296 test = (2, 2);
2297 let url = &format!(
2298 "{}/21/country/0011001000100010100010110001110100000111000010111000100000010101",
2299 base_url
2300 );
2301 let res = client.get(url).send().await.map_err(|_| test)?;
2302 let text = res.text().await.map_err(|_| test)?;
2303 if text != "Brunei" {
2304 return Err(test);
2305 }
2306 test = (2, 3);
2307 let url = &format!(
2308 "{}/21/country/1001010011001110010011100110001000100110100111001001000100110001",
2309 base_url
2310 );
2311 let res = client.get(url).send().await.map_err(|_| test)?;
2312 let text = res.text().await.map_err(|_| test)?;
2313 if text != "Brazil" {
2314 return Err(test);
2315 }
2316 test = (2, 4);
2317 let url = &format!(
2318 "{}/21/country/0101110100010001110001111100100111000111100010111100111101110001",
2319 base_url
2320 );
2321 let res = client.get(url).send().await.map_err(|_| test)?;
2322 let text = res.text().await.map_err(|_| test)?;
2323 if text != "Mongolia" {
2324 return Err(test);
2325 }
2326 test = (2, 5);
2327 let url = &format!(
2328 "{}/21/country/0011100111101001000010001100001100111111101001100110000010101011",
2329 base_url
2330 );
2331 let res = client.get(url).send().await.map_err(|_| test)?;
2332 let text = res.text().await.map_err(|_| test)?;
2333 if text != "Nepal" {
2334 return Err(test);
2335 }
2336 test = (2, 6);
2337 let url = &format!(
2338 "{}/21/country/0100011111000110101110101100011001101001111111001011000011101111",
2339 base_url
2340 );
2341 let res = client.get(url).send().await.map_err(|_| test)?;
2342 let text = res.text().await.map_err(|_| test)?;
2343 if text != "Belgium" {
2344 return Err(test);
2345 }
2346 test = (2, 7);
2347 let url = &format!(
2348 "{}/21/country/0100111100110010101001010001010100100110110000100100101011011111",
2349 base_url
2350 );
2351 let res = client.get(url).send().await.map_err(|_| test)?;
2352 let text = res.text().await.map_err(|_| test)?;
2353 if text != "Iceland" {
2354 return Err(test);
2355 }
2356 tx.send((false, 300).into()).await.unwrap();
2358
2359 Ok(())
2360}
2361
2362struct TextTester {
2363 client: reqwest::Client,
2364 url: String,
2365}
2366
2367impl TextTester {
2368 fn new(url: String) -> Self {
2369 Self {
2370 client: new_client(),
2371 url,
2372 }
2373 }
2374 async fn test(&self, test: TaskTest, i: &str, code: StatusCode, o: &str) -> ValidateResult {
2375 let res = self
2376 .client
2377 .post(&self.url)
2378 .body(i.to_owned())
2379 .send()
2380 .await
2381 .map_err(|_| test)?;
2382 if res.status() != code {
2383 return Err(test);
2384 }
2385 let text = res.text().await.map_err(|_| test)?;
2386 if text != o {
2387 return Err(test);
2388 }
2389 Ok(())
2390 }
2391}
2392
2393async fn validate_22(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
2394 let t = TextTester::new(format!("{}/22/integers", base_url));
2396 t.test(
2397 (1, 1),
2398 "\
23991
2400",
2401 StatusCode::OK,
2402 "🎁",
2403 )
2404 .await?;
2405 t.test(
2406 (1, 2),
2407 "\
24081
24091
24102
24112
24123
24133
24144
2415",
2416 StatusCode::OK,
2417 "🎁".repeat(4).as_str(),
2418 )
2419 .await?;
2420 t.test(
2421 (1, 3),
2422 "\
24231
24243
24251
24262
24274
24282
24293
2430",
2431 StatusCode::OK,
2432 "🎁".repeat(4).as_str(),
2433 )
2434 .await?;
2435 t.test(
2436 (1, 4),
2437 "\
243811111111111111111111
2439555555555555555
244033333333
244168
2442555555555555555
244333333333
24444444
244511111111111111111111
24464444
2447",
2448 StatusCode::OK,
2449 "🎁".repeat(68).as_str(),
2450 )
2451 .await?;
2452 t.test(
2453 (1, 5),
2454 include_str!("../assets/numbers.txt"),
2455 StatusCode::OK,
2456 "🎁".repeat(120003).as_str(),
2457 )
2458 .await?;
2459 tx.send((true, 0).into()).await.unwrap();
2461 tx.send(SubmissionUpdate::Save).await.unwrap();
2462
2463 let t = TextTester::new(format!("{}/22/rocket", base_url));
2465 t.test(
2466 (2, 1),
2467 "\
24682
24690 0 0
24700 0 1
24711
24720 1
2473",
2474 StatusCode::OK,
2475 "1 1.000",
2476 )
2477 .await?;
2478 t.test(
2479 (2, 2),
2480 "\
24815
24820 1 0
2483-2 2 3
24843 -3 -5
24851 1 5
24864 3 5
24874
24880 1
24892 4
24903 4
24911 2
2492",
2493 StatusCode::OK,
2494 "3 26.123",
2495 )
2496 .await?;
2497 t.test(
2498 (2, 3),
2499 "\
25005
25010 1 0
2502-2 2 3
25033 -3 -5
25041 1 5
25054 3 5
25065
25070 1
25081 3
25093 4
25100 2
25112 4
2512",
2513 StatusCode::OK,
2514 "2 18.776",
2515 )
2516 .await?;
2517 t.test(
2518 (2, 4),
2519 "\
25205
25210 1 0
2522-2 2 3
25233 -3 -5
25241 1 5
25254 3 5
25261
25270 4
2528",
2529 StatusCode::OK,
2530 "1 6.708",
2531 )
2532 .await?;
2533 t.test(
2534 (2, 5),
2535 "\
25365
25370 1 0
2538-2 2 3
25393 -3 -5
25401 1 5
25414 3 5
25425
25430 4
25440 1
25451 2
25462 0
25470 3
2548",
2549 StatusCode::OK,
2550 "1 6.708",
2551 )
2552 .await?;
2553 t.test(
2554 (2, 6),
2555 "\
255621
2557570 -435 923
2558672 -762 -218
2559707 16 640
2560311 902 47
2561-963 -399 -773
2562788 532 -704
2563703 475 -145
2564-303 -394 -369
2565699 -640 952
2566-341 -221 743
2567740 -146 544
2568-424 655 179
2569-630 161 690
2570789 -848 -517
2571-14 -893 551
2572-48 815 962
2573528 552 -96
2574337 983 165
2575-565 459 -90
257681 -476 301
2577-685 -319 698
257824
25790 2
25802 4
25814 6
25826 10
258310 17
258417 20
258520 18
258618 11
258711 7
25887 5
25895 3
25903 0
25910 1
25921 12
259312 13
259413 19
259519 20
259620 16
259716 14
259814 15
259915 9
26009 8
26018 6
260211 16
2603",
2604 StatusCode::OK,
2605 "5 7167.055",
2606 )
2607 .await?;
2608 t.test(
2609 (2, 7),
2610 "\
261175
2612570 -435 923
2613672 -762 -218
2614707 16 640
2615311 902 47
2616-963 -399 -773
2617788 532 -704
2618703 475 -145
2619-303 -394 -369
2620699 -640 952
2621-341 -221 743
2622740 -146 544
2623-424 655 179
2624-630 161 690
2625789 -848 -517
2626-14 -893 551
2627-48 815 962
2628528 552 -96
2629337 983 165
2630-565 459 -90
263181 -476 301
2632-685 -319 698
2633-264 96 361
2634796 94 402
2635983 763 -953
2636711 -221 -866
2637-578 128 -178
2638-464 117 304
2639426 -433 -961
2640-626 -779 -596
2641-117 -88 349
2642880 -286 -527
2643941 -451 177
2644627 -832 286
2645593 370 -436
2646609 431 -681
2647-549 -690 447
2648957 849 -162
2649189 290 -485
2650-914 -447 -61
2651367 731 825
2652-177 432 -675
2653-926 -811 198
2654-379 345 831
2655-669 -134 804
2656956 380 -427
2657213 -954 -357
2658-806 -663 583
26597 -460 374
2660-384 -797 -404
2661-793 -333 196
2662402 175 329
2663703 9 -926
2664599 559 -844
266564 343 885
2666-865 -49 -373
2667-728 880 -164
2668830 528 -394
2669931 -782 -365
2670661 -528 931
2671-764 34 -289
2672442 298 983
2673-899 382 -967
2674662 361 -85
2675775 98 -519
2676202 335 60
2677474 823 -677
2678-708 41 127
2679-974 718 81
2680443 -526 -945
2681-279 778 -271
2682896 26 -902
2683-977 -233 837
2684151 -22 -454
2685824 -472 471
2686702 871 -244
268773
26880 1
26890 2
26900 4
26910 5
26920 7
26931 10
269410 11
269511 25
269612 13
269713 27
269814 29
269915 30
270016 17
270117 35
270218 36
270319 6
27042 3
270520 22
270621 19
270722 40
270823 60
270924 42
271025 26
271126 43
271227 28
271328 45
271429 47
27153 12
271630 31
271731 68
271832 50
271934 16
272035 52
272136 54
272237 38
272338 57
272439 21
27254 14
272640 59
272741 23
272842 61
272943 44
273044 63
273145 64
273246 65
273347 46
273449 32
273549 68
27365 15
273750 33
273851 34
273952 70
274054 73
274155 37
274256 74
274357 56
274458 39
274559 58
27466 18
274763 62
274865 66
274966 67
275067 48
275169 51
27527 20
275370 71
275471 72
275572 53
275673 55
27578 1
27588 9
27599 23
27609 24
2761",
2762 StatusCode::OK,
2763 "20 27826.439",
2764 )
2765 .await?;
2766 t.test(
2767 (2, 8),
2768 "\
276970
2770788 532 -704
2771703 475 -145
2772-303 -394 -369
2773699 -640 952
2774-341 -221 743
2775740 -146 544
2776-424 655 179
2777-630 161 690
2778789 -848 -517
2779-14 -893 551
2780-48 815 962
2781528 552 -96
2782337 983 165
2783-565 459 -90
278481 -476 301
2785-685 -319 698
2786-264 96 361
2787796 94 402
2788983 763 -953
2789711 -221 -866
2790-578 128 -178
2791-464 117 304
2792426 -433 -961
2793-626 -779 -596
2794-117 -88 349
2795880 -286 -527
2796941 -451 177
2797627 -832 286
2798593 370 -436
2799609 431 -681
2800-549 -690 447
2801957 849 -162
2802189 290 -485
2803-914 -447 -61
2804367 731 825
2805-177 432 -675
2806-926 -811 198
2807-379 345 831
2808-669 -134 804
2809956 380 -427
2810213 -954 -357
2811-806 -663 583
28127 -460 374
2813-384 -797 -404
2814-793 -333 196
2815402 175 329
2816703 9 -926
2817599 559 -844
281864 343 885
2819-865 -49 -373
2820-728 880 -164
2821830 528 -394
2822931 -782 -365
2823661 -528 931
2824-764 34 -289
2825442 298 983
2826-899 382 -967
2827662 361 -85
2828775 98 -519
2829202 335 60
2830474 823 -677
2831-708 41 127
2832-974 718 81
2833443 -526 -945
2834-279 778 -271
2835896 26 -902
2836-977 -233 837
2837151 -22 -454
2838824 -472 471
2839702 871 -244
284070
28410 10
28420 2
28430 3
28441 22
284510 21
284611 1
284712 11
284813 27
284914 15
285015 4
285116 31
285217 33
285318 19
285419 7
28552 12
285620 53
285721 37
285822 39
285923 40
286024 23
286125 24
286226 25
286327 26
286427 6
286528 14
286629 30
28673 13
286830 46
286930 69
287031 47
287133 18
287233 48
287334 33
287435 34
287537 20
287638 55
287739 56
287839 57
28794 16
288040 59
288141 60
288242 62
288343 63
288444 28
288544 65
288645 29
288746 68
288847 32
288948 49
289049 50
28915 17
289250 51
289351 35
289453 36
289555 54
289656 38
289757 58
289859 41
28996 5
290060 61
290161 42
290262 43
290363 64
290464 44
290565 45
290667 66
290768 67
29087 9
29098 0
29109 8
2911",
2912 StatusCode::OK,
2913 "23 34029.320",
2914 )
2915 .await?;
2916 tx.send((false, 600).into()).await.unwrap();
2918
2919 Ok(())
2920}