Skip to content

Commit 0f3d79e

Browse files
authored
Try #4:
2 parents 690a8ee + fa5f7e4 commit 0f3d79e

File tree

6 files changed

+169
-28
lines changed

6 files changed

+169
-28
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

processor/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ serde_json = "1.0.64"
2121
valuer-client = { path = "../valuer-client" }
2222
strum = { version = "0.20.0", features = ["derive"] }
2323
base64 = "0.13.0"
24+
rand = "0.8.3"
25+
rand_chacha = "0.3.0"

processor/src/fake.rs

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//! Pure implementation that returns valid, but fake data
2+
3+
use crate::{JobProgress, ProtocolSender, Request};
4+
use judge_apis::judge_log::{JudgeLog, JudgeLogSubtaskRow, JudgeLogTestRow};
5+
use pom::TestId;
6+
use rand::{
7+
distributions::{Alphanumeric, Uniform},
8+
prelude::SliceRandom,
9+
Rng, SeedableRng,
10+
};
11+
use rand_chacha::ChaChaRng;
12+
use std::hash::{Hash, Hasher};
13+
use tokio::sync::{mpsc, oneshot};
14+
use valuer_api::{status_codes, JudgeLogKind, Status, StatusKind, SubtaskId};
15+
16+
#[derive(Clone)]
17+
pub struct FakeSettings {}
18+
19+
pub fn judge(req: Request, settings: FakeSettings) -> JobProgress {
20+
let (done_tx, done_rx) = oneshot::channel();
21+
let (events_tx, events_rx) = mpsc::channel(1);
22+
tokio::task::spawn(async move {
23+
let mut protocol_sender = ProtocolSender {
24+
sent: Vec::new(),
25+
tx: events_tx,
26+
debug_dump_dir: None,
27+
};
28+
29+
do_judge(req, &mut protocol_sender, settings).await;
30+
31+
done_tx.send(Ok(())).ok();
32+
});
33+
JobProgress { events_rx, done_rx }
34+
}
35+
36+
fn stable_hash<T: Hash + ?Sized>(val: &T) -> u64 {
37+
let mut h = std::collections::hash_map::DefaultHasher::new();
38+
val.hash(&mut h);
39+
h.finish()
40+
}
41+
42+
fn generate_string((len_lo, len_hi): (usize, usize), rng: &mut ChaChaRng) -> String {
43+
let dist = Uniform::new(len_lo, len_hi);
44+
let len = rng.sample(dist);
45+
46+
(0..len).map(|_| rng.sample(Alphanumeric) as char).collect()
47+
}
48+
49+
fn generate_judge_log(kind: JudgeLogKind, rng: &mut ChaChaRng) -> JudgeLog {
50+
let test_count = rng.sample(Uniform::new(3_u32, 20));
51+
let make_status = |rng: &mut ChaChaRng| Status {
52+
kind: [StatusKind::Accepted, StatusKind::Rejected]
53+
.choose(&mut *rng)
54+
.copied()
55+
.unwrap(),
56+
code: [
57+
status_codes::WRONG_ANSWER,
58+
status_codes::TEST_PASSED,
59+
status_codes::TIME_LIMIT_EXCEEDED,
60+
status_codes::RUNTIME_ERROR,
61+
]
62+
.choose(&mut *rng)
63+
.copied()
64+
.unwrap()
65+
.to_owned(),
66+
};
67+
let tests = (0..test_count)
68+
.map(|id| JudgeLogTestRow {
69+
test_id: TestId::make(id + 1),
70+
status: Some(make_status(&mut *rng)),
71+
test_stdin: Some(generate_string((3, 100), rng)),
72+
test_stdout: Some(generate_string((3, 100), rng)),
73+
test_stderr: Some(generate_string((3, 100), rng)),
74+
test_answer: Some(generate_string((3, 100), rng)),
75+
time_usage: Some(rng.sample(Uniform::new(1_000_000, 1_000_000_000))),
76+
memory_usage: Some(rng.sample(Uniform::new(1_000_000, 1_000_000_000))),
77+
})
78+
.collect();
79+
let subtask_count = rng.sample(Uniform::new(1_u32, 10));
80+
let subtasks = (0..subtask_count)
81+
.map(|id| JudgeLogSubtaskRow {
82+
subtask_id: SubtaskId::make(id + 1),
83+
score: Some(rng.sample(Uniform::new(0, 100))),
84+
})
85+
.collect();
86+
JudgeLog {
87+
kind,
88+
tests,
89+
subtasks,
90+
score: rng.sample(Uniform::new(0, 100)),
91+
status: make_status(rng),
92+
compile_log: (generate_string((10, 200), rng)),
93+
is_full: false,
94+
}
95+
}
96+
97+
async fn do_judge(req: Request, protocol_sender: &mut ProtocolSender, _settings: FakeSettings) {
98+
for kind in JudgeLogKind::list() {
99+
let seed = stable_hash(&(&req.toolchain_name, &req.run_source, kind.as_str()));
100+
tracing::info!(kind = kind.as_str(), seed = seed, "generating judge log");
101+
let mut rng = ChaChaRng::seed_from_u64(seed);
102+
let log = generate_judge_log(kind, &mut rng);
103+
protocol_sender.send_log(log).await;
104+
}
105+
}

processor/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
mod compile;
55
mod exec_test;
6+
pub mod fake;
67
mod request_builder;
78
mod transform_judge_log;
89

src/main.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ struct Args {
3030
/// Directory containing judging logs. Set to `/dev/null` to disable logging
3131
#[clap(long, default_value = "/var/log/judges")]
3232
logs: PathBuf,
33+
/// Enable fake mode.
34+
/// In this mode judge never loads problems or toolchains and just
35+
/// generates random data for requests
36+
#[clap(long)]
37+
fake: bool,
3338
}
3439

3540
async fn create_clients(args: &Args) -> anyhow::Result<processor::Clients> {
@@ -54,18 +59,10 @@ async fn create_clients(args: &Args) -> anyhow::Result<processor::Clients> {
5459
})
5560
}
5661

57-
#[tokio::main]
58-
async fn main() -> anyhow::Result<()> {
59-
tracing_subscriber::fmt()
60-
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
61-
.init();
62-
let args: Args = Clap::parse();
62+
async fn initialize_normal(args: &Args) -> anyhow::Result<rest::ServeKind> {
6363
let clients = create_clients(&args)
6464
.await
6565
.context("failed to initialize dependency clients")?;
66-
tracing::info!("Running REST API");
67-
let cfg = rest::RestConfig { port: args.port };
68-
6966
let settings = {
7067
let checker_logs = match &args.logs {
7168
p if p == Path::new("/dev/null") => (None),
@@ -81,6 +78,30 @@ async fn main() -> anyhow::Result<()> {
8178
}
8279
processor::Settings { checker_logs }
8380
};
84-
rest::serve(cfg, clients, settings).await?;
81+
Ok(rest::ServeKind::Normal { settings, clients })
82+
}
83+
84+
fn initialize_fake() -> rest::ServeKind {
85+
rest::ServeKind::Fake {
86+
settings: processor::fake::FakeSettings {},
87+
}
88+
}
89+
90+
#[tokio::main]
91+
async fn main() -> anyhow::Result<()> {
92+
tracing_subscriber::fmt()
93+
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
94+
.init();
95+
let args: Args = Clap::parse();
96+
tracing::info!("Running REST API");
97+
let cfg = rest::RestConfig { port: args.port };
98+
99+
let serve_config = if args.fake {
100+
initialize_fake()
101+
} else {
102+
initialize_normal(&args).await?
103+
};
104+
105+
rest::serve(cfg, serve_config).await?;
85106
Ok(())
86107
}

src/rest.rs

+28-18
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,19 @@ impl JudgeJob {
4242
}
4343
}
4444

45+
pub enum ServeKind {
46+
Normal {
47+
clients: processor::Clients,
48+
settings: processor::Settings,
49+
},
50+
Fake {
51+
settings: processor::fake::FakeSettings,
52+
},
53+
}
54+
4555
struct State {
4656
judge: RwLock<HashMap<Uuid, Arc<Mutex<JudgeJob>>>>,
47-
clients: processor::Clients,
48-
settings: processor::Settings,
57+
kind: ServeKind,
4958
}
5059

5160
async fn start_job(
@@ -58,15 +67,21 @@ async fn start_job(
5867
run_source: req.run_source.0,
5968
};
6069
let job_id = Uuid::new_v4();
61-
let mut settings = state.settings.clone();
62-
{
63-
let mut job_id_s = Uuid::encode_buffer();
64-
let job_id_s = job_id.to_hyphenated().encode_lower(&mut job_id_s);
65-
if let Some(p) = &mut settings.checker_logs {
66-
p.push(&*job_id_s);
70+
71+
let mut progress = match &state.kind {
72+
ServeKind::Normal { settings, clients } => {
73+
let mut settings = settings.clone();
74+
{
75+
let mut job_id_s = Uuid::encode_buffer();
76+
let job_id_s = job_id.to_hyphenated().encode_lower(&mut job_id_s);
77+
if let Some(p) = &mut settings.checker_logs {
78+
p.push(&*job_id_s);
79+
}
80+
}
81+
processor::judge(proc_request, clients.clone(), settings)
6782
}
68-
}
69-
let mut progress = processor::judge(proc_request, state.clients.clone(), settings);
83+
ServeKind::Fake { settings } => processor::fake::judge(proc_request, settings.clone()),
84+
};
7085
let job = JudgeJob {
7186
id: job_id,
7287
live_test: None,
@@ -154,16 +169,11 @@ async fn get_job_judge_log(
154169
}
155170

156171
/// Serves api
157-
#[tracing::instrument(skip(cfg, clients, settings))]
158-
pub async fn serve(
159-
cfg: RestConfig,
160-
clients: processor::Clients,
161-
settings: processor::Settings,
162-
) -> anyhow::Result<()> {
172+
#[tracing::instrument(skip(cfg, kind))]
173+
pub async fn serve(cfg: RestConfig, kind: ServeKind) -> anyhow::Result<()> {
163174
let state = Arc::new(State {
164175
judge: RwLock::new(HashMap::new()),
165-
clients,
166-
settings,
176+
kind,
167177
});
168178
let state2 = state.clone();
169179
let route_create_job = warp::post()

0 commit comments

Comments
 (0)