From eabe73ddc04e8a4877e066447a3e21dcc8dc3aee Mon Sep 17 00:00:00 2001 From: fdb-hiroshima <35889323+fdb-hiroshima@users.noreply.github.com> Date: Sat, 6 Apr 2019 17:41:57 +0200 Subject: [PATCH] Add tests for plume webserver (#513) * begin setup front-end test environment with selenium * run migrations before tests * use https for tests --- .circleci/config.yml | 91 +++++++++++++++---- .circleci/images/plume-buildenv/Caddyfile | 6 ++ .circleci/images/plume-buildenv/Dockerfile | 19 +++- .circleci/images/plume-buildenv/cargo_config | 3 + .gitignore | 1 + Cargo.toml | 1 + plume-models/src/config.rs | 2 +- script/browser_test/__init__.py | 0 script/browser_test/instance.py | 7 ++ script/browser_test/utils.py | 22 +++++ script/run_browser_test.sh | 26 ++++++ .../{compute_coverage.sh => run_unit_test.sh} | 1 - script/upload_coverage.sh | 3 + src/main.rs | 22 ++--- src/routes/likes.rs | 5 +- src/routes/reshares.rs | 5 +- src/test_routes.rs | 2 + 17 files changed, 171 insertions(+), 45 deletions(-) create mode 100644 .circleci/images/plume-buildenv/Caddyfile create mode 100644 .circleci/images/plume-buildenv/cargo_config create mode 100644 script/browser_test/__init__.py create mode 100644 script/browser_test/instance.py create mode 100644 script/browser_test/utils.py create mode 100755 script/run_browser_test.sh rename script/{compute_coverage.sh => run_unit_test.sh} (86%) create mode 100755 script/upload_coverage.sh create mode 100644 src/test_routes.rs diff --git a/.circleci/config.yml b/.circleci/config.yml index 966c867..2745a90 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,18 +1,34 @@ version: 2.1 aliases: + - &plume-docker + image: plumeorg/plume-buildenv:v0.0.5 - &defaults docker: - - image: plumeorg/plume-buildenv:v0.0.3 + - *plume-docker working_directory: ~/projects/Plume - &postgresql docker: - - image: plumeorg/plume-buildenv:v0.0.3 + - *plume-docker - image: circleci/postgres:9.6-alpine environment: POSTGRES_USER: postgres POSTGRES_DB: plume working_directory: ~/projects/Plume + - &selenium + docker: + - *plume-docker + - image: elgalu/selenium:latest + working_directory: ~/projects/Plume + - &postgresql_selenium + docker: + - *plume-docker + - image: circleci/postgres:9.6-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_DB: plume + - image: elgalu/selenium:latest + working_directory: ~/projects/Plume - &attach_workspace attach_workspace: @@ -25,13 +41,13 @@ aliases: - &env_postgresql environment: - MIGRATION_DIR: migrations/postgres + MIGRATION_DIRECTORY: migrations/postgres FEATURES: postgres DATABASE_URL: postgres://postgres@localhost/plume RUST_TEST_THREADS: 1 - &env_sqlite environment: - MIGRATION_DIR: migrations/sqlite + MIGRATION_DIRECTORY: migrations/sqlite FEATURES: sqlite DATABASE_URL: plume.sqlite3 RUST_TEST_THREADS: 1 @@ -101,26 +117,48 @@ aliases: name: clippy command: cargo clippy --no-default-features --features="${FEATURES}" --release -p plume-cli -- -D warnings - *save_cache_cli - - &test_plume + - &test_unit steps: - *attach_workspace - run: name: Set cache key command: echo "$FEATURES" > /FEATURES - - run: - name: Set compiler flags - # rustflags = ["-Clink-dead-code", "-Clink-args=-Xlinker --no-keep-memory -Xlinker --reduce-memory-overheads"] - command: echo "W3RhcmdldC54ODZfNjQtdW5rbm93bi1saW51eC1nbnVdCnJ1c3RmbGFncyA9IFsiLUNsaW5rLWRlYWQtY29kZSIsICItQ2xpbmstYXJncz0tWGxpbmtlciAtLW5vLWtlZXAtbWVtb3J5IC1YbGlua2VyIC0tcmVkdWNlLW1lbW9yeS1vdmVyaGVhZHMiXQoK" | base64 -d >> ~/.cargo/config - *restore_cache_plume_dead_code - run: name: clippy command: cargo clippy --no-default-features --features="${FEATURES}" --release -- -D warnings - - run: + - run: name: compile test command: cargo test --no-default-features --features="${FEATURES}" --all --exclude plume-front --no-run || cargo test --no-default-features --features="${FEATURES}" --all --exclude plume-front --no-run - - run: - name: run test and upload coverage - command: ./script/compute_coverage.sh + - run: + name: run test + command: ./script/run_unit_test.sh + - run: + name: upload coverage + command: ./script/upload_coverage.sh unit + - *save_cache_plume_dead_code + + - &test_browser + steps: + - *attach_workspace + - run: + name: Set cache key + command: echo "$FEATURES" > /FEATURES + - *restore_cache_plume_dead_code + - run: + name: install server + command: cargo install --debug --no-default-features --features="${FEATURES}",test --path . || cargo install --debug --no-default-features --features="${FEATURES}",test --path . + - run: + name: install plm + command: cargo install --debug --no-default-features --features="${FEATURES}" --path plume-cli || cargo install --debug --no-default-features --features="${FEATURES}" --path plume-cli + - run: + name: run test + command: ./script/run_browser_test.sh + environment: + BROWSER: firefox + - run: + name: upload coverage + command: ./script/upload_coverage.sh integration - *save_cache_plume_dead_code jobs: @@ -160,16 +198,25 @@ jobs: <<: *env_sqlite <<: *test_cli - test_plume_postgresql: + test_unit_postgresql: <<: *postgresql <<: *env_postgresql - <<: *test_plume + <<: *test_unit - test_plume_sqlite: + test_unit_sqlite: <<: *defaults <<: *env_sqlite - <<: *test_plume + <<: *test_unit + test_browser_postgresql: + <<: *postgresql_selenium + <<: *env_postgresql + <<: *test_browser + + test_browser_sqlite: + <<: *selenium + <<: *env_sqlite + <<: *test_browser workflows: version: 2 @@ -188,9 +235,15 @@ workflows: - test_cli_sqlite: requires: - download_deps - - test_plume_postgresql: + - test_unit_postgresql: requires: - download_deps - - test_plume_sqlite: + - test_unit_sqlite: requires: - download_deps + - test_browser_postgresql: + requires: + - build_web + - test_browser_sqlite: + requires: + - build_web diff --git a/.circleci/images/plume-buildenv/Caddyfile b/.circleci/images/plume-buildenv/Caddyfile new file mode 100644 index 0000000..cc7a435 --- /dev/null +++ b/.circleci/images/plume-buildenv/Caddyfile @@ -0,0 +1,6 @@ +localhost:443 { + proxy / localhost:7878 { + transparent + } + tls self_signed +} diff --git a/.circleci/images/plume-buildenv/Dockerfile b/.circleci/images/plume-buildenv/Dockerfile index 465c760..90ab99e 100644 --- a/.circleci/images/plume-buildenv/Dockerfile +++ b/.circleci/images/plume-buildenv/Dockerfile @@ -4,16 +4,29 @@ ENV PATH="/root/.cargo/bin:${PATH}" #install native/circleci/build dependancies RUN apt update &&\ apt install -y git ssh tar gzip ca-certificates &&\ - apt install -y binutils-dev build-essential cmake curl gcc gettext git libcurl4-openssl-dev libdw-dev libelf-dev libiberty-dev libpq-dev libsqlite3-dev libssl-dev make openssl pkg-config postgresql postgresql-contrib python zlib1g-dev + apt install -y binutils-dev build-essential cmake curl gcc gettext git libcurl4-openssl-dev libdw-dev libelf-dev libiberty-dev libpq-dev libsqlite3-dev libssl-dev make openssl pkg-config postgresql postgresql-contrib python zlib1g-dev python3-pip #install and configure rust RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-03-23 -y &&\ rustup component add rustfmt clippy &&\ - rustup component add rust-std --target wasm32-unknown-unknown &&\ - cargo install cargo-web &&\ + rustup component add rust-std --target wasm32-unknown-unknown + +#compile some deps +RUN cargo install cargo-web &&\ + cargo install diesel_cli --no-default-features --features postgres,sqlite --version '=1.3.0' &&\ rm -fr ~/.cargo/registry #install coverage tools RUN curl -L https://github.com/SimonKagstrom/kcov/archive/master.tar.gz | tar xz &&\ mkdir -p kcov-master/build && cd kcov-master/build && cmake .. && make &&\ make install && cd ../.. && rm -rf kcov-master + +#set some compilation parametters +COPY cargo_config /root/.cargo/config + +#install selenium for front end tests +RUN pip3 install selenium + +#install and configure caddy +RUN curl https://getcaddy.com | bash -s personal +COPY Caddyfile /Caddyfile diff --git a/.circleci/images/plume-buildenv/cargo_config b/.circleci/images/plume-buildenv/cargo_config new file mode 100644 index 0000000..10d9285 --- /dev/null +++ b/.circleci/images/plume-buildenv/cargo_config @@ -0,0 +1,3 @@ +[target.x86_64-unknown-linux-gnu] +# link dead code for coverage, attempt to reduce linking memory usage to not get killed +rustflags = ["-Clink-dead-code", "-Clink-args=-Xlinker --no-keep-memory -Xlinker --reduce-memory-overheads"] diff --git a/.gitignore b/.gitignore index e0d6ad4..b24dc86 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ main.css *.wasm *.js .buildconfig +__pycache__ diff --git a/Cargo.toml b/Cargo.toml index 7392b31..316a1cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ default = ["postgres"] postgres = ["plume-models/postgres", "diesel/postgres"] sqlite = ["plume-models/sqlite", "diesel/sqlite"] debug-mailer = [] +test = [] [workspace] members = ["plume-api", "plume-cli", "plume-models", "plume-common", "plume-front"] diff --git a/plume-models/src/config.rs b/plume-models/src/config.rs index cc28db5..8300e3a 100644 --- a/plume-models/src/config.rs +++ b/plume-models/src/config.rs @@ -188,7 +188,7 @@ lazy_static! { pub static ref CONFIG: Config = Config { base_url: var("BASE_URL").unwrap_or_else(|_| format!( "127.0.0.1:{}", - var("ROCKET_PORT").unwrap_or_else(|_| "8000".to_owned()) + var("ROCKET_PORT").unwrap_or_else(|_| "7878".to_owned()) )), db_name: DB_NAME, #[cfg(feature = "postgres")] diff --git a/script/browser_test/__init__.py b/script/browser_test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/script/browser_test/instance.py b/script/browser_test/instance.py new file mode 100644 index 0000000..ceb7231 --- /dev/null +++ b/script/browser_test/instance.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +from utils import Browser + +class InstanceName(Browser): + def test_name_in_title(self): + self.get("/") + self.assertIn("plume-test", self.driver.title) diff --git a/script/browser_test/utils.py b/script/browser_test/utils.py new file mode 100644 index 0000000..df07eb1 --- /dev/null +++ b/script/browser_test/utils.py @@ -0,0 +1,22 @@ +#!/usr/bin/python3 +import unittest,os +from selenium import webdriver +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities + +class Browser(unittest.TestCase): + def setUp(self): + if os.environ["BROWSER"] == "firefox": + capabilities=DesiredCapabilities.FIREFOX + elif os.environ["BROWSER"] == "chrome": + capabilities=DesiredCapabilities.CHROME + else: + raise Exception("No browser was requested") + capabilities['acceptSslCerts'] = True + self.driver = webdriver.Remote( + command_executor='http://localhost:24444/wd/hub', + desired_capabilities=capabilities) + def tearDown(self): + self.driver.close() + + def get(self, url): + return self.driver.get("https://localhost" + url) diff --git a/script/run_browser_test.sh b/script/run_browser_test.sh new file mode 100755 index 0000000..bbebc53 --- /dev/null +++ b/script/run_browser_test.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -eo pipefail + +export ROCKET_SECRET_KEY="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + +mkdir -p "target/cov/plume" +mkdir -p "target/cov/plm" +plm='kcov --exclude-pattern=/.cargo,/usr/lib --verify target/cov/plm plm' + +diesel migration run +diesel migration redo +$plm instance new -d plume-test.local -n plume-test +$plm users new -n admin -N 'Admin' -e 'email@exemple.com' -p 'password' +$plm search init + +kcov --exclude-pattern=/.cargo,/usr/lib --verify target/cov/plume plume & +caddy -conf /Caddyfile & + +until curl http://localhost:7878/test/health -f; do sleep 1; done 2>/dev/null >/dev/null + +cd $(dirname $0)/browser_test/ +python3 -m unittest *.py + +kill -SIGINT %1 +kill -SIGKILL %2 +wait diff --git a/script/compute_coverage.sh b/script/run_unit_test.sh similarity index 86% rename from script/compute_coverage.sh rename to script/run_unit_test.sh index 9ed4c5b..3f15b6c 100755 --- a/script/compute_coverage.sh +++ b/script/run_unit_test.sh @@ -8,4 +8,3 @@ for file in target/debug/*-*[^\.d]; do kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$filename" "$file" fi done -bash <(curl -s https://codecov.io/bash) diff --git a/script/upload_coverage.sh b/script/upload_coverage.sh new file mode 100755 index 0000000..b417529 --- /dev/null +++ b/script/upload_coverage.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -eo pipefail +bash <(curl -s https://codecov.io/bash) -F $1 diff --git a/src/main.rs b/src/main.rs index 393c88f..659fc6f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,6 +59,8 @@ mod mail; #[macro_use] mod template_utils; mod routes; +#[cfg(feature = "test")] +mod test_routes; include!(concat!(env!("OUT_DIR"), "/templates.rs")); @@ -122,6 +124,7 @@ Then try to restart Plume let search_unlocker = searcher.clone(); ctrlc::set_handler(move || { + search_unlocker.commit(); search_unlocker.drop_writer(); exit(0); }) @@ -133,7 +136,7 @@ Then try to restart Plume println!("Please refer to the documentation to see how to configure it."); } - rocket::custom(CONFIG.rocket.clone().unwrap()) + let rocket = rocket::custom(CONFIG.rocket.clone().unwrap()) .mount( "/", routes![ @@ -258,16 +261,6 @@ Then try to restart Plume "/@//inbox".to_owned(), rocket::http::Method::Post, ), - ( - "/login".to_owned(), - "/login".to_owned(), - rocket::http::Method::Post, - ), - ( - "/users/new".to_owned(), - "/users/new".to_owned(), - rocket::http::Method::Post, - ), ( "/api/".to_owned(), "/api/".to_owned(), @@ -276,6 +269,9 @@ Then try to restart Plume ]) .finalize() .expect("main: csrf fairing creation error"), - ) - .launch(); + ); + + #[cfg(feature = "test")] + let rocket = rocket.mount("/test", routes![test_routes::health,]); + rocket.launch(); } diff --git a/src/routes/likes.rs b/src/routes/likes.rs index b088d15..a0f7e33 100644 --- a/src/routes/likes.rs +++ b/src/routes/likes.rs @@ -43,10 +43,7 @@ pub fn create( #[post("/~///like", rank = 2)] pub fn create_auth(blog: String, slug: String, i18n: I18n) -> Flash { utils::requires_login( - &i18n!( - i18n.catalog, - "To like a post, you need to be logged in" - ), + &i18n!(i18n.catalog, "To like a post, you need to be logged in"), uri!(create: blog = blog, slug = slug), ) } diff --git a/src/routes/reshares.rs b/src/routes/reshares.rs index 26e1c3d..15c9481 100644 --- a/src/routes/reshares.rs +++ b/src/routes/reshares.rs @@ -43,10 +43,7 @@ pub fn create( #[post("/~///reshare", rank = 1)] pub fn create_auth(blog: String, slug: String, i18n: I18n) -> Flash { utils::requires_login( - &i18n!( - i18n.catalog, - "To reshare a post, you need to be logged in" - ), + &i18n!(i18n.catalog, "To reshare a post, you need to be logged in"), uri!(create: blog = blog, slug = slug), ) } diff --git a/src/test_routes.rs b/src/test_routes.rs new file mode 100644 index 0000000..a24e1c7 --- /dev/null +++ b/src/test_routes.rs @@ -0,0 +1,2 @@ +#[get("/health")] +pub fn health() {}