Commit 90692a74 authored by MrMan's avatar MrMan

Merge branch '38-preliminary-e2e-testing' into 'master'

Resolve "Preliminary E2E testing"

Closes #38

See merge request !19
parents 90211a3b 2a3455f7
Pipeline #47899110 passed with stage
in 6 minutes and 48 seconds
This diff is collapsed.
......@@ -19,7 +19,17 @@ failure = "0.1.1"
askama = "0.6.4"
chrono = { version = "0.4", features = ["serde"] }
clap = "2.31.2"
actix-web = "0.6"
actix-web = "0.7.2"
uuid = { version = "0.6", features = ["v4"] }
rusqlite = { version = "0.13.0", features = ["bundled"] }
simple-signal = "1.1.1"
\ No newline at end of file
simple-signal = "1.1.1"
futures = "0.1.25"
serde_json = "*"
[dev-dependencies]
tempfile = "3"
mail = { version = "0.6.7", features = ["smtp"] }
rand = "0.5.0"
new-tokio-smtp = "0.8.1"
reqwest = "0.9.9"
base64 = "0.10.1"
......@@ -14,11 +14,13 @@ VERSION=$(shell awk '/version\s+=\s+\"([0-9|\.]+)\"$$/{print $$3}' Cargo.toml)
CARGO := $(shell command -v cargo 2> /dev/null)
CARGO_WATCH := $(shell command -v cargo-watch 2> /dev/null)
ENV=development # | production
# ENV = development | production
ENV=development
IMAGE_NAME:=postmgr
BUILDER_IMAGE_NAME:=postmgr/builder
REGISTRY_PATH=registry.gitlab.com/postmgr
LOCAL_TEST_IMAGE_NAME=postmgr-test
FQ_IMAGE_NAME=$(REGISTRY_PATH)/$(IMAGE_NAME):$(VERSION)
FQ_BUILDER_IMAGE_NAME=$(REGISTRY_PATH)/$(BUILDER_IMAGE_NAME):$(VERSION)
......@@ -58,11 +60,18 @@ run:
test:
cargo test
test-e2e:
cargo test -- --ignored
watch: check-tool-cargo check-tool-cargo-watch
cargo watch -x build
image:
docker build -f infra/docker/Dockerfile -t $(FQ_IMAGE_NAME) .
docker build \
-f infra/docker/Dockerfile \
-t $(FQ_IMAGE_NAME) \
-t $(LOCAL_TEST_IMAGE_NAME) \
.
builder-image:
docker build -f infra/docker/builder.Dockerfile -t $(FQ_BUILDER_IMAGE_NAME) .
......@@ -80,6 +89,7 @@ container:
docker stop $(CONTAINER_NAME) || true
docker rm $(CONTAINER_NAME) || true
docker run \
--detach \
-p 2525:25 \
-p 5875:587 \
-e CONFIG_PATH=/usr/src/postmgr/infra/conf/${ENV}.toml \
......@@ -94,4 +104,4 @@ container-shell:
$(FQ_IMAGE_NAME) \
/bin/bash
test-container: image container
test-container: container
......@@ -2,19 +2,18 @@
`postmgr` is a tool for managing instsances of [Postfix][postfix]. `postmgr` aims to provide:
- Mostly transparent daemonization of Postfix
- Easier management, administration, and configuration for Postfix
- A web interface baked in
- An easy to use web interface for mailbox and other management tasks
# Quick Start #
The quickest way to get started with `postmgr` is to use one of our prebuilt containers. If you want to build your own container or other deployment method with `postmgr`, you can obtain the `postmgr` binary, and as long as you tell `postmgr` where it can find the other binaries it needs, it will manage them.
**`postmgr` is meant to be run in a properly sandboxed/isolated (i.e. containerized) environment** -- it attempts to overwrite files in directories like `/etc/postfix` due to `postfix`'s shoddy support for determining `config_directory` ("-c" and/or `MAIL_CONFIG` do not completely ensure alternate configuration directories) consistently for *all* related processes.
## Containerized ##
The quickest way to get started with `postmgr` is to use one of our prebuilt containers. If you want to build your own container or other deployment method with `postmgr`, you can obtain the `postmgr` binary, and as long as you tell `postmgr` where it can find the other binaries it needs, it will manage them.
[There is one primary container][gitlab-docker-repo] that is maintained by this project.
The [`postmgr` container][gitlab-docker-repo] is the primary container of this project.
You **should** be able to download the single container, connect it to your container orchestration process of choice, and have a fully functional, relatively secure, manageable Postfix installation. If this is ever not-true, [file a bug][gitlab-issues].
You **should** be able to download the single container, connect it to your container orchestration process of choice, and have a fully functional, mostly secure, manageable Postfix installation. If this is ever not-true, [file a bug][gitlab-issues].
## Binary ##
......
......@@ -8,14 +8,14 @@ newaliases_bin_path = "/usr/bin/newaliases"
sendmail_bin_path = "/usr/bin/sendmail"
mailq_bin_path = "/usr/bin/mailq"
# All on-disk data is stored at or below this folder
data_dir = "./infra/runtime/data/postfix"
# All on-disk config is stored at or below this folder
config_dir = "./infra/runtime/config/postfix"
# All generated configuration will be copied here
config_output_dir = "./infra/runtime/config/postfix/generated"
# NOTE: if you change this value, you must change it when launching the container as well
# Postfix (when launched as a subprocess) does *not* keep consistent ENV in subprocesses
# this means that postconf will report /etc/postfix (the default location) despite setting "-c" flag and/or MAIL_CONFIG
config_output_dir = "/etc/postfix"
# The server's internet hostname (in Postfix, `myhostname`)
internet_hostname = "mail.localhost.localdomain"
......@@ -30,7 +30,7 @@ default_domain_name = "$mydomain"
inbound_domain_names = ["$myhostname", "localhost.$mydomain", "localhost", "$mydomain"]
## Which subnets are allowed to relay mail through this server (in Postfix, `mynetworks`)
allowed_relay_cidrs = ["127.0.0.0/8"]
allowed_relay_cidrs = ["127.0.0.0/8", "172.17.0.0/16"]
## Which destinations to relay mail to (in Postfix, `relay_domains`)
allowed_relay_destinations = ["$mydestination"]
......@@ -67,14 +67,14 @@ submission_qmgr_group_name = "submission"
postmaster_user = "root"
[postfix.auth]
backend = "Cyrus" # only "Cyrus" allowed
backend = "Dovecot" # only "Dovecot" allowed
[postfix.db]
backend = "SQLite" # "SQLite" or "Postgres"
[postfix.db.sqlite]
in_memory = false
path = "./infra/runtime/data/db.sqlite"
path = "/var/mail/db.sqlite"
#[postfix.db.postgres]
#host = ""
......
......@@ -8,9 +8,6 @@ newaliases_bin_path = "/usr/bin/newaliases"
sendmail_bin_path = "/usr/sbin/sendmail" # Default for debian stretch installation
mailq_bin_path = "/usr/bin/mailq"
# All on-disk data is stored at or below this folder
data_dir = "./infra/runtime/data/postfix"
# All on-disk config is stored at or below this folder
config_dir = "./infra/runtime/config/postfix"
......@@ -30,7 +27,7 @@ default_domain_name = "$mydomain"
inbound_domain_names = ["$myhostname", "localhost.$mydomain", "localhost", "$mydomain"]
## Which subnets are allowed to relay mail through this server (in Postfix, `mynetworks`)
allowed_relay_cidrs = ["127.0.0.0/8"]
allowed_relay_cidrs = ["127.0.0.0/8", "172.17.0.0/16"]
## Which destinations to relay mail to (in Postfix, `relay_domains`)
allowed_relay_destinations = ["$mydestination"]
......@@ -67,14 +64,14 @@ submission_qmgr_group_name = "submission"
postmaster_user = "root"
[postfix.auth]
backend = "Cyrus" # only "Cyrus" allowed
backend = "Dovecot" # only "Dovecot" allowed
[postfix.db]
backend = "SQLite" # "SQLite" or "Postgres"
[postfix.db.sqlite]
in_memory = false
path = "./infra/runtime/data/db.sqlite"
path = "/var/mail/db.sqlite"
#[postfix.db.postgres]
#host = ""
......
FROM rust:1.27.1
FROM rust:1.32-slim
WORKDIR /usr/src/postmgr
COPY . .
# Install postfix
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install postfix rsyslog telnet ca-certificates libsasl2-modules
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install ca-certificates make postfix \
rsyslog telnet dovecot-imapd dovecot-pop3d dovecot-sqlite dovecot-pgsql
RUN ln -s /usr/sbin/postfix /usr/bin/postfix
# Add submission group for postfix to use
......
......@@ -77,7 +77,7 @@ pub fn make_admin_db(db_cfg: DBCfg) -> Result<Box<AdminDB>, Error> {
pub trait MailboxDB
where
Self: Connectable + SupportsVAliasLookup + SupportsVMailboxLookup + SupportsCyrusAuth
Self: Connectable + SupportsVAliasLookup + SupportsVMailboxLookup + SupportsDovecotAuth
{
// Initialize the database connection (if necessary), idempotently performing
// all early/pre-work data changes and migrations necessary for a Postfix data holding db
......@@ -90,7 +90,7 @@ where
fn get_mailbox_users_by_uuids(&self, uuids: &[String]) -> Result<Vec<ModelWithUUID<MailboxUser>>, Error>;
fn remove_mailbox_user_by_email(&self, emails: String) -> Result<(), Error>;
fn remove_mailbox_user_by_username(&self, username: String) -> Result<(), Error>;
}
impl MailboxDB for DB {
......@@ -122,9 +122,9 @@ impl MailboxDB for DB {
}
}
fn remove_mailbox_user_by_email(&self, emails: String) -> Result<(), Error> {
fn remove_mailbox_user_by_username(&self, username: String) -> Result<(), Error> {
match self {
DB::SQLite(db) => db.remove_mailbox_user_by_email(emails),
DB::SQLite(db) => db.remove_mailbox_user_by_username(username),
_ => Err(Error::NotSupported)
}
}
......@@ -191,11 +191,11 @@ impl SupportsVAliasLookup for DB {
pub trait SupportsVMailboxLookup {
// Write out the file that postfix will use as configuration for performing virtual mailbox lookups
fn write_vmailbox_lookup_config_file(&self, output_path: &Path, mailbox_base_dir: String) -> Result<(), Error>;
fn write_vmailbox_lookup_config_file(&self, output_path: &Path, mailbox_base_dir: &str) -> Result<(), Error>;
}
impl SupportsVMailboxLookup for DB {
fn write_vmailbox_lookup_config_file(&self, output_path: &Path, mailbox_base_dir: String) -> Result<(), Error> {
fn write_vmailbox_lookup_config_file(&self, output_path: &Path, mailbox_base_dir: &str) -> Result<(), Error> {
match self {
DB::SQLite(db) => db.write_vmailbox_lookup_config_file(output_path, mailbox_base_dir),
_ => Err(Error::NotSupported)
......@@ -204,38 +204,55 @@ impl SupportsVMailboxLookup for DB {
}
// TODO: this can probably be generalized in the future to SupportsAuth<T> when Dovecot auth is added
pub trait SupportsCyrusAuth {
type Template;
pub trait SupportsDovecotAuth {
type ConfigTemplate;
type SQLConfigTemplate;
fn cyrus_config_file_name(&self) -> Result<&'static str, Error>;
fn dovecot_sasl_path(&self) -> Result<&'static str, Error>;
fn cyrus_config_file_path(&self, config_dir: &Path) -> Result<String, Error>;
fn dovecot_config_dir(&self) -> Result<&'static str, Error>;
// Write out the config file that cyrus can use
fn write_cyrus_smtpd_config_file(&self, config_dir: &Path) -> Result<(), Error>;
fn dovecot_config_filename(&self) -> Result<&'static str, Error>;
fn dovecot_sql_config_filename(&self) -> Result<&'static str, Error>;
fn write_dovecot_config_files(&self) -> Result<(), Error>;
}
impl SupportsCyrusAuth for DB {
type Template = Box<Any>;
impl SupportsDovecotAuth for DB {
type ConfigTemplate = Box<Any>;
type SQLConfigTemplate = Box<Any>;
fn dovecot_sasl_path(&self) -> Result<&'static str, Error> {
match self {
DB::SQLite(db) => db.dovecot_sasl_path(),
_ => Err(Error::NotSupported)
}
}
fn dovecot_config_dir(&self) -> Result<&'static str, Error> {
match self {
DB::SQLite(db) => db.dovecot_config_dir(),
_ => Err(Error::NotSupported)
}
}
fn cyrus_config_file_name(&self) -> Result<&'static str, Error> {
fn dovecot_config_filename(&self) -> Result<&'static str, Error> {
match self {
DB::SQLite(db) => db.cyrus_config_file_name(),
DB::SQLite(db) => db.dovecot_config_filename(),
_ => Err(Error::NotSupported)
}
}
fn cyrus_config_file_path(&self, config_dir: &Path) -> Result<String, Error> {
fn dovecot_sql_config_filename(&self) -> Result<&'static str, Error> {
match self {
DB::SQLite(db) => db.cyrus_config_file_path(config_dir),
DB::SQLite(db) => db.dovecot_config_filename(),
_ => Err(Error::NotSupported)
}
}
// Write out the config file that cyrus can use
fn write_cyrus_smtpd_config_file(&self, config_dir: &Path) -> Result<(), Error> {
fn write_dovecot_config_files(&self) -> Result<(), Error> {
match self {
DB::SQLite(db) => db.write_cyrus_smtpd_config_file(config_dir),
DB::SQLite(db) => db.write_dovecot_config_files(),
_ => Err(Error::NotSupported)
}
}
......
......@@ -14,7 +14,7 @@ use self::schema::{ADMIN_MIGRATIONS, MAILBOX_MIGRATIONS};
use std::ffi::OsStr;
use std::fs::{create_dir_all, File};
use std::io::Write;
use std::path::Path;
use std::path::{Path, PathBuf};
use make_absolute_path_from_str;
pub struct SQLiteDB {
......@@ -136,10 +136,10 @@ impl MailboxDB for SQLiteDB {
ModelWithUUID::<MailboxUser>::find_by_uuids(self, uuids)
}
fn remove_mailbox_user_by_email(&self, email: String) -> Result<(), Error> {
let users = ModelWithUUID::<MailboxUser>::find_by_text_field(self, "email", email)?;
if users.len() == 0 { return Err(Error::DBError(String::from("failed to find user with given email"))); }
if users.len() > 1 { return Err(Error::DBError(String::from("found multiple users with given email"))); }
fn remove_mailbox_user_by_username(&self, username: String) -> Result<(), Error> {
let users = ModelWithUUID::<MailboxUser>::find_by_text_field(self, "username", username)?;
if users.len() == 0 { return Err(Error::DBError(String::from("failed to find user with given username"))); }
if users.len() > 1 { return Err(Error::DBError(String::from("found multiple users with given username"))); }
users[0].delete(self)
}
}
......@@ -248,7 +248,7 @@ struct SQLiteVirtualMailboxLookupConfigTemplate<'a> {
}
impl SupportsVMailboxLookup for SQLiteDB {
fn write_vmailbox_lookup_config_file(&self, output_path: &Path, mailbox_base_dir: String) -> Result<(), Error> {
fn write_vmailbox_lookup_config_file(&self, output_path: &Path, mailbox_base_dir: &str) -> Result<(), Error> {
let filename = output_path.file_name()
.unwrap_or(OsStr::new("<filename unspecified>"))
.to_str()
......@@ -259,7 +259,7 @@ impl SupportsVMailboxLookup for SQLiteDB {
filename,
generation_time: Local::now().to_string(),
abs_db_path: self.make_absolute_db_path()?,
mailbox_base_dir
mailbox_base_dir: String::from(mailbox_base_dir)
};
// Ensure the output directory we're supposed to be writing to exists
......@@ -279,43 +279,82 @@ impl SupportsVMailboxLookup for SQLiteDB {
}
#[derive(Template)]
#[template(path = "config/cyrus_sasl/sqlite_smtpd.conf.jinja")]
pub struct CyrusSMTPDCfgTemplate {
#[template(path = "config/dovecot/dovecot.conf")]
pub struct DovecotConfTemplate {
filename: String,
generation_time: String,
sql_config_file_abs_path: String,
abs_db_path: String
}
impl SupportsCyrusAuth for SQLiteDB {
type Template = CyrusSMTPDCfgTemplate;
#[derive(Template)]
#[template(path = "config/dovecot/dovecot-sql.conf.ext")]
pub struct DovecotSQLConfTemplate {
filename: String,
generation_time: String,
abs_db_path: String
}
fn cyrus_config_file_name(&self) -> Result<&'static str, Error> { Ok("smtpd.conf") }
impl SupportsDovecotAuth for SQLiteDB {
type ConfigTemplate = DovecotConfTemplate;
type SQLConfigTemplate = DovecotSQLConfTemplate;
fn cyrus_config_file_path(&self, config_dir: &Path) -> Result<String, Error> {
let output_path = config_dir.join(self.cyrus_config_file_name()?);
output_path.to_str().map(String::from).ok_or(Error::InvalidOrMissingConfig("failed to generate path for cyrus config"))
}
fn dovecot_sasl_path(&self) -> Result<&'static str, Error> { Ok("private/auth") }
fn write_cyrus_smtpd_config_file(&self, config_dir: &Path) -> Result<(), Error> {
if config_dir.is_absolute() { warn!("starting path while writing cyrus smtpd_config_file is not absolute"); }
fn dovecot_config_dir(&self) -> Result<&'static str, Error> { Ok("/etc/dovecot") }
let filename = self.cyrus_config_file_name()?;
let template = CyrusSMTPDCfgTemplate {
filename: filename.to_string(),
fn dovecot_config_filename(&self) -> Result<&'static str, Error> { Ok("dovecot.conf") }
fn dovecot_sql_config_filename(&self) -> Result<&'static str, Error> { Ok("dovecot-sql.conf.ext") }
fn write_dovecot_config_files(&self) -> Result<(), Error> {
// Create the dovecot config directory if it doesn't exist
let config_dir = PathBuf::from(self.dovecot_config_dir()?);
if !config_dir.exists() { create_dir_all(&config_dir)?; }
let config_filename = self.dovecot_config_filename()?;
let sql_config_filename = self.dovecot_sql_config_filename()?;
// Build path & string to represent dovecot config file path
let config_file_abs_path = PathBuf::from(&config_dir).join(config_filename);
let config_file_abs_path_str = config_file_abs_path
.to_str()
.map(String::from)
.ok_or(Error::InvalidEnvironment("invalid dovecot config file path"))?;
// Build path & string to represent dovecto SQL config file path
let sql_config_file_abs_path = PathBuf::from(&config_dir).join(sql_config_filename);
let sql_config_file_abs_path_str = sql_config_file_abs_path
.to_str()
.map(String::from)
.ok_or(Error::InvalidEnvironment("invalid dovecot sql config file path"))?;
if !config_file_abs_path.is_absolute() { warn!("dovecot config file path is not absolute"); }
if !sql_config_file_abs_path.is_absolute() { warn!("dovecot sql config file path is not absolute"); }
// Build the template for the main config file
let template = DovecotConfTemplate {
filename: config_filename.to_string(),
generation_time: Local::now().to_string(),
sql_config_file_abs_path: sql_config_file_abs_path_str.clone(),
abs_db_path: self.make_absolute_db_path()?
};
// Ensure the config directory exists
if !config_dir.exists() { create_dir_all(&config_dir)?; }
// Write the main config file to disk
debug!("writing dovecot config file @ [{}]", config_file_abs_path_str);
let mut config_file = File::create(config_file_abs_path)?;
config_file.write_all(template.render()?.as_bytes())?;
// Generate the output path the config will be written to
let output_path_str = self.cyrus_config_file_path(config_dir)?;
// Build the template for the SQLite config file
let template = DovecotSQLConfTemplate {
filename: config_filename.to_string(),
generation_time: Local::now().to_string(),
abs_db_path: self.make_absolute_db_path()?
};
// Render the file contents, write them to disk
debug!("writing cyrus smtpd config file @ [{}]", output_path_str);
let mut query_config_file = File::create(output_path_str)?;
query_config_file.write_all(template.render()?.as_bytes())?;
// Write the main config file to disk
debug!("writing dovecot sql config file @ [{}]", sql_config_file_abs_path_str);
let mut config_file = File::create(sql_config_file_abs_path)?;
config_file.write_all(template.render()?.as_bytes())?;
Ok(())
}
......
......@@ -6,7 +6,7 @@ use rusqlite::Row;
use rusqlite::types::ToSql;
use super::super::*;
const COLUMNS: &'static [&'static str] = &["uuid", "email", "password", "quota"];
const COLUMNS: &'static [&'static str] = &["uuid", "username", "domain", "password", "quota_gb"];
impl HasSQLTable<SQLiteDB> for ModelWithUUID<MailboxUser> {
fn sql_tbl_name() -> &'static str { "mailbox_users" }
......@@ -16,10 +16,11 @@ impl HasSQLTable<SQLiteDB> for ModelWithUUID<MailboxUser> {
impl<'a, 'stmt> DBEntity<SQLiteDB, Row<'a, 'stmt>> for ModelWithUUID<MailboxUser> {
fn from_row(row: &Row) -> Result<Self, Error> {
let uuid = row.get_checked("uuid")?;
let email = row.get_checked("email")?;
let username = row.get_checked("username")?;
let domain = row.get_checked("domain")?;
let password = row.get_checked("password")?;
let quota = row.get_checked("quota")?;
let model = MailboxUser { email, password, quota };
let quota_gb = row.get_checked("quota_gb")?;
let model = MailboxUser { username, domain, password, quota_gb };
Ok(ModelWithUUID { uuid, model })
}
......@@ -27,7 +28,13 @@ impl<'a, 'stmt> DBEntity<SQLiteDB, Row<'a, 'stmt>> for ModelWithUUID<MailboxUser
let c: &SQLiteConnection = get_sqlite_connection(db)?;
let mut stmt = gen_insert_stmt(c, Self::sql_tbl_name(), Self::sql_tbl_columns())?;
let inserted_row_count = stmt.execute(&[&self.uuid as &ToSql , &self.model.email, &self.model.password, &self.model.quota])?;
let inserted_row_count = stmt.execute(&[
&self.uuid as &ToSql,
&self.model.username,
&self.model.domain,
&self.model.password,
&self.model.quota_gb
])?;
if inserted_row_count == 1 { return Ok(self); }
Err(Error::DBError(String::from("Statement executed but unaffected row count returned: insertion (likely) failed")))
......@@ -98,9 +105,11 @@ mod tests {
use models::{DBEntity, ModelWithUUID, PaginationOptions};
const TEST_USER_EMAIL: &'static str = "[email protected]";
const TEST_USER_DOMAIN: &'static str = "localhost";
const TEST_USER_PASSWORD: &'static str = "test";
const ADMIN_USER_EMAIL: &'static str = "[email protected]";
const ADMIN_USER_DOMAIN: &'static str = "localhost";
const ADMIN_USER_PASSWORD: &'static str = "admin";
#[test]
......@@ -108,7 +117,11 @@ mod tests {
let mut db = SQLiteDB::new(SQLiteDBCfg::in_memory());
let _ = db.connect();
let model = MailboxUser::new(String::from(TEST_USER_EMAIL), String::from(TEST_USER_PASSWORD));
let model = MailboxUser::new(
String::from(TEST_USER_EMAIL),
String::from(TEST_USER_DOMAIN),
String::from(TEST_USER_PASSWORD)
);
let entity = ModelWithUUID::from_model(model);
let create_result = entity.insert(&db);
......@@ -120,7 +133,11 @@ mod tests {
let mut db = SQLiteDB::new(SQLiteDBCfg::in_memory());
let _ = db.connect();
let model = MailboxUser::new(String::from(TEST_USER_EMAIL), String::from(TEST_USER_PASSWORD));
let model = MailboxUser::new(
String::from(TEST_USER_EMAIL),
String::from(TEST_USER_DOMAIN),
String::from(TEST_USER_PASSWORD)
);
let entity = ModelWithUUID::from_model(model);
let create_result = entity.insert(&db);
......@@ -139,7 +156,11 @@ mod tests {
let mut db = SQLiteDB::new(SQLiteDBCfg::in_memory());
let _ = db.connect();
let model = MailboxUser::new(String::from(TEST_USER_EMAIL), String::from(TEST_USER_PASSWORD));
let model = MailboxUser::new(
String::from(TEST_USER_EMAIL),
String::from(TEST_USER_DOMAIN),
String::from(TEST_USER_PASSWORD)
);
let entity = ModelWithUUID::from_model(model);
// create the user
......@@ -161,7 +182,11 @@ mod tests {
let mut db = SQLiteDB::new(SQLiteDBCfg::in_memory());
let _ = db.connect();
let model = MailboxUser::new(String::from(TEST_USER_EMAIL), String::from(TEST_USER_PASSWORD));
let model = MailboxUser::new(
String::from(TEST_USER_EMAIL),
String::from(TEST_USER_DOMAIN),
String::from(TEST_USER_PASSWORD)
);
let entity = ModelWithUUID::from_model(model);
// create the user
......@@ -184,10 +209,19 @@ mod tests {
let mut db = SQLiteDB::new(SQLiteDBCfg::in_memory());
let _ = db.connect();
let test_model = MailboxUser::new(String::from(TEST_USER_EMAIL), String::from(TEST_USER_PASSWORD));
let test_model = MailboxUser::new(
String::from(TEST_USER_EMAIL),
String::from(TEST_USER_DOMAIN),
String::from(TEST_USER_PASSWORD)
);
let test_entity = ModelWithUUID::from_model(test_model);
let admin_model = MailboxUser::new(String::from(ADMIN_USER_EMAIL), String::from(ADMIN_USER_PASSWORD));
let admin_model = MailboxUser::new(
String::from(ADMIN_USER_EMAIL),
String::from(ADMIN_USER_DOMAIN),
String::from(ADMIN_USER_PASSWORD),
);
let admin_entity = ModelWithUUID::from_model(admin_model);
// create the user
......@@ -212,12 +246,20 @@ mod tests {
let _ = db.connect();
// create the user
let model = MailboxUser::new(String::from(TEST_USER_EMAIL), String::from(TEST_USER_PASSWORD));
let model = MailboxUser::new(
String::from(TEST_USER_EMAIL),
String::from(TEST_USER_DOMAIN),
String::from(TEST_USER_PASSWORD)
);
let entity = ModelWithUUID::from_model(model);
let _ = entity.insert(&db).expect("test entity create failed");
// find the user by email field
let find_result = ModelWithUUID::<MailboxUser>::find_by_text_field(&db, "email", String::from(TEST_USER_EMAIL)).expect("listing failed");