From cd4805fb4709066d1f08dff9ae34e4335784821e Mon Sep 17 00:00:00 2001 From: sarutora Date: Tue, 3 Jan 2023 11:11:51 -0800 Subject: [PATCH 1/6] added framework Anansi --- frameworks/Rust/anansi/Cargo.toml | 17 ++++ frameworks/Rust/anansi/README.md | 93 +++++++++++++++++++ frameworks/Rust/anansi/anansi.dockerfile | 11 +++ frameworks/Rust/anansi/benchmark_config.json | 26 ++++++ frameworks/Rust/anansi/settings.toml | 18 ++++ .../Rust/anansi/src/hello/migrations/mod.rs | 3 + frameworks/Rust/anansi/src/hello/mod.rs | 6 ++ frameworks/Rust/anansi/src/hello/records.rs | 22 +++++ frameworks/Rust/anansi/src/hello/urls.rs | 3 + frameworks/Rust/anansi/src/hello/world/mod.rs | 1 + .../src/hello/world/templates/.parsed/base.in | 10 ++ .../world/templates/.parsed/base_args.in | 1 + .../hello/world/templates/.parsed/fortunes.in | 7 ++ .../hello/world/templates/.parsed/index.in | 1 + .../src/hello/world/templates/base.rs.html | 10 ++ .../hello/world/templates/fortunes.rs.html | 11 +++ .../Rust/anansi/src/hello/world/views.rs | 85 +++++++++++++++++ .../Rust/anansi/src/http_errors/500.html | 11 +++ frameworks/Rust/anansi/src/http_errors/mod.rs | 1 + .../templates/.parsed/not_found.in | 11 +++ .../http_errors/templates/not_found.rs.html | 11 +++ .../Rust/anansi/src/http_errors/views.rs | 12 +++ frameworks/Rust/anansi/src/main.rs | 23 +++++ frameworks/Rust/anansi/src/project.rs | 7 ++ frameworks/Rust/anansi/src/urls.rs | 11 +++ 25 files changed, 412 insertions(+) create mode 100644 frameworks/Rust/anansi/Cargo.toml create mode 100755 frameworks/Rust/anansi/README.md create mode 100644 frameworks/Rust/anansi/anansi.dockerfile create mode 100755 frameworks/Rust/anansi/benchmark_config.json create mode 100644 frameworks/Rust/anansi/settings.toml create mode 100644 frameworks/Rust/anansi/src/hello/migrations/mod.rs create mode 100644 frameworks/Rust/anansi/src/hello/mod.rs create mode 100644 frameworks/Rust/anansi/src/hello/records.rs create mode 100644 frameworks/Rust/anansi/src/hello/urls.rs create mode 100644 frameworks/Rust/anansi/src/hello/world/mod.rs create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/base.rs.html create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html create mode 100644 frameworks/Rust/anansi/src/hello/world/views.rs create mode 100644 frameworks/Rust/anansi/src/http_errors/500.html create mode 100644 frameworks/Rust/anansi/src/http_errors/mod.rs create mode 100644 frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in create mode 100644 frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html create mode 100644 frameworks/Rust/anansi/src/http_errors/views.rs create mode 100644 frameworks/Rust/anansi/src/main.rs create mode 100644 frameworks/Rust/anansi/src/project.rs create mode 100644 frameworks/Rust/anansi/src/urls.rs diff --git a/frameworks/Rust/anansi/Cargo.toml b/frameworks/Rust/anansi/Cargo.toml new file mode 100644 index 00000000000..c594fc27813 --- /dev/null +++ b/frameworks/Rust/anansi/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +members = [ + ".", +] + +[package] +name = "tfb-anansi" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anansi = { git = "https://github.com/saru-tora/anansi", features = ["postgres"] } +async-trait = "0.1.57" +rand = "0.8.4" +serde = { version = "1.0", features = ["derive"] } diff --git a/frameworks/Rust/anansi/README.md b/frameworks/Rust/anansi/README.md new file mode 100755 index 00000000000..00f3c8d36e0 --- /dev/null +++ b/frameworks/Rust/anansi/README.md @@ -0,0 +1,93 @@ +# Congratulations! + +You have successfully built a new test in the suite! + +There are some remaining tasks to do before you are ready to open a pull request, however. + +## Next Steps + +1. Gather your source code. + +You will need to ensure that your source code is beneath this directory. The most common solution is to include a `src` directory and place your source code there. + +2. Edit `benchmark_config.json` + +You will need alter `benchmark_config.json` to have the appropriate end-points and port specified. + +3. Create `anansi.dockerfile` + +This is the dockerfile that is built into a docker image and run when a benchmark test is run. Specifically, this file tells the suite how to build and start your test application. + +You can create multiple implementations and they will all conform to `[name in benchmark_config.json].dockerfile`. For example, the `default` implementation in `benchmark_config.json` will be `anansi.dockerfile`, but if you wanted to make another implementation that did only the database tests for MySQL, you could make `anansi-mysql.dockerfile` and have an entry in your `benchmark_config.json` for `anansi-mysql`. + +4. Test your application + + $ tfb --mode verify --test anansi + +This will run the suite in `verify` mode for your test. This means that no benchmarks will be captured and we will test that we can hit your implementation end-points specified by `benchmark_config.json` and that the response is correct. + +Once you are able to successfully run your test through our suite in this way **and** your test passes our validation, you may move on to the next step. + +5. Add your test to `.github/workflows/build.yml` + +Edit `.github/workflows/build.yml` to ensure that Github Actions will automatically run our verification tests against your new test. This file is kept in alphabetical order, so find where `TESTDIR=Rust/anansi` should be inserted under `env > matrix` and put it there. + +6. Fix this `README.md` and open a pull request + +Starting on line 49 is your actual `README.md` that will sit with your test implementation. Update all the dummy values to their correct values so that when people visit your test in our Github repository, they will be greated with information on how your test implementation works and where to look for useful source code. + +After you have the real `README.md` file in place, delete everything above line 59 and you are ready to open a pull request. + +Thanks and Cheers! + + + + + + + +# Anansi Benchmarking Test + +### Test Type Implementation Source Code + +* [JSON](Relative/Path/To/Your/Source/File) +* [PLAINTEXT](Relative/Path/To/Your/Source/File) +* [DB](Relative/Path/To/Your/Source/File) +* [QUERY](Relative/Path/To/Your/Source/File) +* [CACHED QUERY](Relative/Path/To/Your/Source/File) +* [UPDATE](Relative/Path/To/Your/Source/File) +* [FORTUNES](Relative/Path/To/Your/Source/File) + +## Important Libraries +The tests were run with: +* [Software](https://www.example1.com/) +* [Example](http://www.example2.com/) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?queries= + +### CACHED QUERY + +http://localhost:8080/cached_query?queries= + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Rust/anansi/anansi.dockerfile b/frameworks/Rust/anansi/anansi.dockerfile new file mode 100644 index 00000000000..d44d92db5f5 --- /dev/null +++ b/frameworks/Rust/anansi/anansi.dockerfile @@ -0,0 +1,11 @@ +FROM rust:1.64 + +ADD ./ /anansi +WORKDIR /anansi + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/tfb-anansi 8080 diff --git a/frameworks/Rust/anansi/benchmark_config.json b/frameworks/Rust/anansi/benchmark_config.json new file mode 100755 index 00000000000..a1766c91ef7 --- /dev/null +++ b/frameworks/Rust/anansi/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "anansi", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Anansi", + "language": "Rust", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "Anansi", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/anansi/settings.toml b/frameworks/Rust/anansi/settings.toml new file mode 100644 index 00000000000..d551b84e4d6 --- /dev/null +++ b/frameworks/Rust/anansi/settings.toml @@ -0,0 +1,18 @@ +secret_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +login_url = "/login" +smtp_relay = "" +smtp_username = "" +smtp_password = "" + +[caches] + +[caches.default] +location = "" + +[databases] + +[databases.default] +name = "hello_world" +user = "benchmarkdbuser" +password = "benchmarkdbpass" +address = "tfb-database" diff --git a/frameworks/Rust/anansi/src/hello/migrations/mod.rs b/frameworks/Rust/anansi/src/hello/migrations/mod.rs new file mode 100644 index 00000000000..72ca3a1f046 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/migrations/mod.rs @@ -0,0 +1,3 @@ +use anansi::migrations::prelude::*; + +local_migrations! {} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/mod.rs b/frameworks/Rust/anansi/src/hello/mod.rs new file mode 100644 index 00000000000..b7e0b361315 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/mod.rs @@ -0,0 +1,6 @@ +pub mod urls; +pub mod records; +pub mod migrations; + +pub const APP_NAME: &'static str = "hello"; +pub mod world; diff --git a/frameworks/Rust/anansi/src/hello/records.rs b/frameworks/Rust/anansi/src/hello/records.rs new file mode 100644 index 00000000000..860fe659088 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/records.rs @@ -0,0 +1,22 @@ +#![allow(non_snake_case)] +use anansi::{record, Relate, FromParams}; +use anansi::records::{BigInt, Text}; +use serde::Serialize; + +#[record(table_name = "World")] +#[derive(Relate, FromParams, Serialize)] +pub struct World { + pub randomNumber: BigInt, +} + +#[record(table_name = "Fortune")] +#[derive(Relate, FromParams)] +pub struct Fortune { + pub message: Text, +} + +impl Fortune { + pub fn additional() -> Self { + Self {id: BigInt::new(0), message: Text::from("Additional fortune added at request time.".to_string())} + } +} diff --git a/frameworks/Rust/anansi/src/hello/urls.rs b/frameworks/Rust/anansi/src/hello/urls.rs new file mode 100644 index 00000000000..8eaf0efb443 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/urls.rs @@ -0,0 +1,3 @@ +use anansi::web::prelude::*; + +routes! {} diff --git a/frameworks/Rust/anansi/src/hello/world/mod.rs b/frameworks/Rust/anansi/src/hello/world/mod.rs new file mode 100644 index 00000000000..20758cc636c --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/mod.rs @@ -0,0 +1 @@ +pub mod views; \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in new file mode 100644 index 00000000000..c96f18be24a --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in @@ -0,0 +1,10 @@ +{let mut _c = String::new();_c.push_str(" + + + + ");_c.push_str(&_base_args._title);_c.push_str(" + + + ");_c.push_str(&_base_args._content);_c.push_str(" + +");Ok(anansi::web::Response::new(200, _c.into_bytes()))} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in new file mode 100644 index 00000000000..9ad5b91f42b --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in @@ -0,0 +1 @@ +pub struct Args {pub _title: String,pub _content: String,}impl anansi::cache::Cacheable for Args {fn to_bytes(&self) -> Vec {let mut v = vec![];v.append(&mut self._title.len().to_ne_bytes().to_vec());v.append(&mut self._title.as_bytes().to_vec());v.append(&mut self._content.len().to_ne_bytes().to_vec());v.append(&mut self._content.as_bytes().to_vec());v} fn from_bytes(mut __b: Vec) -> anansi::web::Result {let mut buf = __b.split_off(8); let l = usize::from_ne_bytes(__b.try_into().unwrap()); let mut __b = buf.split_off(l); let _title = String::from_utf8(buf)?;let mut buf = __b.split_off(8); let l = usize::from_ne_bytes(__b.try_into().unwrap()); let mut __b = buf.split_off(l); let _content = String::from_utf8(buf)?;Ok(Self {_title, _content, })}} impl Args {pub fn new() -> Self {Self {_title: String::new(), _content: String::new(), }}} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in new file mode 100644 index 00000000000..ccd8658237e --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in @@ -0,0 +1,7 @@ +{_args._content = {let mut _c = String::new();_c.push_str("

");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str("

+ + + ");for fortune in fortunes {_c.push_str(" + + ");}_c.push_str(" +
idmessage
");_c.push_str(&anansi::web::html_escape(&format!("{}", fortune.pk())));_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", fortune.message)));_c.push_str("
"); _c};_args._title = {let mut _c = String::new();_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str(""); _c};_args} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in new file mode 100644 index 00000000000..17b9c49d56b --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in @@ -0,0 +1 @@ +{_args._title = {let mut _c = String::new();_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str(""); _c};_args._content = {let mut _c = String::new();_c.push_str("

");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str("

"); _c};_args} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html new file mode 100644 index 00000000000..98d083caa91 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html @@ -0,0 +1,10 @@ + + + + + @block title + + + @block content + + diff --git a/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html new file mode 100644 index 00000000000..0550776a99b --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html @@ -0,0 +1,11 @@ +@block title {@title} + +@block content { +

@title

+ + + @for fortune in fortunes { + + } +
idmessage
@fortune.pk()@fortune.message
+} diff --git a/frameworks/Rust/anansi/src/hello/world/views.rs b/frameworks/Rust/anansi/src/hello/world/views.rs new file mode 100644 index 00000000000..0531fc6755f --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/views.rs @@ -0,0 +1,85 @@ +use crate::prelude::*; +use super::super::records::{World, Fortune}; +use serde::Serialize; +use anansi::check; +use anansi::web::Parameters; +use anansi::records::BigInt; +use rand::Rng; + +#[derive(Serialize)] +struct Message { + message: &'static str, +} + +fn get_query(params: &Parameters) -> i16 { + if let Ok(q) = params.get("queries") { + if let Ok(q) = q.parse() { + if q > 1 { + return if q <= 500 { + q + } else { + 500 + }; + } + } + } + 1 +} + +#[base_view] +fn base(_req: &mut R) -> Result {} + +#[viewer] +impl WorldView { + #[check(Group::is_visitor)] + pub async fn json(req: &mut R) -> Result { + let message = Message {message: "Hello, World!"}; + Response::json(&message) + } + async fn get_world(req: &R) -> Result { + let random_id = rand::thread_rng().gen_range(1..=10_000); + World::find(BigInt::new(random_id)).get(req).await + } + async fn get_worlds(req: &R) -> Result> { + let q = get_query(req.params()); + let mut worlds = Vec::with_capacity(q as usize); + for _ in 0..q { + let world = Self::get_world(req).await?; + worlds.push(world); + } + Ok(worlds) + } + #[check(Group::is_visitor)] + pub async fn db(req: &mut R) -> Result { + let world = Self::get_world(req).await?; + Response::json(&world) + } + #[check(Group::is_visitor)] + pub async fn queries(req: &mut R) -> Result { + let worlds = Self::get_worlds(req).await?; + Response::json(&worlds) + } + #[view(Group::is_visitor)] + pub async fn fortunes(req: &mut R) -> Result { + let title = "Fortunes"; + let mut fortunes = Fortune::get_all().query(req).await?; + fortunes.push(Fortune::additional()); + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); + } + #[check(Group::is_visitor)] + pub async fn updates(req: &mut R) -> Result { + let mut worlds = Self::get_worlds(req).await?; + transact!(req, { + for world in &mut worlds { + world.randomNumber = BigInt::new(rand::thread_rng().gen_range(1..=10_000)); + world.save(req).await?; + } + Ok(()) + })?; + Response::json(&worlds) + } + #[check(Group::is_visitor)] + pub async fn plaintext(req: &mut R) -> Result { + Ok(Response::text("Hello, World!".to_string())) + } +} diff --git a/frameworks/Rust/anansi/src/http_errors/500.html b/frameworks/Rust/anansi/src/http_errors/500.html new file mode 100644 index 00000000000..1c14f7cd7f3 --- /dev/null +++ b/frameworks/Rust/anansi/src/http_errors/500.html @@ -0,0 +1,11 @@ + + + + + 500 Internal Server Error + + +

Internal Server Error

+

Sorry, something went wrong.

+ + diff --git a/frameworks/Rust/anansi/src/http_errors/mod.rs b/frameworks/Rust/anansi/src/http_errors/mod.rs new file mode 100644 index 00000000000..38b44033152 --- /dev/null +++ b/frameworks/Rust/anansi/src/http_errors/mod.rs @@ -0,0 +1 @@ +pub mod views; diff --git a/frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in b/frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in new file mode 100644 index 00000000000..79a388a74b5 --- /dev/null +++ b/frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in @@ -0,0 +1,11 @@ +{let mut _c = String::new();_c.push_str(" + + + + Not Found + + +

404

+

Page not found.

+ +");Ok(anansi::web::Response::new(200, _c.into_bytes()))} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html b/frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html new file mode 100644 index 00000000000..eaf9a979ee7 --- /dev/null +++ b/frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html @@ -0,0 +1,11 @@ + + + + + Not Found + + +

404

+

Page not found.

+ + diff --git a/frameworks/Rust/anansi/src/http_errors/views.rs b/frameworks/Rust/anansi/src/http_errors/views.rs new file mode 100644 index 00000000000..4bcc7ac523e --- /dev/null +++ b/frameworks/Rust/anansi/src/http_errors/views.rs @@ -0,0 +1,12 @@ +use anansi::{check, viewer, render}; +use anansi::web::{Result, Response}; +use anansi::util::auth::records::Group; +use crate::project::Request; + +#[viewer] +impl ErrorView { + #[check(Group::is_visitor)] + pub async fn not_found(_req: &mut R) -> Result { + render!("not_found") + } +} diff --git a/frameworks/Rust/anansi/src/main.rs b/frameworks/Rust/anansi/src/main.rs new file mode 100644 index 00000000000..0c8972ace4e --- /dev/null +++ b/frameworks/Rust/anansi/src/main.rs @@ -0,0 +1,23 @@ +use anansi::*; +use anansi::util::{auth, sessions, admin}; + +mod urls; +mod project; +mod http_errors; +mod hello; + +apps! { + auth, + sessions, + hello, +} + +app_statics! { + admin, +} + +app_admins! { + auth, +} + +main!(); diff --git a/frameworks/Rust/anansi/src/project.rs b/frameworks/Rust/anansi/src/project.rs new file mode 100644 index 00000000000..415bd89ffdc --- /dev/null +++ b/frameworks/Rust/anansi/src/project.rs @@ -0,0 +1,7 @@ +use anansi::project::prelude::*; + +app_cache!(local); + +database!(postgres); + +middleware!(); diff --git a/frameworks/Rust/anansi/src/urls.rs b/frameworks/Rust/anansi/src/urls.rs new file mode 100644 index 00000000000..b9b5e0edfef --- /dev/null +++ b/frameworks/Rust/anansi/src/urls.rs @@ -0,0 +1,11 @@ +use anansi::web::prelude::*; +use crate::hello::world::views::WorldView; + +routes! { + path!("/json", WorldView::json), + path!("/db", WorldView::db), + path!("/queries", WorldView::queries), + path!("/fortunes", WorldView::fortunes), + path!("/updates", WorldView::updates), + path!("/plaintext", WorldView::plaintext), +} From a1e97093f9d2d39c5966c264d09ea801cf4ef63e Mon Sep 17 00:00:00 2001 From: sarutora Date: Fri, 20 Jan 2023 22:01:18 -0800 Subject: [PATCH 2/6] made server bind to 0.0.0.0 --- frameworks/Rust/anansi/Cargo.toml | 2 +- frameworks/Rust/anansi/README.md | 19 +++------- frameworks/Rust/anansi/anansi.dockerfile | 2 +- frameworks/Rust/anansi/benchmark_config.json | 4 ++ frameworks/Rust/anansi/src/hello/records.rs | 37 ++++++++++++++++--- .../Rust/anansi/src/hello/world/views.rs | 23 +++++++----- .../Rust/anansi/src/http_errors/views.rs | 4 +- frameworks/Rust/anansi/src/main.rs | 11 +----- 8 files changed, 59 insertions(+), 43 deletions(-) diff --git a/frameworks/Rust/anansi/Cargo.toml b/frameworks/Rust/anansi/Cargo.toml index c594fc27813..3ff45867743 100644 --- a/frameworks/Rust/anansi/Cargo.toml +++ b/frameworks/Rust/anansi/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anansi = { git = "https://github.com/saru-tora/anansi", features = ["postgres"] } +anansi = { git = "https://github.com/saru-tora/anansi", features = ["postgres", "minimal"] } async-trait = "0.1.57" rand = "0.8.4" serde = { version = "1.0", features = ["derive"] } diff --git a/frameworks/Rust/anansi/README.md b/frameworks/Rust/anansi/README.md index 00f3c8d36e0..e9c9aa25ff2 100755 --- a/frameworks/Rust/anansi/README.md +++ b/frameworks/Rust/anansi/README.md @@ -46,22 +46,15 @@ Thanks and Cheers! -# Anansi Benchmarking Test +# [Anansi](https://saru-tora.github.io/anansi/) web framework + +## Description + +Anansi is a simple full-stack web framework for Rust. ### Test Type Implementation Source Code -* [JSON](Relative/Path/To/Your/Source/File) -* [PLAINTEXT](Relative/Path/To/Your/Source/File) -* [DB](Relative/Path/To/Your/Source/File) -* [QUERY](Relative/Path/To/Your/Source/File) -* [CACHED QUERY](Relative/Path/To/Your/Source/File) -* [UPDATE](Relative/Path/To/Your/Source/File) -* [FORTUNES](Relative/Path/To/Your/Source/File) - -## Important Libraries -The tests were run with: -* [Software](https://www.example1.com/) -* [Example](http://www.example2.com/) +All tests can be found in: src/hello/world/views.rs ## Test URLs ### JSON diff --git a/frameworks/Rust/anansi/anansi.dockerfile b/frameworks/Rust/anansi/anansi.dockerfile index d44d92db5f5..e5ebea9375d 100644 --- a/frameworks/Rust/anansi/anansi.dockerfile +++ b/frameworks/Rust/anansi/anansi.dockerfile @@ -8,4 +8,4 @@ RUN RUSTFLAGS="-C target-cpu=native" cargo build --release EXPOSE 8080 -CMD ./target/release/tfb-anansi 8080 +CMD RUST_LOG=info ./target/release/tfb-anansi 0.0.0.0:8080 diff --git a/frameworks/Rust/anansi/benchmark_config.json b/frameworks/Rust/anansi/benchmark_config.json index a1766c91ef7..068fd352f28 100755 --- a/frameworks/Rust/anansi/benchmark_config.json +++ b/frameworks/Rust/anansi/benchmark_config.json @@ -5,6 +5,10 @@ "default": { "json_url": "/json", "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8080, "approach": "Realistic", "classification": "Fullstack", diff --git a/frameworks/Rust/anansi/src/hello/records.rs b/frameworks/Rust/anansi/src/hello/records.rs index 860fe659088..ac9bd52796d 100644 --- a/frameworks/Rust/anansi/src/hello/records.rs +++ b/frameworks/Rust/anansi/src/hello/records.rs @@ -1,22 +1,47 @@ #![allow(non_snake_case)] -use anansi::{record, Relate, FromParams}; -use anansi::records::{BigInt, Text}; +use async_trait::async_trait; +use anansi::web::{Result, BaseRequest}; +use anansi::record; +use anansi::records::{Relate, Int, Text, random_int}; use serde::Serialize; #[record(table_name = "World")] -#[derive(Relate, FromParams, Serialize)] +#[derive(Serialize)] pub struct World { - pub randomNumber: BigInt, + #[field(primary_key = "true", default_fn = "random_int")] + pub id: Int, + pub randomNumber: Int, +} + +#[async_trait] +impl Relate for World { + async fn on_save(&self, _req: &R) -> Result<()> { + Ok(()) + } + async fn on_delete(&self, _req: &R) -> Result<()> { + unimplemented!(); + } } #[record(table_name = "Fortune")] -#[derive(Relate, FromParams)] pub struct Fortune { + #[field(primary_key = "true", default_fn = "random_int")] + pub id: Int, pub message: Text, } impl Fortune { pub fn additional() -> Self { - Self {id: BigInt::new(0), message: Text::from("Additional fortune added at request time.".to_string())} + Self {id: Int::new(0), message: Text::from("Additional fortune added at request time.".to_string())} + } +} + +#[async_trait] +impl Relate for Fortune { + async fn on_save(&self, _req: &R) -> Result<()> { + unimplemented!(); + } + async fn on_delete(&self, _req: &R) -> Result<()> { + unimplemented!(); } } diff --git a/frameworks/Rust/anansi/src/hello/world/views.rs b/frameworks/Rust/anansi/src/hello/world/views.rs index 0531fc6755f..2369f5e8c07 100644 --- a/frameworks/Rust/anansi/src/hello/world/views.rs +++ b/frameworks/Rust/anansi/src/hello/world/views.rs @@ -3,7 +3,7 @@ use super::super::records::{World, Fortune}; use serde::Serialize; use anansi::check; use anansi::web::Parameters; -use anansi::records::BigInt; +use anansi::records::Int; use rand::Rng; #[derive(Serialize)] @@ -26,19 +26,22 @@ fn get_query(params: &Parameters) -> i16 { 1 } +fn random_num() -> Int { + Int::new(rand::thread_rng().gen_range(1..=10_000)) +} + #[base_view] fn base(_req: &mut R) -> Result {} #[viewer] impl WorldView { - #[check(Group::is_visitor)] + #[check(Site::is_visitor)] pub async fn json(req: &mut R) -> Result { let message = Message {message: "Hello, World!"}; Response::json(&message) } async fn get_world(req: &R) -> Result { - let random_id = rand::thread_rng().gen_range(1..=10_000); - World::find(BigInt::new(random_id)).get(req).await + World::find(random_num()).get(req).await } async fn get_worlds(req: &R) -> Result> { let q = get_query(req.params()); @@ -49,36 +52,36 @@ impl WorldView { } Ok(worlds) } - #[check(Group::is_visitor)] + #[check(Site::is_visitor)] pub async fn db(req: &mut R) -> Result { let world = Self::get_world(req).await?; Response::json(&world) } - #[check(Group::is_visitor)] + #[check(Site::is_visitor)] pub async fn queries(req: &mut R) -> Result { let worlds = Self::get_worlds(req).await?; Response::json(&worlds) } - #[view(Group::is_visitor)] + #[view(Site::is_visitor)] pub async fn fortunes(req: &mut R) -> Result { let title = "Fortunes"; let mut fortunes = Fortune::get_all().query(req).await?; fortunes.push(Fortune::additional()); fortunes.sort_by(|it, next| it.message.cmp(&next.message)); } - #[check(Group::is_visitor)] + #[check(Site::is_visitor)] pub async fn updates(req: &mut R) -> Result { let mut worlds = Self::get_worlds(req).await?; transact!(req, { for world in &mut worlds { - world.randomNumber = BigInt::new(rand::thread_rng().gen_range(1..=10_000)); + world.randomNumber = random_num(); world.save(req).await?; } Ok(()) })?; Response::json(&worlds) } - #[check(Group::is_visitor)] + #[check(Site::is_visitor)] pub async fn plaintext(req: &mut R) -> Result { Ok(Response::text("Hello, World!".to_string())) } diff --git a/frameworks/Rust/anansi/src/http_errors/views.rs b/frameworks/Rust/anansi/src/http_errors/views.rs index 4bcc7ac523e..ef211964bdc 100644 --- a/frameworks/Rust/anansi/src/http_errors/views.rs +++ b/frameworks/Rust/anansi/src/http_errors/views.rs @@ -1,11 +1,11 @@ use anansi::{check, viewer, render}; use anansi::web::{Result, Response}; -use anansi::util::auth::records::Group; use crate::project::Request; +use anansi::site::Site; #[viewer] impl ErrorView { - #[check(Group::is_visitor)] + #[check(Site::is_visitor)] pub async fn not_found(_req: &mut R) -> Result { render!("not_found") } diff --git a/frameworks/Rust/anansi/src/main.rs b/frameworks/Rust/anansi/src/main.rs index 0c8972ace4e..6b16bb774fd 100644 --- a/frameworks/Rust/anansi/src/main.rs +++ b/frameworks/Rust/anansi/src/main.rs @@ -1,5 +1,4 @@ use anansi::*; -use anansi::util::{auth, sessions, admin}; mod urls; mod project; @@ -7,17 +6,9 @@ mod http_errors; mod hello; apps! { - auth, - sessions, hello, } -app_statics! { - admin, -} - -app_admins! { - auth, -} +app_statics! {} main!(); From 46e8be801676652135686bde972284371ebfff30 Mon Sep 17 00:00:00 2001 From: sarutora Date: Sun, 22 Jan 2023 10:34:23 -0800 Subject: [PATCH 3/6] fixed db tests --- frameworks/Rust/anansi/Cargo.toml | 2 +- frameworks/Rust/anansi/README.md | 4 +--- frameworks/Rust/anansi/anansi.dockerfile | 2 +- frameworks/Rust/anansi/settings.toml | 1 + frameworks/Rust/anansi/src/hello/records.rs | 2 +- .../Rust/anansi/src/hello/world/templates/.parsed/base.in | 1 - .../anansi/src/hello/world/templates/.parsed/fortunes.in | 5 ++--- .../Rust/anansi/src/hello/world/templates/base.rs.html | 1 - .../Rust/anansi/src/hello/world/templates/fortunes.rs.html | 1 - frameworks/Rust/anansi/src/hello/world/views.rs | 4 ++-- 10 files changed, 9 insertions(+), 14 deletions(-) diff --git a/frameworks/Rust/anansi/Cargo.toml b/frameworks/Rust/anansi/Cargo.toml index 3ff45867743..acc193e62e5 100644 --- a/frameworks/Rust/anansi/Cargo.toml +++ b/frameworks/Rust/anansi/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anansi = { git = "https://github.com/saru-tora/anansi", features = ["postgres", "minimal"] } +anansi = { git = "https://github.com/saru-tora/anansi", rev = "1eafd78", features = ["postgres", "minimal"] } async-trait = "0.1.57" rand = "0.8.4" serde = { version = "1.0", features = ["derive"] } diff --git a/frameworks/Rust/anansi/README.md b/frameworks/Rust/anansi/README.md index e9c9aa25ff2..4032be94cd5 100755 --- a/frameworks/Rust/anansi/README.md +++ b/frameworks/Rust/anansi/README.md @@ -46,9 +46,7 @@ Thanks and Cheers! -# [Anansi](https://saru-tora.github.io/anansi/) web framework - -## Description +# [Anansi](https://saru-tora.github.io/anansi/) Benchmarking Test Anansi is a simple full-stack web framework for Rust. diff --git a/frameworks/Rust/anansi/anansi.dockerfile b/frameworks/Rust/anansi/anansi.dockerfile index e5ebea9375d..1d8ded92d09 100644 --- a/frameworks/Rust/anansi/anansi.dockerfile +++ b/frameworks/Rust/anansi/anansi.dockerfile @@ -8,4 +8,4 @@ RUN RUSTFLAGS="-C target-cpu=native" cargo build --release EXPOSE 8080 -CMD RUST_LOG=info ./target/release/tfb-anansi 0.0.0.0:8080 +CMD RUST_LOG=off ./target/release/tfb-anansi 0.0.0.0:8080 diff --git a/frameworks/Rust/anansi/settings.toml b/frameworks/Rust/anansi/settings.toml index d551b84e4d6..b1d2fd84b21 100644 --- a/frameworks/Rust/anansi/settings.toml +++ b/frameworks/Rust/anansi/settings.toml @@ -16,3 +16,4 @@ name = "hello_world" user = "benchmarkdbuser" password = "benchmarkdbpass" address = "tfb-database" +max_conn = 512 diff --git a/frameworks/Rust/anansi/src/hello/records.rs b/frameworks/Rust/anansi/src/hello/records.rs index ac9bd52796d..9df45db2f02 100644 --- a/frameworks/Rust/anansi/src/hello/records.rs +++ b/frameworks/Rust/anansi/src/hello/records.rs @@ -16,7 +16,7 @@ pub struct World { #[async_trait] impl Relate for World { async fn on_save(&self, _req: &R) -> Result<()> { - Ok(()) + unimplemented!(); } async fn on_delete(&self, _req: &R) -> Result<()> { unimplemented!(); diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in index c96f18be24a..c93a1f8edc3 100644 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in @@ -1,7 +1,6 @@ {let mut _c = String::new();_c.push_str(" - ");_c.push_str(&_base_args._title);_c.push_str(" diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in index ccd8658237e..7cf8984f743 100644 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in @@ -1,7 +1,6 @@ -{_args._content = {let mut _c = String::new();_c.push_str("

");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str("

- +{_args._title = {let mut _c = String::new();_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str(""); _c};_args._content = {let mut _c = String::new();_c.push_str("
");for fortune in fortunes {_c.push_str(" ");}_c.push_str(" -
idmessage
");_c.push_str(&anansi::web::html_escape(&format!("{}", fortune.pk())));_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", fortune.message)));_c.push_str("
"); _c};_args._title = {let mut _c = String::new();_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str(""); _c};_args} \ No newline at end of file + "); _c};_args} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html index 98d083caa91..440d37a95eb 100644 --- a/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html +++ b/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html @@ -1,7 +1,6 @@ - @block title diff --git a/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html index 0550776a99b..0d4e369792a 100644 --- a/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html +++ b/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html @@ -1,7 +1,6 @@ @block title {@title} @block content { -

@title

@for fortune in fortunes { diff --git a/frameworks/Rust/anansi/src/hello/world/views.rs b/frameworks/Rust/anansi/src/hello/world/views.rs index 2369f5e8c07..f862961652a 100644 --- a/frameworks/Rust/anansi/src/hello/world/views.rs +++ b/frameworks/Rust/anansi/src/hello/world/views.rs @@ -12,7 +12,7 @@ struct Message { } fn get_query(params: &Parameters) -> i16 { - if let Ok(q) = params.get("queries") { + if let Ok(q) = params.get("q") { if let Ok(q) = q.parse() { if q > 1 { return if q <= 500 { @@ -75,7 +75,7 @@ impl WorldView { transact!(req, { for world in &mut worlds { world.randomNumber = random_num(); - world.save(req).await?; + world.update(req).await?; } Ok(()) })?; From 579374c8dcdd1ae1667113e989bd59dd75a785c7 Mon Sep 17 00:00:00 2001 From: sarutora Date: Mon, 23 Jan 2023 18:32:05 -0800 Subject: [PATCH 4/6] added raw tests --- frameworks/Rust/anansi/Cargo.toml | 5 +- frameworks/Rust/anansi/anansi-raw.dockerfile | 11 ++ frameworks/Rust/anansi/benchmark_config.json | 29 +++- frameworks/Rust/anansi/src/hello/mod.rs | 1 + frameworks/Rust/anansi/src/hello/world/mod.rs | 6 +- frameworks/Rust/anansi/src/hello/world/raw.rs | 133 ++++++++++++++++++ .../world/templates/.parsed/raw_fortunes.in | 5 + .../world/templates/raw_fortunes.rs.html | 10 ++ .../Rust/anansi/src/hello/world/util.rs | 16 +++ .../Rust/anansi/src/hello/world/views.rs | 40 ++---- .../Rust/anansi/src/http_errors/views.rs | 2 +- frameworks/Rust/anansi/src/urls.rs | 13 ++ 12 files changed, 234 insertions(+), 37 deletions(-) create mode 100644 frameworks/Rust/anansi/anansi-raw.dockerfile create mode 100644 frameworks/Rust/anansi/src/hello/world/raw.rs create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in create mode 100644 frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html create mode 100644 frameworks/Rust/anansi/src/hello/world/util.rs diff --git a/frameworks/Rust/anansi/Cargo.toml b/frameworks/Rust/anansi/Cargo.toml index acc193e62e5..55d1901dcd2 100644 --- a/frameworks/Rust/anansi/Cargo.toml +++ b/frameworks/Rust/anansi/Cargo.toml @@ -8,10 +8,11 @@ name = "tfb-anansi" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +raw = [] [dependencies] -anansi = { git = "https://github.com/saru-tora/anansi", rev = "1eafd78", features = ["postgres", "minimal"] } +anansi = { git = "https://github.com/saru-tora/anansi", rev = "9522722", features = ["postgres", "minimal"] } async-trait = "0.1.57" rand = "0.8.4" serde = { version = "1.0", features = ["derive"] } diff --git a/frameworks/Rust/anansi/anansi-raw.dockerfile b/frameworks/Rust/anansi/anansi-raw.dockerfile new file mode 100644 index 00000000000..96c284a8b7a --- /dev/null +++ b/frameworks/Rust/anansi/anansi-raw.dockerfile @@ -0,0 +1,11 @@ +FROM rust:1.64 + +ADD ./ /anansi +WORKDIR /anansi + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features raw + +EXPOSE 8080 + +CMD RUST_LOG=off ./target/release/tfb-anansi 0.0.0.0:8080 diff --git a/frameworks/Rust/anansi/benchmark_config.json b/frameworks/Rust/anansi/benchmark_config.json index 068fd352f28..38cb7c49251 100755 --- a/frameworks/Rust/anansi/benchmark_config.json +++ b/frameworks/Rust/anansi/benchmark_config.json @@ -5,10 +5,10 @@ "default": { "json_url": "/json", "plaintext_url": "/plaintext", - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -24,6 +24,27 @@ "display_name": "Anansi", "notes": "", "versus": "None" + }, + "raw": { + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Anansi", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "Anansi [raw]", + "notes": "", + "versus": "None" } } ] diff --git a/frameworks/Rust/anansi/src/hello/mod.rs b/frameworks/Rust/anansi/src/hello/mod.rs index b7e0b361315..2266878c520 100644 --- a/frameworks/Rust/anansi/src/hello/mod.rs +++ b/frameworks/Rust/anansi/src/hello/mod.rs @@ -1,4 +1,5 @@ pub mod urls; +#[cfg(not(feature = "raw"))] pub mod records; pub mod migrations; diff --git a/frameworks/Rust/anansi/src/hello/world/mod.rs b/frameworks/Rust/anansi/src/hello/world/mod.rs index 20758cc636c..2d3508e5707 100644 --- a/frameworks/Rust/anansi/src/hello/world/mod.rs +++ b/frameworks/Rust/anansi/src/hello/world/mod.rs @@ -1 +1,5 @@ -pub mod views; \ No newline at end of file +#[cfg(not(feature = "raw"))] +pub mod views; +#[cfg(feature = "raw")] +pub mod raw; +pub mod util; diff --git a/frameworks/Rust/anansi/src/hello/world/raw.rs b/frameworks/Rust/anansi/src/hello/world/raw.rs new file mode 100644 index 00000000000..24baf746bc4 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/raw.rs @@ -0,0 +1,133 @@ +use crate::prelude::*; +use serde::Serialize; +use anansi::check; +use anansi::db::postgres::{PgDbRow, PgQuery}; +use super::util::get_query; +use std::borrow::Cow; +use anansi::db::DbRow; +use rand::Rng; +use std::fmt::Write; + +thread_local!(static UPDATES: Vec> = { + let mut updates = vec![Cow::from("")]; + for num in 1..=500u16 { + let mut pl = 1; + let mut q = "UPDATE world SET randomnumber = CASE id ".to_string(); + for _ in 1..=num { + let _ = write!(q, "WHEN ${} THEN ${} ", pl, pl + 1); + pl += 2; + } + + q.push_str("ELSE randomnumber END WHERE id IN ("); + + for _ in 1..=num { + let _ = write!(q, "${},", pl); + pl += 1; + } + + q.pop(); + q.push(')'); + + updates.push(Cow::from(q)); + } + updates +}); + +fn random_num() -> i32 { + rand::thread_rng().gen_range(1..=10_000) +} + +#[derive(Copy, Clone, Serialize, Debug)] +pub struct World { + id: i32, + randomnumber: i32, +} + +#[derive(Serialize, Debug)] +pub struct Fortune { + id: i32, + message: Cow<'static, str>, +} + +#[base_view] +fn base(_req: &mut R) -> Result {} + +#[viewer] +impl WorldView { + async fn get_world(req: &R) -> Result { + PgQuery::new("SELECT * FROM world WHERE id = $1") + .bind(random_num()) + .fetch_one(req) + .await + } + async fn get_worlds(req: &R) -> Result> { + let q = get_query(req.params()); + let mut worlds = Vec::with_capacity(q as usize); + for _ in 0..q { + let row = Self::get_world(req).await?; + let world = World { + id: row.try_i32("id")?, + randomnumber: row.try_i32("randomnumber")?, + }; + worlds.push(world); + } + Ok(worlds) + } + #[check(Site::is_visitor)] + pub async fn db(req: &mut R) -> Result { + let row = Self::get_world(req).await?; + let world = World { + id: row.try_i32("id")?, + randomnumber: row.try_i32("randomnumber")?, + }; + Response::json(&world) + } + #[check(Site::is_visitor)] + pub async fn queries(req: &mut R) -> Result { + let worlds = Self::get_worlds(req).await?; + Response::json(&worlds) + } + #[view(Site::is_visitor)] + pub async fn raw_fortunes(req: &mut R) -> Result { + let title = "Fortunes"; + let rows = PgQuery::new("SELECT * FROM fortune") + .fetch_all(req) + .await?; + let mut fortunes = vec![Fortune { + id: 0, + message: Cow::Borrowed("Additional fortune added at request time.") + }]; + for row in rows { + fortunes.push(Fortune { + id: row.try_i32("id")?, + message: Cow::Owned(row.try_string("message")?), + }) + } + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); + } + #[check(Site::is_visitor)] + pub async fn updates(req: &mut R) -> Result { + let q = get_query(req.params()) as usize; + let mut worlds = Vec::with_capacity(q); + let mut update = Cow::from(""); + UPDATES.with(|u| { + update = u[q].clone(); + }); + let mut updates = PgQuery::new(&update); + for _ in 0..q { + let row = Self::get_world(req).await?; + let world = World { + id: row.try_i32("id")?, + randomnumber: random_num(), + }; + updates = updates.bind(world.id) + .bind(world.randomnumber); + worlds.push(world); + } + for world in &worlds { + updates = updates.bind(world.id); + } + updates.execute(req).await?; + Response::json(&worlds) + } +} diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in new file mode 100644 index 00000000000..3f510b939d2 --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in @@ -0,0 +1,5 @@ +{_args._title = {let mut _c = String::new();_c.push_str(&anansi::web::html_escape(&format!("{}", title))); _c}; +_args._content = {let mut _c = String::new();_c.push_str("
idmessage
"); +for fortune in fortunes {_c.push_str(""); +} _c.push_str("
idmessage
"); _c.push_str(&anansi::web::html_escape(&format!("{}", fortune.id))); +_c.push_str(""); _c.push_str(&anansi::web::html_escape(&format!("{}", fortune.message))); _c.push_str("
"); _c};_args} diff --git a/frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html new file mode 100644 index 00000000000..1ad9bd10a1f --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html @@ -0,0 +1,10 @@ +@block title {@title} + +@block content { + + + @for fortune in fortunes { + + } +
idmessage
@fortune.id@fortune.message
+} diff --git a/frameworks/Rust/anansi/src/hello/world/util.rs b/frameworks/Rust/anansi/src/hello/world/util.rs new file mode 100644 index 00000000000..8e8998f2b1f --- /dev/null +++ b/frameworks/Rust/anansi/src/hello/world/util.rs @@ -0,0 +1,16 @@ +use anansi::web::Parameters; + +pub fn get_query(params: &Parameters) -> i16 { + if let Ok(q) = params.get("q") { + if let Ok(q) = q.parse() { + if q > 1 { + return if q <= 500 { + q + } else { + 500 + }; + } + } + } + 1 +} diff --git a/frameworks/Rust/anansi/src/hello/world/views.rs b/frameworks/Rust/anansi/src/hello/world/views.rs index f862961652a..4714e249c92 100644 --- a/frameworks/Rust/anansi/src/hello/world/views.rs +++ b/frameworks/Rust/anansi/src/hello/world/views.rs @@ -1,35 +1,20 @@ use crate::prelude::*; +use anansi::records::Int; use super::super::records::{World, Fortune}; +use super::util::get_query; use serde::Serialize; -use anansi::check; -use anansi::web::Parameters; -use anansi::records::Int; +use anansi::{check, raw_bulk_update}; use rand::Rng; +fn random_num() -> Int { + Int::new(rand::thread_rng().gen_range(1..=10_000)) +} + #[derive(Serialize)] struct Message { message: &'static str, } -fn get_query(params: &Parameters) -> i16 { - if let Ok(q) = params.get("q") { - if let Ok(q) = q.parse() { - if q > 1 { - return if q <= 500 { - q - } else { - 500 - }; - } - } - } - 1 -} - -fn random_num() -> Int { - Int::new(rand::thread_rng().gen_range(1..=10_000)) -} - #[base_view] fn base(_req: &mut R) -> Result {} @@ -72,13 +57,10 @@ impl WorldView { #[check(Site::is_visitor)] pub async fn updates(req: &mut R) -> Result { let mut worlds = Self::get_worlds(req).await?; - transact!(req, { - for world in &mut worlds { - world.randomNumber = random_num(); - world.update(req).await?; - } - Ok(()) - })?; + for world in &mut worlds { + world.randomNumber = random_num(); + } + transact!(req, raw_bulk_update!(req, World, &worlds, randomNumber).await)?; Response::json(&worlds) } #[check(Site::is_visitor)] diff --git a/frameworks/Rust/anansi/src/http_errors/views.rs b/frameworks/Rust/anansi/src/http_errors/views.rs index ef211964bdc..04872858818 100644 --- a/frameworks/Rust/anansi/src/http_errors/views.rs +++ b/frameworks/Rust/anansi/src/http_errors/views.rs @@ -1,7 +1,7 @@ use anansi::{check, viewer, render}; use anansi::web::{Result, Response}; -use crate::project::Request; use anansi::site::Site; +use crate::project::Request; #[viewer] impl ErrorView { diff --git a/frameworks/Rust/anansi/src/urls.rs b/frameworks/Rust/anansi/src/urls.rs index b9b5e0edfef..c8fd7a1ec44 100644 --- a/frameworks/Rust/anansi/src/urls.rs +++ b/frameworks/Rust/anansi/src/urls.rs @@ -1,6 +1,8 @@ use anansi::web::prelude::*; +#[cfg(not(feature = "raw"))] use crate::hello::world::views::WorldView; +#[cfg(not(feature = "raw"))] routes! { path!("/json", WorldView::json), path!("/db", WorldView::db), @@ -9,3 +11,14 @@ routes! { path!("/updates", WorldView::updates), path!("/plaintext", WorldView::plaintext), } + +#[cfg(feature = "raw")] +use crate::hello::world::raw::WorldView; + +#[cfg(feature = "raw")] +routes! { + path!("/db", WorldView::db), + path!("/queries", WorldView::queries), + path!("/fortunes", WorldView::raw_fortunes), + path!("/updates", WorldView::updates), +} From 13ad9a2f336e2aa1b39f0c6bdf34c20fa8be2e9b Mon Sep 17 00:00:00 2001 From: sarutora Date: Wed, 25 Jan 2023 19:09:54 -0800 Subject: [PATCH 5/6] added cache test --- frameworks/Rust/anansi/Cargo.toml | 3 +- frameworks/Rust/anansi/anansi.dockerfile | 5 +++- frameworks/Rust/anansi/benchmark_config.json | 1 + frameworks/Rust/anansi/settings.toml | 2 +- .../Rust/anansi/src/hello/world/views.rs | 28 ++++++++++++++++--- frameworks/Rust/anansi/src/main.rs | 21 +++++++++++++- frameworks/Rust/anansi/src/project.rs | 4 +++ frameworks/Rust/anansi/src/urls.rs | 1 + 8 files changed, 57 insertions(+), 8 deletions(-) diff --git a/frameworks/Rust/anansi/Cargo.toml b/frameworks/Rust/anansi/Cargo.toml index 55d1901dcd2..08b92229014 100644 --- a/frameworks/Rust/anansi/Cargo.toml +++ b/frameworks/Rust/anansi/Cargo.toml @@ -12,7 +12,8 @@ edition = "2021" raw = [] [dependencies] -anansi = { git = "https://github.com/saru-tora/anansi", rev = "9522722", features = ["postgres", "minimal"] } +anansi = { git = "https://github.com/saru-tora/anansi", rev = "2567157", features = ["postgres", "minimal", "redis"] } async-trait = "0.1.57" rand = "0.8.4" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/frameworks/Rust/anansi/anansi.dockerfile b/frameworks/Rust/anansi/anansi.dockerfile index 1d8ded92d09..bf6f7596193 100644 --- a/frameworks/Rust/anansi/anansi.dockerfile +++ b/frameworks/Rust/anansi/anansi.dockerfile @@ -1,5 +1,7 @@ FROM rust:1.64 +RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server + ADD ./ /anansi WORKDIR /anansi @@ -8,4 +10,5 @@ RUN RUSTFLAGS="-C target-cpu=native" cargo build --release EXPOSE 8080 -CMD RUST_LOG=off ./target/release/tfb-anansi 0.0.0.0:8080 +ENV RUST_LOG=off +CMD service redis-server start && ./target/release/tfb-anansi 0.0.0.0:8080 diff --git a/frameworks/Rust/anansi/benchmark_config.json b/frameworks/Rust/anansi/benchmark_config.json index 38cb7c49251..621fafdbdba 100755 --- a/frameworks/Rust/anansi/benchmark_config.json +++ b/frameworks/Rust/anansi/benchmark_config.json @@ -9,6 +9,7 @@ "fortune_url": "/fortunes", "query_url": "/queries?q=", "update_url": "/updates?q=", + "cached_query_url": "/cached-queries?q=", "port": 8080, "approach": "Realistic", "classification": "Fullstack", diff --git a/frameworks/Rust/anansi/settings.toml b/frameworks/Rust/anansi/settings.toml index b1d2fd84b21..ea5f708b543 100644 --- a/frameworks/Rust/anansi/settings.toml +++ b/frameworks/Rust/anansi/settings.toml @@ -7,7 +7,7 @@ smtp_password = "" [caches] [caches.default] -location = "" +location = "redis://127.0.0.1/" [databases] diff --git a/frameworks/Rust/anansi/src/hello/world/views.rs b/frameworks/Rust/anansi/src/hello/world/views.rs index 4714e249c92..5ee366c73b6 100644 --- a/frameworks/Rust/anansi/src/hello/world/views.rs +++ b/frameworks/Rust/anansi/src/hello/world/views.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use anansi::cache::prelude::*; use anansi::records::Int; use super::super::records::{World, Fortune}; use super::util::get_query; @@ -6,8 +7,12 @@ use serde::Serialize; use anansi::{check, raw_bulk_update}; use rand::Rng; -fn random_num() -> Int { - Int::new(rand::thread_rng().gen_range(1..=10_000)) +fn random_i32() -> i32 { + rand::thread_rng().gen_range(1..=10_000) +} + +fn random_int() -> Int { + Int::new(random_i32()) } #[derive(Serialize)] @@ -26,7 +31,7 @@ impl WorldView { Response::json(&message) } async fn get_world(req: &R) -> Result { - World::find(random_num()).get(req).await + World::find(random_int()).get(req).await } async fn get_worlds(req: &R) -> Result> { let q = get_query(req.params()); @@ -58,7 +63,7 @@ impl WorldView { pub async fn updates(req: &mut R) -> Result { let mut worlds = Self::get_worlds(req).await?; for world in &mut worlds { - world.randomNumber = random_num(); + world.randomNumber = random_int(); } transact!(req, raw_bulk_update!(req, World, &worlds, randomNumber).await)?; Response::json(&worlds) @@ -67,4 +72,19 @@ impl WorldView { pub async fn plaintext(req: &mut R) -> Result { Ok(Response::text("Hello, World!".to_string())) } + #[check(Site::is_visitor)] + pub async fn cached_queries(req: &mut R) -> Result { + let q = get_query(req.params()); + let mut ids = vec![]; + for _ in 0..q { + ids.push(random_i32().to_string()); + } + let mut worlds = vec!['[' as u8]; + for mut world in req.cache().get_many(ids).await? { + worlds.append(&mut world); + } + worlds.pop(); + worlds.push(']' as u8); + Response::json_bytes(worlds) + } } diff --git a/frameworks/Rust/anansi/src/main.rs b/frameworks/Rust/anansi/src/main.rs index 6b16bb774fd..54ea7cfc5d6 100644 --- a/frameworks/Rust/anansi/src/main.rs +++ b/frameworks/Rust/anansi/src/main.rs @@ -11,4 +11,23 @@ apps! { app_statics! {} -main!(); +#[cfg(feature = "raw")] +min_main!(); + +#[cfg(not(feature = "raw"))] +min_main!(server, { + { + use anansi::cache::prelude::*; + use hello::records::World; + use anansi::records::Record; + let worlds = World::get_all().raw_query(&server.pool).await.expect("problem fetching worlds"); + let mut items = vec![]; + for world in worlds { + let id = world.pk().to_string(); + let mut bytes = serde_json::to_vec(&world).expect("problem serializing world"); + bytes.push(',' as u8); + items.push((id, bytes)); + } + server.cache.set_many(&items).await.expect("problem caching world"); + } +}); diff --git a/frameworks/Rust/anansi/src/project.rs b/frameworks/Rust/anansi/src/project.rs index 415bd89ffdc..08b6f41e15b 100644 --- a/frameworks/Rust/anansi/src/project.rs +++ b/frameworks/Rust/anansi/src/project.rs @@ -1,7 +1,11 @@ use anansi::project::prelude::*; +#[cfg(feature = "raw")] app_cache!(local); +#[cfg(not(feature = "raw"))] +app_cache!(redis); + database!(postgres); middleware!(); diff --git a/frameworks/Rust/anansi/src/urls.rs b/frameworks/Rust/anansi/src/urls.rs index c8fd7a1ec44..beefcc8825b 100644 --- a/frameworks/Rust/anansi/src/urls.rs +++ b/frameworks/Rust/anansi/src/urls.rs @@ -10,6 +10,7 @@ routes! { path!("/fortunes", WorldView::fortunes), path!("/updates", WorldView::updates), path!("/plaintext", WorldView::plaintext), + path!("/cached-queries", WorldView::cached_queries), } #[cfg(feature = "raw")] From c71bc6e28874901bf93e3969db860f4acff5259d Mon Sep 17 00:00:00 2001 From: sarutora Date: Fri, 3 Feb 2023 09:00:46 -0800 Subject: [PATCH 6/6] updated README --- frameworks/Rust/anansi/README.md | 50 +------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/frameworks/Rust/anansi/README.md b/frameworks/Rust/anansi/README.md index 4032be94cd5..ebddef843ca 100755 --- a/frameworks/Rust/anansi/README.md +++ b/frameworks/Rust/anansi/README.md @@ -1,58 +1,10 @@ -# Congratulations! - -You have successfully built a new test in the suite! - -There are some remaining tasks to do before you are ready to open a pull request, however. - -## Next Steps - -1. Gather your source code. - -You will need to ensure that your source code is beneath this directory. The most common solution is to include a `src` directory and place your source code there. - -2. Edit `benchmark_config.json` - -You will need alter `benchmark_config.json` to have the appropriate end-points and port specified. - -3. Create `anansi.dockerfile` - -This is the dockerfile that is built into a docker image and run when a benchmark test is run. Specifically, this file tells the suite how to build and start your test application. - -You can create multiple implementations and they will all conform to `[name in benchmark_config.json].dockerfile`. For example, the `default` implementation in `benchmark_config.json` will be `anansi.dockerfile`, but if you wanted to make another implementation that did only the database tests for MySQL, you could make `anansi-mysql.dockerfile` and have an entry in your `benchmark_config.json` for `anansi-mysql`. - -4. Test your application - - $ tfb --mode verify --test anansi - -This will run the suite in `verify` mode for your test. This means that no benchmarks will be captured and we will test that we can hit your implementation end-points specified by `benchmark_config.json` and that the response is correct. - -Once you are able to successfully run your test through our suite in this way **and** your test passes our validation, you may move on to the next step. - -5. Add your test to `.github/workflows/build.yml` - -Edit `.github/workflows/build.yml` to ensure that Github Actions will automatically run our verification tests against your new test. This file is kept in alphabetical order, so find where `TESTDIR=Rust/anansi` should be inserted under `env > matrix` and put it there. - -6. Fix this `README.md` and open a pull request - -Starting on line 49 is your actual `README.md` that will sit with your test implementation. Update all the dummy values to their correct values so that when people visit your test in our Github repository, they will be greated with information on how your test implementation works and where to look for useful source code. - -After you have the real `README.md` file in place, delete everything above line 59 and you are ready to open a pull request. - -Thanks and Cheers! - - - - - - - # [Anansi](https://saru-tora.github.io/anansi/) Benchmarking Test Anansi is a simple full-stack web framework for Rust. ### Test Type Implementation Source Code -All tests can be found in: src/hello/world/views.rs +All tests can be found in: src/hello/world/ ## Test URLs ### JSON