add tests, setup ci

This commit is contained in:
Alexey Proshutinskiy 2021-09-02 18:58:44 +03:00
parent 414cff0779
commit 31145f447e
6 changed files with 101 additions and 370 deletions

36
.circleci/config.yml Normal file
View File

@ -0,0 +1,36 @@
version: 2.1
orbs:
docker: circleci/docker@1.5.0
jobs:
Build and test Rust service:
docker:
- image: circleci/rust:latest
resource_class: xlarge
environment:
RUST_BACKTRACE: full
steps:
- checkout
- run: |
sudo bash .github/download_marine.sh
- restore_cache:
keys:
- connector-test00-{{ checksum "Cargo.lock" }}
- run: |
cd ./service
rustup target add wasm32-wasi
- run: ./build.sh
- run: |
cargo test --no-fail-fast --release --all-features
- save_cache:
paths:
- ~/.cargo
- ~/.rustup
key: connector-test00-{{ checksum "Cargo.lock" }}
workflows:
version: 2
CircleCI:
jobs:
- Build and test Rust service

14
.github/download_marine.sh vendored Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
set -o pipefail -o errexit -o nounset
set -x
MARINE_RELEASE="https://api.github.com/repos/fluencelabs/marine/releases/latest"
OUT_DIR=/usr/local/bin
# get metadata about release
curl -s -H "Accept: application/vnd.github.v3+json" $MARINE_RELEASE |
# extract url and name for asset with name "marine"
# also append $OUT_DIR to each name so file is saved to $OUT_DIR
jq -r ".assets | .[] | select(.name == \"marine\") | \"\(.browser_download_url) $OUT_DIR/\(.name)\"" |
# download assets
xargs -n2 bash -c 'curl -L $0 -o $1 && chmod +x $1'

View File

@ -39,3 +39,4 @@ marine-rs-sdk = "0.6.10"
[dev-dependencies] [dev-dependencies]
temporary = "0.6" temporary = "0.6"
marine-rs-sdk-test = "0.2.0"

View File

@ -4,8 +4,8 @@ set -o errexit -o nounset -o pipefail
# set current working directory to script directory to run script from everywhere # set current working directory to script directory to run script from everywhere
cd "$(dirname "$0")" cd "$(dirname "$0")"
# build aqua-dht.wasm # build test.wasm
marine build --release marine build --release --bin test
# copy .wasm to artifacts # copy .wasm to artifacts
rm -f artifacts/* rm -f artifacts/*
@ -14,6 +14,3 @@ cp target/wasm32-wasi/release/test.wasm artifacts/
# download SQLite 3 to use in tests # download SQLite 3 to use in tests
curl -L https://github.com/fluencelabs/sqlite/releases/download/v0.14.0_w/sqlite3.wasm -o artifacts/sqlite3.wasm curl -L https://github.com/fluencelabs/sqlite/releases/download/v0.14.0_w/sqlite3.wasm -o artifacts/sqlite3.wasm
# generate Aqua bindings
#marine aqua artifacts/aqua-dht.wasm -s AquaDHT -i aqua-dht >../aqua/dht.aqua

View File

@ -1,365 +0,0 @@
extern crate sqlite;
extern crate temporary;
use sqlite::{Connection, OpenFlags, State, Type, Value};
use std::path::Path;
macro_rules! ok(($result:expr) => ($result.unwrap()));
#[test]
fn connection_changes() {
let connection = setup_users(":memory:");
assert_eq!(connection.changes(), 1);
assert_eq!(connection.total_changes(), 1);
ok!(connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL, NULL)"));
assert_eq!(connection.changes(), 1);
assert_eq!(connection.total_changes(), 2);
ok!(connection.execute("UPDATE users SET name = 'Bob' WHERE id = 1"));
assert_eq!(connection.changes(), 1);
assert_eq!(connection.total_changes(), 3);
ok!(connection.execute("DELETE FROM users"));
assert_eq!(connection.changes(), 2);
assert_eq!(connection.total_changes(), 5);
}
#[test]
fn connection_error() {
let connection = setup_users(":memory:");
match connection.execute(":)") {
Err(error) => assert_eq!(
error.message,
Some(String::from(r#"unrecognized token: ":""#))
),
_ => unreachable!(),
}
}
#[test]
fn connection_iterate() {
macro_rules! pair(
($one:expr, $two:expr) => (($one, Some($two)));
);
let connection = setup_users(":memory:");
let mut done = false;
let statement = "SELECT * FROM users";
ok!(connection.iterate(statement, |pairs| {
assert_eq!(pairs.len(), 5);
assert_eq!(pairs[0], pair!("id", "1"));
assert_eq!(pairs[1], pair!("name", "Alice"));
assert_eq!(pairs[2], pair!("age", "42.69"));
assert_eq!(pairs[3], pair!("photo", "\x42\x69"));
assert_eq!(pairs[4], ("email", None));
done = true;
true
}));
assert!(done);
}
#[test]
fn connection_open_with_flags() {
use temporary::Directory;
let directory = ok!(Directory::new("sqlite"));
let path = directory.path().join("database.sqlite3");
setup_users(&path);
let flags = OpenFlags::new().set_read_only();
let connection = ok!(Connection::open_with_flags(path, flags));
match connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL)") {
Err(_) => {}
_ => unreachable!(),
}
}
#[test]
fn connection_set_busy_handler() {
use std::thread;
use temporary::Directory;
let directory = ok!(Directory::new("sqlite"));
let path = directory.path().join("database.sqlite3");
setup_users(&path);
let guards = (0..100)
.map(|_| {
let path = path.to_path_buf();
thread::spawn(move || {
let mut connection = ok!(sqlite::open(&path));
ok!(connection.set_busy_handler(|_| true));
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, 2i64));
ok!(statement.bind(2, "Bob"));
ok!(statement.bind(3, 69.42));
ok!(statement.bind(4, &[0x69u8, 0x42u8][..]));
ok!(statement.bind(5, ()));
assert_eq!(ok!(statement.next()), State::Done);
true
})
})
.collect::<Vec<_>>();
for guard in guards {
assert!(ok!(guard.join()));
}
}
#[test]
fn cursor_read() {
let connection = setup_users(":memory:");
ok!(connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL, NULL)"));
let statement = "SELECT id, age FROM users ORDER BY 1 DESC";
let statement = ok!(connection.prepare(statement));
let mut count = 0;
let mut cursor = statement.cursor();
while let Some(row) = ok!(cursor.next()) {
let id = row[0].as_integer().unwrap();
if id == 1 {
assert_eq!(row[1].as_float().unwrap(), 42.69);
} else if id == 2 {
assert_eq!(row[1].as_float().unwrap_or(69.42), 69.42);
} else {
assert!(false);
}
count += 1;
}
assert_eq!(count, 2);
}
#[test]
fn cursor_wildcard() {
let connection = setup_english(":memory:");
let statement = "SELECT value FROM english WHERE value LIKE '%type'";
let statement = ok!(connection.prepare(statement));
let mut count = 0;
let mut cursor = statement.cursor();
while let Some(_) = ok!(cursor.next()) {
count += 1;
}
assert_eq!(count, 6);
}
#[test]
fn cursor_wildcard_with_binding() {
let connection = setup_english(":memory:");
let statement = "SELECT value FROM english WHERE value LIKE ?";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, "%type"));
let mut count = 0;
let mut cursor = statement.cursor();
while let Some(_) = ok!(cursor.next()) {
count += 1;
}
assert_eq!(count, 6);
}
#[test]
fn cursor_workflow() {
let connection = setup_users(":memory:");
let select = "SELECT id, name FROM users WHERE id = ?";
let mut select = ok!(connection.prepare(select)).cursor();
let insert = "INSERT INTO users (id, name) VALUES (?, ?)";
let mut insert = ok!(connection.prepare(insert)).cursor();
for _ in 0..10 {
ok!(select.bind(&[Value::Integer(1)]));
assert_eq!(
ok!(ok!(select.next())),
&[Value::Integer(1), Value::String("Alice".to_string())]
);
assert_eq!(ok!(select.next()), None);
}
ok!(select.bind(&[Value::Integer(42)]));
assert_eq!(ok!(select.next()), None);
ok!(insert.bind(&[Value::Integer(42), Value::String("Bob".to_string())]));
assert_eq!(ok!(insert.next()), None);
ok!(select.bind(&[Value::Integer(42)]));
assert_eq!(
ok!(ok!(select.next())),
&[Value::Integer(42), Value::String("Bob".to_string())]
);
assert_eq!(ok!(select.next()), None);
}
#[test]
fn statement_bind() {
let connection = setup_users(":memory:");
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, 2i64));
ok!(statement.bind(2, "Bob"));
ok!(statement.bind(3, 69.42));
ok!(statement.bind(4, &[0x69u8, 0x42u8][..]));
ok!(statement.bind(5, ()));
assert_eq!(ok!(statement.next()), State::Done);
}
#[test]
fn statement_bind_with_optional() {
let connection = setup_users(":memory:");
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, None::<i64>));
ok!(statement.bind(2, None::<&str>));
ok!(statement.bind(3, None::<f64>));
ok!(statement.bind(4, None::<&[u8]>));
ok!(statement.bind(5, None::<&str>));
assert_eq!(ok!(statement.next()), State::Done);
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, Some(2i64)));
ok!(statement.bind(2, Some("Bob")));
ok!(statement.bind(3, Some(69.42)));
ok!(statement.bind(4, Some(&[0x69u8, 0x42u8][..])));
ok!(statement.bind(5, None::<&str>));
assert_eq!(ok!(statement.next()), State::Done);
}
#[test]
fn statement_count() {
let connection = setup_users(":memory:");
let statement = "SELECT * FROM users";
let mut statement = ok!(connection.prepare(statement));
assert_eq!(ok!(statement.next()), State::Row);
assert_eq!(statement.count(), 5);
}
#[test]
fn statement_name() {
let connection = setup_users(":memory:");
let statement = "SELECT id, name, age, photo AS user_photo FROM users";
let statement = ok!(connection.prepare(statement));
let names = statement.names();
assert_eq!(names, vec!["id", "name", "age", "user_photo"]);
assert_eq!("user_photo", statement.name(3));
}
#[test]
fn statement_kind() {
let connection = setup_users(":memory:");
let statement = "SELECT * FROM users";
let mut statement = ok!(connection.prepare(statement));
assert_eq!(statement.kind(0), Type::Null);
assert_eq!(statement.kind(1), Type::Null);
assert_eq!(statement.kind(2), Type::Null);
assert_eq!(statement.kind(3), Type::Null);
assert_eq!(ok!(statement.next()), State::Row);
assert_eq!(statement.kind(0), Type::Integer);
assert_eq!(statement.kind(1), Type::String);
assert_eq!(statement.kind(2), Type::Float);
assert_eq!(statement.kind(3), Type::Binary);
}
#[test]
fn statement_read() {
let connection = setup_users(":memory:");
let statement = "SELECT * FROM users";
let mut statement = ok!(connection.prepare(statement));
assert_eq!(ok!(statement.next()), State::Row);
assert_eq!(ok!(statement.read::<i64>(0)), 1);
assert_eq!(ok!(statement.read::<String>(1)), String::from("Alice"));
assert_eq!(ok!(statement.read::<f64>(2)), 42.69);
assert_eq!(ok!(statement.read::<Vec<u8>>(3)), vec![0x42, 0x69]);
assert_eq!(ok!(statement.read::<Value>(4)), Value::Null);
assert_eq!(ok!(statement.next()), State::Done);
}
#[test]
fn statement_read_with_optional() {
let connection = setup_users(":memory:");
let statement = "SELECT * FROM users";
let mut statement = ok!(connection.prepare(statement));
assert_eq!(ok!(statement.next()), State::Row);
assert_eq!(ok!(statement.read::<Option<i64>>(0)), Some(1));
assert_eq!(
ok!(statement.read::<Option<String>>(1)),
Some(String::from("Alice"))
);
assert_eq!(ok!(statement.read::<Option<f64>>(2)), Some(42.69));
assert_eq!(
ok!(statement.read::<Option<Vec<u8>>>(3)),
Some(vec![0x42, 0x69])
);
assert_eq!(ok!(statement.read::<Option<String>>(4)), None);
assert_eq!(ok!(statement.next()), State::Done);
}
#[test]
fn statement_wildcard() {
let connection = setup_english(":memory:");
let statement = "SELECT value FROM english WHERE value LIKE '%type'";
let mut statement = ok!(connection.prepare(statement));
let mut count = 0;
while let State::Row = ok!(statement.next()) {
count += 1;
}
assert_eq!(count, 6);
}
#[test]
fn statement_wildcard_with_binding() {
let connection = setup_english(":memory:");
let statement = "SELECT value FROM english WHERE value LIKE ?";
let mut statement = ok!(connection.prepare(statement));
ok!(statement.bind(1, "%type"));
let mut count = 0;
while let State::Row = ok!(statement.next()) {
count += 1;
}
assert_eq!(count, 6);
}
fn setup_english<T: AsRef<Path>>(path: T) -> Connection {
let connection = ok!(sqlite::open(path));
ok!(connection.execute(
"
CREATE TABLE english (value TEXT);
INSERT INTO english VALUES ('cerotype');
INSERT INTO english VALUES ('metatype');
INSERT INTO english VALUES ('ozotype');
INSERT INTO english VALUES ('phenotype');
INSERT INTO english VALUES ('plastotype');
INSERT INTO english VALUES ('undertype');
INSERT INTO english VALUES ('nonsence');
",
));
connection
}
fn setup_users<T: AsRef<Path>>(path: T) -> Connection {
let connection = ok!(sqlite::open(path));
ok!(connection.execute(
"
CREATE TABLE users (id INTEGER, name TEXT, age REAL, photo BLOB, email TEXT);
INSERT INTO users VALUES (1, 'Alice', 42.69, X'4269', NULL);
",
));
connection
}

48
tests/tests.rs Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern crate marine_rs_sdk_test;
mod tests {
use marine_rs_sdk_test::marine_test;
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test1(test: marine_test_env::test::ModuleInterface) {
test.test1()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test2(test: marine_test_env::test::ModuleInterface) {
test.test2()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test3(test: marine_test_env::test::ModuleInterface) {
test.test3()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test4(test: marine_test_env::test::ModuleInterface) {
test.test4()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test5(test: marine_test_env::test::ModuleInterface) {
test.test5()
}
}