fix: extra tests and sqlite module bump to 0.17.1 [fixes VM-226] (#7)

This commit is contained in:
raftedproc 2023-02-17 20:38:01 +03:00 committed by GitHub
parent 6f91fcc2df
commit 5060bb6e8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 585 additions and 8 deletions

View File

@ -13,4 +13,4 @@ mkdir -p artifacts
cp target/wasm32-wasi/release/test.wasm artifacts/
# download SQLite 3 to use in tests
curl -L https://github.com/fluencelabs/sqlite/releases/download/v0.15.0_w/sqlite3.wasm -o artifacts/sqlite3.wasm
curl -L https://github.com/fluencelabs/sqlite/releases/download/v0.17.1_w/sqlite3.wasm -o artifacts/sqlite3.wasm

View File

@ -1,9 +1,9 @@
use marine_rs_sdk::marine;
use marine_sqlite_connector::State;
use marine_sqlite_connector::Value;
use marine_sqlite_connector::{version, State, Value};
pub fn main() {}
// Projection with binding in a filter
#[marine]
pub fn test1() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
@ -11,9 +11,9 @@ pub fn test1() {
connection
.execute(
"
CREATE TABLE users (name TEXT, age INTEGER);
INSERT INTO users VALUES ('Alice', 42);
INSERT INTO users VALUES ('Bob', 69);
CREATE TABLE users (name TEXT, age INTEGER, weight DOUBLE);
INSERT INTO users VALUES ('Alice', 42, 100.15);
INSERT INTO users VALUES ('Bob', 69, 200.11);
",
)
.unwrap();
@ -27,8 +27,39 @@ pub fn test1() {
assert_eq!(statement.next().unwrap(), State::Row);
assert_eq!(statement.read::<String>(0).unwrap(), "Bob");
assert_eq!(statement.read::<i64>(1).unwrap(), 69);
assert_eq!(statement.read::<f64>(2).unwrap(), 200.11);
assert_eq!(connection.total_changes(), 2);
let mut statement = connection
.prepare("SELECT * FROM users WHERE weight > ?")
.unwrap();
statement.bind(1, 150.1).unwrap();
assert_eq!(statement.next().unwrap(), State::Row);
assert_eq!(statement.read::<String>(0).unwrap(), "Bob");
assert_eq!(statement.read::<i64>(1).unwrap(), 69);
assert_eq!(statement.read::<f64>(2).unwrap(), 200.11);
assert_eq!(connection.total_changes(), 2);
connection
.execute("UPDATE users SET age = 20 WHERE age = 69;")
.unwrap();
let mut cursor = connection
.prepare("SELECT * FROM users WHERE age < ?")
.unwrap()
.cursor();
cursor.bind(&[Value::Integer(30)]).unwrap();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_string().unwrap(), "Bob");
assert_eq!(row[1].as_integer().unwrap(), 20);
assert_eq!(row[2].as_float().unwrap(), 200.11);
}
assert_eq!(connection.total_changes(), 3);
}
// Another projection with binding in a filter
#[marine]
pub fn test2() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
@ -54,8 +85,10 @@ pub fn test2() {
assert_eq!(row[0].as_string().unwrap(), "Bob");
assert_eq!(row[1].as_integer().unwrap(), 69);
}
assert_eq!(connection.total_changes(), 2);
}
// BLOB binding
#[marine]
pub fn test3() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
@ -63,13 +96,13 @@ pub fn test3() {
connection
.execute(
"
CREATE TABLE test (number INTEGER, blob BLOB NOT NULL);
CREATE TABLE test (number INTEGER, blob BLOB NOT NULL, blob_nullable BLOB);
",
)
.unwrap();
let mut cursor = connection
.prepare("INSERT OR REPLACE INTO test VALUES (?, ?)")
.prepare("INSERT OR REPLACE INTO test (number, blob) VALUES (?, ?);")
.unwrap();
cursor.bind(1, &Value::Integer(50)).unwrap();
@ -77,8 +110,10 @@ pub fn test3() {
// check that blob is not null
assert!(cursor.next().is_ok());
assert_eq!(connection.total_changes(), 1);
}
// BLOB
#[marine]
pub fn test4() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
@ -110,4 +145,506 @@ pub fn test4() {
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_binary().unwrap().to_vec(), vec![1, 2, 3]);
}
assert_eq!(connection.total_changes(), 1);
}
//GROUP BY + ORDER BY
#[marine]
pub fn test5() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"
CREATE TABLE users (name TEXT, age INTEGER);
INSERT INTO users VALUES ('Alice', 42);
INSERT INTO users VALUES ('2ndAlice', 42);
",
)
.unwrap();
connection
.execute(
"
INSERT INTO users VALUES ('PreAlice', 41);
INSERT INTO users VALUES ('AliceInAthens', 43);
INSERT INTO users VALUES ('Bob', 69);
",
)
.unwrap();
let mut cursor = connection
.prepare("SELECT age, count(*) FROM users GROUP BY age ORDER BY 1")
.unwrap()
.cursor();
let mut res: Vec<i64> = vec![];
while let Some(row) = cursor.next().unwrap() {
res.push(row[0].as_integer().unwrap());
}
assert_eq!(res, vec![41, 42, 43, 69]);
// Check the second column
assert_eq!(connection.total_changes(), 5);
connection.execute("DROP TABLE users;").unwrap();
assert_eq!(connection.execute("DROP TABLE users;").is_err(), true);
}
// ORDER BY
#[marine]
pub fn test6() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"
CREATE TABLE users (name TEXT, age INTEGER);
INSERT INTO users VALUES ('Alice', 42);
INSERT INTO users VALUES ('2ndAlice', 42);
INSERT INTO users VALUES ('PreAlice', 41);
INSERT INTO users VALUES ('AliceInAthens', 43);
INSERT INTO users VALUES ('Bob', 69);
",
)
.unwrap();
let mut statement = connection
.prepare("SELECT * FROM users WHERE age >= ? ORDER BY age ASC")
.unwrap();
statement.bind(1, 43).unwrap();
assert_eq!(statement.next().unwrap(), State::Row);
assert_eq!(statement.read::<String>(0).unwrap(), "AliceInAthens");
assert_eq!(statement.read::<i64>(1).unwrap(), 43);
assert_eq!(statement.next().unwrap(), State::Row);
assert_eq!(statement.read::<String>(0).unwrap(), "Bob");
assert_eq!(statement.read::<i64>(1).unwrap(), 69);
assert_eq!(connection.total_changes(), 5);
}
// view
#[marine]
pub fn test7() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"
CREATE TABLE users (name TEXT, age INTEGER);
INSERT INTO users VALUES ('Alice', 42);
INSERT INTO users VALUES ('2ndAlice', 42);
INSERT INTO users VALUES ('PreAlice', 41);
INSERT INTO users VALUES ('AliceInAthens', 43);
INSERT INTO users VALUES ('Bob', 69);
CREATE VIEW view1 as SELECT * FROM users WHERE age >= 43;
",
)
.unwrap();
let mut cursor = connection
.prepare("SELECT name, count(*) FROM view1 GROUP BY name ORDER BY name")
.unwrap()
.cursor();
let golden = vec!["AliceInAthens", "Bob"];
let mut golden_it = golden.iter();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_string().unwrap(), *golden_it.next().unwrap());
}
assert_eq!(connection.total_changes(), 5);
}
#[marine]
pub fn test8() {
assert!(version() >= 3040001 as usize);
}
// json
#[marine]
pub fn test9() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"CREATE TABLE j2(id INTEGER PRIMARY KEY, json, src);
INSERT INTO j2(id,json,src)
VALUES(1,'{
\"firstName\": \"John\",
\"lastName\": \"Smith\",
\"isAlive\": true,
\"age\": 25,
\"address\": {
\"streetAddress\": \"21 2nd Street\",
\"city\": \"New York\",
\"state\": \"NY\",
\"postalCode\": \"10021-3100\"
},
\"phoneNumbers\": [
{
\"type\": \"home\",
\"number\": \"212 555-1234\"
},
{
\"type\": \"office\",
\"number\": \"646 555-4567\"
}
],
\"children\": [],
\"spouse\": null
}','https://en.wikipedia.org/wiki/JSON');
INSERT INTO j2(id,json,src)
VALUES(2, '{
\"id\": \"0001\",
\"type\": \"donut\",
\"name\": \"Cake\",
\"ppu\": 0.55,
\"batters\":
{
\"batter\":
[
{ \"id\": \"1001\", \"type\": \"Regular\" },
{ \"id\": \"1002\", \"type\": \"Chocolate\" },
{ \"id\": \"1003\", \"type\": \"Blueberry\" },
{ \"id\": \"1004\", \"type\": \"Devil''s Food\" }
]
},
\"topping\":
[
{ \"id\": \"5001\", \"type\": \"None\" },
{ \"id\": \"5002\", \"type\": \"Glazed\" },
{ \"id\": \"5005\", \"type\": \"Sugar\" },
{ \"id\": \"5007\", \"type\": \"Powdered Sugar\" },
{ \"id\": \"5006\", \"type\": \"Chocolate with Sprinkles\" },
{ \"id\": \"5003\", \"type\": \"Chocolate\" },
{ \"id\": \"5004\", \"type\": \"Maple\" }
]
}','https://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html');
INSERT INTO j2(id,json,src)
VALUES(3,'[
{
\"id\": \"0001\",
\"type\": \"donut\",
\"name\": \"Cake\",
\"ppu\": 0.55,
\"batters\":
{
\"batter\":
[
{ \"id\": \"1001\", \"type\": \"Regular\" },
{ \"id\": \"1002\", \"type\": \"Chocolate\" },
{ \"id\": \"1003\", \"type\": \"Blueberry\" },
{ \"id\": \"1004\", \"type\": \"Devil''s Food\" }
]
},
\"topping\":
[
{ \"id\": \"5001\", \"type\": \"None\" },
{ \"id\": \"5002\", \"type\": \"Glazed\" },
{ \"id\": \"5005\", \"type\": \"Sugar\" },
{ \"id\": \"5007\", \"type\": \"Powdered Sugar\" },
{ \"id\": \"5006\", \"type\": \"Chocolate with Sprinkles\" },
{ \"id\": \"5003\", \"type\": \"Chocolate\" },
{ \"id\": \"5004\", \"type\": \"Maple\" }
]
},
{
\"id\": \"0002\",
\"type\": \"donut\",
\"name\": \"Raised\",
\"ppu\": 0.55,
\"batters\":
{
\"batter\":
[
{ \"id\": \"1001\", \"type\": \"Regular\" }
]
},
\"topping\":
[
{ \"id\": \"5001\", \"type\": \"None\" },
{ \"id\": \"5002\", \"type\": \"Glazed\" },
{ \"id\": \"5005\", \"type\": \"Sugar\" },
{ \"id\": \"5003\", \"type\": \"Chocolate\" },
{ \"id\": \"5004\", \"type\": \"Maple\" }
]
},
{
\"id\": \"0003\",
\"type\": \"donut\",
\"name\": \"Old Fashioned\",
\"ppu\": 0.55,
\"batters\":
{
\"batter\":
[
{ \"id\": \"1001\", \"type\": \"Regular\" },
{ \"id\": \"1002\", \"type\": \"Chocolate\" }
]
},
\"topping\":
[
{ \"id\": \"5001\", \"type\": \"None\" },
{ \"id\": \"5002\", \"type\": \"Glazed\" },
{ \"id\": \"5003\", \"type\": \"Chocolate\" },
{ \"id\": \"5004\", \"type\": \"Maple\" }
]
}
]','https://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html');",
)
.unwrap();
let mut cursor = connection
.prepare("SELECT id, json_valid(json), json_type(json), '|' FROM j2 ORDER BY id;")
.unwrap()
.cursor();
let golden = vec!["object", "object", "array"];
let mut golden_it = golden.iter();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[2].as_string().unwrap(), *golden_it.next().unwrap());
}
assert_eq!(connection.total_changes(), 3);
}
// fts5
#[marine]
pub fn test10() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"
CREATE VIRTUAL TABLE email USING fts5(sender, subject, body);
INSERT INTO email VALUES ('Alice', 'How deep is the hole', 'Nobody knows');
INSERT INTO email VALUES ('Wonderland', 'Hatter', 'Normality. I know this');
INSERT INTO email VALUES ('Rabbit the optimist', 'He never sleeps', 'Never I said you know');
",
)
.unwrap();
let mut cursor = connection
.prepare("SELECT sender FROM email WHERE body MATCH 'know';")
.unwrap()
.cursor();
let golden = vec!["Wonderland", "Rabbit the optimist"];
let mut golden_it = golden.iter();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_string().unwrap(), *golden_it.next().unwrap());
}
}
// rtree
#[marine]
pub fn test11() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"
CREATE VIRTUAL TABLE demo_index USING rtree(
id, -- Integer primary key
minX, maxX, -- Minimum and maximum X coordinate
minY, maxY -- Minimum and maximum Y coordinate
);
INSERT INTO demo_index VALUES
(28215, -80.781227, -80.604706, 35.208813, 35.297367),
(28216, -80.957283, -80.840599, 35.235920, 35.367825),
(28217, -80.960869, -80.869431, 35.133682, 35.208233),
(28226, -80.878983, -80.778275, 35.060287, 35.154446),
(28227, -80.745544, -80.555382, 35.130215, 35.236916),
(28244, -80.844208, -80.841988, 35.223728, 35.225471),
(28262, -80.809074, -80.682938, 35.276207, 35.377747),
(28269, -80.851471, -80.735718, 35.272560, 35.407925),
(28270, -80.794983, -80.728966, 35.059872, 35.161823),
(28273, -80.994766, -80.875259, 35.074734, 35.172836),
(28277, -80.876793, -80.767586, 35.001709, 35.101063),
(28278, -81.058029, -80.956375, 35.044701, 35.223812),
(28280, -80.844208, -80.841972, 35.225468, 35.227203),
(28282, -80.846382, -80.844193, 35.223972, 35.225655);
",
)
.unwrap();
let mut cursor = connection
.prepare(
"SELECT A.id FROM demo_index AS A, demo_index AS B
WHERE A.maxX>=B.minX AND A.minX<=B.maxX
AND A.maxY>=B.minY AND A.minY<=B.maxY
AND B.id=28269 ORDER BY 1;",
)
.unwrap()
.cursor();
let golden = vec![28215, 28216, 28262, 28269];
let mut golden_it = golden.iter();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_integer().unwrap(), *golden_it.next().unwrap());
}
}
// triggers
#[marine]
pub fn test12() {
let connection = marine_sqlite_connector::open(":memory:").unwrap();
connection
.execute(
"
CREATE TABLE leads (
id integer PRIMARY KEY,
first_name text NOT NULL,
last_name text NOT NULL,
phone text NOT NULL,
email text NOT NULL
);
",
)
.unwrap();
connection
.execute(
"
CREATE TRIGGER validate_email_before_insert_leads
BEFORE INSERT ON leads
BEGIN
SELECT
CASE
WHEN NEW.email NOT LIKE '%_@__%.__%' THEN
RAISE (ABORT,'Invalid email address')
END;
END;
",
)
.unwrap();
connection
.execute(
"
INSERT INTO leads (first_name, last_name, email, phone)
VALUES ('John', 'Doe', 'john.doe@sqlitetutorial.net', '4089009334');
",
)
.unwrap();
assert!(connection
.execute(
"
INSERT INTO leads (first_name,last_name,email,phone)
VALUES('John','Doe','jjj','4089009334');
",
)
.is_err());
let mut cursor = connection
.prepare(
"
SELECT first_name, last_name, email FROM leads;
",
)
.unwrap()
.cursor();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_string().unwrap(), "John");
assert_eq!(row[2].as_string().unwrap(), "john.doe@sqlitetutorial.net");
}
// ON UPDATE
connection
.execute(
"
CREATE TABLE lead_logs (
id INTEGER PRIMARY KEY,
old_id int,
new_id int,
old_phone text,
new_phone text,
old_email text,
new_email text,
user_action text,
created_at text
);
",
)
.unwrap();
connection
.execute(
"
CREATE TRIGGER log_contact_after_update
AFTER UPDATE ON leads
WHEN old.phone <> new.phone
OR old.email <> new.email
BEGIN
INSERT INTO lead_logs (
old_id,
new_id,
old_phone,
new_phone,
old_email,
new_email,
user_action,
created_at
)
VALUES
(
old.id,
new.id,
old.phone,
new.phone,
old.email,
new.email,
'UPDATE',
DATETIME('NOW')
) ;
END;
",
)
.unwrap();
connection
.execute(
"
UPDATE leads
SET
last_name = 'Smith'
WHERE
id = 1;
",
)
.unwrap();
let mut statement = connection
.prepare(
"
SELECT count(*) FROM lead_logs;
",
)
.unwrap();
assert_eq!(statement.next().unwrap(), State::Row);
assert_eq!(statement.read::<i64>(0).unwrap(), 0);
connection
.execute(
"
UPDATE leads
SET
phone = '4089998888',
email = 'john.smith@sqlitetutorial.net'
WHERE
id = 1;
",
)
.unwrap();
let mut cursor = connection
.prepare(
"
SELECT old_phone,new_phone,old_email,new_email,user_action
FROM lead_logs;
",
)
.unwrap()
.cursor();
while let Some(row) = cursor.next().unwrap() {
assert_eq!(row[0].as_string().unwrap(), "4089009334");
assert_eq!(row[1].as_string().unwrap(), "4089998888");
assert_eq!(row[2].as_string().unwrap(), "john.doe@sqlitetutorial.net");
assert_eq!(row[3].as_string().unwrap(), "john.smith@sqlitetutorial.net");
assert_eq!(row[4].as_string().unwrap(), "UPDATE");
}
}

View File

@ -36,4 +36,44 @@ mod tests {
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()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test6(test: marine_test_env::test::ModuleInterface) {
test.test6()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test7(test: marine_test_env::test::ModuleInterface) {
test.test7()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test8(test: marine_test_env::test::ModuleInterface) {
test.test8()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test9(test: marine_test_env::test::ModuleInterface) {
test.test9()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test10(test: marine_test_env::test::ModuleInterface) {
test.test10()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test11(test: marine_test_env::test::ModuleInterface) {
test.test11()
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn test12(test: marine_test_env::test::ModuleInterface) {
test.test12()
}
}