Skip to content

Commit

Permalink
✨ Sequentially run all the requests in the script file (#40)
Browse files Browse the repository at this point in the history
GH-10

* First pass at running all the reqeusts in a file

* updated cli message

* clippy fixes

* Added a reset function for the ScriptEngine

* cargo fmt
  • Loading branch information
dylanowen authored Feb 13, 2020
1 parent 056120b commit 81192a3
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 144 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
target
*.swp
.snapshot.json
.idea
50 changes: 33 additions & 17 deletions src/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl Controller {
pub fn execute(
&mut self,
offset: usize,
all: bool,
env: String,
script_file: &Path,
snapshot_file: &Path,
Expand All @@ -101,7 +102,7 @@ impl Controller {
}),
}?;

let snapshot_script = match read_to_string(snapshot_file) {
let mut snapshot = match read_to_string(snapshot_file) {
Ok(script) => Ok(script),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
Ok(String::from(BoaScriptEngine::empty()))
Expand All @@ -114,21 +115,26 @@ impl Controller {
let engine = &mut self.engine;
let outputter = &mut self.outputter;

engine.initialize(env_file, env, snapshot_script).unwrap();
engine.initialize(&env_file, &env).unwrap();

let request_script = file.request_script(offset);
let request_script = request_script.process(engine).map_err(|err| Error {
kind: ScriptEngineError(script_file.to_path_buf(), err),
})?;
let request_scripts = file.request_scripts(offset, all);

for request_script in request_scripts {
engine.reset(&snapshot).unwrap();

outputter.output_request(&request_script.request).unwrap();
let request_script = request_script.process(engine).map_err(|err| Error {
kind: ScriptEngineError(script_file.to_path_buf(), err),
})?;

let response = request_script.request.execute()?;
outputter.output_request(&request_script.request).unwrap();

self.response_handler
.handle(engine, outputter, &request_script, response.into())
.unwrap();
let snapshot = engine.snapshot().unwrap();
let response = request_script.request.execute()?;

self.response_handler
.handle(engine, outputter, &request_script, response.into())
.unwrap();
snapshot = engine.snapshot().unwrap();
}

std::fs::write(snapshot_file, snapshot).unwrap();

Expand All @@ -137,13 +143,23 @@ impl Controller {
}

impl File {
fn request_script(&self, offset: usize) -> &RequestScript<Unprocessed> {
self.request_scripts
fn request_scripts(
&self,
offset: usize,
all: bool,
) -> impl Iterator<Item = &RequestScript<Unprocessed>> {
let mut scripts = self
.request_scripts
.iter()
.find(|request_script| {
request_script.selection.start.line <= offset
.filter(move |request_script| {
(all || request_script.selection.start.line <= offset)
&& request_script.selection.end.line > offset
})
.unwrap()
.peekable();

match scripts.peek() {
Some(_) => scripts,
None => panic!("Couldn't find any scripts in our file at the given line number"),
}
}
}
179 changes: 151 additions & 28 deletions src/controller/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::controller::Controller;
use http_test_server::TestServer;
use http_test_server::{Request, TestServer};
use std::io::Write;
use std::sync::mpsc::Receiver;
use tempfile::NamedTempFile;

#[test]
Expand Down Expand Up @@ -36,61 +37,183 @@ fn test() {
let env = String::from("dev");

controller
.execute(offset, env, &script_file, &snapshot_file, &env_file)
.execute(offset, false, env, &script_file, &snapshot_file, &env_file)
.unwrap();
}

#[test]
fn test_last_line() {
let server = TestServer::new().unwrap();
server.create_resource("/first");
server.create_resource("/second");
let _requests = server.requests();
let mut requests = multi_line_setup(
17,
false,
r#"
POST http://localhost:{{port}}/first HTTP/1.1
Accept: */*
Content-Type: application/json
let mut snapshot_file = NamedTempFile::new().unwrap();
{
"id": 1
}
writeln!(snapshot_file, "{{}}").unwrap();
> {%
console.log('test');
%}
let snapshot_file = snapshot_file.into_temp_path();
###
GET http://localhost:{{port}}/second HTTP/1.1
Accept: */*
"#,
)
.into_iter();

let mut env_file = NamedTempFile::new().unwrap();
let _second = requests.next().expect("We should have a first request");
assert_eq!(None, requests.next(), "We should only have 1 request");
}

writeln!(env_file, "{{}}").unwrap();
#[test]
fn test_all_requests() {
let mut requests = multi_line_setup(
0,
true,
r#"
GET http://localhost:{{port}}/first HTTP/1.1
Accept: */*
Content-Type: application/json
let env_file = env_file.into_temp_path();
{
"id": 1
}
let mut script_file = NamedTempFile::new().unwrap();
writeln!(
script_file,
"\
POST http://localhost:{port}/first HTTP/1.1
###
GET http://localhost:{{port}}/second HTTP/1.1
Accept: */*
Content-Type: application/json
"#,
)
.into_iter();

{{
\"id\": 1
}}
let _first = requests.next().expect("We should have a first request");
let _second = requests.next().expect("We should have a second request");
assert_eq!(None, requests.next(), "We should only have 2 requests");
}

> {{%
console.log('test');
%}}
#[test]
fn test_all_global_object() {
let mut requests = multi_line_setup(
0,
true,
r#"
GET http://localhost:{{port}}/first HTTP/1.1
Accept: */*
Content-Type: application/json
> {%
client.global.set('global_state', response.body.response);
%}
###
GET http://localhost:{port}/second HTTP/1.1
GET http://localhost:{{port}}/{{global_state}} HTTP/1.1
Accept: */*
"#,
)
.into_iter();

",
let _first = requests.next().expect("We should have a first request");
let second = requests.next().expect("We should have a second request");
assert_eq!(None, requests.next(), "We should only have 2 requests");

assert_eq!(
"/some_response", second.url,
"We should be able to pass state via the global object"
);
}

/// This test ensures that we must operate through the global object and that we don't propagate state
/// via global variables
#[test]
fn test_all_global_state() {
let mut requests = multi_line_setup(
0,
true,
r#"
GET http://localhost:{{port}}/first HTTP/1.1
> {%
var someGlobal = "global";
client.global.set('global_state', response.body.response);
%}
###
GET http://localhost:{{port}}/second HTTP/1.1
> {%
console.log(someGlobal);
var found = someGlobal !== undefined;
client.global.set('found', found);
%}
###
GET http://localhost:{{port}}/{{found}}
"#,
)
.into_iter();

let _first = requests.next().expect("We should have a first request");
let _second = requests.next().expect("We should have a second request");
let third = requests.next().expect("We should have a second request");
assert_eq!(None, requests.next(), "We should only have 2 requests");

assert_eq!(
"/false", third.url,
"We should not persist global variables across runs"
);
}

fn multi_line_setup(offset: usize, all: bool, scripts: &str) -> Receiver<Request> {
let server = TestServer::new().unwrap();
server.create_resource("/first").body(
r#"{
"response": "some_response"
}"#,
);
server.create_resource("/second");
let requests = server.requests();

let mut snapshot_file = NamedTempFile::new().unwrap();

writeln!(snapshot_file, "{{}}").unwrap();

let snapshot_file = snapshot_file.into_temp_path();

let mut env_file = NamedTempFile::new().unwrap();

writeln!(
env_file,
r#"{{
"dev": {{
"port": {port}
}}
}}"#,
port = server.port()
)
.unwrap();

let env_file = env_file.into_temp_path();

let mut script_file = NamedTempFile::new().unwrap();
writeln!(script_file, "{}", scripts,).unwrap();

let script_file = script_file.into_temp_path();
let mut controller = Controller::default();

let offset = 17;
let env = String::from("dev");

controller
.execute(offset, env, &script_file, &snapshot_file, &env_file)
.execute(offset, all, env, &script_file, &snapshot_file, &env_file)
.unwrap();

requests
}
7 changes: 7 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,18 +345,25 @@ fn main() {
.validator(is_valid_line_number)
.required(true),
)
.arg(
Arg::with_name("ALL")
.short("a")
.help("Sequentially run all the requests in the file"),
)
.usage("dot-http [OPTIONS] <FILE>")
.get_matches();

let script_file = matches.value_of("FILE").unwrap().to_string();
let offset: usize = matches.value_of("LINE").unwrap().parse().unwrap();
let all: bool = matches.is_present("ALL");
let env = matches.value_of("ENVIRONMENT").unwrap().to_string();
let env_file = matches.value_of("ENV_FILE").unwrap().to_string();
let snapshot_file = matches.value_of("SNAPSHOT_FILE").unwrap().to_string();

let mut controller = Controller::default();
match controller.execute(
offset,
all,
env,
Path::new(&script_file),
Path::new(&snapshot_file),
Expand Down
17 changes: 9 additions & 8 deletions src/response_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ pub trait ResponseHandler {
type Engine: ScriptEngine;
type Outputter: Outputter<Response = Self::Response>;
type Response: Into<ScriptResponse>;

fn handle(
&mut self,
&self,
engine: &mut Self::Engine,
outputter: &mut Self::Outputter,
request_script: &RequestScript<Processed>,
Expand All @@ -49,11 +50,11 @@ pub trait ResponseHandler {
if let Some(Handler { script, selection }) = &request_script.handler {
let script_response: ScriptResponse = response.into();
self.inject(engine, script_response)?;
let expr = engine.parse(Script {
let expr = engine.parse(&Script {
selection: selection.clone(),
src: script.clone(),
src: script,
})?;
engine.execute(expr)?;
engine.execute(&expr)?;
}
Ok(())
}
Expand All @@ -67,17 +68,17 @@ pub trait ResponseHandler {
"var response = {};",
serde_json::to_string(&script_response).unwrap()
);
let expr = engine.parse(Script::internal_script(script))?;
engine.execute(expr)?;
let expr = engine.parse(&Script::internal_script(&script))?;
engine.execute(&expr)?;
if let Ok(serde_json::Value::Object(response_body)) =
serde_json::from_str(script_response.body.as_str())
{
let script = format!(
"response.body = {};",
serde_json::to_string(&response_body).unwrap()
);
let expr = engine.parse(Script::internal_script(script)).unwrap();
engine.execute(expr).unwrap();
let expr = engine.parse(&Script::internal_script(&script)).unwrap();
engine.execute(&expr).unwrap();
}
Ok(())
}
Expand Down
Loading

0 comments on commit 81192a3

Please sign in to comment.