mailpot/core/tests/settings_json.rs

224 lines
7.7 KiB
Rust

/*
* This file is part of mailpot
*
* Copyright 2023 - Manos Pitsidianakis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use jsonschema::JSONSchema;
use mailpot::{Configuration, Connection, SendMail};
use mailpot_tests::init_stderr_logging;
use serde_json::{json, Value};
use tempfile::TempDir;
#[test]
fn test_settings_json() {
init_stderr_logging();
let tmp_dir = TempDir::new().unwrap();
let db_path = tmp_dir.path().join("mpot.db");
std::fs::copy("../mailpot-tests/for_testing.db", &db_path).unwrap();
let mut perms = std::fs::metadata(&db_path).unwrap().permissions();
#[allow(clippy::permissions_set_readonly_false)]
perms.set_readonly(false);
std::fs::set_permissions(&db_path, perms).unwrap();
let config = Configuration {
send_mail: SendMail::ShellCommand("/usr/bin/false".to_string()),
db_path,
data_path: tmp_dir.path().to_path_buf(),
administrators: vec![],
};
let db = Connection::open_or_create_db(config).unwrap().trusted();
let list = db.lists().unwrap().remove(0);
let archived_at_link_settings_schema =
std::fs::read_to_string("./settings_json_schemas/archivedatlink.json").unwrap();
println!("Testing that inserting settings works…");
let (settings_pk, settings_val, last_modified): (i64, Value, i64) = {
let mut stmt = db
.connection
.prepare(
"INSERT INTO list_settings_json(name, list, value) \
VALUES('ArchivedAtLinkSettings', ?, ?) RETURNING pk, value, last_modified;",
)
.unwrap();
stmt.query_row(
rusqlite::params![
&list.pk(),
&json!({
"template": "https://www.example.com/{{msg_id}}.html",
"preserve_carets": false
}),
],
|row| {
let pk: i64 = row.get("pk")?;
let value: Value = row.get("value")?;
let last_modified: i64 = row.get("last_modified")?;
Ok((pk, value, last_modified))
},
)
.unwrap()
};
db.connection
.execute_batch("UPDATE list_settings_json SET is_valid = 1;")
.unwrap();
println!("Testing that schema is actually valid…");
let schema: Value = serde_json::from_str(&archived_at_link_settings_schema).unwrap();
let compiled = JSONSchema::compile(&schema).expect("A valid schema");
if let Err(errors) = compiled.validate(&settings_val) {
for err in errors {
eprintln!("Error: {err}");
}
panic!("Could not validate settings.");
};
println!("Testing that inserting invalid settings aborts…");
{
let mut stmt = db
.connection
.prepare(
"INSERT OR REPLACE INTO list_settings_json(name, list, value) \
VALUES('ArchivedAtLinkSettings', ?, ?) RETURNING pk, value;",
)
.unwrap();
assert_eq!(
"new settings value is not valid according to the json schema. Rolling back \
transaction.",
&stmt
.query_row(
rusqlite::params![
&list.pk(),
&json!({
"template": "https://www.example.com/msg-id}.html" // should be msg_id
}),
],
|row| {
let pk: i64 = row.get("pk")?;
let value: Value = row.get("value")?;
Ok((pk, value))
},
)
.unwrap_err()
.to_string()
);
};
println!("Testing that updating settings with invalid value aborts…");
{
let mut stmt = db
.connection
.prepare(
"UPDATE list_settings_json SET value = ? WHERE name = 'ArchivedAtLinkSettings' \
RETURNING pk, value;",
)
.unwrap();
assert_eq!(
"new settings value is not valid according to the json schema. Rolling back \
transaction.",
&stmt
.query_row(
rusqlite::params![&json!({
"template": "https://www.example.com/msg-id}.html" // should be msg_id
}),],
|row| {
let pk: i64 = row.get("pk")?;
let value: Value = row.get("value")?;
Ok((pk, value))
},
)
.unwrap_err()
.to_string()
);
};
std::thread::sleep(std::time::Duration::from_millis(1000));
println!("Finally, testing that updating schema reverifies settings…");
{
let mut stmt = db
.connection
.prepare(
"UPDATE settings_json_schema SET id = ? WHERE id = 'ArchivedAtLinkSettings' \
RETURNING pk;",
)
.unwrap();
stmt.query_row([&"ArchivedAtLinkSettingsv2"], |_| Ok(()))
.unwrap();
};
let (new_name, is_valid, new_last_modified): (String, bool, i64) = {
let mut stmt = db
.connection
.prepare("SELECT name, is_valid, last_modified from list_settings_json WHERE pk = ?;")
.unwrap();
stmt.query_row([&settings_pk], |row| {
Ok((
row.get("name")?,
row.get("is_valid")?,
row.get("last_modified")?,
))
})
.unwrap()
};
assert_eq!(&new_name, "ArchivedAtLinkSettingsv2");
assert!(is_valid);
assert!(new_last_modified != last_modified);
}
#[test]
fn test_settings_json_schemas() {
init_stderr_logging();
let tmp_dir = TempDir::new().unwrap();
let db_path = tmp_dir.path().join("mpot.db");
std::fs::copy("../mailpot-tests/for_testing.db", &db_path).unwrap();
let mut perms = std::fs::metadata(&db_path).unwrap().permissions();
#[allow(clippy::permissions_set_readonly_false)]
perms.set_readonly(false);
std::fs::set_permissions(&db_path, perms).unwrap();
let config = Configuration {
send_mail: SendMail::ShellCommand("/usr/bin/false".to_string()),
db_path,
data_path: tmp_dir.path().to_path_buf(),
administrators: vec![],
};
let db = Connection::open_or_create_db(config).unwrap().trusted();
let schemas: Vec<String> = {
let mut stmt = db
.connection
.prepare("SELECT value FROM list_settings_json;")
.unwrap();
let iter = stmt
.query_map([], |row| {
let value: String = row.get("value")?;
Ok(value)
})
.unwrap();
let mut ret = vec![];
for item in iter {
ret.push(item.unwrap());
}
ret
};
println!("Testing that schemas are valid…");
for schema in schemas {
let schema: Value = serde_json::from_str(&schema).unwrap();
let _compiled = JSONSchema::compile(&schema).expect("A valid schema");
}
}