Skip to content

Commit

Permalink
chore: simplify personas to be an inline trait of a grunt, rather tha…
Browse files Browse the repository at this point in the history
…n a reference to a map
  • Loading branch information
klardotsh committed Feb 22, 2022
1 parent 94c9dbd commit 053f413
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 217 deletions.
75 changes: 35 additions & 40 deletions examples/simpleish/seatrial.ron
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,46 @@
grunts: [
(
base_name: "Postmaster General",
persona: "poster_child",
count: 1,
persona: (
timeout: Seconds(30),
sequence: [
LuaFunction("generate_profile"),
Http(Post(
url: "/profile",
body: LuaTableValue("profile"),
headers: { "Content-Type": Value("application/json") },
)),
Combinator(AllOf([
WarnUnlessStatusCodeInRange(200, 299),
WarnUnlessHeaderExists("X-Never-Gonna-Give-You-Up"),
]))
]
),
),
(
base_name: "Reloader Grunt",
persona: "spam_reloader",
count: 10,
),
],
persona: (
timeout: Seconds(30),

personas: {
"poster_child": (
timeout: Seconds(30),
sequence: [
LuaFunction("generate_profile"),
Http(Post(
url: "/profile",
body: LuaTableValue("profile"),
headers: { "Content-Type": Value("application/json") },
)),
Combinator(AllOf([
WarnUnlessStatusCodeInRange(200, 299),
WarnUnlessHeaderExists("X-Never-Gonna-Give-You-Up"),
]))
]
sequence: [
LuaFunction("generate_30_day_range"),
Http(Get(
url: "/calendar",
params: {
"start_date": LuaTableValue("start_date"),
"end_date": LuaTableValue("end_date"),
},
)),
Combinator(AllOf([
WarnUnlessStatusCodeInRange(200, 299),
WarnUnlessHeaderExists("X-Never-Gonna-Give-You-Up"),
LuaFunction("is_valid_esoteric_format"),
])),
ControlFlow(GoTo(index: 0, max_times: 2)),
],
),
),
"spam_reloader": (
timeout: Seconds(30),

sequence: [
LuaFunction("generate_30_day_range"),
Http(Get(
url: "/calendar",
params: {
"start_date": LuaTableValue("start_date"),
"end_date": LuaTableValue("end_date"),
},
)),
Combinator(AllOf([
WarnUnlessStatusCodeInRange(200, 299),
WarnUnlessHeaderExists("X-Never-Gonna-Give-You-Up"),
LuaFunction("is_valid_esoteric_format"),
])),
ControlFlow(GoTo(index: 0, max_times: 2)),
],
),
},
],
)
4 changes: 2 additions & 2 deletions src/combinator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use nanoserde::DeRon;

use crate::persona::Persona;
use crate::grunt::Grunt;
use crate::pipeline::action::PipelineAction;
use crate::pipeline::step_handler::{
StepCompletion, StepError, StepHandler, StepHandlerInit, StepResult,
Expand All @@ -22,7 +22,7 @@ pub enum Action {
pub struct CombinatorHandler;

impl StepHandler for CombinatorHandler {
fn new(_: &str, _: &Persona) -> StepHandlerInit<Self> {
fn new(_: &Grunt) -> StepHandlerInit<Self> {
Ok(Self {})
}

Expand Down
63 changes: 54 additions & 9 deletions src/grunt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,60 @@ use nanoserde::DeRon;

use std::fmt::Display;

#[cfg(test)]
use crate::config_duration::ConfigDuration;
use crate::persona::{Persona, PersonaSpec};
use crate::situation::{SituationParseErr, SituationParseErrKind};

// build out of a GruntSpec during Situation construction
#[derive(Clone, Debug)]
pub struct Grunt {
pub name: String,
pub persona_idx: usize,
pub persona: Persona,
}

impl Grunt {
pub fn from_spec_with_multiplier(
spec: &GruntSpec,
multiplier: usize,
) -> Result<Vec<Self>, SituationParseErr> {
let num_grunts = spec.real_count() * multiplier;
if num_grunts < 1 {
return Err(SituationParseErr {
kind: SituationParseErrKind::Semantics {
message: "if provided, grunt count must be >=1".into(),
location: "unknown".into(), // this gets replaced upstream
},
});
}

let mut grunts: Vec<Self> = Vec::with_capacity(num_grunts);
for slot in 0..num_grunts {
grunts.push(Grunt {
name: spec.formatted_name(slot),
persona: (&spec.persona).into(),
});
}

Ok(grunts)
}
}

#[derive(Clone, Debug, DeRon)]
pub struct GruntSpec {
pub base_name: Option<String>,
pub persona: String,
pub persona: PersonaSpec,
pub count: Option<usize>,
}

impl GruntSpec {
pub fn formatted_name(&self, uniqueness: impl Display) -> String {
format!(
"{} {}",
self.base_name
.clone()
.unwrap_or_else(|| format!("Grunt<{}>", self.persona)),
self.base_name.clone().unwrap_or_else(|| format!(
"Grunt<taking {} actions>",
self.persona.sequence.len()
)),
uniqueness,
)
}
Expand All @@ -36,7 +69,11 @@ impl GruntSpec {
fn test_formatted_name() {
let spec = GruntSpec {
base_name: Some("Jimbo Gruntseph".into()),
persona: "blahblah".into(),
persona: PersonaSpec {
headers: None,
sequence: vec![],
timeout: ConfigDuration::Seconds(30),
},
count: None,
};

Expand All @@ -47,18 +84,26 @@ fn test_formatted_name() {
fn test_formatted_name_no_base() {
let spec = GruntSpec {
base_name: None,
persona: "blahblah".into(),
persona: PersonaSpec {
headers: None,
sequence: vec![],
timeout: ConfigDuration::Seconds(30),
},
count: None,
};

assert_eq!("Grunt<blahblah> 1", spec.formatted_name(1));
assert_eq!("Grunt<taking 0 actions> 1", spec.formatted_name(1));
}

#[test]
fn test_real_count() {
let spec = GruntSpec {
base_name: None,
persona: "blahblah".into(),
persona: PersonaSpec {
headers: None,
sequence: vec![],
timeout: ConfigDuration::Seconds(30),
},
count: None,
};

Expand Down
11 changes: 4 additions & 7 deletions src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ureq::{Agent, AgentBuilder};
use std::collections::HashMap;

use crate::config_duration::ConfigDuration;
use crate::persona::Persona;
use crate::grunt::Grunt;
use crate::pipeline::action::{ConfigActionMap, PipelineAction, Reference};
use crate::pipeline::step_handler::{
StepCompletion, StepError, StepHandler, StepHandlerInit, StepResult,
Expand Down Expand Up @@ -114,14 +114,11 @@ pub struct HttpHandler {
}

impl StepHandler for HttpHandler {
fn new(grunt_name: &str, persona: &Persona) -> StepHandlerInit<Self> {
fn new(grunt: &Grunt) -> StepHandlerInit<Self> {
Ok(Self {
agent: AgentBuilder::new()
.user_agent(&format!(
"seatrial/grunt={}/persona={}",
grunt_name, persona.name
))
.timeout((&persona.spec.timeout).into())
.user_agent(&format!("seatrial/grunt={}", grunt.name,))
.timeout((&grunt.persona.timeout).into())
.build(),
})
}
Expand Down
102 changes: 62 additions & 40 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use url::Url;

use std::str::FromStr;
use std::sync::{mpsc, Arc, Barrier};
use std::sync::mpsc::channel;
use std::sync::{Arc, Barrier};
use std::thread;
use std::thread::JoinHandle;

Expand Down Expand Up @@ -37,12 +38,10 @@ fn main() -> std::io::Result<()> {
.unwrap();

// TODO: get rid of unwrap!
let situations: Vec<Arc<Situation>> = args
let situations: Vec<Situation> = args
.situations
.iter()
.map(|situation| {
Arc::new(Situation::from_spec(situation, &base_url, args.multiplier).unwrap())
})
.map(|situation| Situation::from_spec(situation, &base_url, args.multiplier).unwrap())
.collect();

// TODO: find a less hacky way of dealing with situation lifecycles. this is a brute-force
Expand All @@ -54,44 +53,75 @@ fn main() -> std::io::Result<()> {
// no need for any of the ephemeral *Spec objects at this point
drop(args);

let mut situation_threads: Vec<JoinHandle<()>> = Vec::with_capacity(situations.len());
let (sit_tx, sit_rx) = channel::<Result<(), StepHandlerInitError>>();
let barrier = Arc::new(Barrier::new(situations.len()));
let situation_threads = situations
.iter()
.map(|situation| {
let sit_tx = sit_tx.clone();
let barrier = barrier.clone();

thread::spawn(move || {
let (grunt_tx, grunt_rx) = channel::<Result<(), StepHandlerInitError>>();

let grunt_threads: Vec<_> = situation
.grunts
.iter()
.map(|grunt| {
let grunt_tx = grunt_tx.clone();
let barrier = barrier.clone();
let situation = situation.clone();
thread::spawn(move || {
grunt_tx
.send(grunt_worker(barrier, &situation, grunt))
.unwrap()
})
})
.collect();

drop(grunt_tx);

for thread in grunt_threads {
match grunt_rx.recv().unwrap() {
Ok(_) => {
// there's no actual guarantee here that thread is the same thread taht
// sent whatever data we got, and that's okay, we're using this as a
// lazy place to just ensure all threads have finished, not as a proper
// data consolidation step
thread.join().unwrap();
sit_tx.send(Ok(()))
}
res @ Err(_) => sit_tx.send(res),
}
.ok();
}
})
})
.collect::<Vec<JoinHandle<_>>>();

for situation in situations {
let barrier = barrier.clone();

situation_threads.push(thread::spawn(move || {
let (tx, rx) = mpsc::channel();

for grunt in &situation.grunts {
let barrier = barrier.clone();
let situation = situation.clone();
let tx = tx.clone();

thread::spawn(move || grunt_worker(barrier, situation, grunt, tx));
}

// have to drop the original tx to get refcounts correct, else controller thread will
// hang indefinitely while rx thinks it has potential inbound data
drop(tx);

// does this even do anything to hold the thread open?
for _ in rx {}
}));
}
drop(sit_tx);

for thread in situation_threads {
thread.join().unwrap();
match sit_rx.recv() {
Ok(_) => {
// there's no actual guarantee here that thread is the same thread taht sent
// whatever data we got, and that's okay, we're using this as a lazy place to just
// ensure all threads have finished, not as a proper data consolidation step
thread.join().unwrap();
Ok(())
}
Err(err) => Err(err),
}
.expect("internal error: situation thread did not join");
}

Ok(())
}

fn grunt_worker(
barrier: Arc<Barrier>,
situation: Arc<Situation>,
situation: &Situation,
grunt: &Grunt,
tx: mpsc::Sender<()>,
) -> Result<(), StepHandlerInitError> {
if situation.lua_file.is_none() {
unimplemented!("situations without 'lua_file' are not currently supported");
Expand All @@ -108,12 +138,7 @@ fn grunt_worker(

barrier.wait();

for step_result in Pipeline::new(
&grunt.name,
&situation.base_url,
&situation.personas[grunt.persona_idx],
Some(&lua),
)? {
for step_result in Pipeline::new(grunt, &situation.base_url, Some(&lua))? {
match step_result {
Ok(PipelineStepResult::Ok) => {}

Expand Down Expand Up @@ -142,9 +167,6 @@ fn grunt_worker(

grunt_exit(grunt);

// TODO should probably handle this more UX-sanely
tx.send(()).unwrap();

Ok(())
}

Expand Down
Loading

0 comments on commit 053f413

Please sign in to comment.