Skip to content
Snippets Groups Projects
Unverified Commit d47d1266 authored by Louis's avatar Louis :fire:
Browse files

Merge branch 'Testing'

parents 42fd908f ca63042a
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. ...@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- [DEV] Initial test scaffolding
## [0.2.0] ## [0.2.0]
### Added ### Added
......
...@@ -235,6 +235,11 @@ dependencies = [ ...@@ -235,6 +235,11 @@ dependencies = [
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "interpolate_idents"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "isatty" name = "isatty"
version = "0.1.7" version = "0.1.7"
...@@ -639,6 +644,7 @@ dependencies = [ ...@@ -639,6 +644,7 @@ dependencies = [
"docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"formdata 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "formdata 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
"interpolate_idents 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"rhai 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rhai 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
...@@ -858,6 +864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" ...@@ -858,6 +864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" "checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
"checksum interpolate_idents 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c038526b1556151b78f71b3e4cb107cf58c4dfc426a64a398c61f76a42a4e08"
"checksum isatty 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a118a53ba42790ef25c82bb481ecf36e2da892646cccd361e69a6bb881e19398" "checksum isatty 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a118a53ba42790ef25c82bb481ecf36e2da892646cccd361e69a6bb881e19398"
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
......
...@@ -37,3 +37,6 @@ hyper = "0.10" ...@@ -37,3 +37,6 @@ hyper = "0.10"
rand = "0.3" rand = "0.3"
rhai = "0.7" rhai = "0.7"
serde_yaml = "0.7.3" serde_yaml = "0.7.3"
[dev-dependencies]
interpolate_idents = "0.2.4"
example/files/adorable-puppy.jpg

73 KiB

file,author/attribution, link
adorable-puppy.jpg,Photo by mentatdgt from Pexels,https://www.pexels.com/photo/white-brown-and-black-shih-tzu-puppy-936317/
math.aswm,Github: Hanks10100,https://github.com/Hanks10100/wasm-examples
File added
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Swerve Example</title> <title>Swerve Example</title>
<link rel="stylesheet" href="/css/styles.css"> <link rel="stylesheet" href="css/styles.css">
</head> </head>
<body> <body>
<h1>It's Swervin' Time</h1> <h1>It's Swervin' Time</h1>
<p>This page is part of the swerve example, and includes a stylesheet and stuff.</p> <p>This page is part of the swerve example, and includes a stylesheet and stuff.</p>
<script async src="js/say_hello.js"></script>
</body> </body>
</html> </html>
\ No newline at end of file
document.addEventListener('DOMContentLoaded', function() {
console.log("The dom has loaded!")
})
\ No newline at end of file
pub use std::path::PathBuf; pub use std::path::PathBuf;
pub use std::env::current_dir; pub use std::env::current_dir;
pub use std::default::Default;
pub const USAGE: &'static str = " pub const USAGE: &'static str = "
Static file swerver and api mocker for local development. Static file swerver and api mocker for local development.
...@@ -21,7 +22,7 @@ Web Server Options: ...@@ -21,7 +22,7 @@ Web Server Options:
-c=<path>, --config=<path> Path to the .swerve config file -c=<path>, --config=<path> Path to the .swerve config file
-t=<num>, --threads=<num> Number of worker threads to use for serving files; defaults to 32 -t=<num>, --threads=<num> Number of worker threads to use for serving files; defaults to 32
Data Handling Options Data Handling Options:
-u, --upload Support file uploads to '/upload' -u, --upload Support file uploads to '/upload'
-U=<path>, --upload-path=<path> Set the url path that will accept file uploads. Implies 'upload' flag if not present -U=<path>, --upload-path=<path> Set the url path that will accept file uploads. Implies 'upload' flag if not present
...@@ -54,4 +55,22 @@ impl Args { ...@@ -54,4 +55,22 @@ impl Args {
).to_string_lossy().into_owned()) ).to_string_lossy().into_owned())
) )
} }
}
impl Default for Args {
fn default() -> Self {
Args {
flag_dir: Some(String::from("")),
flag_port: Some(8000),
flag_config: None,
flag_threads: Some(32),
flag_address: Some(String::from("localhost")),
flag_help: false,
flag_quiet: false,
flag_no_index: false,
flag_upload: false,
flag_upload_path: None,
flag_license: false,
}
}
} }
\ No newline at end of file
...@@ -3,9 +3,8 @@ use std::convert::AsRef; ...@@ -3,9 +3,8 @@ use std::convert::AsRef;
use std::io::prelude::*; use std::io::prelude::*;
use std::io; use std::io;
use std::fs::File; use std::fs::File;
use std::io::BufReader;
use std::default::Default; use std::default::Default;
use serde::{Deserialize, Deserializer, de::{self, Error}}; use serde::{Deserialize, Deserializer, de};
use std::fmt; use std::fmt;
use serde_yaml as yaml; use serde_yaml as yaml;
......
...@@ -13,4 +13,5 @@ extern crate rand; ...@@ -13,4 +13,5 @@ extern crate rand;
pub mod cli; pub mod cli;
pub mod routing; pub mod routing;
pub mod scripting; pub mod scripting;
\ No newline at end of file pub mod server;
...@@ -8,98 +8,10 @@ extern crate docopt; ...@@ -8,98 +8,10 @@ extern crate docopt;
extern crate swerve; extern crate swerve;
extern crate rhai; extern crate rhai;
use rhai::Engine; use std::process;
use std::{path, process, io};
use std::fs::{self, File};
use docopt::Docopt; use docopt::Docopt;
use rocket::response::NamedFile;
use rocket::http::ContentType;
use rocket::{Response, Request};
use swerve::cli; use swerve::cli;
use swerve::routing; use swerve::server;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use rocket::response::Responder;
struct TypedFile {
file: File,
content_type: Option<ContentType>,
path: PathBuf,
}
impl TypedFile {
pub fn open<P: AsRef<Path>>(path: P, content_type: Option<rocket::http::ContentType>) -> TypedFile {
let file = File::open(path.as_ref()).unwrap();
TypedFile { file, content_type, path: (*path.as_ref()).to_path_buf() }
}
}
impl rocket::response::Responder<'static> for TypedFile {
fn respond_to(self, _: &Request) -> Result<Response<'static>, rocket::http::Status> {
let mut response = Response::new();
if let Some(content_type) = self.content_type {
response.set_header(content_type);
} else {
response.set_header(ContentType::from_extension(&self.path.extension().unwrap().to_string_lossy()).unwrap());
}
response.set_streamed_body(BufReader::new(self.file));
Ok(response)
}
}
#[get("/")]
fn serve_root(args: rocket::State<cli::Args>) -> Option<TypedFile> {
serve_files(None, args)
}
#[get("/<file..>")]
fn serve_files(file: Option<path::PathBuf>, args: rocket::State<cli::Args>) -> Option<TypedFile> {
let stub = match file {
Some(path) => path,
None => path::PathBuf::from(""),
};
let path = args.get_dir().join(stub);
let meta = match fs::metadata(&path) {
Ok(metadata) => metadata,
_ => return None,
};
if meta.is_dir() && !args.flag_no_index {
Some(TypedFile::open(path.join("index.html"), None))
} else {
if &path.extension().unwrap().to_string_lossy() == "wasm" {
Some( TypedFile::open(path, Some(ContentType::new("application", "wasm"))))
} else {
Some(TypedFile::open(path, None))
}
}
}
fn config_from_args(args: cli::Args, config: cli::SwerveConfig) -> rocket::Config {
let mut builder = rocket::Config::build(rocket::config::Environment::Development);
if let Some(threads) = args.flag_threads {
builder = builder.workers(threads);
} else {
builder = builder.workers(config.server.threads);
}
if let Some(port) = args.flag_port {
builder = builder.port(port);
} else {
builder = builder.port(config.server.port);
}
if let Some(address) = args.flag_address {
builder = builder.address(address);
} else {
builder = builder.address(config.server.address);
}
builder.finalize().unwrap()
}
fn main() { fn main() {
let args: cli::Args = Docopt::new(cli::USAGE) let args: cli::Args = Docopt::new(cli::USAGE)
...@@ -107,18 +19,8 @@ fn main() { ...@@ -107,18 +19,8 @@ fn main() {
.unwrap_or_else(|e| e.exit()); .unwrap_or_else(|e| e.exit());
let is_quiet = args.flag_quiet; let is_quiet = args.flag_quiet;
macro_rules! printq {
($( $x:expr ),+) => {
{
if !is_quiet {
println!($($x),*);
}
}
}
}
if args.flag_help { if args.flag_help {
printq!("{}", cli::USAGE); if !is_quiet { println!("{}", cli::USAGE); }
process::exit(0); process::exit(0);
} }
...@@ -133,38 +35,6 @@ fn main() { ...@@ -133,38 +35,6 @@ fn main() {
std::process::exit(2); std::process::exit(2);
}); });
let server_config = config_from_args(args.clone(), swerve_config.clone()); let server = server::create_server(args.clone(), swerve_config.clone());
// printq!("{:?}", swerve_config); server.launch();
printq!("");
let mut server = rocket::custom(server_config, false)
.manage(args.clone())
.manage(swerve_config);
if let Some(ref upload_path) = args.flag_upload_path {
printq!("[SETUP] Accepting uploads at {}", upload_path);
server = server.mount(upload_path, routes![swerve::routing::mock_upload::to_file]);
} else if args.flag_upload {
printq!("[SETUP] Accepting uploads at /upload");
server = server.mount("/upload", routes![swerve::routing::mock_upload::to_file]);
}
server = server.mount("/", routes![
serve_root,
serve_files,
routing::scripting::route_script
]);
if !args.flag_quiet {
server = server.attach(rocket::fairing::AdHoc::on_launch(move |rckt| {
let config = rckt.config();
println!("[SETUP] Swerve is configured with {} worker threads", config.workers);
println!("[SETUP] Swerving files from http://{}:{}\n", config.address, config.port);
}))
.attach(rocket::fairing::AdHoc::on_response(|req, _res| {
println!("[REQUEST] {} {}", req.method(), req.uri());
}));
}
{
server.launch();
}
} }
\ No newline at end of file
use cli;
use std::fs;
use std::path;
use rocket::{self, http::ContentType};
use routing::request::TypedFile;
#[get("/")]
fn serve_root(args: rocket::State<cli::Args>) -> Option<TypedFile> {
serve_files(None, args)
}
#[get("/<file..>")]
fn serve_files(file: Option<path::PathBuf>, args: rocket::State<cli::Args>) -> Option<TypedFile> {
let stub = match file {
Some(path) => path,
None => path::PathBuf::from(""),
};
let path = args.get_dir().join(stub);
let meta = match fs::metadata(&path) {
Ok(metadata) => metadata,
_ => return None,
};
if meta.is_dir() && !args.flag_no_index {
Some(TypedFile::open(path.join("index.html"), None))
} else {
if &path.extension().unwrap().to_string_lossy() == "wasm" {
Some( TypedFile::open(path, Some(ContentType::new("application", "wasm"))))
} else {
Some(TypedFile::open(path, None))
}
}
}
pub mod mock_upload; pub mod mock_upload;
pub mod request; pub mod request;
pub mod scripting; pub mod scripting;
\ No newline at end of file pub mod core;
use rocket::{self, Outcome, http, Response};
use rocket::request::{FromRequest, Request}; use rocket::request::{FromRequest, Request};
use rocket::{Outcome, http}; use rocket::http::ContentType;
use hyper::header::Headers; use hyper::header::Headers;
use std::path::{Path, PathBuf};
use std::io::BufReader;
use std::fs::File;
#[derive(Debug)] #[derive(Debug)]
pub struct ConvertedHeaders { pub struct ConvertedHeaders {
...@@ -26,4 +30,30 @@ impl <'a, 'req>FromRequest<'a, 'req> for ConvertedHeaders { ...@@ -26,4 +30,30 @@ impl <'a, 'req>FromRequest<'a, 'req> for ConvertedHeaders {
inner: hyper_headers inner: hyper_headers
}) })
} }
} }
\ No newline at end of file
pub struct TypedFile {
file: File,
content_type: Option<ContentType>,
path: PathBuf,
}
impl TypedFile {
pub fn open<P: AsRef<Path>>(path: P, content_type: Option<rocket::http::ContentType>) -> TypedFile {
let file = File::open(path.as_ref()).unwrap();
TypedFile { file, content_type, path: (*path.as_ref()).to_path_buf() }
}
}
impl rocket::response::Responder<'static> for TypedFile {
fn respond_to(self, _: &Request) -> Result<Response<'static>, rocket::http::Status> {
let mut response = Response::new();
if let Some(content_type) = self.content_type {
response.set_header(content_type);
} else {
response.set_header(ContentType::from_extension(&self.path.extension().unwrap().to_string_lossy()).unwrap());
}
response.set_streamed_body(BufReader::new(self.file));
Ok(response)
}
}
mod server;
pub use self::server::create_server;
\ No newline at end of file
use rocket::{self, Rocket, Config};
use cli::{Args, SwerveConfig};
use routing;
pub fn create_server(args: Args, config: SwerveConfig) -> Rocket {
let server_config = server_config_from_input(args.clone(), config.clone());
let mut server = Rocket::custom(server_config, false)
.manage(args.clone())
.manage(config.clone());
let quiet = args.flag_quiet;
if let Some(ref upload_path) = args.flag_upload_path {
if !quiet { println!("[SETUP] Accepting uploads at {}", upload_path) }
server = server.mount(upload_path, routes![routing::mock_upload::to_file]);
} else if args.flag_upload {
if !quiet { println!("[SETUP] Accepting uploads at /upload") }
server = server.mount("/upload", routes![routing::mock_upload::to_file]);
}
server = server.mount("/", routes![
routing::core::serve_root,
routing::core::serve_files,
routing::scripting::route_script
]);
if !quiet {
server = server.attach(rocket::fairing::AdHoc::on_launch(move |rckt| {
let conf = rckt.config();
println!("[SETUP] Swerve is configured with {} worker threads", conf.workers);
println!("[SETUP] Swerving files from http://{}:{}\n", conf.address, conf.port);
}))
.attach(rocket::fairing::AdHoc::on_response(|req, _res| {
println!("[REQUEST] {} {}", req.method(), req.uri());
}));
}
server
}
fn server_config_from_input(args: Args, config: SwerveConfig) -> Config {
let mut builder = Config::build(rocket::config::Environment::Development);
if let Some(threads) = args.flag_threads {
builder = builder.workers(threads);
} else {
builder = builder.workers(config.server.threads);
}
if let Some(port) = args.flag_port {
builder = builder.port(port);
} else {
builder = builder.port(config.server.port);
}
if let Some(address) = args.flag_address {
builder = builder.address(address);
} else {
builder = builder.address(config.server.address);
}
builder.finalize().unwrap()
}
\ No newline at end of file
extern crate rocket;
extern crate swerve;
use swerve::cli::{Args, SwerveConfig};
use swerve::server::create_server;
use rocket::local::Client;
use rocket::http::Status;
const INDEX_PAGE: &'static str = include_str!("../example/index.html");
#[test]
fn test_serves_index() {
let args = Args {
flag_dir: Some(String::from("example")),
..Args::default()
};
let config = SwerveConfig::default();
let server = create_server(args, config);
let client = Client::new(server).expect("valid server instance");
let mut response = client.get("/").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string(), Some(INDEX_PAGE.into()));
}
\ No newline at end of file
#![feature(plugin)]
#![plugin(interpolate_idents)]
extern crate rocket;
extern crate swerve;
use swerve::cli::{Args, SwerveConfig};
use swerve::server::create_server;
use rocket::local::Client;
use rocket::http::ContentType;
macro_rules! test_type {
($name:ident, $path:expr, $content_path:expr) => (interpolate_idents! {
#[test]
fn [returns_some_type_for_ $name]() {
let args = Args {
flag_dir: Some(String::from("example")),
flag_quiet: true,
..Args::default()
};
let config = SwerveConfig::default();
let server = create_server(args, config);
let client = Client::new(server).expect("valid server instance");
let response = client.get($path).dispatch();
assert_eq!(response.content_type(), Some($content_path));
}
});
($name:ident, $path:expr) => (interpolate_idents! {
#[test]
fn [returns_no_type_for_ $name]() {
let args = Args {
flag_dir: Some(String::from("example")),
flag_quiet: true,
..Args::default()
};
let config = SwerveConfig::default();
let server = create_server(args, config);
let client = Client::new(server).expect("valid server instance");
let response = client.get($path).dispatch();
assert_eq!(response.content_type(), None);
}
});
}
test_type!(html, "/index.html", ContentType::HTML);
test_type!(css, "/css/styles.css", ContentType::CSS);
test_type!(javascript, "/js/say_hello.js", ContentType::JavaScript);
test_type!(csv, "/files/attribution.csv", ContentType::CSV);
test_type!(image_jpeg, "/files/adorable-puppy.jpg", ContentType::JPEG);
test_type!(web_assembly, "/files/math.wasm", ContentType::new("application", "wasm"));
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment