From d30b5db6f3eabd2a550ef05e6203d3c7ef19e9c7 Mon Sep 17 00:00:00 2001 From: Melody Horn / boringcactus Date: Sun, 13 Jun 2021 20:48:15 -0600 Subject: pass the first halfish of tutorial 1 tests --- src/bin/tosin-admin.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++++- src/urls.rs | 10 +++++---- tests/tutorial/mod.rs | 39 +++++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 16 deletions(-) diff --git a/src/bin/tosin-admin.rs b/src/bin/tosin-admin.rs index a1f03fb..3eb57a1 100644 --- a/src/bin/tosin-admin.rs +++ b/src/bin/tosin-admin.rs @@ -1,5 +1,31 @@ +use std::env::set_current_dir; +use std::fs; +use std::io::Write as _; +use std::process::Command; + use structopt::StructOpt; +const TOSIN_DEPENDENCY: &str = concat!(r#"tosin = { path = ""#, env!("CARGO_MANIFEST_DIR"), r#"" }"#); +const PROJECT_MAIN: &str = r#" +use tosin::Settings; +use tosin::contrib::admin; +use tosin::urls::{UrlMap, url_map}; + +fn urls() -> UrlMap { + url_map! { + "admin" / ..admin::site::urls(), + } +} + +fn settings() -> Settings { + Settings { + ..Settings::default() + } +} + +tosin::main!(urls(), settings()); +"#; + #[derive(StructOpt, Debug)] enum Opt { /// Start a new project/site (can contain multiple apps) @@ -10,5 +36,35 @@ enum Opt { fn main() { let opts = Opt::from_args(); - dbg!(opts); + match opts { + Opt::StartProject { name } => { + match name { + Some(name) => { + // there's a name, so we're creating a project. + // TODO make this all more robust + let cargo_new = Command::new("cargo") + .args(&["new", "--bin", &name]) + .status() + .unwrap(); + if !cargo_new.success() { + panic!("cargo new failed"); + } + + set_current_dir(name).unwrap(); + + let mut cargo_toml = fs::OpenOptions::new() + .append(true) + .open("Cargo.toml") + .unwrap(); + writeln!(cargo_toml, "{}", TOSIN_DEPENDENCY).unwrap(); + drop(cargo_toml); + + fs::write("src/main.rs", PROJECT_MAIN).unwrap(); + } + None => { + todo!("absorb existing Rust project maybe??") + } + } + } + } } diff --git a/src/urls.rs b/src/urls.rs index 80eba9e..2668835 100644 --- a/src/urls.rs +++ b/src/urls.rs @@ -1,6 +1,8 @@ use crate::http::Response; pub use crate::url_map; +pub use warp::path as warp_path; + pub type UrlMap = warp::filters::BoxedFilter<(Response,)>; #[doc(hidden)] @@ -40,20 +42,20 @@ macro_rules! __url_map_inner { ($chain:ident @rest) => { $chain }; (@one => $view:expr) => { - ::warp::path::end().map($view) + $crate::urls::warp_path::end().map($view) }; (@one $head:tt $(/ $tail:tt)* => $view:expr) => { - ::warp::path!($head $(/ $tail)*).map($view) + $crate::urls::warp_path!($head $(/ $tail)*).map($view) }; (@one $head:tt $(/ $tail:tt)* $child:expr) => { - ::warp::path!($head $(/ $tail)*).and($child) + $crate::urls::warp_path!($head $(/ $tail)*).and($child) }; } #[macro_export] macro_rules! url_map { ($($body:tt)*) => {{ - use ::warp::Filter; + use $crate::http::Filter; $crate::__url_map_inner!(@root $($body)*) .boxed() }}; diff --git a/tests/tutorial/mod.rs b/tests/tutorial/mod.rs index 576d3af..54f9c9f 100644 --- a/tests/tutorial/mod.rs +++ b/tests/tutorial/mod.rs @@ -1,8 +1,12 @@ use std::env::set_current_dir; use std::fs; -use std::io::Read; +use std::io::{BufRead, BufReader}; use std::path::Path; -use std::process::Command; +use std::process::{Command, Stdio}; +use std::thread::sleep; +use std::time::Duration; + +use rand::prelude::*; trait ExitStatusExt { fn check(self); @@ -18,13 +22,13 @@ const CARGO: &str = env!("CARGO"); const PROJECT_DIR: &str = env!("CARGO_MANIFEST_DIR"); const TOSIN_ADMIN: &str = env!("CARGO_BIN_EXE_tosin-admin"); -fn get(url: &'static str) -> (hyper::StatusCode, String) { +fn get(url: &str) -> (hyper::StatusCode, String) { let get = async { - use hyper::{Client, Uri}; + use hyper::Client; let client = Client::new(); - let res = client.get(Uri::from_static(url)).await.unwrap(); + let res = client.get(url.parse().unwrap()).await.unwrap(); let status = res.status(); @@ -44,6 +48,11 @@ pub fn step1(dest: &str) { // tosin-admin start-project {dest} set_current_dir(PROJECT_DIR).unwrap(); set_current_dir("target").unwrap(); + if fs::metadata("tests").is_err() { + fs::create_dir("tests").unwrap(); + } + set_current_dir("tests").unwrap(); + fs::write("Cargo.toml", "[workspace]\nmembers = ['tutorial1']").unwrap(); if fs::metadata(dest).is_ok() { fs::remove_dir_all(dest).unwrap(); } @@ -59,20 +68,28 @@ pub fn step1(dest: &str) { assert!(fs::read_to_string("src/main.rs").unwrap().contains("tosin::main!")); // cargo run run-server + let port = thread_rng().gen_range(8081u16..9000u16); let mut server = Command::new(CARGO) - .args(&["run", "run-server", "8069"]) + .args(&["run", "run-server", &format!("{}", port)]) + .stdout(Stdio::piped()) .spawn() .unwrap(); - let server_poke = get("http://127.0.0.1:8069"); + let mut server_output = String::new(); + let server_stdout = server.stdout.take().unwrap(); + let mut server_stdout = BufReader::new(server_stdout); + server_stdout.read_line(&mut server_output).unwrap(); + assert!(server_output.contains(&format!("http://127.0.0.1:{}", port))); + sleep(Duration::from_secs_f32(0.5)); + let server_poke = get(&format!("http://127.0.0.1:{}/", port)); assert_eq!(server_poke.0, hyper::StatusCode::NOT_FOUND); + if let Ok(Some(exit_status)) = server.try_wait() { + exit_status.check(); + } server.kill().unwrap(); - let mut server_stdout = String::new(); - server.stdout.unwrap().read_to_string(&mut server_stdout).unwrap(); - assert!(server_stdout.contains("http://127.0.0.1:8069")); // could `cargo run start-app polls` or `tosin-admin start-app polls` so // flip a coin i guess - if rand::random() { + if random() { let mut cmd = Command::new(CARGO); cmd.arg("run"); cmd -- cgit v1.2.3