1pub mod args;
2
3use chrono::{DateTime, TimeDelta, Utc};
4use html_compare_rs::{HtmlCompareOptions, HtmlComparer};
5use jsonwebtoken::decode_header;
6use reqwest::{
7 header::{self, HeaderValue},
8 multipart::{Form, Part},
9 redirect::Policy,
10 Client, StatusCode,
11};
12use serde_json::json;
13use shuttlings::{SubmissionState, SubmissionUpdate};
14use tokio::{
15 sync::mpsc::Sender,
16 time::{sleep, Duration},
17};
18use tracing::info;
19use uuid::Uuid;
20
21pub const SUPPORTED_CHALLENGES: &[&str] = &["-1", "2", "5", "9", "12", "16", "19", "23"];
22pub const SUBMISSION_TIMEOUT: u64 = 60;
23
24pub async fn run(url: String, id: Uuid, number: &str, tx: Sender<SubmissionUpdate>) {
25 info!(%id, %url, %number, "Starting submission");
26
27 tx.send(SubmissionState::Running.into()).await.unwrap();
28 tx.send(SubmissionUpdate::Save).await.unwrap();
29
30 tokio::select! {
31 _ = validate(url.as_str(), number, tx.clone()) => (),
32 _ = sleep(Duration::from_secs(SUBMISSION_TIMEOUT)) => {
33 info!(%id, %url, %number, "Submission timed out");
35 tx.send("Timed out".to_owned().into()).await.unwrap();
36 tx.send(SubmissionState::Done.into()).await.unwrap();
37 tx.send(SubmissionUpdate::Save).await.unwrap();
38 },
39 };
40 info!(%id, %url, %number, "Completed submission");
41}
42
43type TaskTest = (i32, i32);
45type ValidateResult = std::result::Result<(), TaskTest>;
47
48pub async fn validate(url: &str, number: &str, tx: Sender<SubmissionUpdate>) {
49 let txc = tx.clone();
50 if let Err((task, test)) = match number {
51 "-1" => validate_minus1(url, txc).await,
52 "2" => validate_2(url, txc).await,
53 "5" => validate_5(url, txc).await,
54 "9" => validate_9(url, txc).await,
55 "12" => validate_12(url, txc).await,
56 "16" => validate_16(url, txc).await,
57 "19" => validate_19(url, txc).await,
58 "23" => validate_23(url, txc).await,
59 _ => {
60 tx.send(
61 format!("Validating Challenge {number} is not supported yet! Check for updates.")
62 .into(),
63 )
64 .await
65 .unwrap();
66 return;
67 }
68 } {
69 info!(%url, %number, %task, %test, "Submission failed");
70 tx.send(format!("Task {task}: test #{test} failed 🟥").into())
71 .await
72 .unwrap();
73 }
74 tx.send(SubmissionState::Done.into()).await.unwrap();
75 tx.send(SubmissionUpdate::Save).await.unwrap();
76}
77
78fn new_client_base() -> reqwest::ClientBuilder {
79 reqwest::ClientBuilder::new()
80 .http1_only()
81 .connect_timeout(Duration::from_secs(3))
82 .redirect(Policy::limited(3))
83 .referer(false)
84 .timeout(Duration::from_secs(60))
85}
86fn new_client() -> reqwest::Client {
87 new_client_base().build().unwrap()
88}
89fn new_client_with_cookies() -> reqwest::Client {
90 new_client_base().cookie_store(true).build().unwrap()
91}
92
93macro_rules! assert_status {
94 ($res:expr, $test:expr, $expected_status:expr) => {
95 if $res.status() != $expected_status {
96 return Err($test);
97 }
98 };
99}
100
101macro_rules! assert_text {
102 ($res:expr, $test:expr, $expected_text:expr) => {
103 if $res.text().await.map_err(|_| $test)? != $expected_text {
104 return Err($test);
105 }
106 };
107}
108
109macro_rules! assert_json {
110 ($res:expr, $test:expr, $expected_json:expr) => {
111 if $res.json::<serde_json::Value>().await.map_err(|_| $test)? != $expected_json {
112 return Err($test);
113 }
114 };
115}
116
117macro_rules! assert_text_starts_with {
118 ($res:expr, $test:expr, $expected_text:expr) => {
119 if !$res
120 .text()
121 .await
122 .map_err(|_| $test)?
123 .starts_with($expected_text)
124 {
125 return Err($test);
126 }
127 };
128}
129
130macro_rules! assert_ {
131 ($test:expr, $expected_true:expr) => {
132 if !$expected_true {
133 return Err($test);
134 }
135 };
136}
137
138macro_rules! assert_eq_ {
139 ($test:expr, $left:expr, $right:expr) => {
140 if $left != $right {
141 return Err($test);
142 }
143 };
144}
145
146macro_rules! assert_neq_ {
147 ($test:expr, $left:expr, $right:expr) => {
148 if $left == $right {
149 return Err($test);
150 }
151 };
152}
153
154async fn validate_minus1(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
155 let client = new_client();
156 let mut test: TaskTest;
157 test = (1, 1);
159 let url = &format!("{}/", base_url);
160 let res = client.get(url).send().await.map_err(|_| test)?;
161 assert_status!(res, test, StatusCode::OK);
162 assert_text!(res, test, "Hello, bird!");
163 tx.send((true, 0).into()).await.unwrap();
165 tx.send(SubmissionUpdate::Save).await.unwrap();
166
167 test = (2, 1);
169 let url = &format!("{}/-1/seek", base_url);
170 let client_no_redir = reqwest::ClientBuilder::new()
171 .http1_only()
172 .connect_timeout(Duration::from_secs(3))
173 .redirect(Policy::none())
174 .referer(false)
175 .timeout(Duration::from_secs(60))
176 .build()
177 .unwrap();
178 let res = client_no_redir.get(url).send().await.map_err(|_| test)?;
179 assert_status!(res, test, StatusCode::FOUND);
180 if res.headers().get(header::LOCATION)
181 != Some(&HeaderValue::from_static(
182 "https://www.youtube.com/watch?v=9Gc4QTqslN4",
183 ))
184 {
185 return Err(test);
186 }
187 tx.send((false, 0).into()).await.unwrap();
189
190 Ok(())
191}
192
193async fn validate_2(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
194 let client = new_client();
195 let mut test: TaskTest;
196 test = (1, 1);
198 let url = &format!("{}/2/dest?from=10.0.0.0&key=1.2.3.255", base_url);
199 let res = client.get(url).send().await.map_err(|_| test)?;
200 assert_text!(res, test, "11.2.3.255");
201 test = (1, 2);
202 let url = &format!("{}/2/dest?from=128.128.33.0&key=255.0.255.33", base_url);
203 let res = client.get(url).send().await.map_err(|_| test)?;
204 assert_text!(res, test, "127.128.32.33");
205 test = (1, 3);
206 let url = &format!("{}/2/dest?from=192.168.0.1&key=72.96.8.7", base_url);
207 let res = client.get(url).send().await.map_err(|_| test)?;
208 assert_text!(res, test, "8.8.8.8");
209 tx.send((false, 0).into()).await.unwrap();
211 tx.send(SubmissionUpdate::Save).await.unwrap();
212
213 test = (2, 1);
215 let url = &format!("{}/2/key?from=10.0.0.0&to=11.2.3.255", base_url);
216 let res = client.get(url).send().await.map_err(|_| test)?;
217 assert_text!(res, test, "1.2.3.255");
218 test = (2, 2);
219 let url = &format!("{}/2/key?from=128.128.33.0&to=127.128.32.33", base_url);
220 let res = client.get(url).send().await.map_err(|_| test)?;
221 assert_text!(res, test, "255.0.255.33");
222 test = (2, 3);
223 let url = &format!("{}/2/key?from=192.168.0.1&to=8.8.8.8", base_url);
224 let res = client.get(url).send().await.map_err(|_| test)?;
225 assert_text!(res, test, "72.96.8.7");
226 tx.send((true, 0).into()).await.unwrap();
228 tx.send(SubmissionUpdate::Save).await.unwrap();
229
230 test = (3, 1);
232 let url = &format!("{}/2/v6/dest?from=fe80::1&key=5:6:7::3333", base_url);
233 let res = client.get(url).send().await.map_err(|_| test)?;
234 assert_text!(res, test, "fe85:6:7::3332");
235 test = (3, 2);
236 let url = &format!(
237 "{}/2/v6/dest?from=aaaa:0:0:0::aaaa&key=ffff:ffff:c:0:0:c:1234:ffff",
238 base_url
239 );
240 let res = client.get(url).send().await.map_err(|_| test)?;
241 assert_text!(res, test, "5555:ffff:c::c:1234:5555");
242 test = (3, 3);
243 let url = &format!(
244 "{}/2/v6/dest?from=feed:beef:deaf:bad:cafe::&key=::dab:bed:ace:dad",
245 base_url
246 );
247 let res = client.get(url).send().await.map_err(|_| test)?;
248 assert_text!(res, test, "feed:beef:deaf:bad:c755:bed:ace:dad");
249 test = (3, 4);
250 let url = &format!("{}/2/v6/key?from=fe80::1&to=fe85:6:7::3332", base_url);
251 let res = client.get(url).send().await.map_err(|_| test)?;
252 assert_text!(res, test, "5:6:7::3333");
253 test = (3, 5);
254 let url = &format!(
255 "{}/2/v6/key?from=aaaa::aaaa&to=5555:ffff:c:0:0:c:1234:5555",
256 base_url
257 );
258 let res = client.get(url).send().await.map_err(|_| test)?;
259 assert_text!(res, test, "ffff:ffff:c::c:1234:ffff");
260 test = (3, 6);
261 let url = &format!(
262 "{}/2/v6/key?from=feed:beef:deaf:bad:cafe::&to=feed:beef:deaf:bad:c755:bed:ace:dad",
263 base_url
264 );
265 let res = client.get(url).send().await.map_err(|_| test)?;
266 assert_text!(res, test, "::dab:bed:ace:dad");
267 tx.send((false, 50).into()).await.unwrap();
269 tx.send(SubmissionUpdate::Save).await.unwrap();
270
271 Ok(())
272}
273
274async fn validate_5(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
275 let client = new_client();
276 let mut test: TaskTest;
277 let url = &format!("{}/5/manifest", base_url);
278 const CT: &str = "Content-Type";
279 const TOML: &str = "application/toml";
280 const YAML: &str = "application/yaml";
281 const JSON: &str = "application/json";
282 test = (1, 1);
284 let res = client
285 .post(url)
286 .header(CT, TOML)
287 .body(
288 r#"
289[package]
290name = "not-a-gift-order"
291authors = ["Not Santa"]
292keywords = ["Christmas 2024"]
293
294[[package.metadata.orders]]
295item = "Toy car"
296quantity = 2
297
298[[package.metadata.orders]]
299item = "Lego brick"
300quantity = 230
301"#,
302 )
303 .send()
304 .await
305 .map_err(|_| test)?;
306 assert_status!(res, test, StatusCode::OK);
307 assert_text!(res, test, "Toy car: 2\nLego brick: 230");
308 test = (1, 2);
309 let res = client
310 .post(url)
311 .header(CT, TOML)
312 .body(
313 r#"
314[package]
315name = "coal-in-a-bowl"
316authors = ["H4CK3R_13E7"]
317keywords = ["Christmas 2024"]
318
319[[package.metadata.orders]]
320item = "Coal"
321quantity = "Hahaha get rekt"
322"#,
323 )
324 .send()
325 .await
326 .map_err(|_| test)?;
327 assert_status!(res, test, StatusCode::NO_CONTENT);
328 test = (1, 3);
329 let res = client
330 .post(url)
331 .header(CT, TOML)
332 .body(
333 r#"
334[package]
335name = "coal-in-a-bowl"
336authors = ["H4CK3R_13E7"]
337keywords = ["Christmas 2024"]
338
339package.metadata.orders = []
340"#,
341 )
342 .send()
343 .await
344 .map_err(|_| test)?;
345 assert_status!(res, test, StatusCode::NO_CONTENT);
346 test = (1, 4);
347 let res = client
348 .post(url)
349 .header(CT, TOML)
350 .body(
351 r#"
352[package]
353name = "not-a-gift-order"
354authors = ["Not Santa"]
355keywords = ["Christmas 2024"]
356
357[[package.metadata.orders]]
358item = "Toy car"
359quantity = 2
360
361[[package.metadata.orders]]
362item = "Lego brick"
363quantity = 1.5
364
365[[package.metadata.orders]]
366item = "Doll"
367quantity = 2
368
369[[package.metadata.orders]]
370quantity = 5
371item = "Cookie:::\n"
372
373[[package.metadata.orders]]
374item = "Thing"
375count = 3
376"#,
377 )
378 .send()
379 .await
380 .map_err(|_| test)?;
381 assert_status!(res, test, StatusCode::OK);
382 assert_text!(res, test, "Toy car: 2\nDoll: 2\nCookie:::\n: 5");
383 tx.send((false, 0).into()).await.unwrap();
385 tx.send(SubmissionUpdate::Save).await.unwrap();
386
387 test = (2, 1);
389 let res = client
390 .post(url)
391 .header(CT, TOML)
392 .body(
393 r#"
394[package]
395name = false
396authors = ["Not Santa"]
397keywords = ["Christmas 2024"]
398"#,
399 )
400 .send()
401 .await
402 .map_err(|_| test)?;
403 assert_status!(res, test, StatusCode::BAD_REQUEST);
404 assert_text!(res, test, "Invalid manifest");
405 test = (2, 2);
406 let res = client
407 .post(url)
408 .header(CT, TOML)
409 .body(
410 r#"
411[package]
412name = "not-a-gift-order"
413authors = ["Not Santa"]
414keywords = ["Christmas 2024"]
415
416[profile.release]
417incremental = "stonks"
418"#,
419 )
420 .send()
421 .await
422 .map_err(|_| test)?;
423 assert_status!(res, test, StatusCode::BAD_REQUEST);
424 assert_text!(res, test, "Invalid manifest");
425 test = (2, 3);
426 let res = client
427 .post(url)
428 .header(CT, TOML)
429 .body(
430 r#"
431[package]
432name = "big-chungus"
433version = "2.0.24"
434edition = "2024"
435resolver = "2"
436readme.workspace = true
437keywords = ["Christmas 2024"]
438
439[dependencies]
440shuttle-runtime = "1.0.0+when"
441
442[target.shuttlings.dependencies]
443cch24-validator = "5+more"
444
445[profile.release]
446incremental = false
447
448[package.metadata.stuff]
449thing = ["yes", "no"]
450"#,
451 )
452 .send()
453 .await
454 .map_err(|_| test)?;
455 assert_status!(res, test, StatusCode::NO_CONTENT);
456 test = (2, 4);
457 let res = client
458 .post(url)
459 .header(CT, TOML)
460 .body(
461 r#"
462[package]
463name = "chig-bungus"
464edition = "2023"
465
466[workspace.dependencies]
467shuttle-bring-your-own-cloud = "0.0.0"
468"#,
469 )
470 .send()
471 .await
472 .map_err(|_| test)?;
473 assert_status!(res, test, StatusCode::BAD_REQUEST);
474 assert_text!(res, test, "Invalid manifest");
475 test = (2, 5);
476 let res = client
477 .post(url)
478 .header(CT, TOML)
479 .body(
480 r#"
481[package]
482name = "chig-bungus"
483
484[workspace]
485resolver = "135"
486
487[workspace.dependencies]
488shuttle-bring-your-own-cloud = "0.0.0"
489"#,
490 )
491 .send()
492 .await
493 .map_err(|_| test)?;
494 assert_status!(res, test, StatusCode::BAD_REQUEST);
495 assert_text!(res, test, "Invalid manifest");
496 tx.send((false, 0).into()).await.unwrap();
498 tx.send(SubmissionUpdate::Save).await.unwrap();
499
500 test = (3, 1);
502 let res = client
503 .post(url)
504 .header(CT, TOML)
505 .body(
506 r#"
507[package]
508name = "grass"
509authors = ["A vegan cow"]
510keywords = ["Moooooo"]
511"#,
512 )
513 .send()
514 .await
515 .map_err(|_| test)?;
516 assert_status!(res, test, StatusCode::BAD_REQUEST);
517 assert_text!(res, test, "Magic keyword not provided");
518 test = (3, 2);
519 let res = client
520 .post(url)
521 .header(CT, TOML)
522 .body(
523 r#"
524[package]
525name = "chig-bungus"
526
527[workspace]
528resolver = "2"
529
530[workspace.dependencies]
531shuttle-bring-your-own-cloud = "0.0.0"
532"#,
533 )
534 .send()
535 .await
536 .map_err(|_| test)?;
537 assert_status!(res, test, StatusCode::BAD_REQUEST);
538 assert_text!(res, test, "Magic keyword not provided");
539 test = (3, 3);
540 let res = client
541 .post(url)
542 .header(CT, TOML)
543 .body(
544 r#"
545[package]
546name = "slurp"
547authors = ["A crazy cow"]
548keywords = ["MooOooooooOOOOoo00oo=oOooooo", "Mew", "Moh", "Christmas 2024"]
549metadata.orders = [{ item = "Milk 🥛", quantity = 1 }]
550"#,
551 )
552 .send()
553 .await
554 .map_err(|_| test)?;
555 assert_status!(res, test, StatusCode::OK);
556 assert_text!(res, test, "Milk 🥛: 1");
557 test = (3, 4);
558 let res = client
559 .post(url)
560 .header(CT, TOML)
561 .body(
562 r#"
563[package]
564name = "snow"
565authors = ["The Cow of Christmas"]
566keywords = ["Moooooo Merry Christmas 2024"]
567"#,
568 )
569 .send()
570 .await
571 .map_err(|_| test)?;
572 assert_status!(res, test, StatusCode::BAD_REQUEST);
573 assert_text!(res, test, "Magic keyword not provided");
574 tx.send((true, 0).into()).await.unwrap();
576 tx.send(SubmissionUpdate::Save).await.unwrap();
577
578 test = (4, 1);
580 let res = client
581 .post(url)
582 .header(CT, "text/html")
583 .body("<h1>Hello, bird!</h1>")
584 .send()
585 .await
586 .map_err(|_| test)?;
587 assert_status!(res, test, StatusCode::UNSUPPORTED_MEDIA_TYPE);
588 test = (4, 2);
589 let res = client
590 .post(url)
591 .header(CT, YAML)
592 .body(
593 r#"
594package:
595 name: big-chungus-sleigh
596 version: "2.0.24"
597 metadata:
598 orders:
599 - item: "Toy train"
600 quantity: 5
601 - item: "Toy car"
602 quantity: 3
603 rust-version: "1.69"
604 keywords:
605 - "Christmas 2024"
606"#,
607 )
608 .send()
609 .await
610 .map_err(|_| test)?;
611 assert_status!(res, test, StatusCode::OK);
612 assert_text!(res, test, "Toy train: 5\nToy car: 3");
613 test = (4, 3);
614 let res = client
615 .post(url)
616 .header(CT, YAML)
617 .body(
618 r#"
619package:
620 name: big-chungus-sleigh
621 metadata:
622 orders:
623 - item: "Toy train"
624 quantity: 5
625 - item: "Coal"
626 - item: "Horse"
627 quantity: 2
628 keywords:
629 - "Christmas 2024"
630"#,
631 )
632 .send()
633 .await
634 .map_err(|_| test)?;
635 assert_status!(res, test, StatusCode::OK);
636 assert_text!(res, test, "Toy train: 5\nHorse: 2");
637 test = (4, 4);
638 let res = client
639 .post(url)
640 .header(CT, YAML)
641 .body(
642 r#"
643package:
644 name: big-chungus-sleigh
645 metadata:
646 orders:
647 - item: "Toy train"
648 quantity: 5
649 rust-version: true
650 keywords:
651 - "Christmas 2024"
652"#,
653 )
654 .send()
655 .await
656 .map_err(|_| test)?;
657 assert_status!(res, test, StatusCode::BAD_REQUEST);
658 assert_text!(res, test, "Invalid manifest");
659 test = (4, 5);
660 let res = client
661 .post(url)
662 .header(CT, JSON)
663 .body(
664 r#"
665{
666 "package": {
667 "name": "big-chungus-sleigh",
668 "version": "2.0.24",
669 "metadata": {
670 "orders": [
671 {
672 "item": "Toy train",
673 "quantity": 5
674 },
675 {
676 "item": "Toy car",
677 "quantity": 3
678 }
679 ]
680 },
681 "rust-version": "1.69",
682 "keywords": [
683 "Christmas 2024"
684 ]
685 }
686}
687"#,
688 )
689 .send()
690 .await
691 .map_err(|_| test)?;
692 assert_status!(res, test, StatusCode::OK);
693 assert_text!(res, test, "Toy train: 5\nToy car: 3");
694 test = (4, 6);
695 let res = client
696 .post(url)
697 .header(CT, JSON)
698 .body(
699 r#"
700{
701 "package": {
702 "name": "big-chungus-sleigh",
703 "metadata": {
704 "orders": [
705 {
706 "item": "Toy train",
707 "quantity": 5
708 },
709 {
710 "item": "Coal"
711 },
712 {
713 "item": "Horse",
714 "quantity": 2
715 }
716 ]
717 },
718 "keywords": [
719 "Christmas 2024"
720 ]
721 }
722}
723"#,
724 )
725 .send()
726 .await
727 .map_err(|_| test)?;
728 assert_status!(res, test, StatusCode::OK);
729 assert_text!(res, test, "Toy train: 5\nHorse: 2");
730 test = (4, 7);
731 let res = client
732 .post(url)
733 .header(CT, JSON)
734 .body(
735 r#"
736{
737 "package": {
738 "name": "big-chungus-sleigh",
739 "metadata": {
740 "orders": [
741 {
742 "item": "Toy train",
743 "quantity": 5
744 }
745 ]
746 }
747 }
748}
749"#,
750 )
751 .send()
752 .await
753 .map_err(|_| test)?;
754 assert_status!(res, test, StatusCode::BAD_REQUEST);
755 assert_text!(res, test, "Magic keyword not provided");
756 tx.send((false, 70).into()).await.unwrap();
758 tx.send(SubmissionUpdate::Save).await.unwrap();
759
760 Ok(())
761}
762
763async fn validate_9(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
764 let client = new_client();
765 let mut test: TaskTest;
766 test = (1, 1);
768 let url = &format!("{}/9/milk", base_url);
769 let start = Utc::now();
770 let res = client.post(url).send().await.map_err(|_| test)?;
771 assert_status!(res, test, StatusCode::OK);
772 assert_text!(res, test, "Milk withdrawn\n");
773 let res = client.post(url).send().await.map_err(|_| test)?;
774 assert_status!(res, test, StatusCode::OK);
775 assert_text!(res, test, "Milk withdrawn\n");
776 let res = client.post(url).send().await.map_err(|_| test)?;
777 assert_status!(res, test, StatusCode::OK);
778 assert_text!(res, test, "Milk withdrawn\n");
779 let res = client.post(url).send().await.map_err(|_| test)?;
780 assert_status!(res, test, StatusCode::OK);
781 assert_text!(res, test, "Milk withdrawn\n");
782 let res = client.post(url).send().await.map_err(|_| test)?;
783 assert_status!(res, test, StatusCode::OK);
784 assert_text!(res, test, "Milk withdrawn\n");
785 let end = Utc::now();
786 if end - start > TimeDelta::milliseconds(500) {
787 tx.send(SubmissionUpdate::LogLine(
788 "Info: High network latency detected. This test is timing-sensitive and might therefore fail.".to_owned()
789 ))
790 .await
791 .unwrap();
792 }
793 let res = client.post(url).send().await.map_err(|_| test)?;
794 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
795 assert_text!(res, test, "No milk available\n");
796 sleep(Duration::from_secs(1)).await;
797 let res = client.post(url).send().await.map_err(|_| test)?;
798 assert_status!(res, test, StatusCode::OK);
799 assert_text!(res, test, "Milk withdrawn\n");
800 let res = client.post(url).send().await.map_err(|_| test)?;
801 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
802 assert_text!(res, test, "No milk available\n");
803 sleep(Duration::from_secs(2)).await;
804 let res = client.post(url).send().await.map_err(|_| test)?;
805 assert_status!(res, test, StatusCode::OK);
806 assert_text!(res, test, "Milk withdrawn\n");
807 let res = client.post(url).send().await.map_err(|_| test)?;
808 assert_status!(res, test, StatusCode::OK);
809 assert_text!(res, test, "Milk withdrawn\n");
810 let res = client.post(url).send().await.map_err(|_| test)?;
811 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
812 assert_text!(res, test, "No milk available\n");
813 let res = client.post(url).send().await.map_err(|_| test)?;
814 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
815 assert_text!(res, test, "No milk available\n");
816 tx.send((false, 0).into()).await.unwrap();
818 tx.send(SubmissionUpdate::Save).await.unwrap();
819
820 sleep(Duration::from_secs(5)).await;
822
823 test = (2, 1);
825 let res = client
826 .post(url)
827 .json(&json!({"liters": 2}))
828 .send()
829 .await
830 .map_err(|_| test)?;
831 assert_status!(res, test, StatusCode::OK);
832 let j = res.json::<serde_json::Value>().await.map_err(|_| test)?;
833 assert_!(
834 test,
835 j.as_object().is_some_and(|o| o.len() == 1
836 && o.get("gallons").is_some_and(|g| g
837 .as_f64()
838 .is_some_and(|f| (f / 0.5283441 - 1.0).abs() < 0.0001)))
839 );
840 test = (2, 2);
841 let res = client
842 .post(url)
843 .json(&json!({"gallons": -2.000000000000001}))
844 .send()
845 .await
846 .map_err(|_| test)?;
847 assert_status!(res, test, StatusCode::OK);
848 let j = res.json::<serde_json::Value>().await.map_err(|_| test)?;
849 assert_!(
850 test,
851 j.as_object().is_some_and(|o| o.len() == 1
852 && o.get("liters").is_some_and(|g| g
853 .as_f64()
854 .is_some_and(|f| (f / -7.5708237 - 1.0).abs() < 0.0001)))
855 );
856 test = (2, 3);
857 let res = client.post(url).send().await.map_err(|_| test)?;
858 assert_status!(res, test, StatusCode::OK);
859 assert_text!(res, test, "Milk withdrawn\n");
860 test = (2, 4);
861 let res = client
862 .post(url)
863 .json(&json!({}))
864 .send()
865 .await
866 .map_err(|_| test)?;
867 assert_status!(res, test, StatusCode::BAD_REQUEST);
868 test = (2, 5);
869 let res = client
870 .post(url)
871 .json(&json!({"liters": 0, "gallons": 1337}))
872 .send()
873 .await
874 .map_err(|_| test)?;
875 assert_status!(res, test, StatusCode::BAD_REQUEST);
876 test = (2, 6);
877 let res = client.post(url).send().await.map_err(|_| test)?;
878 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
879 assert_text!(res, test, "No milk available\n");
880 test = (2, 7);
881 sleep(Duration::from_secs(1)).await;
882 let res = client
883 .post(url)
884 .header("Content-Type", "application/json")
885 .body("")
886 .send()
887 .await
888 .map_err(|_| test)?;
889 assert_status!(res, test, StatusCode::BAD_REQUEST);
890 test = (2, 8);
891 sleep(Duration::from_secs(1)).await;
892 let res = client
893 .post(url)
894 .header("Content-Type", "application/json")
895 .body("")
896 .send()
897 .await
898 .map_err(|_| test)?;
899 assert_status!(res, test, StatusCode::BAD_REQUEST);
900 test = (2, 9);
901 sleep(Duration::from_secs(1)).await;
902 let res = client
903 .post(url)
904 .header("Content-Type", "application/json")
905 .body("{'liters':0}")
906 .send()
907 .await
908 .map_err(|_| test)?;
909 assert_status!(res, test, StatusCode::BAD_REQUEST);
910 test = (2, 10);
911 sleep(Duration::from_secs(1)).await;
912 let res = client
913 .post(url)
914 .json(&json!({"liters": 123123123123.0}))
916 .send()
917 .await
918 .map_err(|_| test)?;
919 assert_status!(res, test, StatusCode::OK);
920 let j = res.json::<serde_json::Value>().await.map_err(|_| test)?;
921 assert_!(
922 test,
923 j.as_object().is_some_and(|o| o.len() == 1
924 && o.get("gallons").is_some_and(|g| g
925 .as_f64()
926 .is_some_and(|f| (f / 32525687000.0 - 1.0).abs() < 0.0001)))
927 );
928 test = (2, 11);
929 sleep(Duration::from_secs(1)).await;
930 let res = client
931 .post(url)
932 .header("Content-Type", "text/html")
933 .body(r#"{"liters":0}"#)
934 .send()
935 .await
936 .map_err(|_| test)?;
937 assert_status!(res, test, StatusCode::OK);
938 assert_text!(res, test, "Milk withdrawn\n");
939 tx.send((false, 0).into()).await.unwrap();
941 tx.send(SubmissionUpdate::Save).await.unwrap();
942
943 sleep(Duration::from_secs(5)).await;
945
946 test = (3, 1);
948 let res = client
949 .post(url)
950 .json(&json!({"litres": 7.4}))
951 .send()
952 .await
953 .map_err(|_| test)?;
954 assert_status!(res, test, StatusCode::OK);
955 let j = res.json::<serde_json::Value>().await.map_err(|_| test)?;
956 assert_!(
957 test,
958 j.as_object().is_some_and(|o| o.len() == 1
959 && o.get("pints").is_some_and(|g| g
960 .as_f64()
961 .is_some_and(|f| (f / 13.02218 - 1.0).abs() < 0.0001)))
962 );
963 test = (3, 2);
964 let res = client
965 .post(url)
966 .json(&json!({"pints": 32630.25}))
967 .send()
968 .await
969 .map_err(|_| test)?;
970 assert_status!(res, test, StatusCode::OK);
971 let j = res.json::<serde_json::Value>().await.map_err(|_| test)?;
972 assert_!(
973 test,
974 j.as_object().is_some_and(|o| o.len() == 1
975 && o.get("litres").is_some_and(|g| g
976 .as_f64()
977 .is_some_and(|f| (f / 18542.508 - 1.0).abs() < 0.0001)))
978 );
979 test = (3, 3);
980 let res = client
981 .post(url)
982 .json(&json!({"litres": -0.0}))
983 .send()
984 .await
985 .map_err(|_| test)?;
986 assert_status!(res, test, StatusCode::OK);
987 let j = res.json::<serde_json::Value>().await.map_err(|_| test)?;
988 assert_!(
989 test,
990 j.as_object().is_some_and(|o| o.len() == 1
991 && o.get("pints")
992 .is_some_and(|g| g.as_f64().is_some_and(|f| f == 0.0)))
993 );
994 test = (3, 4);
995 let res = client
996 .post(url)
997 .json(&json!({"litres": 7.4, "liters": 7.4}))
998 .send()
999 .await
1000 .map_err(|_| test)?;
1001 assert_status!(res, test, StatusCode::BAD_REQUEST);
1002 test = (3, 5);
1003 let res = client
1004 .post(url)
1005 .json(r#"{"litres": 7.4, "litres": 7.6}"#)
1006 .send()
1007 .await
1008 .map_err(|_| test)?;
1009 assert_status!(res, test, StatusCode::BAD_REQUEST);
1010 test = (3, 6);
1011 sleep(Duration::from_secs(1)).await;
1012 let res = client
1013 .post(url)
1014 .json(&json!({"gallons": 2, "pints": 0}))
1015 .send()
1016 .await
1017 .map_err(|_| test)?;
1018 assert_status!(res, test, StatusCode::BAD_REQUEST);
1019 test = (3, 7);
1020 let res = client.post(url).send().await.map_err(|_| test)?;
1021 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
1022 assert_text!(res, test, "No milk available\n");
1023 tx.send((true, 0).into()).await.unwrap();
1025 tx.send(SubmissionUpdate::Save).await.unwrap();
1026
1027 test = (4, 1);
1029 let refill_url = &format!("{}/9/refill", base_url);
1030 let res = client.post(refill_url).send().await.map_err(|_| test)?;
1031 assert_status!(res, test, StatusCode::OK);
1032 test = (4, 2);
1033 let res = client.post(url).send().await.map_err(|_| test)?;
1034 assert_status!(res, test, StatusCode::OK);
1035 assert_text!(res, test, "Milk withdrawn\n");
1036 let res = client.post(url).send().await.map_err(|_| test)?;
1037 assert_status!(res, test, StatusCode::OK);
1038 assert_text!(res, test, "Milk withdrawn\n");
1039 let res = client.post(url).send().await.map_err(|_| test)?;
1040 assert_status!(res, test, StatusCode::OK);
1041 assert_text!(res, test, "Milk withdrawn\n");
1042 let res = client.post(url).send().await.map_err(|_| test)?;
1043 assert_status!(res, test, StatusCode::OK);
1044 assert_text!(res, test, "Milk withdrawn\n");
1045 let res = client.post(url).send().await.map_err(|_| test)?;
1046 assert_status!(res, test, StatusCode::OK);
1047 assert_text!(res, test, "Milk withdrawn\n");
1048 let res = client.post(url).send().await.map_err(|_| test)?;
1049 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
1050 assert_text!(res, test, "No milk available\n");
1051 let res = client.post(refill_url).send().await.map_err(|_| test)?;
1052 assert_status!(res, test, StatusCode::OK);
1053 let res = client.post(url).send().await.map_err(|_| test)?;
1054 assert_status!(res, test, StatusCode::OK);
1055 assert_text!(res, test, "Milk withdrawn\n");
1056 let res = client.post(url).send().await.map_err(|_| test)?;
1057 assert_status!(res, test, StatusCode::OK);
1058 assert_text!(res, test, "Milk withdrawn\n");
1059 let res = client.post(url).send().await.map_err(|_| test)?;
1060 assert_status!(res, test, StatusCode::OK);
1061 assert_text!(res, test, "Milk withdrawn\n");
1062 let res = client.post(url).send().await.map_err(|_| test)?;
1063 assert_status!(res, test, StatusCode::OK);
1064 assert_text!(res, test, "Milk withdrawn\n");
1065 let res = client.post(url).send().await.map_err(|_| test)?;
1066 assert_status!(res, test, StatusCode::OK);
1067 assert_text!(res, test, "Milk withdrawn\n");
1068 let res = client.post(url).send().await.map_err(|_| test)?;
1069 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
1070 assert_text!(res, test, "No milk available\n");
1071 let res = client.post(url).send().await.map_err(|_| test)?;
1072 assert_status!(res, test, StatusCode::TOO_MANY_REQUESTS);
1073 assert_text!(res, test, "No milk available\n");
1074 tx.send((false, 75).into()).await.unwrap();
1076 tx.send(SubmissionUpdate::Save).await.unwrap();
1077
1078 Ok(())
1079}
1080
1081async fn validate_12(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1082 let client = new_client();
1083 let mut test: TaskTest;
1084 test = (1, 1);
1086 let reset_url = &format!("{}/12/reset", base_url);
1087 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1088 assert_status!(res, test, StatusCode::OK);
1089 assert_text!(
1090 res,
1091 test,
1092 "\
1093⬜⬛⬛⬛⬛⬜
1094⬜⬛⬛⬛⬛⬜
1095⬜⬛⬛⬛⬛⬜
1096⬜⬛⬛⬛⬛⬜
1097⬜⬜⬜⬜⬜⬜
1098"
1099 );
1100 test = (1, 2);
1101 let board_url = &format!("{}/12/board", base_url);
1102 let res = client.get(board_url).send().await.map_err(|_| test)?;
1103 assert_status!(res, test, StatusCode::OK);
1104 assert_text!(
1105 res,
1106 test,
1107 "\
1108⬜⬛⬛⬛⬛⬜
1109⬜⬛⬛⬛⬛⬜
1110⬜⬛⬛⬛⬛⬜
1111⬜⬛⬛⬛⬛⬜
1112⬜⬜⬜⬜⬜⬜
1113"
1114 );
1115 tx.send((false, 0).into()).await.unwrap();
1117 tx.send(SubmissionUpdate::Save).await.unwrap();
1118
1119 test = (2, 1);
1121 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1122 assert_status!(res, test, StatusCode::OK);
1123 assert_text!(
1124 res,
1125 test,
1126 "\
1127⬜⬛⬛⬛⬛⬜
1128⬜⬛⬛⬛⬛⬜
1129⬜⬛⬛⬛⬛⬜
1130⬜⬛⬛⬛⬛⬜
1131⬜⬜⬜⬜⬜⬜
1132"
1133 );
1134 async fn place(
1135 client: &Client,
1136 base_url: &str,
1137 test: TaskTest,
1138 team: &str,
1139 col: i32,
1140 ) -> Result<reqwest::Response, TaskTest> {
1141 client
1142 .post(format!("{}/12/place/{}/{}", base_url, team, col))
1143 .send()
1144 .await
1145 .map_err(|_| test)
1146 }
1147 let res = place(&client, base_url, test, "cookie", 1).await?;
1148 assert_status!(res, test, StatusCode::OK);
1149 assert_text!(
1150 res,
1151 test,
1152 "\
1153⬜⬛⬛⬛⬛⬜
1154⬜⬛⬛⬛⬛⬜
1155⬜⬛⬛⬛⬛⬜
1156⬜🍪⬛⬛⬛⬜
1157⬜⬜⬜⬜⬜⬜
1158"
1159 );
1160 let res = place(&client, base_url, test, "cookie", 1).await?;
1161 assert_status!(res, test, StatusCode::OK);
1162 assert_text!(
1163 res,
1164 test,
1165 "\
1166⬜⬛⬛⬛⬛⬜
1167⬜⬛⬛⬛⬛⬜
1168⬜🍪⬛⬛⬛⬜
1169⬜🍪⬛⬛⬛⬜
1170⬜⬜⬜⬜⬜⬜
1171"
1172 );
1173 let res = place(&client, base_url, test, "cookie", 1).await?;
1174 assert_status!(res, test, StatusCode::OK);
1175 assert_text!(
1176 res,
1177 test,
1178 "\
1179⬜⬛⬛⬛⬛⬜
1180⬜🍪⬛⬛⬛⬜
1181⬜🍪⬛⬛⬛⬜
1182⬜🍪⬛⬛⬛⬜
1183⬜⬜⬜⬜⬜⬜
1184"
1185 );
1186 let res = place(&client, base_url, test, "cookie", 1).await?;
1187 assert_status!(res, test, StatusCode::OK);
1188 assert_text!(
1189 res,
1190 test,
1191 "\
1192⬜🍪⬛⬛⬛⬜
1193⬜🍪⬛⬛⬛⬜
1194⬜🍪⬛⬛⬛⬜
1195⬜🍪⬛⬛⬛⬜
1196⬜⬜⬜⬜⬜⬜
1197🍪 wins!
1198"
1199 );
1200 let res = place(&client, base_url, test, "cookie", 1).await?;
1201 assert_status!(res, test, StatusCode::SERVICE_UNAVAILABLE);
1202 assert_text!(
1203 res,
1204 test,
1205 "\
1206⬜🍪⬛⬛⬛⬜
1207⬜🍪⬛⬛⬛⬜
1208⬜🍪⬛⬛⬛⬜
1209⬜🍪⬛⬛⬛⬜
1210⬜⬜⬜⬜⬜⬜
1211🍪 wins!
1212"
1213 );
1214 let res = place(&client, base_url, test, "milk", 2).await?;
1215 assert_status!(res, test, StatusCode::SERVICE_UNAVAILABLE);
1216 assert_text!(
1217 res,
1218 test,
1219 "\
1220⬜🍪⬛⬛⬛⬜
1221⬜🍪⬛⬛⬛⬜
1222⬜🍪⬛⬛⬛⬜
1223⬜🍪⬛⬛⬛⬜
1224⬜⬜⬜⬜⬜⬜
1225🍪 wins!
1226"
1227 );
1228 let res = client.get(board_url).send().await.map_err(|_| test)?;
1229 assert_status!(res, test, StatusCode::OK);
1230 assert_text!(
1231 res,
1232 test,
1233 "\
1234⬜🍪⬛⬛⬛⬜
1235⬜🍪⬛⬛⬛⬜
1236⬜🍪⬛⬛⬛⬜
1237⬜🍪⬛⬛⬛⬜
1238⬜⬜⬜⬜⬜⬜
1239🍪 wins!
1240"
1241 );
1242 test = (2, 2);
1243 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1244 assert_status!(res, test, StatusCode::OK);
1245 assert_text!(
1246 res,
1247 test,
1248 "\
1249⬜⬛⬛⬛⬛⬜
1250⬜⬛⬛⬛⬛⬜
1251⬜⬛⬛⬛⬛⬜
1252⬜⬛⬛⬛⬛⬜
1253⬜⬜⬜⬜⬜⬜
1254"
1255 );
1256 let res = place(&client, base_url, test, "cookie", 1).await?;
1257 assert_status!(res, test, StatusCode::OK);
1258 let res = place(&client, base_url, test, "milk", 2).await?;
1259 assert_status!(res, test, StatusCode::OK);
1260 let res = place(&client, base_url, test, "cookie", 2).await?;
1261 assert_status!(res, test, StatusCode::OK);
1262 let res = place(&client, base_url, test, "milk", 3).await?;
1263 assert_status!(res, test, StatusCode::OK);
1264 let res = place(&client, base_url, test, "milk", 3).await?;
1265 assert_status!(res, test, StatusCode::OK);
1266 let res = place(&client, base_url, test, "cookie", 3).await?;
1267 assert_status!(res, test, StatusCode::OK);
1268 let res = place(&client, base_url, test, "milk", 4).await?;
1269 assert_status!(res, test, StatusCode::OK);
1270 let res = place(&client, base_url, test, "milk", 4).await?;
1271 assert_status!(res, test, StatusCode::OK);
1272 let res = place(&client, base_url, test, "milk", 4).await?;
1273 assert_status!(res, test, StatusCode::OK);
1274 let res = place(&client, base_url, test, "cookie", 4).await?;
1275 assert_status!(res, test, StatusCode::OK);
1276 assert_text!(
1277 res,
1278 test,
1279 "\
1280⬜⬛⬛⬛🍪⬜
1281⬜⬛⬛🍪🥛⬜
1282⬜⬛🍪🥛🥛⬜
1283⬜🍪🥛🥛🥛⬜
1284⬜⬜⬜⬜⬜⬜
1285🍪 wins!
1286"
1287 );
1288 tokio::time::sleep(Duration::from_millis(1000)).await;
1289 test = (2, 3);
1290 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1291 assert_status!(res, test, StatusCode::OK);
1292 assert_text!(
1293 res,
1294 test,
1295 "\
1296⬜⬛⬛⬛⬛⬜
1297⬜⬛⬛⬛⬛⬜
1298⬜⬛⬛⬛⬛⬜
1299⬜⬛⬛⬛⬛⬜
1300⬜⬜⬜⬜⬜⬜
1301"
1302 );
1303 let res = place(&client, base_url, test, "cookie", 1).await?;
1304 assert_status!(res, test, StatusCode::OK);
1305 let res = place(&client, base_url, test, "cookie", 1).await?;
1306 assert_status!(res, test, StatusCode::OK);
1307 let res = place(&client, base_url, test, "cookie", 1).await?;
1308 assert_status!(res, test, StatusCode::OK);
1309 let res = place(&client, base_url, test, "milk", 1).await?;
1310 assert_status!(res, test, StatusCode::OK);
1311 let res = place(&client, base_url, test, "milk", 2).await?;
1312 assert_status!(res, test, StatusCode::OK);
1313 let res = place(&client, base_url, test, "milk", 2).await?;
1314 assert_status!(res, test, StatusCode::OK);
1315 let res = place(&client, base_url, test, "milk", 2).await?;
1316 assert_status!(res, test, StatusCode::OK);
1317 let res = place(&client, base_url, test, "cookie", 2).await?;
1318 assert_status!(res, test, StatusCode::OK);
1319 let res = place(&client, base_url, test, "cookie", 3).await?;
1320 assert_status!(res, test, StatusCode::OK);
1321 let res = place(&client, base_url, test, "cookie", 3).await?;
1322 assert_status!(res, test, StatusCode::OK);
1323 let res = place(&client, base_url, test, "cookie", 3).await?;
1324 assert_status!(res, test, StatusCode::OK);
1325 let res = place(&client, base_url, test, "milk", 3).await?;
1326 assert_status!(res, test, StatusCode::OK);
1327 let res = place(&client, base_url, test, "milk", 4).await?;
1328 assert_status!(res, test, StatusCode::OK);
1329 let res = place(&client, base_url, test, "milk", 4).await?;
1330 assert_status!(res, test, StatusCode::OK);
1331 let res = place(&client, base_url, test, "milk", 4).await?;
1332 assert_status!(res, test, StatusCode::OK);
1333 let res = place(&client, base_url, test, "cookie", 4).await?;
1334 assert_status!(res, test, StatusCode::OK);
1335 assert_text!(
1336 res,
1337 test,
1338 "\
1339⬜🥛🍪🥛🍪⬜
1340⬜🍪🥛🍪🥛⬜
1341⬜🍪🥛🍪🥛⬜
1342⬜🍪🥛🍪🥛⬜
1343⬜⬜⬜⬜⬜⬜
1344No winner.
1345"
1346 );
1347 tokio::time::sleep(Duration::from_millis(1000)).await;
1348 test = (2, 4);
1349 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1350 assert_status!(res, test, StatusCode::OK);
1351 assert_text!(
1352 res,
1353 test,
1354 "\
1355⬜⬛⬛⬛⬛⬜
1356⬜⬛⬛⬛⬛⬜
1357⬜⬛⬛⬛⬛⬜
1358⬜⬛⬛⬛⬛⬜
1359⬜⬜⬜⬜⬜⬜
1360"
1361 );
1362 let res = place(&client, base_url, test, "cookie", 1).await?;
1363 assert_status!(res, test, StatusCode::OK);
1364 let res = place(&client, base_url, test, "milk", 2).await?;
1365 assert_status!(res, test, StatusCode::OK);
1366 let res = place(&client, base_url, test, "cookie", 2).await?;
1367 assert_status!(res, test, StatusCode::OK);
1368 let res = place(&client, base_url, test, "milk", 2).await?;
1369 assert_status!(res, test, StatusCode::OK);
1370 let res = place(&client, base_url, test, "milk", 1).await?;
1371 assert_status!(res, test, StatusCode::OK);
1372 let res = place(&client, base_url, test, "cookie", 1).await?;
1373 assert_status!(res, test, StatusCode::OK);
1374 let res = place(&client, base_url, test, "cookie", 3).await?;
1375 assert_status!(res, test, StatusCode::OK);
1376 let res = place(&client, base_url, test, "milk", 3).await?;
1377 assert_status!(res, test, StatusCode::OK);
1378 let res = place(&client, base_url, test, "milk", 2).await?;
1379 assert_status!(res, test, StatusCode::OK);
1380 let res = place(&client, base_url, test, "milk", 4).await?;
1381 assert_status!(res, test, StatusCode::OK);
1382 let res = place(&client, base_url, test, "cookie", 3).await?;
1383 assert_status!(res, test, StatusCode::OK);
1384 let res = place(&client, base_url, test, "milk", 1).await?;
1385 assert_status!(res, test, StatusCode::OK);
1386 assert_text!(
1387 res,
1388 test,
1389 "\
1390⬜🥛🥛⬛⬛⬜
1391⬜🍪🥛🍪⬛⬜
1392⬜🥛🍪🥛⬛⬜
1393⬜🍪🥛🍪🥛⬜
1394⬜⬜⬜⬜⬜⬜
1395🥛 wins!
1396"
1397 );
1398 test = (2, 5);
1399 let res = place(&client, base_url, test, "milk", 4).await?;
1400 assert_status!(res, test, StatusCode::SERVICE_UNAVAILABLE);
1401 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1402 assert_status!(res, test, StatusCode::OK);
1403 let res = place(&client, base_url, test, "cookie", 0).await?;
1404 assert_status!(res, test, StatusCode::BAD_REQUEST);
1405 let res = place(&client, base_url, test, "cookie", 5).await?;
1406 assert_status!(res, test, StatusCode::BAD_REQUEST);
1407 let res = place(&client, base_url, test, "cookie", -2).await?;
1408 assert_status!(res, test, StatusCode::BAD_REQUEST);
1409 let res = client
1410 .post(format!("{}/12/place/cookie/one", base_url))
1411 .send()
1412 .await
1413 .map_err(|_| test)?;
1414 assert_status!(res, test, StatusCode::BAD_REQUEST);
1415 let res = place(&client, base_url, test, "plastic", 1).await?;
1416 assert_status!(res, test, StatusCode::BAD_REQUEST);
1417 tx.send((true, 0).into()).await.unwrap();
1419 tx.send(SubmissionUpdate::Save).await.unwrap();
1420
1421 test = (3, 1);
1423 let url = &format!("{}/12/random-board", base_url);
1424 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1425 assert_status!(res, test, StatusCode::OK);
1426 let res = client.get(url).send().await.map_err(|_| test)?;
1427 assert_status!(res, test, StatusCode::OK);
1428 assert_text_starts_with!(
1429 res,
1430 test,
1431 "\
1432⬜🍪🍪🍪🍪⬜
1433⬜🥛🍪🍪🥛⬜
1434⬜🥛🥛🥛🥛⬜
1435⬜🍪🥛🍪🥛⬜
1436⬜⬜⬜⬜⬜⬜
1437"
1438 );
1439 let res = client.get(url).send().await.map_err(|_| test)?;
1440 assert_status!(res, test, StatusCode::OK);
1441 assert_text_starts_with!(
1442 res,
1443 test,
1444 "\
1445⬜🍪🥛🍪🍪⬜
1446⬜🥛🍪🥛🍪⬜
1447⬜🥛🍪🍪🍪⬜
1448⬜🍪🥛🥛🥛⬜
1449⬜⬜⬜⬜⬜⬜
1450"
1451 );
1452 let res = client.get(url).send().await.map_err(|_| test)?;
1453 assert_status!(res, test, StatusCode::OK);
1454 assert_text_starts_with!(
1455 res,
1456 test,
1457 "\
1458⬜🍪🍪🥛🍪⬜
1459⬜🍪🥛🍪🍪⬜
1460⬜🥛🍪🍪🥛⬜
1461⬜🍪🥛🍪🍪⬜
1462⬜⬜⬜⬜⬜⬜
1463"
1464 );
1465 let res = client.get(url).send().await.map_err(|_| test)?;
1466 assert_status!(res, test, StatusCode::OK);
1467 assert_text_starts_with!(
1468 res,
1469 test,
1470 "\
1471⬜🥛🍪🍪🥛⬜
1472⬜🥛🍪🍪🍪⬜
1473⬜🍪🥛🥛🥛⬜
1474⬜🍪🥛🍪🥛⬜
1475⬜⬜⬜⬜⬜⬜
1476"
1477 );
1478 let res = client.get(url).send().await.map_err(|_| test)?;
1479 assert_status!(res, test, StatusCode::OK);
1480 assert_text_starts_with!(
1481 res,
1482 test,
1483 "\
1484⬜🥛🥛🥛🍪⬜
1485⬜🍪🍪🍪🥛⬜
1486⬜🥛🍪🍪🥛⬜
1487⬜🍪🥛🥛🍪⬜
1488⬜⬜⬜⬜⬜⬜
1489"
1490 );
1491 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1492 assert_status!(res, test, StatusCode::OK);
1493 let res = client.get(url).send().await.map_err(|_| test)?;
1494 assert_status!(res, test, StatusCode::OK);
1495 assert_text_starts_with!(
1496 res,
1497 test,
1498 "\
1499⬜🍪🍪🍪🍪⬜
1500⬜🥛🍪🍪🥛⬜
1501⬜🥛🥛🥛🥛⬜
1502⬜🍪🥛🍪🥛⬜
1503⬜⬜⬜⬜⬜⬜
1504"
1505 );
1506 tx.send((false, 75).into()).await.unwrap();
1508 tx.send(SubmissionUpdate::Save).await.unwrap();
1509
1510 Ok(())
1511}
1512
1513async fn validate_16(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1514 let mut test: TaskTest;
1515 test = (1, 1);
1517 let url1 = &format!("{}/16/wrap", base_url);
1518 let url2 = &format!("{}/16/unwrap", base_url);
1519 let client = new_client_with_cookies();
1520 let payload = json!({"cookie": "yum"});
1521 let res = client
1522 .post(url1)
1523 .json(&payload)
1524 .send()
1525 .await
1526 .map_err(|_| test)?;
1527 assert_status!(res, test, StatusCode::OK);
1528 let h = res
1529 .headers()
1530 .get(header::SET_COOKIE)
1531 .ok_or(test)?
1532 .to_str()
1533 .map_err(|_| test)?;
1534 let h = h.strip_prefix("gift=").ok_or(test)?;
1535 decode_header(h).map_err(|_| test)?;
1536 let res = client.get(url2).send().await.map_err(|_| test)?;
1537 assert_status!(res, test, StatusCode::OK);
1538 assert_text!(res, test, serde_json::to_string(&payload).unwrap());
1539 test = (1, 2);
1540 let c1 = new_client_with_cookies();
1541 let c2 = new_client_with_cookies();
1542 let c3 = new_client_with_cookies();
1543 let p1 = json!({"recipient": "p1", "gifts": ["Toy train", "Caramel corn", "Potato"]});
1544 let p2 = json!({"recipient": "p2", "gifts": ["Toy train", "Caramel corn", "Potato"]});
1545 let p3 = json!({"recipient": "p3", "gifts": ["Toy train", "Caramel corn", "Potato"]});
1546 let res = c1.post(url1).json(&p1).send().await.map_err(|_| test)?;
1547 assert_status!(res, test, StatusCode::OK);
1548 let res = c2.post(url1).json(&p2).send().await.map_err(|_| test)?;
1549 assert_status!(res, test, StatusCode::OK);
1550 let res = c3.post(url1).json(&p3).send().await.map_err(|_| test)?;
1551 assert_status!(res, test, StatusCode::OK);
1552 let res = c1.get(url2).send().await.map_err(|_| test)?;
1553 assert_status!(res, test, StatusCode::OK);
1554 assert_json!(res, test, p1);
1555 let res = c3.get(url2).send().await.map_err(|_| test)?;
1556 assert_status!(res, test, StatusCode::OK);
1557 assert_json!(res, test, p3);
1558 test = (1, 3);
1559 let client = new_client();
1560 let res = client.get(url2).send().await.map_err(|_| test)?;
1561 assert_status!(res, test, StatusCode::BAD_REQUEST);
1562 test = (1, 4);
1563 let client = new_client();
1564 let res = client
1565 .get(url2)
1566 .header("Cookie", "candy=5")
1567 .send()
1568 .await
1569 .map_err(|_| test)?;
1570 assert_status!(res, test, StatusCode::BAD_REQUEST);
1571 tx.send((true, 0).into()).await.unwrap();
1573 tx.send(SubmissionUpdate::Save).await.unwrap();
1574
1575 let client = new_client();
1577 let url = &format!("{}/16/decode", base_url);
1578 test = (2, 1);
1579 let res = client
1580 .post(url)
1581 .body(
1582 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJyZWluZGVlclNuYWNrIjoiY2Fycm90cyIsInNhbnRhSGF0Q29sb3IiOiJyZWQiLCJzbm93R2xvYmVDb2xsZWN0aW9uIjo1LCJzdG9ja2luZ1N0dWZmZXJzIjpbInlvLXlvIiwiY2FuZHkiLCJrZXljaGFpbiJdLCJ0cmVlSGVpZ2h0Ijo3fQ.EoWSlwZIMHdtd96U_FkfQ9SkbzskSvgEaRpsUeZQFJixDW57vZud_k-MK1R1LEGoJRPGttJvG_5ewdK9O46OuaGW4DHIOWIFLxSYFTJBdFMVmAWC6snqartAFr2U-LWxTwJ09WNpPBcL67YCx4HQsoGZ2mxRVNIKxR7IEfkZDhmpDkiAUbtKyn0H1EVERP1gdbzHUGpLd7wiuzkJnjenBgLPifUevxGPgj535cp8I6EeE4gLdMEm3lbUW4wX_GG5t6_fDAF4URfiAOkSbiIW6lKcSGD9MBVEGps88lA2REBEjT4c7XHw4Tbxci2-knuJm90zIA9KX92t96tF3VFKEA"
1583 )
1584 .send()
1585 .await
1586 .map_err(|_| test)?;
1587 assert_status!(res, test, StatusCode::OK);
1588 assert_json!(
1589 res,
1590 test,
1591 json!({"stockingStuffers":["yo-yo","candy","keychain"],"reindeerSnack":"carrots","treeHeight":7,"santaHatColor":"red","snowGlobeCollection":5})
1592 );
1593 test = (2, 2);
1594 let res = client
1595 .post(url)
1596 .body(
1597 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJnaWZ0cyI6WyJDb2FsIl19.DaVXV_czINRO1Cvhw33YSPSpV7_TYTqp7gIB_XiVl5fh3K9zkmDItBFLxJHyb7TRw_CGrAYwfinxn6_Dn9MMhp8d3tc-UnRskOxNHpqwU9EcbDtn31uHStT5sLfzdK0fdAc1XUJnr-9dbiGiYARO9YK7HAijdR8bCRMtvMUgIHsumWHO5BEE4CCeVgypzkebsoaev495OE0VNCfn1rSbTKR12xiIFoPCZALV9_slqoZvO59K0x8DSppx7uHApGjXvS6JmyjVgMJNuJoPrIYzc0nytVCa5uLjYIadS2inw7Sty1Jj-sLi8AgtYCXcpyB59MUXNP5xze_Sat8hmQ_NzQ"
1598 )
1599 .send()
1600 .await
1601 .map_err(|_| test)?;
1602 assert_status!(res, test, StatusCode::UNAUTHORIZED);
1603 test = (2, 3);
1604 let res = client
1605 .post(url)
1606 .body(
1607 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjYW5kbGVTY2VudHMiOlsicGluZSIsImNpbm5hbW9uIiwidmFuaWxsYSJdLCJmZXN0aXZlU29ja3MiOjEyLCJnaWZ0VGFncyI6WyJwZXJzb25hbGl6ZWQiLCJibGFuayIsInNwYXJrbHkiXSwiZ2luZ2VyYnJlYWRIb3VzZUtpdHMiOjMsImhvdENvY29hU3RvY2siOjI1fQ.GgYB9NXomy-s_lzmoRC-BFHUvrSMjDMcZ4jFCre6NaPJA2fKr--cadxerpody-H5wV19N2zguNb5gr6dt7-suegC8D2ANe9mExohY9tuqgGKRJdLqtmb8U91T_iRg2kyAyhrv3HlSUHQP3sxvAO7jcwLtbePQehtzb6Hv9tZqNCojxMJmAhrJxz41fnD9wvTsEZVpQVwo21C-GIpZKRUGJnaL6OU9IAY6D4PMUr4X9OjEC1zSdQWpYUW_8CHrGNYPVg-6ZpdEvkejxZGTwPg8pMPPSxRa6g0v7Scx-50pgjcP15VK2OUaF9xce7MReJOgI2dxtF35DpYT-UNsIWDKg"
1608 )
1609 .send()
1610 .await
1611 .map_err(|_| test)?;
1612 assert_status!(res, test, StatusCode::OK);
1613 assert_json!(
1614 res,
1615 test,
1616 json!({"giftTags":["personalized","blank","sparkly"],"hotCocoaStock":25,"candleScents":["pine","cinnamon","vanilla"],"gingerbreadHouseKits":3,"festiveSocks":12})
1617 );
1618 test = (2, 4);
1619 let res = client
1620 .post(url)
1621 .body(
1622 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJjYXJvbGluZ1JvdXRlIjpbIk1haW4gU3RyZWV0IiwiRWxtIEF2ZW51ZSIsIkJha2VyIFN0cmVldCJdLCJjb29raWVSZWNpcGVzIjpbInN1Z2FyIGNvb2tpZXMiLCJzbmlja2VyZG9vZGxlcyIsInNob3J0YnJlYWQiXSwiZmVzdGl2ZVB1bmNoSW5ncmVkaWVudHMiOlsiY3JhbmJlcnJ5IGp1aWNlIiwiZ2luZ2VyIGFsZSIsIm9yYW5nZSBzbGljZXMiXSwiZmlyZXBsYWNlTWFudGxlRGVjb3IiOlsiZ2FybGFuZCIsInN0b2NraW5ncyIsImNhbmRsZXMiXSwiZ2lmdENhcmRPcHRpb25zIjpbImJvb2tzdG9yZSIsImNvZmZlZSBzaG9wIiwib25saW5lIHJldGFpbGVyIl0sImhvbGlkYXlDYXJkTGlzdCI6WyJmYW1pbHkiLCJmcmllbmRzIiwiY293b3JrZXJzIl0sIm51dGNyYWNrZXJDb2xsZWN0aW9uU2l6ZXMiOnsibGFyZ2UiOjEsIm1lZGl1bSI6Mywic21hbGwiOjV9LCJzbm93bWFuQnVpbGRpbmdLaXRzIjo0fQ.ZAThp4qXSV1eY8swvPa9OmQrTglgILGWHzR_DN-gslN1dYNPszb2Hy322hiHIht_ASdXcV7-LNatS-P1yIpg7YnIRpZUgg5_Cb3uvucuna0npqfV3U3tTeqDAikPCs5bc7pWjawVscvabJjDm-WPCwLe9o4YMCSFb_XPra6lAHARRrMyqms2PjjdBE3WcUT_wYQq7WwgChXCXHMCOa1XoKIMoegSesYdSXNbbrckDvwdty9GsASCHaX9TAIY4TNdSdl3RanqDlrRDdwjvs5A9dQUul-JzHLxvSodJAGqxxPODNG_P1l0KRlmlVZVZSRqgFC_wH3sziHyVsM1WayjWQ"
1623 )
1624 .send()
1625 .await
1626 .map_err(|_| test)?;
1627 assert_status!(res, test, StatusCode::OK);
1628 assert_json!(
1629 res,
1630 test,
1631 json!({"cookieRecipes":["sugar cookies","snickerdoodles","shortbread"],"fireplaceMantleDecor":["garland","stockings","candles"],"snowmanBuildingKits":4,"holidayCardList":["family","friends","coworkers"],"nutcrackerCollectionSizes":{"small":5,"medium":3,"large":1},"festivePunchIngredients":["cranberry juice","ginger ale","orange slices"],"carolingRoute":["Main Street","Elm Avenue","Baker Street"],"giftCardOptions":["bookstore","coffee shop","online retailer"]})
1632 );
1633 test = (2, 5);
1634 let res = client
1635 .post(url)
1636 .body(
1637 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJlbHZlcyI6WyJKaW5nbGUiLCJUd2lua2xlIiwiVGluc2VsIl0sImdpZnRGYWN0b3J5Ijp7ImxvY2F0aW9uIjoiTm9ydGggUG9sZSIsIm91dHB1dFBlckhvdXIiOjUwMDB9LCJnaWZ0SWRlYXMiOlsidG95IHRyYWluIiwiYWN0aW9uIGZpZ3VyZSIsInRlZGR5IGJlYXIiLCJsZWdvIHNldCJdLCJyZWluZGVlciI6IlJ1ZG9scGgiLCJzYW50YSI6eyJhZ2UiOjE3NTAsIm5hbWUiOiJLcmlzIEtyaW5nbGUifSwic3VycHJpc2VFbGVtZW50Ijp0cnVlLCJ3aXNobGlzdCI6eyJicm90aGVyIjoidmlkZW8gZ2FtZSIsImRhZCI6InNvY2tzIiwibW9tIjoiY2hvY29sYXRlcyIsInNpc3RlciI6InBvcCBjdWx0dXJlIHBvc3RlciJ9LCJ3cmFwcGluZyI6eyJwYXBlclR5cGVzIjpbImdsb3NzeSIsIm1hdHRlIiwic3BhcmtsZSJdfX0.lQDLhwqrWAn8jPV-lzPuEQE7fFt30yao5M7jADhg3ipwRYYOB8g9sT5TrIufKKCMpNk8qxxgZX9rGJrGVqmdVLRXmyMMgxhiVuboxtI8RlhAEgzNQR6z7G3OWJ-ZccOEHVjdXBQwtpQeLMwoDDHK6UnVsWSrLai5n-VI87QOyxz_2VVj_cR9mtsSEU9rMxZBly1KD5-f-pQHwOczOlAerdp-bgQpANH6uR94AQGENMRQaY7tr_ldh5DNpP9gL0K3oZD3HbEBvYv8OS498mq_09BqVFrp9nmgB4JGhYzNqyFbad8f52sdBRle-ewNR55uxDHq6e10IdJQ_PR34gGPjw"
1638 )
1639 .send()
1640 .await
1641 .map_err(|_| test)?;
1642 assert_status!(res, test, StatusCode::UNAUTHORIZED);
1643 test = (2, 6);
1644 let res = client
1645 .post(url)
1646 .body(
1647 "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjYW5keUNhbmVTdG9jayI6MTUwMCwiY2Fyb2xQbGF5bGlzdCI6WyJKaW5nbGUgQmVsbHMiLCJTaWxlbnQgTmlnaHQiLCJEZWNrIHRoZSBIYWxscyJdLCJmYXZvcml0ZUNvb2tpZXMiOlsiY2hvY29sYXRlIGNoaXAiLCJvYXRtZWFsIHJhaXNpbiIsImdpbmdlcmJyZWFkIl0sImdpZnRFeGNoYW5nZVJ1bGVzIjp7Im1heEJ1ZGdldCI6NTAsInRoZW1lIjoiaGFuZG1hZGUifSwicmVpbmRlZXJOYW1lcyI6WyJEYXNoZXIiLCJEYW5jZXIiLCJQcmFuY2VyIiwiVml4ZW4iLCJDb21ldCIsIkN1cGlkIiwiRG9ubmVyIiwiQmxpdHplbiJdLCJzZWNyZXRTYW50YSI6eyJkcmF3RGF0ZSI6IjIwMjMtMTItMDEiLCJwYXJ0aWNpcGFudHMiOlsiQWxpY2UiLCJCb2IiLCJDaGFybGllIl19LCJzbGVpZ2giOnsiY29sb3IiOiJyZWQiLCJmdWVsVHlwZSI6Im1hZ2ljIGR1c3QifSwidHJlZURlY29yYXRpb25zIjpbImxpZ2h0cyIsImJhdWJsZXMiLCJ0aW5zZWwiLCJzdGFyIl19.MGtse2G55XIZTSWa2IdNI6YCKsFKsGEonkH0iIlRUuELY6nBdPnLpI4oFEB4-yK8j2eVcQALS3J3YbVUk-LLpIazaVJ5uJ9r-VvBNZqe_Uih8GQjVmINMEHdQwh6v2T2h4FLOqs2wap4SS6q25BVz2v0urycbCo_6IiHvswgkqRk9ZBA_bFDXEKRCoKLdgcNxnYRbkbLVvOzVpvhHFRYOsiwBxBiMakkjp3ZmvV5vaMQaSFUsmW9CHoU0ffbdwOwyMUXrxphSYB7h4OAZeudnZa7ntoOZ6J3PJQCTvgU7llffTPcdoO6LVoXSD8hiIfvJWPKgsOgasyG_xEQmfGcsA"
1648 )
1649 .send()
1650 .await
1651 .map_err(|_| test)?;
1652 assert_status!(res, test, StatusCode::UNAUTHORIZED);
1653 for (test, txt) in [
1654 ((2, 7), "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJyZWluZGVlclNuYWNrIjoiY2Fycm90cyIsInNhbnRhSGF0Q29sb3IiOiJyZWQiLCJzbm93R2xvYmVDb2xsZWN0aW9uIjo1LCJzdG9ja2luZ1N0dWZmZXJzIjpbInlvLXlvIiwiY2FuZHkiLCJrZXljaGFpbiJdLCJ0cmVlSGVpZ2h0Ijo3fQEoWSlwZIMHdtd96U_FkfQ9SkbzskSvgEaRpsUeZQFJixDW57vZud_k-MK1R1LEGoJRPGttJvG_5ewdK9O46OuaGW4DHIOWIFLxSYFTJBdFMVmAWC6snqartAFr2U-LWxTwJ09WNpPBcL67YCx4HQsoGZ2mxRVNIKxR7IEfkZDhmpDkiAUbtKyn0H1EVERP1gdbzHUGpLd7wiuzkJnjenBgLPifUevxGPgj535cp8I6EeE4gLdMEm3lbUW4wX_GG5t6_fDAF4URfiAOkSbiIW6lKcSGD9MBVEGps88lA2REBEjT4c7XHw4Tbxci2-knuJm90zIA9KX92t96tF3VFKEA"),
1655 ((2, 8), "eyJ0eXAiOiJKV1QiLCJhbGci0iJSUzI1NiJ9.eyJyZWluZGVlclNuYWNrIjoiY2Fycm90cyIsInNhbnRhSGF0Q29sb3IiOiJyZWQiLCJzbm93R2xvYmVDb2xsZWN0aW9uIjo1LCJzdG9ja2luZ1N0dWZmZXJzIjpbInlvLXlvIiwiY2FuZHkiLCJrZXljaGFpbiJdLCJ0cmVlSGVpZ2h0Ijo3fQ.EoWSlwZIMHdtd96U_FkfQ9SkbzskSvgEaRpsUeZQFJixDW57vZud_k-MK1R1LEGoJRPGttJvG_5ewdK9O46OuaGW4DHIOWIFLxSYFTJBdFMVmAWC6snqartAFr2U-LWxTwJ09WNpPBcL67YCx4HQsoGZ2mxRVNIKxR7IEfkZDhmpDkiAUbtKyn0H1EVERP1gdbzHUGpLd7wiuzkJnjenBgLPifUevxGPgj535cp8I6EeE4gLdMEm3lbUW4wX_GG5t6_fDAF4URfiAOkSbiIW6lKcSGD9MBVEGps88lA2REBEjT4c7XHw4Tbxci2-knuJm90zIA9KX92t96tF3VFKEA"),
1656 ((2, 9), "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJy.ZWluZGVlclNuYWNrIjoiY2Fycm90cyIsInNhbnRhSGF0Q29sb3IiOiJyZWQiLCJzbm93R2xvYmVDb2xsZWN0aW9uIjo1LCJzdG9ja2luZ1N0dWZmZXJzIjpbInlvLXlvIiwiY2FuZHkiLCJrZXljaGFpbiJdLCJ0cmVlSGVpZ2h0Ijo3fQ.EoWSlwZIMHdtd96U_FkfQ9SkbzskSvgEaRpsUeZQFJixDW57vZud_k-MK1R1LEGoJRPGttJvG_5ewdK9O46OuaGW4DHIOWIFLxSYFTJBdFMVmAWC6snqartAFr2U-LWxTwJ09WNpPBcL67YCx4HQsoGZ2mxRVNIKxR7IEfkZDhmpDkiAUbtKyn0H1EVERP1gdbzHUGpLd7wiuzkJnjenBgLPifUevxGPgj535cp8I6EeE4gLdMEm3lbUW4wX_GG5t6_fDAF4URfiAOkSbiIW6lKcSGD9MBVEGps88lA2REBEjT4c7XHw4Tbxci2-knuJm90zIA9KX92t96tF3VFKEA"),
1657 ((2, 10), "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.ImNvYWwi.cTlGrCeHzvweR-b7U1PZn3fpNk5P_C8wjTo2s93itoYdzeJwUunHTfPY9MJ3Mmif_2MDveSf7b_xID4fRhnXzEBNblIXtlfoNE1lWGPurOvB8udxxJk30qM6sG-ldK79TKzt784ok1ecyuAP94vMjKK861YUoqq5bfZdr9YwIq0chJOx0RZG0zY2OS7VVoOG-SbOssHb-eZKysCt-r8zrIwJGXoSe6H5ZYX7dN5l9CbJ6t29D89I0SkZj2TI2unBG5UueXIw6VukwREzDPTKJTdh6AbnMRwoi7GGIlayhUaFtAGPrlnS2razOmAWndtSv9rDNELJirN2AQ7iyRbqyg"),
1658 ] {
1659 let res = client.post(url).body(txt).send().await.map_err(|_| test)?;
1660 assert_status!(res, test, StatusCode::BAD_REQUEST);
1661 }
1662 tx.send((false, 200).into()).await.unwrap();
1664 tx.send(SubmissionUpdate::Save).await.unwrap();
1665
1666 Ok(())
1667}
1668
1669async fn validate_19(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
1670 let client = new_client();
1671 let mut test: TaskTest;
1672 test = (1, 1);
1674 let reset_url = &format!("{}/19/reset", base_url);
1675 let cite_url = &format!("{}/19/cite", base_url);
1676 let remove_url = &format!("{}/19/remove", base_url);
1677 let undo_url = &format!("{}/19/undo", base_url);
1678 let draft_url = &format!("{}/19/draft", base_url);
1679 let res = client.post(reset_url).send().await.map_err(|_| test)?;
1680 assert_status!(res, test, StatusCode::OK);
1681
1682 async fn validate_quote(
1683 res: reqwest::Response,
1684 test: (i32, i32),
1685 sent: &serde_json::Value,
1686 version: i64,
1687 ) -> Result<Uuid, TaskTest> {
1688 quote_matches(
1689 test,
1690 sent,
1691 &res.json::<serde_json::Value>().await.map_err(|_| test)?,
1692 version,
1693 )
1694 .await
1695 }
1696 async fn quote_matches(
1697 test: (i32, i32),
1698 exp: &serde_json::Value,
1699 act: &serde_json::Value,
1700 version: i64,
1701 ) -> Result<Uuid, TaskTest> {
1702 assert_eq_!(test, act.as_object().ok_or(test)?.len(), 5);
1703 assert_!(test, act.get("author") == exp.get("author"));
1704 assert_!(test, act.get("quote") == exp.get("quote"));
1705 assert_!(
1706 test,
1707 act.get("version")
1708 .is_some_and(|v| v.as_i64().is_some_and(|v| v == version))
1709 );
1710 act.get("created_at")
1711 .ok_or(test)?
1712 .as_str()
1713 .ok_or(test)?
1714 .parse::<DateTime<Utc>>()
1715 .map_err(|_| test)?;
1716 let id: Uuid = act
1717 .get("id")
1718 .ok_or(test)?
1719 .as_str()
1720 .ok_or(test)?
1721 .parse()
1722 .map_err(|_| test)?;
1723
1724 Ok(id)
1725 }
1726
1727 let quote1 = json!({"author":"Santa","quote":"Ho ho ho! Spread cheer and kindness, for that's the true magic of the season!"});
1728 let quote2 = json!({"author":"Santa's best elf","quote":"In the glow of snow and twinkling light, dreams take flight on a magical night!"});
1729 let quote3 = json!({"author":"Dasher","quote":"Whoosh and clatter, my hooves pitter-patter!"});
1730 let quote4 = json!({"author":"Polar Bear","quote":"Roar!"});
1731 let res = client
1732 .post(draft_url)
1733 .json("e1)
1734 .send()
1735 .await
1736 .map_err(|_| test)?;
1737 assert_status!(res, test, StatusCode::CREATED);
1738 let id = validate_quote(res, test, "e1, 1).await?;
1739
1740 let res = client
1741 .get(format!("{}/{}", cite_url, id))
1742 .send()
1743 .await
1744 .map_err(|_| test)?;
1745 assert_status!(res, test, StatusCode::OK);
1746 validate_quote(res, test, "e1, 1).await?;
1747
1748 let res = client
1749 .put(format!("{}/{}", undo_url, id))
1750 .json("e2)
1751 .send()
1752 .await
1753 .map_err(|_| test)?;
1754 assert_status!(res, test, StatusCode::OK);
1755 let id2 = validate_quote(res, test, "e2, 2).await?;
1756 assert_eq_!(test, id, id2);
1757
1758 let res = client
1759 .delete(format!("{}/{}", remove_url, id))
1760 .send()
1761 .await
1762 .map_err(|_| test)?;
1763 assert_status!(res, test, StatusCode::OK);
1764 validate_quote(res, test, "e2, 2).await?;
1765
1766 let res = client
1767 .get(format!("{}/{}", cite_url, id))
1768 .send()
1769 .await
1770 .map_err(|_| test)?;
1771 assert_status!(res, test, StatusCode::NOT_FOUND);
1772
1773 test = (1, 2);
1774 let res = client
1775 .post(draft_url)
1776 .json("e1)
1777 .send()
1778 .await
1779 .map_err(|_| test)?;
1780 assert_status!(res, test, StatusCode::CREATED);
1781 let id = validate_quote(res, test, "e1, 1).await?;
1782 let res = client
1783 .post(draft_url)
1784 .json("e1)
1785 .send()
1786 .await
1787 .map_err(|_| test)?;
1788 assert_status!(res, test, StatusCode::CREATED);
1789 let id2 = validate_quote(res, test, "e1, 1).await?;
1790 assert_neq_!(test, id, id2);
1791
1792 let res = client
1793 .put(format!("{}/{}", undo_url, id))
1794 .json("e2)
1795 .send()
1796 .await
1797 .map_err(|_| test)?;
1798 assert_status!(res, test, StatusCode::OK);
1799 validate_quote(res, test, "e2, 2).await?;
1800 let res = client
1801 .get(format!("{}/{}", cite_url, id2))
1802 .send()
1803 .await
1804 .map_err(|_| test)?;
1805 assert_status!(res, test, StatusCode::OK);
1806 validate_quote(res, test, "e1, 1).await?;
1807 let res = client
1808 .get(format!("{}/{}", cite_url, id))
1809 .send()
1810 .await
1811 .map_err(|_| test)?;
1812 assert_status!(res, test, StatusCode::OK);
1813 validate_quote(res, test, "e2, 2).await?;
1814
1815 let res = client
1816 .put(format!("{}/{}", undo_url, id))
1817 .json("e3)
1818 .send()
1819 .await
1820 .map_err(|_| test)?;
1821 assert_status!(res, test, StatusCode::OK);
1822 validate_quote(res, test, "e3, 3).await?;
1823 let res = client
1824 .put(format!("{}/{}", undo_url, id))
1825 .json("e1)
1826 .send()
1827 .await
1828 .map_err(|_| test)?;
1829 assert_status!(res, test, StatusCode::OK);
1830 validate_quote(res, test, "e1, 4).await?;
1831
1832 test = (1, 3);
1833 let res = client
1834 .put(format!(
1835 "{}/{}",
1836 undo_url, "00000000-0000-0000-0000-000000000000"
1837 ))
1838 .json("e4)
1839 .send()
1840 .await
1841 .map_err(|_| test)?;
1842 assert_status!(res, test, StatusCode::NOT_FOUND);
1843 let res = client
1844 .delete(format!(
1845 "{}/{}",
1846 remove_url, "00000000-0000-0000-0000-000000000000"
1847 ))
1848 .send()
1849 .await
1850 .map_err(|_| test)?;
1851 assert_status!(res, test, StatusCode::NOT_FOUND);
1852 let res = client
1853 .get(format!(
1854 "{}/{}",
1855 cite_url, "00000000-0000-0000-0000-000000000000"
1856 ))
1857 .send()
1858 .await
1859 .map_err(|_| test)?;
1860 assert_status!(res, test, StatusCode::NOT_FOUND);
1861 let res = client
1862 .put(format!("{}/{}", undo_url, "1234"))
1863 .json("e4)
1864 .send()
1865 .await
1866 .map_err(|_| test)?;
1867 assert_status!(res, test, StatusCode::BAD_REQUEST);
1868
1869 tx.send((true, 0).into()).await.unwrap();
1871 tx.send(SubmissionUpdate::Save).await.unwrap();
1872
1873 test = (2, 1);
1875 let list_url = &format!("{}/19/list", base_url);
1876 async fn validate_quotes(
1877 res: reqwest::Response,
1878 test: (i32, i32),
1879 sent: &[(&serde_json::Value, i64)],
1880 page: i64,
1881 ) -> Result<Option<String>, TaskTest> {
1882 let json = res.json::<serde_json::Value>().await.map_err(|_| test)?;
1883 assert_!(
1884 test,
1885 json.get("page")
1886 .is_some_and(|v| v.as_i64().is_some_and(|v| v == page))
1887 );
1888 let quotes = json.get("quotes").ok_or(test)?.as_array().ok_or(test)?;
1889 for ((v, version), quote) in sent.iter().zip(quotes.iter()) {
1890 quote_matches(test, v, quote, *version).await?;
1891 }
1892 let next_token: Option<String> =
1893 serde_json::from_value(json.get("next_token").ok_or(test)?.clone())
1894 .map_err(|_| test)?;
1895 if let Some(t) = next_token.as_ref() {
1896 if t.chars().any(|c| !c.is_ascii_alphanumeric()) || t.len() != 16 {
1897 return Err(test);
1898 }
1899 }
1900 Ok(next_token)
1901 }
1902 let res = client.get(list_url).send().await.map_err(|_| test)?;
1903 assert_status!(res, test, StatusCode::OK);
1904 let n = validate_quotes(res, test, &[("e1, 4), ("e1, 1)], 1).await?;
1905 assert_!(test, n.is_none());
1906
1907 let res = client
1908 .post(draft_url)
1909 .json("e3)
1910 .send()
1911 .await
1912 .map_err(|_| test)?;
1913 assert_status!(res, test, StatusCode::CREATED);
1914 let id3 = validate_quote(res, test, "e3, 1).await?;
1915 let res = client
1916 .post(draft_url)
1917 .json("e3)
1918 .send()
1919 .await
1920 .map_err(|_| test)?;
1921 assert_status!(res, test, StatusCode::CREATED);
1922 validate_quote(res, test, "e3, 1).await?;
1923
1924 let res = client.get(list_url).send().await.map_err(|_| test)?;
1925 assert_status!(res, test, StatusCode::OK);
1926 let n = validate_quotes(res, test, &[("e1, 4), ("e1, 1), ("e3, 1)], 1).await?;
1927 assert_!(test, n.is_some());
1928 let res = client
1929 .get(format!("{}?token={}", list_url, n.unwrap()))
1930 .send()
1931 .await
1932 .map_err(|_| test)?;
1933 assert_status!(res, test, StatusCode::OK);
1934 let n = validate_quotes(res, test, &[("e3, 1)], 2).await?;
1935 assert_!(test, n.is_none());
1936
1937 test = (2, 2);
1938 let res = client
1939 .delete(format!("{}/{}", remove_url, id3))
1940 .send()
1941 .await
1942 .map_err(|_| test)?;
1943 assert_status!(res, test, StatusCode::OK);
1944 validate_quote(res, test, "e3, 1).await?;
1945 let res = client.get(list_url).send().await.map_err(|_| test)?;
1946 assert_status!(res, test, StatusCode::OK);
1947 let n = validate_quotes(res, test, &[("e1, 4), ("e1, 1), ("e3, 1)], 1).await?;
1948 assert_!(test, n.is_none());
1949
1950 test = (2, 3);
1951 let page1 = &[("e1, 4), ("e1, 1), ("e3, 1)];
1952 let page2 = &[("e2, 1), ("e2, 1), ("e3, 1)];
1953 let page3 = &[("e2, 1), ("e3, 1), ("e1, 1)];
1954 for &(q, v) in page2.iter().chain(page3.iter()) {
1955 let res = client
1956 .post(draft_url)
1957 .json(q)
1958 .send()
1959 .await
1960 .map_err(|_| test)?;
1961 assert_status!(res, test, StatusCode::CREATED);
1962 validate_quote(res, test, q, v).await?;
1963 }
1964
1965 let res = client.get(list_url).send().await.map_err(|_| test)?;
1966 assert_status!(res, test, StatusCode::OK);
1967 let n = validate_quotes(res, test, page1, 1).await?;
1968 assert_!(test, n.is_some());
1969 let res = client
1970 .get(format!("{}?token={}", list_url, n.unwrap()))
1971 .send()
1972 .await
1973 .map_err(|_| test)?;
1974 assert_status!(res, test, StatusCode::OK);
1975 let n = validate_quotes(res, test, page2, 2).await?;
1976 assert_!(test, n.is_some());
1977 let res = client
1978 .get(format!("{}?token={}", list_url, n.unwrap()))
1979 .send()
1980 .await
1981 .map_err(|_| test)?;
1982 assert_status!(res, test, StatusCode::OK);
1983 let n = validate_quotes(res, test, page3, 3).await?;
1984 assert_!(test, n.is_none());
1985
1986 test = (2, 4);
1987 let res = client
1988 .get(format!("{}?token=asd987f69as87d6q", list_url))
1989 .send()
1990 .await
1991 .map_err(|_| test)?;
1992 assert_status!(res, test, StatusCode::BAD_REQUEST);
1993
1994 test = (2, 5);
1995 let res = client.get(list_url).send().await.map_err(|_| test)?;
1996 assert_status!(res, test, StatusCode::OK);
1997 let n1 = validate_quotes(res, test, page1, 1).await?;
1998 assert_!(test, n1.is_some());
1999
2000 let res = client.get(list_url).send().await.map_err(|_| test)?;
2001 assert_status!(res, test, StatusCode::OK);
2002 let n2 = validate_quotes(res, test, page1, 1).await?;
2003 assert_!(test, n2.is_some());
2004
2005 let res = client
2006 .get(format!("{}?token={}", list_url, n1.unwrap()))
2007 .send()
2008 .await
2009 .map_err(|_| test)?;
2010 assert_status!(res, test, StatusCode::OK);
2011 let n1 = validate_quotes(res, test, page2, 2).await?;
2012 assert_!(test, n1.is_some());
2013 let res = client
2014 .get(format!("{}?token={}", list_url, n1.unwrap()))
2015 .send()
2016 .await
2017 .map_err(|_| test)?;
2018 assert_status!(res, test, StatusCode::OK);
2019 let n1 = validate_quotes(res, test, page3, 3).await?;
2020 assert_!(test, n1.is_none());
2021
2022 let res = client
2023 .get(format!("{}?token={}", list_url, n2.unwrap()))
2024 .send()
2025 .await
2026 .map_err(|_| test)?;
2027 assert_status!(res, test, StatusCode::OK);
2028 let n2 = validate_quotes(res, test, page2, 2).await?;
2029 assert_!(test, n2.is_some());
2030 let res = client
2031 .get(format!("{}?token={}", list_url, n2.unwrap()))
2032 .send()
2033 .await
2034 .map_err(|_| test)?;
2035 assert_status!(res, test, StatusCode::OK);
2036 let n2 = validate_quotes(res, test, page3, 3).await?;
2037 assert_!(test, n2.is_none());
2038
2039 tx.send((false, 75).into()).await.unwrap();
2041
2042 Ok(())
2043}
2044
2045async fn validate_23(base_url: &str, tx: Sender<SubmissionUpdate>) -> ValidateResult {
2046 let client = new_client();
2047 let mut test: TaskTest;
2048 test = (1, 1);
2050 let url = &format!("{}/assets/23.html", base_url);
2051 let res = client.get(url).send().await.map_err(|_| test)?;
2052 assert_status!(res, test, StatusCode::OK);
2053 if res.text().await.map_err(|_| test)?.len() != 7163 {
2054 return Err(test);
2055 }
2056 tx.send((false, 0).into()).await.unwrap();
2058 tx.send(SubmissionUpdate::Save).await.unwrap();
2059
2060 let comparer = HtmlComparer::with_options(HtmlCompareOptions {
2061 ignore_whitespace: true,
2062 ignore_attributes: false,
2063 ignored_attributes: Default::default(),
2064 ignore_text: false,
2065 ignore_comments: true,
2066 ignore_sibling_order: false,
2067 ignore_style_contents: false,
2068 });
2069 macro_rules! assert_html {
2070 ($res:expr, $test:expr, $comp:expr, $expected_html:expr) => {
2071 if !$comp
2072 .compare($expected_html, &$res.text().await.map_err(|_| $test)?)
2073 .is_ok_and(|t| t)
2074 {
2075 return Err($test);
2076 }
2077 };
2078 }
2079 test = (2, 1);
2081 let url = &format!("{}/23/star", base_url);
2082 let res = client.get(url).send().await.map_err(|_| test)?;
2083 assert_status!(res, test, StatusCode::OK);
2084 assert_html!(res, test, comparer, r#"<div id="star" class="lit"></div>"#);
2085 tx.send((false, 0).into()).await.unwrap();
2087 tx.send(SubmissionUpdate::Save).await.unwrap();
2088
2089 test = (3, 1);
2091 let res = client
2092 .get(format!("{}/23/present/red", base_url))
2093 .send()
2094 .await
2095 .map_err(|_| test)?;
2096 assert_status!(res, test, StatusCode::OK);
2097 assert_html!(
2098 res,
2099 test,
2100 comparer,
2101 r#"<div class="present red" hx-get="/23/present/blue" hx-swap="outerHTML"><div class="ribbon"></div><div class="ribbon"></div><div class="ribbon"></div><div class="ribbon"></div></div>"#
2102 );
2103 let res = client
2104 .get(format!("{}/23/present/blue", base_url))
2105 .send()
2106 .await
2107 .map_err(|_| test)?;
2108 assert_status!(res, test, StatusCode::OK);
2109 assert_html!(
2110 res,
2111 test,
2112 comparer,
2113 r#"<div class="present blue" hx-get="/23/present/purple" hx-swap="outerHTML"><div class="ribbon"></div><div class="ribbon"></div><div class="ribbon"></div><div class="ribbon"></div></div>"#
2114 );
2115 let res = client
2116 .get(format!("{}/23/present/purple", base_url))
2117 .send()
2118 .await
2119 .map_err(|_| test)?;
2120 assert_status!(res, test, StatusCode::OK);
2121 assert_html!(
2122 res,
2123 test,
2124 comparer,
2125 r#"<div class="present purple" hx-get="/23/present/red" hx-swap="outerHTML"><div class="ribbon"></div><div class="ribbon"></div><div class="ribbon"></div><div class="ribbon"></div></div>"#
2126 );
2127 test = (3, 2);
2128 let res = client
2129 .get(format!("{}/23/present/green", base_url))
2130 .send()
2131 .await
2132 .map_err(|_| test)?;
2133 assert_status!(res, test, StatusCode::IM_A_TEAPOT);
2134 tx.send((false, 0).into()).await.unwrap();
2136 tx.send(SubmissionUpdate::Save).await.unwrap();
2137
2138 test = (4, 1);
2140 let res = client
2141 .get(format!("{}/23/ornament/on/1", base_url))
2142 .send()
2143 .await
2144 .map_err(|_| test)?;
2145 assert_status!(res, test, StatusCode::OK);
2146 assert_html!(
2147 res,
2148 test,
2149 comparer,
2150 r#"<div class="ornament on" id="ornament1" hx-trigger="load delay:2s once" hx-get="/23/ornament/off/1" hx-swap="outerHTML"></div>"#
2151 );
2152 let res = client
2153 .get(format!("{}/23/ornament/off/1", base_url))
2154 .send()
2155 .await
2156 .map_err(|_| test)?;
2157 assert_status!(res, test, StatusCode::OK);
2158 assert_html!(
2159 res,
2160 test,
2161 comparer,
2162 r#"<div class="ornament" id="ornament1" hx-trigger="load delay:2s once" hx-get="/23/ornament/on/1" hx-swap="outerHTML"></div>"#
2163 );
2164 let res = client
2165 .get(format!("{}/23/ornament/off/100", base_url))
2166 .send()
2167 .await
2168 .map_err(|_| test)?;
2169 assert_status!(res, test, StatusCode::OK);
2170 assert_html!(
2171 res,
2172 test,
2173 comparer,
2174 r#"<div class="ornament" id="ornament100" hx-trigger="load delay:2s once" hx-get="/23/ornament/on/100" hx-swap="outerHTML"></div>"#
2175 );
2176 test = (4, 2);
2177 let res = client
2178 .get(format!("{}/23/ornament/on/the_prettiest_one", base_url))
2179 .send()
2180 .await
2181 .map_err(|_| test)?;
2182 assert_status!(res, test, StatusCode::OK);
2183 assert_html!(
2184 res,
2185 test,
2186 comparer,
2187 r#"<div class="ornament on" id="ornamentthe_prettiest_one" hx-trigger="load delay:2s once" hx-get="/23/ornament/off/the_prettiest_one" hx-swap="outerHTML"></div>"#
2188 );
2189 test = (4, 3);
2190 let res = client
2191 .get(format!("{}/23/ornament/maybe-on/1", base_url))
2192 .send()
2193 .await
2194 .map_err(|_| test)?;
2195 assert_status!(res, test, StatusCode::IM_A_TEAPOT);
2196 tx.send((false, 0).into()).await.unwrap();
2198 tx.send(SubmissionUpdate::Save).await.unwrap();
2199
2200 test = (5, 1);
2202 let res = client
2203 .get(format!(
2204 "{}/23/ornament/on/%22%3E%3Cscript%3Ealert%28%22Spicy%20soup%21%22%29%3C%2Fscript%3E",
2205 base_url
2206 ))
2207 .send()
2208 .await
2209 .map_err(|_| test)?;
2210 assert_status!(res, test, StatusCode::OK);
2211 assert_html!(
2212 res,
2213 test,
2214 comparer,
2215 r#"<div class="ornament on" id="ornament"><script>alert("Spicy soup!")</script>" hx-trigger="load delay:2s once" hx-get="/23/ornament/off/"><script>alert("Spicy soup!")</script>" hx-swap="outerHTML"></div>"#
2216 );
2217 tx.send((true, 0).into()).await.unwrap();
2219 tx.send(SubmissionUpdate::Save).await.unwrap();
2220
2221 test = (6, 1);
2223 let url = &format!("{}/23/lockfile", base_url);
2224 let form = Form::new().part(
2225 "lockfile",
2226 Part::bytes(
2227 r#"[[package]]
2228name = "shuttle-runtime"
2229version = "0.49.0"
2230source = "registry+https://github.com/rust-lang/crates.io-index"
2231checksum = "337789faa0372648a8ac286b2f92a53121fe118f12e29009ac504872a5413cc6"
2232
2233[[package]]
2234name = "shuttle-service"
2235version = "0.49.0"
2236source = "registry+https://github.com/rust-lang/crates.io-index"
2237checksum = "22ba454b13e4e29b5b892a62c334360a571de5a25c936283416c94328427dd57"
2238"#
2239 .as_bytes(),
2240 )
2241 .file_name("Cargo.lock")
2242 .mime_str("application/octet-stream")
2243 .unwrap(),
2244 );
2245 let res = client
2246 .post(url)
2247 .multipart(form)
2248 .send()
2249 .await
2250 .map_err(|_| test)?;
2251 assert_status!(res, test, StatusCode::OK);
2252 assert_html!(
2253 res,
2254 test,
2255 comparer,
2256 r#"
2257<div style="background-color:#337789;top:250px;left:160px;"></div>
2258<div style="background-color:#22ba45;top:75px;left:19px;"></div>
2259"#
2260 );
2261 test = (6, 2);
2262 let form = Form::new().part(
2263 "lockfile",
2264 Part::bytes(
2265 r#"# This file is automatically @generated by Cargo.
2266# It is not intended for manual editing.
2267version = 4
2268
2269[[package]]
2270name = "addr2line"
2271version = "0.24.2"
2272source = "registry+https://github.com/rust-lang/crates.io-index"
2273checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
2274dependencies = [
2275 "gimli",
2276]
2277
2278[[package]]
2279name = "adler2"
2280version = "2.0.0"
2281source = "registry+https://github.com/rust-lang/crates.io-index"
2282checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
2283
2284[[package]]
2285name = "ahash"
2286version = "0.8.11"
2287source = "registry+https://github.com/rust-lang/crates.io-index"
2288checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
2289dependencies = [
2290 "cfg-if",
2291 "once_cell",
2292 "version_check",
2293 "zerocopy",
2294]
2295
2296[[package]]
2297name = "aho-corasick"
2298version = "1.1.3"
2299source = "registry+https://github.com/rust-lang/crates.io-index"
2300checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
2301dependencies = [
2302 "memchr",
2303]
2304
2305[[package]]
2306name = "allocator-api2"
2307version = "0.2.21"
2308source = "registry+https://github.com/rust-lang/crates.io-index"
2309checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
2310
2311[[package]]
2312name = "android-tzdata"
2313version = "0.1.1"
2314source = "registry+https://github.com/rust-lang/crates.io-index"
2315checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
2316
2317[[package]]
2318name = "android_system_properties"
2319version = "0.1.5"
2320source = "registry+https://github.com/rust-lang/crates.io-index"
2321checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
2322dependencies = [
2323 "libc",
2324]
2325
2326[[package]]
2327name = "anyhow"
2328version = "1.0.93"
2329source = "registry+https://github.com/rust-lang/crates.io-index"
2330checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
2331
2332[[package]]
2333name = "askama"
2334version = "0.12.1"
2335source = "registry+https://github.com/rust-lang/crates.io-index"
2336checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
2337dependencies = [
2338 "askama_derive",
2339 "askama_escape",
2340 "humansize",
2341 "num-traits",
2342 "percent-encoding",
2343]
2344
2345[[package]]
2346name = "askama_axum"
2347version = "0.4.0"
2348source = "registry+https://github.com/rust-lang/crates.io-index"
2349checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163"
2350dependencies = [
2351 "askama",
2352 "axum-core 0.4.5",
2353 "http 1.1.0",
2354]
2355
2356[[package]]
2357name = "askama_derive"
2358version = "0.12.5"
2359source = "registry+https://github.com/rust-lang/crates.io-index"
2360checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
2361dependencies = [
2362 "askama_parser",
2363 "basic-toml",
2364 "mime",
2365 "mime_guess",
2366 "proc-macro2",
2367 "quote",
2368 "serde",
2369 "syn 2.0.89",
2370]
2371
2372[[package]]
2373name = "askama_escape"
2374version = "0.10.3"
2375source = "registry+https://github.com/rust-lang/crates.io-index"
2376checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
2377
2378[[package]]
2379name = "askama_parser"
2380version = "0.2.1"
2381source = "registry+https://github.com/rust-lang/crates.io-index"
2382checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
2383dependencies = [
2384 "nom",
2385]
2386
2387[[package]]
2388name = "async-stream"
2389version = "0.3.6"
2390source = "registry+https://github.com/rust-lang/crates.io-index"
2391checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
2392dependencies = [
2393 "async-stream-impl",
2394 "futures-core",
2395 "pin-project-lite",
2396]
2397
2398[[package]]
2399name = "async-stream-impl"
2400version = "0.3.6"
2401source = "registry+https://github.com/rust-lang/crates.io-index"
2402checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
2403dependencies = [
2404 "proc-macro2",
2405 "quote",
2406 "syn 2.0.89",
2407]
2408
2409[[package]]
2410name = "async-trait"
2411version = "0.1.83"
2412source = "registry+https://github.com/rust-lang/crates.io-index"
2413checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
2414dependencies = [
2415 "proc-macro2",
2416 "quote",
2417 "syn 2.0.89",
2418]
2419
2420[[package]]
2421name = "atoi"
2422version = "2.0.0"
2423source = "registry+https://github.com/rust-lang/crates.io-index"
2424checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
2425dependencies = [
2426 "num-traits",
2427]
2428
2429[[package]]
2430name = "autocfg"
2431version = "1.4.0"
2432source = "registry+https://github.com/rust-lang/crates.io-index"
2433checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
2434
2435[[package]]
2436name = "axum"
2437version = "0.6.20"
2438source = "registry+https://github.com/rust-lang/crates.io-index"
2439checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
2440dependencies = [
2441 "async-trait",
2442 "axum-core 0.3.4",
2443 "bitflags 1.3.2",
2444 "bytes",
2445 "futures-util",
2446 "http 0.2.12",
2447 "http-body 0.4.6",
2448 "hyper 0.14.31",
2449 "itoa",
2450 "matchit",
2451 "memchr",
2452 "mime",
2453 "percent-encoding",
2454 "pin-project-lite",
2455 "rustversion",
2456 "serde",
2457 "sync_wrapper 0.1.2",
2458 "tower 0.4.13",
2459 "tower-layer",
2460 "tower-service",
2461]
2462
2463[[package]]
2464name = "axum"
2465version = "0.7.9"
2466source = "registry+https://github.com/rust-lang/crates.io-index"
2467checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
2468dependencies = [
2469 "async-trait",
2470 "axum-core 0.4.5",
2471 "bytes",
2472 "futures-util",
2473 "http 1.1.0",
2474 "http-body 1.0.1",
2475 "http-body-util",
2476 "hyper 1.5.1",
2477 "hyper-util",
2478 "itoa",
2479 "matchit",
2480 "memchr",
2481 "mime",
2482 "percent-encoding",
2483 "pin-project-lite",
2484 "rustversion",
2485 "serde",
2486 "serde_json",
2487 "serde_path_to_error",
2488 "serde_urlencoded",
2489 "sync_wrapper 1.0.2",
2490 "tokio",
2491 "tower 0.5.1",
2492 "tower-layer",
2493 "tower-service",
2494 "tracing",
2495]
2496
2497[[package]]
2498name = "axum-core"
2499version = "0.3.4"
2500source = "registry+https://github.com/rust-lang/crates.io-index"
2501checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
2502dependencies = [
2503 "async-trait",
2504 "bytes",
2505 "futures-util",
2506 "http 0.2.12",
2507 "http-body 0.4.6",
2508 "mime",
2509 "rustversion",
2510 "tower-layer",
2511 "tower-service",
2512]
2513
2514[[package]]
2515name = "axum-core"
2516version = "0.4.5"
2517source = "registry+https://github.com/rust-lang/crates.io-index"
2518checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
2519dependencies = [
2520 "async-trait",
2521 "bytes",
2522 "futures-util",
2523 "http 1.1.0",
2524 "http-body 1.0.1",
2525 "http-body-util",
2526 "mime",
2527 "pin-project-lite",
2528 "rustversion",
2529 "sync_wrapper 1.0.2",
2530 "tower-layer",
2531 "tower-service",
2532 "tracing",
2533]
2534
2535[[package]]
2536name = "axum-extra"
2537version = "0.9.6"
2538source = "registry+https://github.com/rust-lang/crates.io-index"
2539checksum = "c794b30c904f0a1c2fb7740f7df7f7972dfaa14ef6f57cb6178dc63e5dca2f04"
2540dependencies = [
2541 "axum 0.7.9",
2542 "axum-core 0.4.5",
2543 "bytes",
2544 "cookie",
2545 "fastrand",
2546 "futures-util",
2547 "http 1.1.0",
2548 "http-body 1.0.1",
2549 "http-body-util",
2550 "mime",
2551 "multer",
2552 "pin-project-lite",
2553 "serde",
2554 "tower 0.5.1",
2555 "tower-layer",
2556 "tower-service",
2557]
2558
2559[[package]]
2560name = "backtrace"
2561version = "0.3.74"
2562source = "registry+https://github.com/rust-lang/crates.io-index"
2563checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
2564dependencies = [
2565 "addr2line",
2566 "cfg-if",
2567 "libc",
2568 "miniz_oxide",
2569 "object",
2570 "rustc-demangle",
2571 "windows-targets 0.52.6",
2572]
2573
2574[[package]]
2575name = "base64"
2576version = "0.21.7"
2577source = "registry+https://github.com/rust-lang/crates.io-index"
2578checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
2579
2580[[package]]
2581name = "base64"
2582version = "0.22.1"
2583source = "registry+https://github.com/rust-lang/crates.io-index"
2584checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
2585
2586[[package]]
2587name = "base64ct"
2588version = "1.6.0"
2589source = "registry+https://github.com/rust-lang/crates.io-index"
2590checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
2591
2592[[package]]
2593name = "basic-toml"
2594version = "0.1.9"
2595source = "registry+https://github.com/rust-lang/crates.io-index"
2596checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
2597dependencies = [
2598 "serde",
2599]
2600
2601[[package]]
2602name = "bitflags"
2603version = "1.3.2"
2604source = "registry+https://github.com/rust-lang/crates.io-index"
2605checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
2606
2607[[package]]
2608name = "bitflags"
2609version = "2.6.0"
2610source = "registry+https://github.com/rust-lang/crates.io-index"
2611checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
2612dependencies = [
2613 "serde",
2614]
2615
2616[[package]]
2617name = "block-buffer"
2618version = "0.10.4"
2619source = "registry+https://github.com/rust-lang/crates.io-index"
2620checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
2621dependencies = [
2622 "generic-array",
2623]
2624
2625[[package]]
2626name = "bumpalo"
2627version = "3.16.0"
2628source = "registry+https://github.com/rust-lang/crates.io-index"
2629checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
2630
2631[[package]]
2632name = "byteorder"
2633version = "1.5.0"
2634source = "registry+https://github.com/rust-lang/crates.io-index"
2635checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
2636
2637[[package]]
2638name = "bytes"
2639version = "1.8.0"
2640source = "registry+https://github.com/rust-lang/crates.io-index"
2641checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
2642
2643[[package]]
2644name = "shuttlings-cch24"
2645version = "0.1.0"
2646dependencies = [
2647 "askama",
2648 "askama_axum",
2649 "axum 0.7.9",
2650 "axum-extra",
2651 "cargo-manifest",
2652 "chrono",
2653 "ipnet",
2654 "jsonwebtoken",
2655 "leaky-bucket",
2656 "rand",
2657 "serde",
2658 "serde_json",
2659 "serde_yml",
2660 "shuttle-axum",
2661 "shuttle-runtime",
2662 "shuttle-shared-db",
2663 "sqlx",
2664 "tokio",
2665 "toml",
2666 "tower-http",
2667 "uuid",
2668]
2669
2670[[package]]
2671name = "signal-hook"
2672version = "0.3.17"
2673source = "registry+https://github.com/rust-lang/crates.io-index"
2674checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
2675dependencies = [
2676 "libc",
2677 "signal-hook-registry",
2678]
2679"#
2680 .as_bytes(),
2681 )
2682 .file_name("Cargo.lock")
2683 .mime_str("application/octet-stream")
2684 .unwrap(),
2685 );
2686 let res = client
2687 .post(url)
2688 .multipart(form)
2689 .send()
2690 .await
2691 .map_err(|_| test)?;
2692 assert_status!(res, test, StatusCode::OK);
2693 assert_html!(
2694 res,
2695 test,
2696 comparer,
2697 r#"
2698<div style="background-color:#dfbe27;top:126px;left:86px;"></div>
2699<div style="background-color:#512761;top:224px;left:187px;"></div>
2700<div style="background-color:#e89da8;top:65px;left:168px;"></div>
2701<div style="background-color:#8e60d3;top:67px;left:13px;"></div>
2702<div style="background-color:#683d79;top:16px;left:231px;"></div>
2703<div style="background-color:#e99994;top:27px;left:35px;"></div>
2704<div style="background-color:#819e72;top:25px;left:219px;"></div>
2705<div style="background-color:#4c95c1;top:11px;left:160px;"></div>
2706<div style="background-color:#b79091;top:223px;left:24px;"></div>
2707<div style="background-color:#a41603;top:247px;left:205px;"></div>
2708<div style="background-color:#19fe8d;top:108px;left:177px;"></div>
2709<div style="background-color:#619743;top:227px;left:75px;"></div>
2710<div style="background-color:#acb116;top:28px;left:107px;"></div>
2711<div style="background-color:#0b5a71;top:166px;left:243px;"></div>
2712<div style="background-color:#c7c24d;top:225px;left:93px;"></div>
2713<div style="background-color:#721cae;top:125px;left:229px;"></div>
2714<div style="background-color:#f28d99;top:236px;left:139px;"></div>
2715<div style="background-color:#ace50b;top:173px;left:232px;"></div>
2716<div style="background-color:#3b829e;top:78px;left:50px;"></div>
2717<div style="background-color:#edca88;top:188px;left:19px;"></div>
2718<div style="background-color:#759fa5;top:119px;left:162px;"></div>
2719<div style="background-color:#09f2bd;top:97px;left:70px;"></div>
2720<div style="background-color:#c794b3;top:12px;left:144px;"></div>
2721<div style="background-color:#8d82cb;top:51px;left:44px;"></div>
2722<div style="background-color:#9d297d;top:235px;left:25px;"></div>
2723<div style="background-color:#72b325;top:79px;left:22px;"></div>
2724<div style="background-color:#8c3c1a;top:54px;left:143px;"></div>
2725<div style="background-color:#823388;top:226px;left:40px;"></div>
2726<div style="background-color:#bef38d;top:69px;left:22px;"></div>
2727<div style="background-color:#b048fb;top:99px;left:253px;"></div>
2728<div style="background-color:#3078c7;top:98px;left:155px;"></div>
2729<div style="background-color:#792967;top:22px;left:23px;"></div>
2730<div style="background-color:#1fd0f2;top:88px;left:65px;"></div>
2731<div style="background-color:#9ac015;top:12px;left:170px;"></div>
2732<div style="background-color:#862158;top:125px;left:71px;"></div>
2733"#
2734 );
2735 test = (6, 3);
2736 let form = Form::new().part(
2737 "blockfile",
2738 Part::bytes(r#"MINE DIAMONDS!!!!"#.as_bytes())
2739 .file_name("Cargo.block")
2740 .mime_str("application/octet-stream")
2741 .unwrap(),
2742 );
2743 let res = client
2744 .post(url)
2745 .multipart(form)
2746 .send()
2747 .await
2748 .map_err(|_| test)?;
2749 assert_status!(res, test, StatusCode::BAD_REQUEST);
2750 test = (6, 4);
2751 let form = Form::new();
2752 let res = client
2753 .post(url)
2754 .multipart(form)
2755 .send()
2756 .await
2757 .map_err(|_| test)?;
2758 assert_status!(res, test, StatusCode::BAD_REQUEST);
2759 test = (6, 5);
2760 let form = Form::new().part(
2761 "lockfile",
2762 Part::bytes(
2763 "[[package]]
2764checksum = \"337789faa0372648a8ac286b2f92a53121fe118f12e29009ac504872a5413cc6\"
2765\x00\x00"
2766 .as_bytes(),
2767 )
2768 .file_name("Cargo.lock")
2769 .mime_str("application/octet-stream")
2770 .unwrap(),
2771 );
2772 let res = client
2773 .post(url)
2774 .multipart(form)
2775 .send()
2776 .await
2777 .map_err(|_| test)?;
2778 assert_status!(res, test, StatusCode::BAD_REQUEST);
2779 test = (6, 5);
2780 let form = Form::new().part(
2781 "lockfile",
2782 Part::bytes(
2783 r#"[[package]]
2784checksum = "337789faa0372648a8ac286b2f92a53121fe118f12e29009ac504872a5413cc6"
2785fn jingle_bells(volume: f32) -> Result<Sound<DingDong>, MusicError> { ... }
2786"#
2787 .as_bytes(),
2788 )
2789 .file_name("Cargo.lock")
2790 .mime_str("application/octet-stream")
2791 .unwrap(),
2792 );
2793 let res = client
2794 .post(url)
2795 .multipart(form)
2796 .send()
2797 .await
2798 .map_err(|_| test)?;
2799 assert_status!(res, test, StatusCode::BAD_REQUEST);
2800 test = (6, 6);
2801 let form = Form::new().part(
2802 "lockfile",
2803 Part::bytes(
2804 r#"[[package]]
2805checksum = "337789faa0372648a8ac286b2f92a53121fe118f12e29009ac504872a5413cc6"
2806"#
2807 .as_bytes(),
2808 )
2809 .file_name("Cargo.lock")
2810 .mime_str("application/octet-stream")
2811 .unwrap(),
2812 );
2813 let res = client
2814 .post(url)
2815 .multipart(form)
2816 .send()
2817 .await
2818 .map_err(|_| test)?;
2819 assert_status!(res, test, StatusCode::OK);
2820 assert_html!(
2821 res,
2822 test,
2823 comparer,
2824 r#"
2825<div style="background-color:#337789;top:250px;left:160px;"></div>
2826"#
2827 );
2828 test = (6, 7);
2829 let form = Form::new().part(
2830 "lockfile",
2831 Part::bytes(
2832 r#"[[package]]
2833checksum = [ "cookie", "milk", "hot cocoa" ]
2834"#
2835 .as_bytes(),
2836 )
2837 .file_name("Cargo.lock")
2838 .mime_str("application/octet-stream")
2839 .unwrap(),
2840 );
2841 let res = client
2842 .post(url)
2843 .multipart(form)
2844 .send()
2845 .await
2846 .map_err(|_| test)?;
2847 assert_status!(res, test, StatusCode::BAD_REQUEST);
2848 test = (6, 8);
2849 let form = Form::new().part(
2850 "lockfile",
2851 Part::bytes(
2852 r#"[[package]]
2853checksum = "337789faa0"
2854"#
2855 .as_bytes(),
2856 )
2857 .file_name("Cargo.lock")
2858 .mime_str("application/octet-stream")
2859 .unwrap(),
2860 );
2861 let res = client
2862 .post(url)
2863 .multipart(form)
2864 .send()
2865 .await
2866 .map_err(|_| test)?;
2867 assert_status!(res, test, StatusCode::OK);
2868 assert_html!(
2869 res,
2870 test,
2871 comparer,
2872 r#"
2873<div style="background-color:#337789;top:250px;left:160px;"></div>
2874"#
2875 );
2876 test = (6, 9);
2877 let form = Form::new().part(
2878 "lockfile",
2879 Part::bytes(
2880 r#"[[package]]
2881checksum = "337789faa0"
2882"#
2883 .as_bytes(),
2884 )
2885 .file_name("Cargo.lock")
2886 .mime_str("application/octet-stream")
2887 .unwrap(),
2888 );
2889 let res = client
2890 .post(url)
2891 .multipart(form)
2892 .send()
2893 .await
2894 .map_err(|_| test)?;
2895 assert_status!(res, test, StatusCode::OK);
2896 assert_html!(
2897 res,
2898 test,
2899 comparer,
2900 r#"
2901<div style="background-color:#337789;top:250px;left:160px;"></div>
2902"#
2903 );
2904 test = (6, 10);
2905 let form = Form::new().part(
2906 "lockfile",
2907 Part::bytes(
2908 r#"[[package]]
2909checksum = "337789FAA0"
2910"#
2911 .as_bytes(),
2912 )
2913 .file_name("Cargo.lock")
2914 .mime_str("application/octet-stream")
2915 .unwrap(),
2916 );
2917 let res = client
2918 .post(url)
2919 .multipart(form)
2920 .send()
2921 .await
2922 .map_err(|_| test)?;
2923 assert_status!(res, test, StatusCode::OK);
2924 assert_html!(
2925 res,
2926 test,
2927 comparer,
2928 r#"
2929<div style="background-color:#337789;top:250px;left:160px;"></div>
2930"#
2931 );
2932 test = (6, 11);
2933 let form = Form::new().part(
2934 "lockfile",
2935 Part::bytes(
2936 r#"[[package]]
2937checksum = "3377QQFAA0"
2938"#
2939 .as_bytes(),
2940 )
2941 .file_name("Cargo.lock")
2942 .mime_str("application/octet-stream")
2943 .unwrap(),
2944 );
2945 let res = client
2946 .post(url)
2947 .multipart(form)
2948 .send()
2949 .await
2950 .map_err(|_| test)?;
2951 assert_status!(res, test, StatusCode::UNPROCESSABLE_ENTITY);
2952 test = (6, 12);
2953 let form = Form::new().part(
2954 "lockfile",
2955 Part::bytes(
2956 r#"[[package]]
2957checksum = "BEEF"
2958"#
2959 .as_bytes(),
2960 )
2961 .file_name("Cargo.lock")
2962 .mime_str("application/octet-stream")
2963 .unwrap(),
2964 );
2965 let res = client
2966 .post(url)
2967 .multipart(form)
2968 .send()
2969 .await
2970 .map_err(|_| test)?;
2971 assert_status!(res, test, StatusCode::UNPROCESSABLE_ENTITY);
2972
2973 tx.send((false, 100).into()).await.unwrap();
2975 tx.send(SubmissionUpdate::Save).await.unwrap();
2976
2977 Ok(())
2978}