Make Vandelay into inbuxa-migrate #1
Generated
+32
-32
@@ -1323,6 +1323,38 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inbuxa-migrate"
|
||||||
|
version = "2026.9.30"
|
||||||
|
dependencies = [
|
||||||
|
"blake3",
|
||||||
|
"calcard",
|
||||||
|
"chrono",
|
||||||
|
"chrono-tz",
|
||||||
|
"clap",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"encodify",
|
||||||
|
"flate2",
|
||||||
|
"indexmap 2.14.2",
|
||||||
|
"mail-parser",
|
||||||
|
"mockito",
|
||||||
|
"num_cpus",
|
||||||
|
"psl",
|
||||||
|
"quick-xml",
|
||||||
|
"regex",
|
||||||
|
"rusqlite",
|
||||||
|
"rustls",
|
||||||
|
"rustls-platform-verifier",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tempfile",
|
||||||
|
"testcontainers",
|
||||||
|
"thiserror",
|
||||||
|
"time",
|
||||||
|
"ureq",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
@@ -2936,38 +2968,6 @@ dependencies = [
|
|||||||
"sha1_smol",
|
"sha1_smol",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vandelay"
|
|
||||||
version = "1.0.11"
|
|
||||||
dependencies = [
|
|
||||||
"blake3",
|
|
||||||
"calcard",
|
|
||||||
"chrono",
|
|
||||||
"chrono-tz",
|
|
||||||
"clap",
|
|
||||||
"crossbeam-channel",
|
|
||||||
"encodify",
|
|
||||||
"flate2",
|
|
||||||
"indexmap 2.14.2",
|
|
||||||
"mail-parser",
|
|
||||||
"mockito",
|
|
||||||
"num_cpus",
|
|
||||||
"psl",
|
|
||||||
"quick-xml",
|
|
||||||
"regex",
|
|
||||||
"rusqlite",
|
|
||||||
"rustls",
|
|
||||||
"rustls-platform-verifier",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tempfile",
|
|
||||||
"testcontainers",
|
|
||||||
"thiserror",
|
|
||||||
"time",
|
|
||||||
"ureq",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|||||||
+7
-17
@@ -1,22 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vandelay"
|
name = "inbuxa-migrate"
|
||||||
description = "JMAP account migration utility"
|
description = "Account migration and backup for inbuxa"
|
||||||
version = "1.0.11"
|
version = "2026.9.30"
|
||||||
authors = ["Stalwart Labs LLC <[email protected]>"]
|
authors = ["John Coffey <[email protected]>"]
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
repository = "https://github.com/stalwartlabs/vandelay"
|
repository = "https://git.coffeylabs.org/inbuxa/inbuxa-migrate"
|
||||||
homepage = "https://github.com/stalwartlabs/vandelay"
|
homepage = "https://git.coffeylabs.org/inbuxa/inbuxa-migrate"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[package.metadata.wix]
|
|
||||||
upgrade-guid = "5C8148E7-34A9-4216-A802-FFB8345AECC4"
|
|
||||||
path-guid = "FA9E97EB-5E5C-4809-9018-9DC1EDB0E93D"
|
|
||||||
license = false
|
|
||||||
eula = false
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "vandelay"
|
name = "inbuxa-migrate"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -52,7 +46,3 @@ psl = "2.1.226"
|
|||||||
mockito = "1.7.2"
|
mockito = "1.7.2"
|
||||||
tempfile = "3.13"
|
tempfile = "3.13"
|
||||||
testcontainers = { version = "0.28", features = ["blocking"] }
|
testcontainers = { version = "0.28", features = ["blocking"] }
|
||||||
|
|
||||||
[profile.dist]
|
|
||||||
inherits = "release"
|
|
||||||
lto = "thin"
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
# SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
#
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
@@ -136,7 +142,7 @@ def export_mail(conn, root):
|
|||||||
if directory is None:
|
if directory is None:
|
||||||
continue
|
continue
|
||||||
sequence += 1
|
sequence += 1
|
||||||
name = f"{stamp}.M{email_id}P{sequence}.vandelay:2,{info}"
|
name = f"{stamp}.M{email_id}P{sequence}.inbuxa-migrate:2,{info}"
|
||||||
with open(os.path.join(directory, "cur", name), "wb") as handle:
|
with open(os.path.join(directory, "cur", name), "wb") as handle:
|
||||||
handle.write(data)
|
handle.write(data)
|
||||||
written += 1
|
written += 1
|
||||||
@@ -320,7 +326,7 @@ def export_files(conn, root):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Export a Vandelay SQLite archive to a directory tree."
|
description="Export an inbuxa-migrate SQLite archive to a directory tree."
|
||||||
)
|
)
|
||||||
parser.add_argument("archive")
|
parser.add_argument("archive")
|
||||||
parser.add_argument("target")
|
parser.add_argument("target")
|
||||||
|
|||||||
+43
-38
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -30,9 +31,9 @@ use crate::types::{ObjectType, parse_object_list};
|
|||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "vandelay",
|
name = "inbuxa-migrate",
|
||||||
version,
|
version,
|
||||||
about = "Vandelay: the JMAP importer-exporter"
|
about = "inbuxa-migrate: account migration and backup for inbuxa"
|
||||||
)]
|
)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
@@ -138,7 +139,7 @@ struct JmapImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "PASS",
|
value_name = "PASS",
|
||||||
help = "Basic password (prefer $VANDELAY_PASSWORD or prompt)"
|
help = "Basic password (prefer $INBUXA_MIGRATE_PASSWORD or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_password: Option<String>,
|
auth_password: Option<String>,
|
||||||
|
|
||||||
@@ -146,7 +147,7 @@ struct JmapImportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Bearer token (value optional: falls back to $VANDELAY_TOKEN or prompt)"
|
help = "Bearer token (value optional: falls back to $INBUXA_MIGRATE_TOKEN or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_bearer: Option<Option<String>>,
|
auth_bearer: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -199,7 +200,7 @@ struct ImapImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "PASS",
|
value_name = "PASS",
|
||||||
help = "Basic password (prefer $VANDELAY_PASSWORD or prompt)"
|
help = "Basic password (prefer $INBUXA_MIGRATE_PASSWORD or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_password: Option<String>,
|
auth_password: Option<String>,
|
||||||
|
|
||||||
@@ -207,7 +208,7 @@ struct ImapImportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Bearer token for XOAUTH2 (value optional: falls back to $VANDELAY_TOKEN or prompt)"
|
help = "Bearer token for XOAUTH2 (value optional: falls back to $INBUXA_MIGRATE_TOKEN or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_bearer: Option<Option<String>>,
|
auth_bearer: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -309,7 +310,7 @@ struct ExportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "PASS",
|
value_name = "PASS",
|
||||||
help = "Basic password (prefer $VANDELAY_PASSWORD or prompt)"
|
help = "Basic password (prefer $INBUXA_MIGRATE_PASSWORD or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_password: Option<String>,
|
auth_password: Option<String>,
|
||||||
|
|
||||||
@@ -317,7 +318,7 @@ struct ExportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Bearer token (value optional: falls back to $VANDELAY_TOKEN or prompt)"
|
help = "Bearer token (value optional: falls back to $INBUXA_MIGRATE_TOKEN or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_bearer: Option<Option<String>>,
|
auth_bearer: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -407,7 +408,7 @@ pub struct ManageSieveImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "PASS",
|
value_name = "PASS",
|
||||||
help = "Basic password (prefer $VANDELAY_PASSWORD or prompt)"
|
help = "Basic password (prefer $INBUXA_MIGRATE_PASSWORD or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_password: Option<String>,
|
auth_password: Option<String>,
|
||||||
|
|
||||||
@@ -415,7 +416,7 @@ pub struct ManageSieveImportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Bearer token for OAUTHBEARER (value optional: $VANDELAY_TOKEN or prompt)"
|
help = "Bearer token for OAUTHBEARER (value optional: $INBUXA_MIGRATE_TOKEN or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_bearer: Option<Option<String>>,
|
auth_bearer: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -457,7 +458,7 @@ pub struct DavImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "PASS",
|
value_name = "PASS",
|
||||||
help = "Basic password (prefer $VANDELAY_PASSWORD or prompt)"
|
help = "Basic password (prefer $INBUXA_MIGRATE_PASSWORD or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_password: Option<String>,
|
auth_password: Option<String>,
|
||||||
|
|
||||||
@@ -465,7 +466,7 @@ pub struct DavImportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Bearer token (value optional: $VANDELAY_TOKEN or prompt)"
|
help = "Bearer token (value optional: $INBUXA_MIGRATE_TOKEN or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_bearer: Option<Option<String>>,
|
auth_bearer: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -560,7 +561,7 @@ fn resolve_managesieve_auth(
|
|||||||
"--auth-user is only valid with --auth-bearer".to_owned(),
|
"--auth-user is only valid with --auth-bearer".to_owned(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let password = secret::resolve(auth_password, "VANDELAY_PASSWORD", "password")?;
|
let password = secret::resolve(auth_password, "INBUXA_MIGRATE_PASSWORD", "password")?;
|
||||||
return Ok(ManageSieveAuth::Basic {
|
return Ok(ManageSieveAuth::Basic {
|
||||||
user: user.to_owned(),
|
user: user.to_owned(),
|
||||||
password,
|
password,
|
||||||
@@ -577,7 +578,7 @@ fn resolve_managesieve_auth(
|
|||||||
let user = auth_user
|
let user = auth_user
|
||||||
.ok_or_else(|| Error::Usage("--auth-user is required with --auth-bearer".to_owned()))?
|
.ok_or_else(|| Error::Usage("--auth-user is required with --auth-bearer".to_owned()))?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let token = secret::resolve(bearer.as_deref(), "VANDELAY_TOKEN", "bearer token")?;
|
let token = secret::resolve(bearer.as_deref(), "INBUXA_MIGRATE_TOKEN", "bearer token")?;
|
||||||
Ok(ManageSieveAuth::Bearer { user, token })
|
Ok(ManageSieveAuth::Bearer { user, token })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,7 +727,7 @@ fn resolve_dav_auth(
|
|||||||
auth_bearer: Option<&Option<String>>,
|
auth_bearer: Option<&Option<String>>,
|
||||||
) -> Result<DavAuth, Error> {
|
) -> Result<DavAuth, Error> {
|
||||||
if let Some(user) = auth_basic {
|
if let Some(user) = auth_basic {
|
||||||
let password = secret::resolve(auth_password, "VANDELAY_PASSWORD", "password")?;
|
let password = secret::resolve(auth_password, "INBUXA_MIGRATE_PASSWORD", "password")?;
|
||||||
return Ok(DavAuth::Basic {
|
return Ok(DavAuth::Basic {
|
||||||
user: user.to_owned(),
|
user: user.to_owned(),
|
||||||
password,
|
password,
|
||||||
@@ -740,7 +741,7 @@ fn resolve_dav_auth(
|
|||||||
let bearer = auth_bearer.ok_or_else(|| {
|
let bearer = auth_bearer.ok_or_else(|| {
|
||||||
Error::Usage("exactly one of --auth-basic / --auth-bearer is required".to_owned())
|
Error::Usage("exactly one of --auth-basic / --auth-bearer is required".to_owned())
|
||||||
})?;
|
})?;
|
||||||
let token = secret::resolve(bearer.as_deref(), "VANDELAY_TOKEN", "bearer token")?;
|
let token = secret::resolve(bearer.as_deref(), "INBUXA_MIGRATE_TOKEN", "bearer token")?;
|
||||||
Ok(DavAuth::Bearer { token })
|
Ok(DavAuth::Bearer { token })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,7 +829,7 @@ fn resolve_imap_auth(
|
|||||||
"--auth-user is only valid with --auth-bearer".to_owned(),
|
"--auth-user is only valid with --auth-bearer".to_owned(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let password = secret::resolve(auth_password, "VANDELAY_PASSWORD", "password")?;
|
let password = secret::resolve(auth_password, "INBUXA_MIGRATE_PASSWORD", "password")?;
|
||||||
return Ok(ImapAuth::Basic {
|
return Ok(ImapAuth::Basic {
|
||||||
user: user.to_owned(),
|
user: user.to_owned(),
|
||||||
password,
|
password,
|
||||||
@@ -845,7 +846,7 @@ fn resolve_imap_auth(
|
|||||||
let user = auth_user
|
let user = auth_user
|
||||||
.ok_or_else(|| Error::Usage("--auth-user is required with --auth-bearer".to_owned()))?
|
.ok_or_else(|| Error::Usage("--auth-user is required with --auth-bearer".to_owned()))?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let token = secret::resolve(bearer.as_deref(), "VANDELAY_TOKEN", "bearer token")?;
|
let token = secret::resolve(bearer.as_deref(), "INBUXA_MIGRATE_TOKEN", "bearer token")?;
|
||||||
Ok(ImapAuth::Bearer { user, token })
|
Ok(ImapAuth::Bearer { user, token })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,7 +922,7 @@ pub struct ExchangeEwsImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "PASS",
|
value_name = "PASS",
|
||||||
help = "Basic password (prefer $VANDELAY_PASSWORD or prompt)"
|
help = "Basic password (prefer $INBUXA_MIGRATE_PASSWORD or prompt)"
|
||||||
)]
|
)]
|
||||||
auth_password: Option<String>,
|
auth_password: Option<String>,
|
||||||
|
|
||||||
@@ -929,7 +930,7 @@ pub struct ExchangeEwsImportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Bearer token (value optional: $VANDELAY_TOKEN or device-code flow)"
|
help = "Bearer token (value optional: $INBUXA_MIGRATE_TOKEN or device-code flow)"
|
||||||
)]
|
)]
|
||||||
auth_bearer: Option<Option<String>>,
|
auth_bearer: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -946,7 +947,7 @@ pub struct ExchangeEwsImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_name = "SECRET",
|
value_name = "SECRET",
|
||||||
help = "OAuth client secret (app-only flow; prefer $VANDELAY_EWS_CLIENT_SECRET)"
|
help = "OAuth client secret (app-only flow; prefer $INBUXA_MIGRATE_EWS_CLIENT_SECRET)"
|
||||||
)]
|
)]
|
||||||
ews_client_secret: Option<String>,
|
ews_client_secret: Option<String>,
|
||||||
|
|
||||||
@@ -1029,7 +1030,7 @@ fn resolve_exchange_ews_auth(args: &ExchangeEwsImportArgs) -> Result<EwsAuth, Er
|
|||||||
if let Some(user) = args.auth_basic.as_deref() {
|
if let Some(user) = args.auth_basic.as_deref() {
|
||||||
let password = secret::resolve(
|
let password = secret::resolve(
|
||||||
args.auth_password.as_deref(),
|
args.auth_password.as_deref(),
|
||||||
"VANDELAY_PASSWORD",
|
"INBUXA_MIGRATE_PASSWORD",
|
||||||
"password",
|
"password",
|
||||||
)?;
|
)?;
|
||||||
return Ok(EwsAuth::Basic {
|
return Ok(EwsAuth::Basic {
|
||||||
@@ -1066,7 +1067,7 @@ fn resolve_exchange_ews_auth(args: &ExchangeEwsImportArgs) -> Result<EwsAuth, Er
|
|||||||
if let Some(secret) = args.ews_client_secret.clone() {
|
if let Some(secret) = args.ews_client_secret.clone() {
|
||||||
let resolved = secret::resolve(
|
let resolved = secret::resolve(
|
||||||
Some(secret.as_str()),
|
Some(secret.as_str()),
|
||||||
"VANDELAY_EWS_CLIENT_SECRET",
|
"INBUXA_MIGRATE_EWS_CLIENT_SECRET",
|
||||||
"client secret",
|
"client secret",
|
||||||
)?;
|
)?;
|
||||||
return Ok(EwsAuth::OAuth(OAuthFlow::ClientCredentials {
|
return Ok(EwsAuth::OAuth(OAuthFlow::ClientCredentials {
|
||||||
@@ -1075,7 +1076,7 @@ fn resolve_exchange_ews_auth(args: &ExchangeEwsImportArgs) -> Result<EwsAuth, Er
|
|||||||
client_secret: resolved,
|
client_secret: resolved,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if let Ok(env_secret) = std::env::var("VANDELAY_EWS_CLIENT_SECRET")
|
if let Ok(env_secret) = std::env::var("INBUXA_MIGRATE_EWS_CLIENT_SECRET")
|
||||||
&& !env_secret.is_empty()
|
&& !env_secret.is_empty()
|
||||||
{
|
{
|
||||||
return Ok(EwsAuth::OAuth(OAuthFlow::ClientCredentials {
|
return Ok(EwsAuth::OAuth(OAuthFlow::ClientCredentials {
|
||||||
@@ -1084,7 +1085,7 @@ fn resolve_exchange_ews_auth(args: &ExchangeEwsImportArgs) -> Result<EwsAuth, Er
|
|||||||
client_secret: env_secret,
|
client_secret: env_secret,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let token = secret::resolve(None, "VANDELAY_TOKEN", "bearer token")?;
|
let token = secret::resolve(None, "INBUXA_MIGRATE_TOKEN", "bearer token")?;
|
||||||
Ok(EwsAuth::Bearer { token })
|
Ok(EwsAuth::Bearer { token })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1125,7 +1126,7 @@ pub struct ExchangeGraphImportArgs {
|
|||||||
long,
|
long,
|
||||||
value_name = "TOKEN",
|
value_name = "TOKEN",
|
||||||
num_args = 0..=1,
|
num_args = 0..=1,
|
||||||
help = "Pre-acquired bearer token (skip device-code flow). Resolves: flag value -> $VANDELAY_GRAPH_TOKEN -> prompt."
|
help = "Pre-acquired bearer token (skip device-code flow). Resolves: flag value -> $INBUXA_MIGRATE_GRAPH_TOKEN -> prompt."
|
||||||
)]
|
)]
|
||||||
access_token: Option<Option<String>>,
|
access_token: Option<Option<String>>,
|
||||||
|
|
||||||
@@ -1168,7 +1169,7 @@ pub struct ExchangeGraphImportArgs {
|
|||||||
help = "Years either side of today to scan for edited recurrence occurrences (max 5)",
|
help = "Years either side of today to scan for edited recurrence occurrences (max 5)",
|
||||||
long_help = "Years either side of today to scan for edited recurrence occurrences.\n \
|
long_help = "Years either side of today to scan for edited recurrence occurrences.\n \
|
||||||
Graph reports a series exception only inside an expanded calendar view, and caps\n \
|
Graph reports a series exception only inside an expanded calendar view, and caps\n \
|
||||||
any single view at five years, so vandelay scans [today - N, today] and\n \
|
any single view at five years, so inbuxa-migrate scans [today - N, today] and\n \
|
||||||
[today, today + N]. An occurrence edited outside that span imports with the\n \
|
[today, today + N]. An occurrence edited outside that span imports with the\n \
|
||||||
series default instead of its edit."
|
series default instead of its edit."
|
||||||
)]
|
)]
|
||||||
@@ -1177,7 +1178,7 @@ pub struct ExchangeGraphImportArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
help = "Skip contact photos (saves one request per contact on large address books)",
|
help = "Skip contact photos (saves one request per contact on large address books)",
|
||||||
long_help = "Skip contact photos.\n Graph will not say which contacts have a photo: $expand=photo comes back empty\n even when one exists, so the only way to find out is to ask for the bytes.\n vandelay therefore spends one extra request per contact. Pass this to skip\n photos entirely on a large address book."
|
long_help = "Skip contact photos.\n Graph will not say which contacts have a photo: $expand=photo comes back empty\n even when one exists, so the only way to find out is to ask for the bytes.\n inbuxa-migrate therefore spends one extra request per contact. Pass this to skip\n photos entirely on a large address book."
|
||||||
)]
|
)]
|
||||||
skip_contact_photos: bool,
|
skip_contact_photos: bool,
|
||||||
|
|
||||||
@@ -1265,7 +1266,11 @@ fn resolve_graph_auth(
|
|||||||
tenant: &str,
|
tenant: &str,
|
||||||
) -> Result<GraphAuth, Error> {
|
) -> Result<GraphAuth, Error> {
|
||||||
if let Some(slot) = access_token {
|
if let Some(slot) = access_token {
|
||||||
let token = secret::resolve(slot.as_deref(), "VANDELAY_GRAPH_TOKEN", "bearer token")?;
|
let token = secret::resolve(
|
||||||
|
slot.as_deref(),
|
||||||
|
"INBUXA_MIGRATE_GRAPH_TOKEN",
|
||||||
|
"bearer token",
|
||||||
|
)?;
|
||||||
return Ok(GraphAuth::PreAcquired { token });
|
return Ok(GraphAuth::PreAcquired { token });
|
||||||
}
|
}
|
||||||
let client_id = client_id
|
let client_id = client_id
|
||||||
@@ -1305,7 +1310,7 @@ fn resolve_auth(
|
|||||||
auth_bearer: Option<&Option<String>>,
|
auth_bearer: Option<&Option<String>>,
|
||||||
) -> Result<Auth, Error> {
|
) -> Result<Auth, Error> {
|
||||||
if let Some(user) = auth_basic {
|
if let Some(user) = auth_basic {
|
||||||
let password = secret::resolve(auth_password, "VANDELAY_PASSWORD", "password")?;
|
let password = secret::resolve(auth_password, "INBUXA_MIGRATE_PASSWORD", "password")?;
|
||||||
return Ok(Auth::Basic {
|
return Ok(Auth::Basic {
|
||||||
user: user.to_owned(),
|
user: user.to_owned(),
|
||||||
password,
|
password,
|
||||||
@@ -1319,7 +1324,7 @@ fn resolve_auth(
|
|||||||
let bearer = auth_bearer.ok_or_else(|| {
|
let bearer = auth_bearer.ok_or_else(|| {
|
||||||
Error::Usage("exactly one of --auth-basic / --auth-bearer is required".to_owned())
|
Error::Usage("exactly one of --auth-basic / --auth-bearer is required".to_owned())
|
||||||
})?;
|
})?;
|
||||||
let token = secret::resolve(bearer.as_deref(), "VANDELAY_TOKEN", "bearer token")?;
|
let token = secret::resolve(bearer.as_deref(), "INBUXA_MIGRATE_TOKEN", "bearer token")?;
|
||||||
Ok(Auth::Bearer { token })
|
Ok(Auth::Bearer { token })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1350,8 +1355,8 @@ mod tests {
|
|||||||
fn auth_password_without_basic_is_usage_error() {
|
fn auth_password_without_basic_is_usage_error() {
|
||||||
let _g = lock();
|
let _g = lock();
|
||||||
unsafe {
|
unsafe {
|
||||||
env::remove_var("VANDELAY_TOKEN");
|
env::remove_var("INBUXA_MIGRATE_TOKEN");
|
||||||
env::remove_var("VANDELAY_PASSWORD");
|
env::remove_var("INBUXA_MIGRATE_PASSWORD");
|
||||||
}
|
}
|
||||||
let bearer: Option<String> = Some("t".to_owned());
|
let bearer: Option<String> = Some("t".to_owned());
|
||||||
let r = resolve_auth(None, Some("hunter2"), Some(&bearer));
|
let r = resolve_auth(None, Some("hunter2"), Some(&bearer));
|
||||||
@@ -1367,8 +1372,8 @@ mod tests {
|
|||||||
fn auth_basic_with_password_resolves() {
|
fn auth_basic_with_password_resolves() {
|
||||||
let _g = lock();
|
let _g = lock();
|
||||||
unsafe {
|
unsafe {
|
||||||
env::remove_var("VANDELAY_TOKEN");
|
env::remove_var("INBUXA_MIGRATE_TOKEN");
|
||||||
env::remove_var("VANDELAY_PASSWORD");
|
env::remove_var("INBUXA_MIGRATE_PASSWORD");
|
||||||
}
|
}
|
||||||
let auth = resolve_auth(Some("alice"), Some("pw"), None).unwrap();
|
let auth = resolve_auth(Some("alice"), Some("pw"), None).unwrap();
|
||||||
match auth {
|
match auth {
|
||||||
@@ -1384,8 +1389,8 @@ mod tests {
|
|||||||
fn auth_bearer_inline_token_resolves() {
|
fn auth_bearer_inline_token_resolves() {
|
||||||
let _g = lock();
|
let _g = lock();
|
||||||
unsafe {
|
unsafe {
|
||||||
env::remove_var("VANDELAY_TOKEN");
|
env::remove_var("INBUXA_MIGRATE_TOKEN");
|
||||||
env::remove_var("VANDELAY_PASSWORD");
|
env::remove_var("INBUXA_MIGRATE_PASSWORD");
|
||||||
}
|
}
|
||||||
let bearer: Option<String> = Some("t".to_owned());
|
let bearer: Option<String> = Some("t".to_owned());
|
||||||
let auth = resolve_auth(None, None, Some(&bearer)).unwrap();
|
let auth = resolve_auth(None, None, Some(&bearer)).unwrap();
|
||||||
@@ -1394,7 +1399,7 @@ mod tests {
|
|||||||
|
|
||||||
fn graph_config(objects: &[&str]) -> Result<GraphImportConfig, Error> {
|
fn graph_config(objects: &[&str]) -> Result<GraphImportConfig, Error> {
|
||||||
let mut argv = vec![
|
let mut argv = vec![
|
||||||
"vandelay",
|
"inbuxa-migrate",
|
||||||
"import",
|
"import",
|
||||||
"exchange-graph",
|
"exchange-graph",
|
||||||
"--access-token",
|
"--access-token",
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -87,7 +88,7 @@ impl DavClient {
|
|||||||
log_level: AtomicU8::new(LEVEL_DEFAULT),
|
log_level: AtomicU8::new(LEVEL_DEFAULT),
|
||||||
retries_total: AtomicU64::new(0),
|
retries_total: AtomicU64::new(0),
|
||||||
retry_after_sleeps: AtomicU64::new(0),
|
retry_after_sleeps: AtomicU64::new(0),
|
||||||
user_agent: format!("vandelay/{}", env!("CARGO_PKG_VERSION")),
|
user_agent: format!("inbuxa-migrate/{}", env!("CARGO_PKG_VERSION")),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -36,7 +37,7 @@ const CALENDAR_ADDRESS_DEPENDENTS: &[&str] = &[
|
|||||||
|
|
||||||
pub fn synthetic_attendee_address(identifier: &str) -> String {
|
pub fn synthetic_attendee_address(identifier: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"urn:x-vandelay:attendee:{}",
|
"urn:x-inbuxa-migrate:attendee:{}",
|
||||||
blake3::hash(identifier.as_bytes()).to_hex()
|
blake3::hash(identifier.as_bytes()).to_hex()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -146,7 +147,7 @@ mod tests {
|
|||||||
let event = json!({
|
let event = json!({
|
||||||
"@type": "Event",
|
"@type": "Event",
|
||||||
"uid": "uid-1",
|
"uid": "uid-1",
|
||||||
"prodId": "vandelay",
|
"prodId": "inbuxa-migrate",
|
||||||
"privacy": "public",
|
"privacy": "public",
|
||||||
"organizerCalendarAddress": "mailto:[email protected]",
|
"organizerCalendarAddress": "mailto:[email protected]",
|
||||||
"recurrenceRule": {"frequency": "daily"},
|
"recurrenceRule": {"frequency": "daily"},
|
||||||
@@ -173,7 +174,7 @@ mod tests {
|
|||||||
let addr = synthetic_attendee_address("Jane Doe");
|
let addr = synthetic_attendee_address("Jane Doe");
|
||||||
assert_eq!(addr, synthetic_attendee_address("Jane Doe"));
|
assert_eq!(addr, synthetic_attendee_address("Jane Doe"));
|
||||||
assert_ne!(addr, synthetic_attendee_address("John Doe"));
|
assert_ne!(addr, synthetic_attendee_address("John Doe"));
|
||||||
assert!(addr.starts_with("urn:x-vandelay:attendee:"));
|
assert!(addr.starts_with("urn:x-inbuxa-migrate:attendee:"));
|
||||||
assert!(
|
assert!(
|
||||||
!addr.starts_with("mailto:"),
|
!addr.starts_with("mailto:"),
|
||||||
"export must never invite a fabricated address"
|
"export must never invite a fabricated address"
|
||||||
@@ -186,7 +187,7 @@ mod tests {
|
|||||||
"1": {
|
"1": {
|
||||||
"@type": "Participant",
|
"@type": "Participant",
|
||||||
"name": "Room 4",
|
"name": "Room 4",
|
||||||
"calendarAddress": "urn:x-vandelay:attendee:abc",
|
"calendarAddress": "urn:x-inbuxa-migrate:attendee:abc",
|
||||||
"email": "[email protected]",
|
"email": "[email protected]",
|
||||||
"roles": {"required": true},
|
"roles": {"required": true},
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -53,7 +54,7 @@ fn build_event_map(raw: &CalendarItemRaw, iana: Option<&str>) -> Map<String, Val
|
|||||||
event.insert(
|
event.insert(
|
||||||
"uid".to_owned(),
|
"uid".to_owned(),
|
||||||
Value::String(format!(
|
Value::String(format!(
|
||||||
"vandelay-ews-event-{}",
|
"inbuxa-migrate-ews-event-{}",
|
||||||
blake3::hash(raw.id.id.as_bytes()).to_hex()
|
blake3::hash(raw.id.id.as_bytes()).to_hex()
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@@ -723,7 +724,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let addr = p["calendarAddress"].as_str().unwrap();
|
let addr = p["calendarAddress"].as_str().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
addr.starts_with("urn:x-vandelay:attendee:"),
|
addr.starts_with("urn:x-inbuxa-migrate:attendee:"),
|
||||||
"a name-only attendee gets a stable synthetic calendarAddress, got {addr}"
|
"a name-only attendee gets a stable synthetic calendarAddress, got {addr}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -771,7 +772,7 @@ mod tests {
|
|||||||
let v = to_jscalendar(&raw).data;
|
let v = to_jscalendar(&raw).data;
|
||||||
let org_addr = v["organizerCalendarAddress"].as_str().unwrap();
|
let org_addr = v["organizerCalendarAddress"].as_str().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
org_addr.starts_with("urn:x-vandelay:attendee:") && !org_addr.contains("mailto:"),
|
org_addr.starts_with("urn:x-inbuxa-migrate:attendee:") && !org_addr.contains("mailto:"),
|
||||||
"an EX organizer must not become mailto:/o=.../cn=...; got {org_addr}"
|
"an EX organizer must not become mailto:/o=.../cn=...; got {org_addr}"
|
||||||
);
|
);
|
||||||
let att = v["participants"]
|
let att = v["participants"]
|
||||||
@@ -921,7 +922,7 @@ mod tests {
|
|||||||
let v = to_jscalendar(&raw).data;
|
let v = to_jscalendar(&raw).data;
|
||||||
let addr = v["organizerCalendarAddress"].as_str().unwrap();
|
let addr = v["organizerCalendarAddress"].as_str().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
addr.starts_with("urn:x-vandelay:attendee:"),
|
addr.starts_with("urn:x-inbuxa-migrate:attendee:"),
|
||||||
"an unresolvable directory reference stays synthetic, got {addr}"
|
"an unresolvable directory reference stays synthetic, got {addr}"
|
||||||
);
|
);
|
||||||
let participants = v["participants"].as_object().unwrap();
|
let participants = v["participants"].as_object().unwrap();
|
||||||
@@ -947,7 +948,7 @@ mod tests {
|
|||||||
v["organizerCalendarAddress"]
|
v["organizerCalendarAddress"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.starts_with("urn:x-vandelay:attendee:")
|
.starts_with("urn:x-inbuxa-migrate:attendee:")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +82,7 @@ impl EwsClient {
|
|||||||
retries_total: AtomicU64::new(0),
|
retries_total: AtomicU64::new(0),
|
||||||
retry_after_sleeps: AtomicU64::new(0),
|
retry_after_sleeps: AtomicU64::new(0),
|
||||||
soap_calls: AtomicU64::new(0),
|
soap_calls: AtomicU64::new(0),
|
||||||
user_agent: format!("vandelay/{}", env!("CARGO_PKG_VERSION")),
|
user_agent: format!("inbuxa-migrate/{}", env!("CARGO_PKG_VERSION")),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -10,7 +11,7 @@ use crate::exchange_ews::parse::{ContactItemRaw, RawContactAddress};
|
|||||||
|
|
||||||
pub fn synthetic_uid(item_id: &str) -> String {
|
pub fn synthetic_uid(item_id: &str) -> String {
|
||||||
let hash = blake3::hash(item_id.as_bytes()).to_hex();
|
let hash = blake3::hash(item_id.as_bytes()).to_hex();
|
||||||
format!("vandelay-ews-syn-{hash}")
|
format!("inbuxa-migrate-ews-syn-{hash}")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_jscontact(raw: &ContactItemRaw) -> Value {
|
pub fn to_jscontact(raw: &ContactItemRaw) -> Value {
|
||||||
@@ -389,7 +390,7 @@ mod tests {
|
|||||||
let u2 = synthetic_uid("ITEM-1");
|
let u2 = synthetic_uid("ITEM-1");
|
||||||
assert_eq!(u1, u2);
|
assert_eq!(u1, u2);
|
||||||
assert_ne!(u1, synthetic_uid("ITEM-2"));
|
assert_ne!(u1, synthetic_uid("ITEM-2"));
|
||||||
assert!(u1.starts_with("vandelay-ews-syn-"));
|
assert!(u1.starts_with("inbuxa-migrate-ews-syn-"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -724,7 +725,7 @@ fn wrap_inner_with_namespaces(inner: &str) -> String {
|
|||||||
return String::new();
|
return String::new();
|
||||||
}
|
}
|
||||||
format!(
|
format!(
|
||||||
"<vandelay-inner xmlns=\"{NS_TYPES}\" xmlns:t=\"{NS_TYPES}\" xmlns:m=\"{NS_MESSAGES}\">{inner}</vandelay-inner>",
|
"<inbuxa-migrate-inner xmlns=\"{NS_TYPES}\" xmlns:t=\"{NS_TYPES}\" xmlns:m=\"{NS_MESSAGES}\">{inner}</inbuxa-migrate-inner>",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -701,7 +702,7 @@ mod tests {
|
|||||||
let p = &conv.data["participants"]["att-1"];
|
let p = &conv.data["participants"]["att-1"];
|
||||||
let addr = p["calendarAddress"].as_str().unwrap();
|
let addr = p["calendarAddress"].as_str().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
addr.starts_with("urn:x-vandelay:attendee:"),
|
addr.starts_with("urn:x-inbuxa-migrate:attendee:"),
|
||||||
"a hybrid X500 reference must not become a malformed mailto, got {addr}"
|
"a hybrid X500 reference must not become a malformed mailto, got {addr}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -755,7 +756,7 @@ mod tests {
|
|||||||
let p = &conv.data["participants"]["att-1"];
|
let p = &conv.data["participants"]["att-1"];
|
||||||
let addr = p["calendarAddress"].as_str().unwrap();
|
let addr = p["calendarAddress"].as_str().unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
addr.starts_with("urn:x-vandelay:attendee:"),
|
addr.starts_with("urn:x-inbuxa-migrate:attendee:"),
|
||||||
"a name-only attendee needs a synthetic calendarAddress, got {addr}"
|
"a name-only attendee needs a synthetic calendarAddress, got {addr}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -799,7 +800,7 @@ mod tests {
|
|||||||
v["organizer"] = json!({"emailAddress": {"name": "Alice Example"}});
|
v["organizer"] = json!({"emailAddress": {"name": "Alice Example"}});
|
||||||
let conv = convert_event(&v, None).unwrap();
|
let conv = convert_event(&v, None).unwrap();
|
||||||
let organizer_address = conv.data["organizerCalendarAddress"].as_str().unwrap();
|
let organizer_address = conv.data["organizerCalendarAddress"].as_str().unwrap();
|
||||||
assert!(organizer_address.starts_with("urn:x-vandelay:attendee:"));
|
assert!(organizer_address.starts_with("urn:x-inbuxa-migrate:attendee:"));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
conv.data["participants"]["organizer"]["calendarAddress"],
|
conv.data["participants"]["organizer"]["calendarAddress"],
|
||||||
organizer_address
|
organizer_address
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -112,7 +113,7 @@ impl GraphClient {
|
|||||||
retries_total: AtomicU64::new(0),
|
retries_total: AtomicU64::new(0),
|
||||||
retry_after_sleeps: AtomicU64::new(0),
|
retry_after_sleeps: AtomicU64::new(0),
|
||||||
requests_total: AtomicU64::new(0),
|
requests_total: AtomicU64::new(0),
|
||||||
user_agent: format!("vandelay/{}", env!("CARGO_PKG_VERSION")),
|
user_agent: format!("inbuxa-migrate/{}", env!("CARGO_PKG_VERSION")),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -354,7 +355,7 @@ fn has_uri_scheme(value: &str) -> bool {
|
|||||||
|
|
||||||
pub fn synthetic_uid(graph_id: &str) -> String {
|
pub fn synthetic_uid(graph_id: &str) -> String {
|
||||||
let hash = blake3::hash(graph_id.as_bytes());
|
let hash = blake3::hash(graph_id.as_bytes());
|
||||||
format!("vandelay-graph-{}", hash.to_hex())
|
format!("inbuxa-migrate-graph-{}", hash.to_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalise_utc_datetime(raw: &str) -> String {
|
fn normalise_utc_datetime(raw: &str) -> String {
|
||||||
@@ -465,7 +466,7 @@ mod tests {
|
|||||||
fn minimal_contact_yields_card_with_synthetic_uid() {
|
fn minimal_contact_yields_card_with_synthetic_uid() {
|
||||||
let c = json!({"id": "GRAPH-1", "displayName": "Alice"});
|
let c = json!({"id": "GRAPH-1", "displayName": "Alice"});
|
||||||
let conv = convert_contact(&c).unwrap();
|
let conv = convert_contact(&c).unwrap();
|
||||||
assert!(conv.uid.starts_with("vandelay-graph-"));
|
assert!(conv.uid.starts_with("inbuxa-migrate-graph-"));
|
||||||
assert_eq!(conv.data["@type"], "Card");
|
assert_eq!(conv.data["@type"], "Card");
|
||||||
assert_eq!(conv.data["kind"], "individual");
|
assert_eq!(conv.data["kind"], "individual");
|
||||||
assert_eq!(conv.data["name"]["full"], "Alice");
|
assert_eq!(conv.data["name"]["full"], "Alice");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -18,7 +19,7 @@ impl MailboxKind {
|
|||||||
"primary" => Ok(MailboxKind::Primary),
|
"primary" => Ok(MailboxKind::Primary),
|
||||||
"archive" => Ok(MailboxKind::Archive),
|
"archive" => Ok(MailboxKind::Archive),
|
||||||
"public-folders" => Err(Error::Usage(
|
"public-folders" => Err(Error::Usage(
|
||||||
"Microsoft Graph does not expose public folders. Run `vandelay import exchange-ews --mailbox-kind public-folders` instead.".to_owned(),
|
"Microsoft Graph does not expose public folders. Run `inbuxa-migrate import exchange-ews --mailbox-kind public-folders` instead.".to_owned(),
|
||||||
)),
|
)),
|
||||||
other => Err(Error::Usage(format!(
|
other => Err(Error::Usage(format!(
|
||||||
"--mailbox-kind must be primary | archive, got {other:?}"
|
"--mailbox-kind must be primary | archive, got {other:?}"
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -139,7 +140,7 @@ impl std::fmt::Display for OriginMismatch {
|
|||||||
}
|
}
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
" on {} (connected to {}); vandelay must use the advertised URL. \
|
" on {} (connected to {}); inbuxa-migrate must use the advertised URL. \
|
||||||
If this is wrong, fix the server's advertised HTTP URL setting.",
|
If this is wrong, fix the server's advertised HTTP URL setting.",
|
||||||
self.session_origin, self.connect_origin
|
self.session_origin, self.connect_origin
|
||||||
)
|
)
|
||||||
|
|||||||
+5
-4
@@ -1,15 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use vandelay::cli::{Action, Cli};
|
use inbuxa_migrate::cli::{Action, Cli};
|
||||||
use vandelay::error::Error;
|
use inbuxa_migrate::error::Error;
|
||||||
use vandelay::inspect;
|
use inbuxa_migrate::inspect;
|
||||||
use vandelay::sync::{self, RunOutcome, Summary};
|
use inbuxa_migrate::sync::{self, RunOutcome, Summary};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let code = run();
|
let code = run();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +53,7 @@ pub fn vcard_to_jscontact(text: &str, item_href: &str) -> Result<JsContact, Calc
|
|||||||
|
|
||||||
pub fn synthesise_uid(item_href: &str) -> String {
|
pub fn synthesise_uid(item_href: &str) -> String {
|
||||||
let hash = blake3::hash(item_href.as_bytes());
|
let hash = blake3::hash(item_href.as_bytes());
|
||||||
format!("vandelay-syn-{}", hash.to_hex())
|
format!("inbuxa-migrate-syn-{}", hash.to_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -208,7 +209,7 @@ END:VCALENDAR\r\n";
|
|||||||
let href = "/dav/card/u/d/no-uid.vcf";
|
let href = "/dav/card/u/d/no-uid.vcf";
|
||||||
let jc = vcard_to_jscontact(no_uid, href).expect("synthetic uid");
|
let jc = vcard_to_jscontact(no_uid, href).expect("synthetic uid");
|
||||||
assert_eq!(jc.uid, synthesise_uid(href));
|
assert_eq!(jc.uid, synthesise_uid(href));
|
||||||
assert!(jc.uid.starts_with("vandelay-syn-"));
|
assert!(jc.uid.starts_with("inbuxa-migrate-syn-"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -385,7 +386,7 @@ fn spawn_token_refresher(
|
|||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
let initial_refresh = initial.as_ref().and_then(|t| t.refresh_token.clone());
|
let initial_refresh = initial.as_ref().and_then(|t| t.refresh_token.clone());
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("vandelay-ews-token-refresh".to_owned())
|
.name("inbuxa-migrate-ews-token-refresh".to_owned())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
let mut next_exp = exp_secs;
|
let mut next_exp = exp_secs;
|
||||||
let mut refresh_token = initial_refresh;
|
let mut refresh_token = initial_refresh;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -395,7 +396,7 @@ fn spawn_token_refresher(
|
|||||||
let shutdown = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
|
let shutdown = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||||
let shutdown_signal = shutdown.clone();
|
let shutdown_signal = shutdown.clone();
|
||||||
let handle = std::thread::Builder::new()
|
let handle = std::thread::Builder::new()
|
||||||
.name("vandelay-graph-token-refresh".to_owned())
|
.name("inbuxa-migrate-graph-token-refresh".to_owned())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
while !shutdown_signal.load(std::sync::atomic::Ordering::Relaxed) {
|
while !shutdown_signal.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
let now = unix_now();
|
let now = unix_now();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -199,7 +200,7 @@ pub fn run(common: CommonConfig, config: ManageSieveImportConfig) -> Result<Summ
|
|||||||
}
|
}
|
||||||
Disposition::Referral => {
|
Disposition::Referral => {
|
||||||
return Err(Error::Connection(format!(
|
return Err(Error::Connection(format!(
|
||||||
"ManageSieve referral on GETSCRIPT {name:?}: {e}; vandelay does not follow referrals"
|
"ManageSieve referral on GETSCRIPT {name:?}: {e}; inbuxa-migrate does not follow referrals"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Disposition::TransportDrop => {
|
Disposition::TransportDrop => {
|
||||||
@@ -536,7 +537,7 @@ fn listscripts_with_retry(
|
|||||||
}
|
}
|
||||||
Disposition::Referral => {
|
Disposition::Referral => {
|
||||||
return Err(Error::Connection(format!(
|
return Err(Error::Connection(format!(
|
||||||
"LISTSCRIPTS referral: {e}; vandelay does not follow referrals"
|
"LISTSCRIPTS referral: {e}; inbuxa-migrate does not follow referrals"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
_ => return Err(Error::Connection(format!("LISTSCRIPTS failed: {e}"))),
|
_ => return Err(Error::Connection(format!("LISTSCRIPTS failed: {e}"))),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -34,7 +35,7 @@ const BAIKAL_YAML: &str = "system:
|
|||||||
timezone: 'UTC'
|
timezone: 'UTC'
|
||||||
card_enabled: true
|
card_enabled: true
|
||||||
cal_enabled: true
|
cal_enabled: true
|
||||||
invite_from: 'noreply@vandelay.test'
|
invite_from: 'noreply@inbuxa-migrate.test'
|
||||||
dav_auth_type: 'Basic'
|
dav_auth_type: 'Basic'
|
||||||
admin_passwordhash: '004b53ae84286ba6003b34e8ef404826'
|
admin_passwordhash: '004b53ae84286ba6003b34e8ef404826'
|
||||||
failed_access_message: 'user %u authentication failure for Baikal'
|
failed_access_message: 'user %u authentication failure for Baikal'
|
||||||
@@ -64,7 +65,7 @@ impl Baikal {
|
|||||||
pub fn start() -> ContainerResult<Self> {
|
pub fn start() -> ContainerResult<Self> {
|
||||||
let db_bytes = build_sqlite_db()?;
|
let db_bytes = build_sqlite_db()?;
|
||||||
|
|
||||||
let image: GenericImage = GenericBuildableImage::new("vandelay-baikal", "test")
|
let image: GenericImage = GenericBuildableImage::new("inbuxa-migrate-baikal", "test")
|
||||||
.with_dockerfile_string(DOCKERFILE.to_owned())
|
.with_dockerfile_string(DOCKERFILE.to_owned())
|
||||||
.with_data(BAIKAL_YAML.as_bytes().to_vec(), "baikal.yaml")
|
.with_data(BAIKAL_YAML.as_bytes().to_vec(), "baikal.yaml")
|
||||||
.with_data(db_bytes, "db.sqlite")
|
.with_data(db_bytes, "db.sqlite")
|
||||||
@@ -325,8 +326,8 @@ fn build_sqlite_db() -> ContainerResult<Vec<u8>> {
|
|||||||
)
|
)
|
||||||
.map_err(|e| ContainerError::Seed(format!("baikal user {name}: {e}")))?;
|
.map_err(|e| ContainerError::Seed(format!("baikal user {name}: {e}")))?;
|
||||||
let uri = format!("principals/{name}");
|
let uri = format!("principals/{name}");
|
||||||
let email = format!("{name}@vandelay.test");
|
let email = format!("{name}@inbuxa-migrate.test");
|
||||||
let display = format!("Vandelay {name}");
|
let display = format!("Inbuxa {name}");
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO principals (uri, email, displayname) VALUES (?1, ?2, ?3)",
|
"INSERT INTO principals (uri, email, displayname) VALUES (?1, ?2, ?3)",
|
||||||
params![uri, email, display],
|
params![uri, email, display],
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -142,7 +143,7 @@ pub struct Cyrus {
|
|||||||
|
|
||||||
impl Cyrus {
|
impl Cyrus {
|
||||||
pub fn start() -> ContainerResult<Self> {
|
pub fn start() -> ContainerResult<Self> {
|
||||||
let image: GenericImage = GenericBuildableImage::new("vandelay-cyrus", "test")
|
let image: GenericImage = GenericBuildableImage::new("inbuxa-migrate-cyrus", "test")
|
||||||
.with_dockerfile_string(DOCKERFILE.to_owned())
|
.with_dockerfile_string(DOCKERFILE.to_owned())
|
||||||
.with_data(IMAPD_CONF.as_bytes().to_vec(), "imapd.conf")
|
.with_data(IMAPD_CONF.as_bytes().to_vec(), "imapd.conf")
|
||||||
.with_data(CYRUS_CONF.as_bytes().to_vec(), "cyrus.conf")
|
.with_data(CYRUS_CONF.as_bytes().to_vec(), "cyrus.conf")
|
||||||
@@ -313,10 +314,13 @@ impl Cyrus {
|
|||||||
) -> ContainerResult<(Vec<u8>, String)> {
|
) -> ContainerResult<(Vec<u8>, String)> {
|
||||||
let mut client = ImapSeed::connect(&self.imap.host, self.imap.port)?;
|
let mut client = ImapSeed::connect(&self.imap.host, self.imap.port)?;
|
||||||
client.login(&account.username, &account.password)?;
|
client.login(&account.username, &account.password)?;
|
||||||
let message_id = format!("<cyrus-added-{tag}-{}@vandelay.test>", account.username);
|
let message_id = format!(
|
||||||
|
"<cyrus-added-{tag}-{}@inbuxa-migrate.test>",
|
||||||
|
account.username
|
||||||
|
);
|
||||||
let body = format!(
|
let body = format!(
|
||||||
"From: cyrus-added-{tag}@vandelay.test\r\n\
|
"From: cyrus-added-{tag}@inbuxa-migrate.test\r\n\
|
||||||
To: {}@vandelay.test\r\n\
|
To: {}@inbuxa-migrate.test\r\n\
|
||||||
Subject: Cyrus added probe {tag}\r\n\
|
Subject: Cyrus added probe {tag}\r\n\
|
||||||
Message-ID: {message_id}\r\n\
|
Message-ID: {message_id}\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
@@ -372,10 +376,10 @@ impl Cyrus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn flag_probe_message() -> Vec<u8> {
|
pub fn flag_probe_message() -> Vec<u8> {
|
||||||
let body = "From: probe-flags@vandelay.test\r\n\
|
let body = "From: probe-flags@inbuxa-migrate.test\r\n\
|
||||||
To: user@vandelay.test\r\n\
|
To: user@inbuxa-migrate.test\r\n\
|
||||||
Subject: Cyrus flag probe\r\n\
|
Subject: Cyrus flag probe\r\n\
|
||||||
Message-ID: <cyrus-flag-probe@vandelay.test>\r\n\
|
Message-ID: <cyrus-flag-probe@inbuxa-migrate.test>\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
Cyrus flag probe body.\r\n";
|
Cyrus flag probe body.\r\n";
|
||||||
|
|||||||
+45
-44
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -89,15 +90,15 @@ fn synth_messages(n: usize) -> Vec<MboxMessage> {
|
|||||||
let mut out = Vec::with_capacity(n);
|
let mut out = Vec::with_capacity(n);
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let body = format!(
|
let body = format!(
|
||||||
"From: sender{i}@vandelay.test\r\n\
|
"From: sender{i}@inbuxa-migrate.test\r\n\
|
||||||
To: user@vandelay.test\r\n\
|
To: user@inbuxa-migrate.test\r\n\
|
||||||
Subject: Synthetic test message {i}\r\n\
|
Subject: Synthetic test message {i}\r\n\
|
||||||
Message-ID: <synth-{i}@vandelay.test>\r\n\
|
Message-ID: <synth-{i}@inbuxa-migrate.test>\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
MIME-Version: 1.0\r\n\
|
MIME-Version: 1.0\r\n\
|
||||||
Content-Type: text/plain; charset=utf-8\r\n\
|
Content-Type: text/plain; charset=utf-8\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
This is synthetic seed message #{i} for vandelay container tests.\r\n",
|
This is synthetic seed message #{i} for inbuxa-migrate container tests.\r\n",
|
||||||
);
|
);
|
||||||
out.push(MboxMessage {
|
out.push(MboxMessage {
|
||||||
raw: body.into_bytes(),
|
raw: body.into_bytes(),
|
||||||
@@ -135,10 +136,10 @@ fn vcard_v3_basic(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCARD\r\n\
|
"BEGIN:VCARD\r\n\
|
||||||
VERSION:3.0\r\n\
|
VERSION:3.0\r\n\
|
||||||
UID:vandelay-card-basic-{i}\r\n\
|
UID:inbuxa-migrate-card-basic-{i}\r\n\
|
||||||
FN:Basic Contact {i}\r\n\
|
FN:Basic Contact {i}\r\n\
|
||||||
N:Contact{i};Basic;;;\r\n\
|
N:Contact{i};Basic;;;\r\n\
|
||||||
EMAIL;TYPE=INTERNET:basic-{i}@vandelay.test\r\n\
|
EMAIL;TYPE=INTERNET:basic-{i}@inbuxa-migrate.test\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -147,14 +148,14 @@ fn vcard_v3_full(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCARD\r\n\
|
"BEGIN:VCARD\r\n\
|
||||||
VERSION:3.0\r\n\
|
VERSION:3.0\r\n\
|
||||||
UID:vandelay-card-full-{i}\r\n\
|
UID:inbuxa-migrate-card-full-{i}\r\n\
|
||||||
FN:Full Contact {i}\r\n\
|
FN:Full Contact {i}\r\n\
|
||||||
N:Contact{i};Full;Middle;;\r\n\
|
N:Contact{i};Full;Middle;;\r\n\
|
||||||
EMAIL;TYPE=INTERNET;TYPE=WORK:full-{i}@vandelay.test\r\n\
|
EMAIL;TYPE=INTERNET;TYPE=WORK:full-{i}@inbuxa-migrate.test\r\n\
|
||||||
TEL;TYPE=CELL:+15550010{i:03}\r\n\
|
TEL;TYPE=CELL:+15550010{i:03}\r\n\
|
||||||
ORG:Vandelay Test\r\n\
|
ORG:Inbuxa Test\r\n\
|
||||||
TITLE:Senior Test Engineer\r\n\
|
TITLE:Senior Test Engineer\r\n\
|
||||||
URL:https://vandelay.test/{i}\r\n\
|
URL:https://inbuxa-migrate.test/{i}\r\n\
|
||||||
NOTE:Synthetic full v3 contact #{i}\r\n\
|
NOTE:Synthetic full v3 contact #{i}\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
@@ -164,11 +165,11 @@ fn vcard_v3_multi_email(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCARD\r\n\
|
"BEGIN:VCARD\r\n\
|
||||||
VERSION:3.0\r\n\
|
VERSION:3.0\r\n\
|
||||||
UID:vandelay-card-multi-{i}\r\n\
|
UID:inbuxa-migrate-card-multi-{i}\r\n\
|
||||||
FN:Multi Email {i}\r\n\
|
FN:Multi Email {i}\r\n\
|
||||||
N:Contact{i};MultiEmail;;;\r\n\
|
N:Contact{i};MultiEmail;;;\r\n\
|
||||||
EMAIL;TYPE=INTERNET;TYPE=HOME:multi-{i}-home@vandelay.test\r\n\
|
EMAIL;TYPE=INTERNET;TYPE=HOME:multi-{i}-home@inbuxa-migrate.test\r\n\
|
||||||
EMAIL;TYPE=INTERNET;TYPE=WORK:multi-{i}-work@vandelay.test\r\n\
|
EMAIL;TYPE=INTERNET;TYPE=WORK:multi-{i}-work@inbuxa-migrate.test\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -177,12 +178,12 @@ fn vcard_v3_org_and_title(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCARD\r\n\
|
"BEGIN:VCARD\r\n\
|
||||||
VERSION:3.0\r\n\
|
VERSION:3.0\r\n\
|
||||||
UID:vandelay-card-org-{i}\r\n\
|
UID:inbuxa-migrate-card-org-{i}\r\n\
|
||||||
FN:Org Contact {i}\r\n\
|
FN:Org Contact {i}\r\n\
|
||||||
N:Contact{i};Org;;Dr.;PhD\r\n\
|
N:Contact{i};Org;;Dr.;PhD\r\n\
|
||||||
ORG:Vandelay Industries;Engineering;Test Group\r\n\
|
ORG:Inbuxa Industries;Engineering;Test Group\r\n\
|
||||||
TITLE:Principal Researcher\r\n\
|
TITLE:Principal Researcher\r\n\
|
||||||
EMAIL;TYPE=INTERNET:org-{i}@vandelay.test\r\n\
|
EMAIL;TYPE=INTERNET:org-{i}@inbuxa-migrate.test\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -194,7 +195,7 @@ fn vcard_v4_basic(i: usize) -> String {
|
|||||||
UID:urn:uuid:00000000-0000-4000-a000-0000{i:08x}\r\n\
|
UID:urn:uuid:00000000-0000-4000-a000-0000{i:08x}\r\n\
|
||||||
FN:V4 Basic {i}\r\n\
|
FN:V4 Basic {i}\r\n\
|
||||||
N:Contact{i};V4Basic;;;\r\n\
|
N:Contact{i};V4Basic;;;\r\n\
|
||||||
EMAIL:v4-basic-{i}@vandelay.test\r\n\
|
EMAIL:v4-basic-{i}@inbuxa-migrate.test\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -206,7 +207,7 @@ fn vcard_v4_with_address(i: usize) -> String {
|
|||||||
UID:urn:uuid:00000000-0000-4000-b000-0000{i:08x}\r\n\
|
UID:urn:uuid:00000000-0000-4000-b000-0000{i:08x}\r\n\
|
||||||
FN:V4 Address {i}\r\n\
|
FN:V4 Address {i}\r\n\
|
||||||
N:Contact{i};V4Address;;;\r\n\
|
N:Contact{i};V4Address;;;\r\n\
|
||||||
EMAIL:v4-address-{i}@vandelay.test\r\n\
|
EMAIL:v4-address-{i}@inbuxa-migrate.test\r\n\
|
||||||
ADR;TYPE=home:;;{i} Test Street;Springfield;OR;97477;US\r\n\
|
ADR;TYPE=home:;;{i} Test Street;Springfield;OR;97477;US\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
@@ -220,7 +221,7 @@ fn vcard_v4_nickname(i: usize) -> String {
|
|||||||
FN:V4 Nick {i}\r\n\
|
FN:V4 Nick {i}\r\n\
|
||||||
N:Contact{i};V4Nick;;;\r\n\
|
N:Contact{i};V4Nick;;;\r\n\
|
||||||
NICKNAME:Nicky{i}\r\n\
|
NICKNAME:Nicky{i}\r\n\
|
||||||
EMAIL:v4-nick-{i}@vandelay.test\r\n\
|
EMAIL:v4-nick-{i}@inbuxa-migrate.test\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -236,7 +237,7 @@ fn vcard_v4_birthday(i: usize) -> String {
|
|||||||
FN:V4 Birthday {i}\r\n\
|
FN:V4 Birthday {i}\r\n\
|
||||||
N:Contact{i};V4Birthday;;;\r\n\
|
N:Contact{i};V4Birthday;;;\r\n\
|
||||||
BDAY:{year:04}{month:02}{day:02}\r\n\
|
BDAY:{year:04}{month:02}{day:02}\r\n\
|
||||||
EMAIL:v4-bday-{i}@vandelay.test\r\n\
|
EMAIL:v4-bday-{i}@inbuxa-migrate.test\r\n\
|
||||||
END:VCARD\r\n"
|
END:VCARD\r\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -245,10 +246,10 @@ fn vcard_v3_apple_item_labels(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCARD\r\n\
|
"BEGIN:VCARD\r\n\
|
||||||
VERSION:3.0\r\n\
|
VERSION:3.0\r\n\
|
||||||
UID:vandelay-card-ablabels-{i}\r\n\
|
UID:inbuxa-migrate-card-ablabels-{i}\r\n\
|
||||||
FN:Apple Labels {i}\r\n\
|
FN:Apple Labels {i}\r\n\
|
||||||
N:Contact{i};AppleLabels;;;\r\n\
|
N:Contact{i};AppleLabels;;;\r\n\
|
||||||
EMAIL;TYPE=INTERNET:ablabels-{i}@vandelay.test\r\n\
|
EMAIL;TYPE=INTERNET:ablabels-{i}@inbuxa-migrate.test\r\n\
|
||||||
ITEM1.X-ABLABEL:Name1\r\n\
|
ITEM1.X-ABLABEL:Name1\r\n\
|
||||||
ITEM2.X-ABLABEL:Name2\r\n\
|
ITEM2.X-ABLABEL:Name2\r\n\
|
||||||
ITEM1.X-ABDATE:20171111\r\n\
|
ITEM1.X-ABDATE:20171111\r\n\
|
||||||
@@ -287,9 +288,9 @@ fn ical_simple_dt(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-simple-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-simple-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T{hour:02}0000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T{hour:02}0000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T{hour:02}3000Z\r\n\
|
DTEND:2025{month:02}{day:02}T{hour:02}3000Z\r\n\
|
||||||
@@ -307,9 +308,9 @@ fn ical_all_day(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-allday-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-allday-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART;VALUE=DATE:2025{month:02}{day:02}\r\n\
|
DTSTART;VALUE=DATE:2025{month:02}{day:02}\r\n\
|
||||||
DTEND;VALUE=DATE:2025{month:02}{next_day:02}\r\n\
|
DTEND;VALUE=DATE:2025{month:02}{next_day:02}\r\n\
|
||||||
@@ -325,9 +326,9 @@ fn ical_multi_day_dt(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-multiday-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-multiday-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T090000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T090000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T170000Z\r\n\
|
DTEND:2025{month:02}{day:02}T170000Z\r\n\
|
||||||
@@ -344,16 +345,16 @@ fn ical_with_organizer_attendees(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-meeting-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-meeting-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T140000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T140000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T150000Z\r\n\
|
DTEND:2025{month:02}{day:02}T150000Z\r\n\
|
||||||
SUMMARY:Sync meeting {i}\r\n\
|
SUMMARY:Sync meeting {i}\r\n\
|
||||||
ORGANIZER;CN=Organiser:mailto:organiser-{i}@vandelay.test\r\n\
|
ORGANIZER;CN=Organiser:mailto:organiser-{i}@inbuxa-migrate.test\r\n\
|
||||||
ATTENDEE;CN=Alice;PARTSTAT=ACCEPTED:mailto:alice-{i}@vandelay.test\r\n\
|
ATTENDEE;CN=Alice;PARTSTAT=ACCEPTED:mailto:alice-{i}@inbuxa-migrate.test\r\n\
|
||||||
ATTENDEE;CN=Bob;PARTSTAT=NEEDS-ACTION:mailto:bob-{i}@vandelay.test\r\n\
|
ATTENDEE;CN=Bob;PARTSTAT=NEEDS-ACTION:mailto:bob-{i}@inbuxa-migrate.test\r\n\
|
||||||
END:VEVENT\r\n\
|
END:VEVENT\r\n\
|
||||||
END:VCALENDAR\r\n"
|
END:VCALENDAR\r\n"
|
||||||
)
|
)
|
||||||
@@ -365,15 +366,15 @@ fn ical_with_categories_location(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-cat-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-cat-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T100000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T100000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T110000Z\r\n\
|
DTEND:2025{month:02}{day:02}T110000Z\r\n\
|
||||||
SUMMARY:Categorised event {i}\r\n\
|
SUMMARY:Categorised event {i}\r\n\
|
||||||
LOCATION:Test Lab\\, Room {i}\r\n\
|
LOCATION:Test Lab\\, Room {i}\r\n\
|
||||||
CATEGORIES:VANDELAY,TEST,FIXTURE\r\n\
|
CATEGORIES:INBUXA,TEST,FIXTURE\r\n\
|
||||||
END:VEVENT\r\n\
|
END:VEVENT\r\n\
|
||||||
END:VCALENDAR\r\n"
|
END:VCALENDAR\r\n"
|
||||||
)
|
)
|
||||||
@@ -385,9 +386,9 @@ fn ical_recurring_daily(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-daily-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-daily-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T070000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T070000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T073000Z\r\n\
|
DTEND:2025{month:02}{day:02}T073000Z\r\n\
|
||||||
@@ -405,9 +406,9 @@ fn ical_recurring_weekly_until(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-weekly-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-weekly-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T160000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T160000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T170000Z\r\n\
|
DTEND:2025{month:02}{day:02}T170000Z\r\n\
|
||||||
@@ -424,9 +425,9 @@ fn ical_with_alarm(i: usize) -> String {
|
|||||||
format!(
|
format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//container-test//EN\r\n\
|
PRODID:-//inbuxa-migrate//container-test//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:vandelay-alarm-{i}@vandelay.test\r\n\
|
UID:inbuxa-migrate-alarm-{i}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:2025{month:02}{day:02}T080000Z\r\n\
|
DTSTART:2025{month:02}{day:02}T080000Z\r\n\
|
||||||
DTEND:2025{month:02}{day:02}T083000Z\r\n\
|
DTEND:2025{month:02}{day:02}T083000Z\r\n\
|
||||||
@@ -445,9 +446,9 @@ pub fn malformed_ical(name: &str) -> RawFixture {
|
|||||||
let body = format!(
|
let body = format!(
|
||||||
"BEGIN:VCALENDAR\r\n\
|
"BEGIN:VCALENDAR\r\n\
|
||||||
VERSION:2.0\r\n\
|
VERSION:2.0\r\n\
|
||||||
PRODID:-//vandelay//broken//EN\r\n\
|
PRODID:-//inbuxa-migrate//broken//EN\r\n\
|
||||||
BEGIN:VEVENT\r\n\
|
BEGIN:VEVENT\r\n\
|
||||||
UID:broken-{name}@vandelay.test\r\n\
|
UID:broken-{name}@inbuxa-migrate.test\r\n\
|
||||||
DTSTAMP:20250101T120000Z\r\n\
|
DTSTAMP:20250101T120000Z\r\n\
|
||||||
DTSTART:NOT-A-DATE\r\n\
|
DTSTART:NOT-A-DATE\r\n\
|
||||||
RRULE:FREQ=BOGUS;INTERVAL=oops\r\n\
|
RRULE:FREQ=BOGUS;INTERVAL=oops\r\n\
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -126,7 +127,7 @@ pub struct Dovecot {
|
|||||||
|
|
||||||
impl Dovecot {
|
impl Dovecot {
|
||||||
pub fn start() -> ContainerResult<Self> {
|
pub fn start() -> ContainerResult<Self> {
|
||||||
let image: GenericImage = GenericBuildableImage::new("vandelay-dovecot", "test")
|
let image: GenericImage = GenericBuildableImage::new("inbuxa-migrate-dovecot", "test")
|
||||||
.with_dockerfile_string(DOCKERFILE.to_owned())
|
.with_dockerfile_string(DOCKERFILE.to_owned())
|
||||||
.with_data(DOVECOT_CONF.as_bytes().to_vec(), "dovecot.conf")
|
.with_data(DOVECOT_CONF.as_bytes().to_vec(), "dovecot.conf")
|
||||||
.with_data(users_file().into_bytes(), "users")
|
.with_data(users_file().into_bytes(), "users")
|
||||||
@@ -374,10 +375,10 @@ impl Dovecot {
|
|||||||
) -> ContainerResult<(Vec<u8>, String)> {
|
) -> ContainerResult<(Vec<u8>, String)> {
|
||||||
let mut client = ImapSeed::connect(&self.imap.host, self.imap.port)?;
|
let mut client = ImapSeed::connect(&self.imap.host, self.imap.port)?;
|
||||||
client.login(&account.username, &account.password)?;
|
client.login(&account.username, &account.password)?;
|
||||||
let message_id = format!("<added-{tag}-{}@vandelay.test>", account.username);
|
let message_id = format!("<added-{tag}-{}@inbuxa-migrate.test>", account.username);
|
||||||
let body = format!(
|
let body = format!(
|
||||||
"From: added-{tag}@vandelay.test\r\n\
|
"From: added-{tag}@inbuxa-migrate.test\r\n\
|
||||||
To: {}@vandelay.test\r\n\
|
To: {}@inbuxa-migrate.test\r\n\
|
||||||
Subject: Added probe {tag}\r\n\
|
Subject: Added probe {tag}\r\n\
|
||||||
Message-ID: {message_id}\r\n\
|
Message-ID: {message_id}\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
@@ -446,10 +447,10 @@ fn histogram_total(h: &HashMap<String, usize>) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn flag_probe_message() -> Vec<u8> {
|
pub fn flag_probe_message() -> Vec<u8> {
|
||||||
let body = "From: probe-flags@vandelay.test\r\n\
|
let body = "From: probe-flags@inbuxa-migrate.test\r\n\
|
||||||
To: user@vandelay.test\r\n\
|
To: user@inbuxa-migrate.test\r\n\
|
||||||
Subject: Flag probe\r\n\
|
Subject: Flag probe\r\n\
|
||||||
Message-ID: <flag-probe@vandelay.test>\r\n\
|
Message-ID: <flag-probe@inbuxa-migrate.test>\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
Flag probe body.\r\n";
|
Flag probe body.\r\n";
|
||||||
@@ -457,8 +458,8 @@ pub fn flag_probe_message() -> Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn no_message_id_probe() -> Vec<u8> {
|
pub fn no_message_id_probe() -> Vec<u8> {
|
||||||
let body = "From: nomid@vandelay.test\r\n\
|
let body = "From: nomid@inbuxa-migrate.test\r\n\
|
||||||
To: user@vandelay.test\r\n\
|
To: user@inbuxa-migrate.test\r\n\
|
||||||
Subject: No Message-ID probe\r\n\
|
Subject: No Message-ID probe\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
@@ -467,10 +468,10 @@ pub fn no_message_id_probe() -> Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn shared_message_id_probe() -> Vec<u8> {
|
pub fn shared_message_id_probe() -> Vec<u8> {
|
||||||
let body = "From: shared@vandelay.test\r\n\
|
let body = "From: shared@inbuxa-migrate.test\r\n\
|
||||||
To: user@vandelay.test\r\n\
|
To: user@inbuxa-migrate.test\r\n\
|
||||||
Subject: Shared MID probe\r\n\
|
Subject: Shared MID probe\r\n\
|
||||||
Message-ID: <shared-mid@vandelay.test>\r\n\
|
Message-ID: <shared-mid@inbuxa-migrate.test>\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
Shared MID body.\r\n";
|
Shared MID body.\r\n";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -63,7 +64,7 @@ pub const ACCOUNT1: &str = "user1";
|
|||||||
pub const ACCOUNT2: &str = "user2";
|
pub const ACCOUNT2: &str = "user2";
|
||||||
pub const ACCOUNT3: &str = "user3";
|
pub const ACCOUNT3: &str = "user3";
|
||||||
|
|
||||||
pub const PASSWORD: &str = "VandelayUser#2026";
|
pub const PASSWORD: &str = "InbuxaUser#2026";
|
||||||
|
|
||||||
pub static MAILBOXES_DEEP: &[MailboxSpec] = &[
|
pub static MAILBOXES_DEEP: &[MailboxSpec] = &[
|
||||||
mailbox!("proj", "Projects", None),
|
mailbox!("proj", "Projects", None),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -22,7 +23,7 @@ pub mod webdav;
|
|||||||
|
|
||||||
pub use error::{ContainerError, ContainerResult};
|
pub use error::{ContainerError, ContainerResult};
|
||||||
|
|
||||||
pub const OWNER_LABEL: &str = "art.stalw.vandelay.itest";
|
pub const OWNER_LABEL: &str = "art.stalw.inbuxa-migrate.itest";
|
||||||
|
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -9,13 +10,13 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::CommonConfig;
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
|
|
||||||
pub fn tmp_archive(tag: &str) -> PathBuf {
|
pub fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-container-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-container-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -137,7 +138,7 @@ pub struct WebDav {
|
|||||||
|
|
||||||
impl WebDav {
|
impl WebDav {
|
||||||
pub fn start() -> ContainerResult<Self> {
|
pub fn start() -> ContainerResult<Self> {
|
||||||
let image: GenericImage = GenericBuildableImage::new("vandelay-webdav", "test")
|
let image: GenericImage = GenericBuildableImage::new("inbuxa-migrate-webdav", "test")
|
||||||
.with_dockerfile_string(DOCKERFILE.to_owned())
|
.with_dockerfile_string(DOCKERFILE.to_owned())
|
||||||
.with_data(APACHE_CONF.as_bytes().to_vec(), "apache.conf")
|
.with_data(APACHE_CONF.as_bytes().to_vec(), "apache.conf")
|
||||||
.with_data(htpasswd_for_test().into_bytes(), "htpasswd")
|
.with_data(htpasswd_for_test().into_bytes(), "htpasswd")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -16,11 +17,11 @@ use integration::validate::{
|
|||||||
contact_card_count, count, open_archive, tmp_archive,
|
contact_card_count, count, open_archive, tmp_archive,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use inbuxa_migrate::error::Error;
|
||||||
|
use inbuxa_migrate::sync::import_dav;
|
||||||
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use vandelay::error::Error;
|
|
||||||
use vandelay::sync::import_dav;
|
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
|
||||||
|
|
||||||
fn dav_config(kind: DavKindArg, account: &Account, dav_root: &str) -> DavImportConfig {
|
fn dav_config(kind: DavKindArg, account: &Account, dav_root: &str) -> DavImportConfig {
|
||||||
let path = match kind {
|
let path = match kind {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -16,9 +17,9 @@ use integration::validate::{
|
|||||||
};
|
};
|
||||||
use integration::{Account, Endpoint};
|
use integration::{Account, Endpoint};
|
||||||
|
|
||||||
use vandelay::error::Error;
|
use inbuxa_migrate::error::Error;
|
||||||
use vandelay::sync::import_imap;
|
use inbuxa_migrate::sync::import_imap;
|
||||||
use vandelay::sync::import_imap::{ImapAuth, ImapImportConfig};
|
use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig};
|
||||||
|
|
||||||
fn imap_config(account: &Account, imap: &Endpoint) -> ImapImportConfig {
|
fn imap_config(account: &Account, imap: &Endpoint) -> ImapImportConfig {
|
||||||
ImapImportConfig {
|
ImapImportConfig {
|
||||||
@@ -327,10 +328,10 @@ fn cyrus_non_ascii_mailbox_names_round_trip() {
|
|||||||
|
|
||||||
let mutf7_name = "Envoy&AOk-s";
|
let mutf7_name = "Envoy&AOk-s";
|
||||||
let utf8_name = "Envoyés";
|
let utf8_name = "Envoyés";
|
||||||
let message = b"From: accents@vandelay.test\r\n\
|
let message = b"From: accents@inbuxa-migrate.test\r\n\
|
||||||
To: user1@vandelay.test\r\n\
|
To: user1@inbuxa-migrate.test\r\n\
|
||||||
Subject: Accents\r\n\
|
Subject: Accents\r\n\
|
||||||
Message-ID: <accents-1@vandelay.test>\r\n\
|
Message-ID: <accents-1@inbuxa-migrate.test>\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
Accented folder probe.\r\n";
|
Accented folder probe.\r\n";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -16,14 +17,14 @@ use integration::validate::{
|
|||||||
mailbox_id_by_path, mailbox_path, open_archive, tmp_archive,
|
mailbox_id_by_path, mailbox_path, open_archive, tmp_archive,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use inbuxa_migrate::error::Error;
|
||||||
|
use inbuxa_migrate::imap::client::{ConnectMode, ImapClient};
|
||||||
|
use inbuxa_migrate::imap::transport::Connector;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig};
|
||||||
|
use inbuxa_migrate::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig};
|
||||||
|
use inbuxa_migrate::sync::{import_imap, import_managesieve};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::error::Error;
|
|
||||||
use vandelay::imap::client::{ConnectMode, ImapClient};
|
|
||||||
use vandelay::imap::transport::Connector;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::import_imap::{ImapAuth, ImapImportConfig};
|
|
||||||
use vandelay::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig};
|
|
||||||
use vandelay::sync::{import_imap, import_managesieve};
|
|
||||||
|
|
||||||
fn imap_config(account: &Account, imap: &integration::Endpoint) -> ImapImportConfig {
|
fn imap_config(account: &Account, imap: &integration::Endpoint) -> ImapImportConfig {
|
||||||
ImapImportConfig {
|
ImapImportConfig {
|
||||||
@@ -526,10 +527,10 @@ fn dovecot_non_ascii_mailbox_names_round_trip() {
|
|||||||
|
|
||||||
let mutf7_name = "Envoy&AOk-s";
|
let mutf7_name = "Envoy&AOk-s";
|
||||||
let utf8_name = "Envoyés";
|
let utf8_name = "Envoyés";
|
||||||
let message = b"From: accents@vandelay.test\r\n\
|
let message = b"From: accents@inbuxa-migrate.test\r\n\
|
||||||
To: user1@vandelay.test\r\n\
|
To: user1@inbuxa-migrate.test\r\n\
|
||||||
Subject: Accents\r\n\
|
Subject: Accents\r\n\
|
||||||
Message-ID: <accents-1@vandelay.test>\r\n\
|
Message-ID: <accents-1@inbuxa-migrate.test>\r\n\
|
||||||
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
Accented folder probe.\r\n";
|
Accented folder probe.\r\n";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -16,11 +17,11 @@ use integration::validate::{
|
|||||||
};
|
};
|
||||||
use integration::{Account, Endpoint};
|
use integration::{Account, Endpoint};
|
||||||
|
|
||||||
|
use inbuxa_migrate::error::Error;
|
||||||
|
use inbuxa_migrate::sync::import_dav;
|
||||||
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use vandelay::error::Error;
|
|
||||||
use vandelay::sync::import_dav;
|
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
|
||||||
|
|
||||||
fn dav_config(kind: DavKindArg, account: &Account, http: &Endpoint) -> DavImportConfig {
|
fn dav_config(kind: DavKindArg, account: &Account, http: &Endpoint) -> DavImportConfig {
|
||||||
DavImportConfig {
|
DavImportConfig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -15,9 +16,9 @@ use integration::validate::{
|
|||||||
use integration::webdav::{AccountSeed, WebDav};
|
use integration::webdav::{AccountSeed, WebDav};
|
||||||
use integration::{Account, Endpoint};
|
use integration::{Account, Endpoint};
|
||||||
|
|
||||||
use vandelay::error::Error;
|
use inbuxa_migrate::error::Error;
|
||||||
use vandelay::sync::import_dav;
|
use inbuxa_migrate::sync::import_dav;
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
||||||
|
|
||||||
fn webdav_config(account: &Account, http: &Endpoint) -> DavImportConfig {
|
fn webdav_config(account: &Account, http: &Endpoint) -> DavImportConfig {
|
||||||
DavImportConfig {
|
DavImportConfig {
|
||||||
@@ -319,7 +320,7 @@ fn webdav_starts_seeds_and_imports() {
|
|||||||
drop(conn);
|
drop(conn);
|
||||||
|
|
||||||
let new_payload = format!(
|
let new_payload = format!(
|
||||||
"added-{} content for vandelay webdav add-after-import probe\n",
|
"added-{} content for inbuxa-migrate webdav add-after-import probe\n",
|
||||||
seed.username
|
seed.username
|
||||||
);
|
);
|
||||||
let new_payload_bytes = new_payload.as_bytes().to_vec();
|
let new_payload_bytes = new_payload.as_bytes().to_vec();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -7,10 +8,10 @@
|
|||||||
mod integration;
|
mod integration;
|
||||||
mod seeder;
|
mod seeder;
|
||||||
|
|
||||||
|
use inbuxa_migrate::jmap::account::{self, AccountSelector};
|
||||||
|
use inbuxa_migrate::jmap::http::{Auth, HttpClient, RetryPolicy};
|
||||||
|
use inbuxa_migrate::jmap::session::Session;
|
||||||
use integration::stalwart::shared as shared_stalwart;
|
use integration::stalwart::shared as shared_stalwart;
|
||||||
use vandelay::jmap::account::{self, AccountSelector};
|
|
||||||
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
|
|
||||||
use vandelay::jmap::session::Session;
|
|
||||||
|
|
||||||
fn admin_client() -> HttpClient {
|
fn admin_client() -> HttpClient {
|
||||||
HttpClient::new(
|
HttpClient::new(
|
||||||
|
|||||||
+66
-51
@@ -1,17 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use vandelay::dav::client::DavClient;
|
use inbuxa_migrate::dav::client::DavClient;
|
||||||
use vandelay::dav::discover::{DavKind, discover};
|
use inbuxa_migrate::dav::discover::{DavKind, discover};
|
||||||
use vandelay::dav::parse::{parse_multistatus, strip_ascii_control_chars};
|
use inbuxa_migrate::dav::parse::{parse_multistatus, strip_ascii_control_chars};
|
||||||
use vandelay::dav::xml;
|
use inbuxa_migrate::dav::xml;
|
||||||
use vandelay::jmap::error::JmapError;
|
use inbuxa_migrate::jmap::error::JmapError;
|
||||||
use vandelay::jmap::http::{Auth, RetryPolicy};
|
use inbuxa_migrate::jmap::http::{Auth, RetryPolicy};
|
||||||
|
|
||||||
fn client(retries: u32) -> DavClient {
|
fn client(retries: u32) -> DavClient {
|
||||||
DavClient::new(
|
DavClient::new(
|
||||||
@@ -75,7 +76,7 @@ fn discovery_resolves_per_user_principal_even_when_url_lists_collections() {
|
|||||||
r#"<?xml version="1.0"?>
|
r#"<?xml version="1.0"?>
|
||||||
<d:multistatus xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
|
<d:multistatus xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
|
||||||
<d:response>
|
<d:response>
|
||||||
<d:href>{url}/dav/cal/secondary@vandelay.org/default/</d:href>
|
<d:href>{url}/dav/cal/secondary@inbuxa-migrate.org/default/</d:href>
|
||||||
<d:propstat>
|
<d:propstat>
|
||||||
<d:prop>
|
<d:prop>
|
||||||
<d:resourcetype><d:collection/><c:calendar/></d:resourcetype>
|
<d:resourcetype><d:collection/><c:calendar/></d:resourcetype>
|
||||||
@@ -101,7 +102,7 @@ fn discovery_resolves_per_user_principal_even_when_url_lists_collections() {
|
|||||||
<d:href>{url}/dav/cal/</d:href>
|
<d:href>{url}/dav/cal/</d:href>
|
||||||
<d:propstat>
|
<d:propstat>
|
||||||
<d:prop>
|
<d:prop>
|
||||||
<d:current-user-principal><d:href>{url}/dav/principals/secondary@vandelay.org/</d:href></d:current-user-principal>
|
<d:current-user-principal><d:href>{url}/dav/principals/secondary@inbuxa-migrate.org/</d:href></d:current-user-principal>
|
||||||
</d:prop>
|
</d:prop>
|
||||||
<d:status>HTTP/1.1 200 OK</d:status>
|
<d:status>HTTP/1.1 200 OK</d:status>
|
||||||
</d:propstat>
|
</d:propstat>
|
||||||
@@ -121,7 +122,7 @@ fn discovery_resolves_per_user_principal_even_when_url_lists_collections() {
|
|||||||
assert_eq!(disc.collections.len(), 1);
|
assert_eq!(disc.collections.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
disc.principal_url.as_deref(),
|
disc.principal_url.as_deref(),
|
||||||
Some(format!("{url}/dav/principals/secondary@vandelay.org/").as_str()),
|
Some(format!("{url}/dav/principals/secondary@inbuxa-migrate.org/").as_str()),
|
||||||
"account identity must be the per-user principal, not the shared base DAV root"
|
"account identity must be the per-user principal, not the shared base DAV root"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -212,7 +213,7 @@ fn discovery_returns_not_found_when_no_collections() {
|
|||||||
let err = discover(&c, DavKind::Caldav, &server.url()).unwrap_err();
|
let err = discover(&c, DavKind::Caldav, &server.url()).unwrap_err();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
err,
|
err,
|
||||||
vandelay::dav::discover::DiscoveryError::NotFound { .. }
|
inbuxa_migrate::dav::discover::DiscoveryError::NotFound { .. }
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,14 +490,14 @@ fn webdav_listing_returns_collection_and_file() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn google_usage_limits_403_classified_retryable() {
|
fn google_usage_limits_403_classified_retryable() {
|
||||||
use vandelay::dav::retry::{DavOutcome, classify};
|
use inbuxa_migrate::dav::retry::{DavOutcome, classify};
|
||||||
let body = br#"{"error":{"errors":[{"domain":"usageLimits"}]}}"#;
|
let body = br#"{"error":{"errors":[{"domain":"usageLimits"}]}}"#;
|
||||||
assert_eq!(classify(403, body), DavOutcome::Retryable);
|
assert_eq!(classify(403, body), DavOutcome::Retryable);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn non_quota_403_is_auth() {
|
fn non_quota_403_is_auth() {
|
||||||
use vandelay::dav::retry::{DavOutcome, classify};
|
use inbuxa_migrate::dav::retry::{DavOutcome, classify};
|
||||||
assert_eq!(classify(403, b"forbidden"), DavOutcome::Auth);
|
assert_eq!(classify(403, b"forbidden"), DavOutcome::Auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,7 +802,7 @@ fn webdav_cycle_breaks_on_lex_smallest() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multiget_405_method_not_allowed_triggers_get_fallback() {
|
fn multiget_405_method_not_allowed_triggers_get_fallback() {
|
||||||
use vandelay::dav::retry::{DavOutcome, classify};
|
use inbuxa_migrate::dav::retry::{DavOutcome, classify};
|
||||||
assert_eq!(classify(405, b""), DavOutcome::Fatal);
|
assert_eq!(classify(405, b""), DavOutcome::Fatal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,8 +894,8 @@ fn streaming_propfind_404_returns_empty_responses() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn source_change_protection_rejects_different_account_id() {
|
fn source_change_protection_rejects_different_account_id() {
|
||||||
|
use inbuxa_migrate::db::{init, sources};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::db::{init, sources};
|
|
||||||
|
|
||||||
let conn = Connection::open_in_memory().unwrap();
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
init::apply_schema(&conn).unwrap();
|
init::apply_schema(&conn).unwrap();
|
||||||
@@ -1049,15 +1050,15 @@ fn webdav_discovery_keeps_only_self_row_as_root() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn webdav_root_collection_is_not_materialised_children_map_to_target_root() {
|
fn webdav_root_collection_is_not_materialised_children_map_to_target_root() {
|
||||||
|
use inbuxa_migrate::dav::discover::DiscoveredCollection;
|
||||||
|
use inbuxa_migrate::dav::href::Href;
|
||||||
|
use inbuxa_migrate::dav::parse::ResourceProps;
|
||||||
|
use inbuxa_migrate::db;
|
||||||
|
use inbuxa_migrate::db::sources::SourceKey;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::TypeCounts;
|
||||||
|
use inbuxa_migrate::sync::import_dav::tree::{WebDavCtx, reconcile_filenodes};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::dav::discover::DiscoveredCollection;
|
|
||||||
use vandelay::dav::href::Href;
|
|
||||||
use vandelay::dav::parse::ResourceProps;
|
|
||||||
use vandelay::db;
|
|
||||||
use vandelay::db::sources::SourceKey;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::TypeCounts;
|
|
||||||
use vandelay::sync::import_dav::tree::{WebDavCtx, reconcile_filenodes};
|
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let url = server.url();
|
let url = server.url();
|
||||||
@@ -1336,10 +1337,10 @@ fn webdav_display_or_basename_test_via_parser_keeps_basename_semantics() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dry_run_writes_nothing_but_emits_per_collection_counts() {
|
fn dry_run_writes_nothing_but_emits_per_collection_counts() {
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg, run};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::CommonConfig;
|
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg, run};
|
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let url = server.url();
|
let url = server.url();
|
||||||
@@ -1381,7 +1382,7 @@ fn dry_run_writes_nothing_but_emits_per_collection_counts() {
|
|||||||
let _items = multistatus_response(&mut server, "PROPFIND", "/dav/cal/u/default/", &items_body);
|
let _items = multistatus_response(&mut server, "PROPFIND", "/dav/cal/u/default/", &items_body);
|
||||||
|
|
||||||
let archive: PathBuf = std::env::temp_dir().join(format!(
|
let archive: PathBuf = std::env::temp_dir().join(format!(
|
||||||
"vandelay-dryrun-{}-{}.sqlite",
|
"inbuxa-migrate-dryrun-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -1449,10 +1450,10 @@ fn dry_run_writes_nothing_but_emits_per_collection_counts() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn dav_source_change_protection_fires_across_users_on_same_root() {
|
fn dav_source_change_protection_fires_across_users_on_same_root() {
|
||||||
use encodify::base64::STANDARD;
|
use encodify::base64::STANDARD;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg, run};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::CommonConfig;
|
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg, run};
|
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let url = server.url();
|
let url = server.url();
|
||||||
@@ -1499,8 +1500,14 @@ fn dav_source_change_protection_fires_across_users_on_same_root() {
|
|||||||
.with_body(&empty_items)
|
.with_body(&empty_items)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let auth_a = format!("Basic {}", STANDARD.encode("[email protected]:passA"));
|
let auth_a = format!(
|
||||||
let auth_b = format!("Basic {}", STANDARD.encode("[email protected]:passB"));
|
"Basic {}",
|
||||||
|
STANDARD.encode("[email protected]:passA")
|
||||||
|
);
|
||||||
|
let auth_b = format!(
|
||||||
|
"Basic {}",
|
||||||
|
STANDARD.encode("[email protected]:passB")
|
||||||
|
);
|
||||||
let principal = |who: &str| {
|
let principal = |who: &str| {
|
||||||
format!(
|
format!(
|
||||||
r#"<?xml version="1.0"?>
|
r#"<?xml version="1.0"?>
|
||||||
@@ -1521,7 +1528,7 @@ fn dav_source_change_protection_fires_across_users_on_same_root() {
|
|||||||
.match_header("authorization", auth_a.as_str())
|
.match_header("authorization", auth_a.as_str())
|
||||||
.with_status(207)
|
.with_status(207)
|
||||||
.with_header("content-type", "application/xml; charset=utf-8")
|
.with_header("content-type", "application/xml; charset=utf-8")
|
||||||
.with_body(principal("secondary@vandelay.org"))
|
.with_body(principal("secondary@inbuxa-migrate.org"))
|
||||||
.create();
|
.create();
|
||||||
let _pb = server
|
let _pb = server
|
||||||
.mock("PROPFIND", "/dav/cal/")
|
.mock("PROPFIND", "/dav/cal/")
|
||||||
@@ -1529,11 +1536,11 @@ fn dav_source_change_protection_fires_across_users_on_same_root() {
|
|||||||
.match_header("authorization", auth_b.as_str())
|
.match_header("authorization", auth_b.as_str())
|
||||||
.with_status(207)
|
.with_status(207)
|
||||||
.with_header("content-type", "application/xml; charset=utf-8")
|
.with_header("content-type", "application/xml; charset=utf-8")
|
||||||
.with_body(principal("tertiary@vandelay.org"))
|
.with_body(principal("tertiary@inbuxa-migrate.org"))
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let archive: PathBuf = std::env::temp_dir().join(format!(
|
let archive: PathBuf = std::env::temp_dir().join(format!(
|
||||||
"vandelay-dav-srcchange-{}-{}.sqlite",
|
"inbuxa-migrate-dav-srcchange-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -1563,19 +1570,27 @@ fn dav_source_change_protection_fires_across_users_on_same_root() {
|
|||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
run(common(&archive), config("[email protected]", "passA")).expect("user A import ok");
|
run(
|
||||||
let err = run(common(&archive), config("[email protected]", "passB")).unwrap_err();
|
common(&archive),
|
||||||
|
config("[email protected]", "passA"),
|
||||||
|
)
|
||||||
|
.expect("user A import ok");
|
||||||
|
let err = run(
|
||||||
|
common(&archive),
|
||||||
|
config("[email protected]", "passB"),
|
||||||
|
)
|
||||||
|
.unwrap_err();
|
||||||
let _ = std::fs::remove_file(&archive);
|
let _ = std::fs::remove_file(&archive);
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, vandelay::error::Error::SourceChange(_)),
|
matches!(err, inbuxa_migrate::error::Error::SourceChange(_)),
|
||||||
"importing a different user into the same archive must trigger source-change protection; got {err:?}"
|
"importing a different user into the same archive must trigger source-change protection; got {err:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn source_change_protection_rejects_different_session_url_same_account() {
|
fn source_change_protection_rejects_different_session_url_same_account() {
|
||||||
|
use inbuxa_migrate::db::{init, sources};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::db::{init, sources};
|
|
||||||
|
|
||||||
let conn = Connection::open_in_memory().unwrap();
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
init::apply_schema(&conn).unwrap();
|
init::apply_schema(&conn).unwrap();
|
||||||
@@ -1627,8 +1642,8 @@ fn etag_missing_in_enumeration_propagates_to_storage_layer() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mixed_source_archive_allows_distinct_kinds_against_same_url() {
|
fn mixed_source_archive_allows_distinct_kinds_against_same_url() {
|
||||||
|
use inbuxa_migrate::db::{init, sources};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::db::{init, sources};
|
|
||||||
|
|
||||||
let conn = Connection::open_in_memory().unwrap();
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
init::apply_schema(&conn).unwrap();
|
init::apply_schema(&conn).unwrap();
|
||||||
@@ -1663,7 +1678,7 @@ fn dav_archive() -> std::path::PathBuf {
|
|||||||
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-mockdav-{}-{:?}-{n}.sqlite",
|
"inbuxa-migrate-mockdav-{}-{:?}-{n}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::thread::current().id(),
|
std::thread::current().id(),
|
||||||
));
|
));
|
||||||
@@ -1671,11 +1686,11 @@ fn dav_archive() -> std::path::PathBuf {
|
|||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
fn caldav_import_config(url: &str) -> vandelay::sync::import_dav::DavImportConfig {
|
fn caldav_import_config(url: &str) -> inbuxa_migrate::sync::import_dav::DavImportConfig {
|
||||||
vandelay::sync::import_dav::DavImportConfig {
|
inbuxa_migrate::sync::import_dav::DavImportConfig {
|
||||||
kind: vandelay::sync::import_dav::DavKindArg::Caldav,
|
kind: inbuxa_migrate::sync::import_dav::DavKindArg::Caldav,
|
||||||
url: url.to_owned(),
|
url: url.to_owned(),
|
||||||
auth: vandelay::sync::import_dav::DavAuth::Basic {
|
auth: inbuxa_migrate::sync::import_dav::DavAuth::Basic {
|
||||||
user: "u".to_owned(),
|
user: "u".to_owned(),
|
||||||
password: "p".to_owned(),
|
password: "p".to_owned(),
|
||||||
},
|
},
|
||||||
@@ -1686,14 +1701,14 @@ fn caldav_import_config(url: &str) -> vandelay::sync::import_dav::DavImportConfi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dav_common(archive: &std::path::Path) -> vandelay::sync::CommonConfig {
|
fn dav_common(archive: &std::path::Path) -> inbuxa_migrate::sync::CommonConfig {
|
||||||
vandelay::sync::CommonConfig {
|
inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.to_path_buf(),
|
archive: archive.to_path_buf(),
|
||||||
threads: 1,
|
threads: 1,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::from_flags(true, 0),
|
logger: inbuxa_migrate::logging::Logger::from_flags(true, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1788,7 +1803,7 @@ END:VCALENDAR
|
|||||||
.create();
|
.create();
|
||||||
|
|
||||||
let archive = dav_archive();
|
let archive = dav_archive();
|
||||||
let summary = vandelay::sync::import_dav::run(
|
let summary = inbuxa_migrate::sync::import_dav::run(
|
||||||
dav_common(&archive),
|
dav_common(&archive),
|
||||||
caldav_import_config(&format!("{url}/dav/cal/u/")),
|
caldav_import_config(&format!("{url}/dav/cal/u/")),
|
||||||
)
|
)
|
||||||
@@ -1828,14 +1843,14 @@ fn credentials_rejected_during_discovery_still_aborts_the_run() {
|
|||||||
.create();
|
.create();
|
||||||
|
|
||||||
let archive = dav_archive();
|
let archive = dav_archive();
|
||||||
let err = vandelay::sync::import_dav::run(
|
let err = inbuxa_migrate::sync::import_dav::run(
|
||||||
dav_common(&archive),
|
dav_common(&archive),
|
||||||
caldav_import_config(&format!("{url}/dav/cal/u/")),
|
caldav_import_config(&format!("{url}/dav/cal/u/")),
|
||||||
)
|
)
|
||||||
.expect_err("credentials rejected for the principal aborts the run");
|
.expect_err("credentials rejected for the principal aborts the run");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, vandelay::error::Error::Connection(_)),
|
matches!(err, inbuxa_migrate::error::Error::Connection(_)),
|
||||||
"discovery-level auth rejection is a whole-run failure, got {err:?}"
|
"discovery-level auth rejection is a whole-run failure, got {err:?}"
|
||||||
);
|
);
|
||||||
assert_eq!(err.exit_code(), 2);
|
assert_eq!(err.exit_code(), 2);
|
||||||
@@ -1871,7 +1886,7 @@ fn dav_import_reports_both_phases_when_every_collection_fails() {
|
|||||||
.create();
|
.create();
|
||||||
|
|
||||||
let archive = dav_archive();
|
let archive = dav_archive();
|
||||||
let outcome = vandelay::sync::import_dav::run_reporting(
|
let outcome = inbuxa_migrate::sync::import_dav::run_reporting(
|
||||||
dav_common(&archive),
|
dav_common(&archive),
|
||||||
caldav_import_config(&format!("{url}/dav/cal/u/")),
|
caldav_import_config(&format!("{url}/dav/cal/u/")),
|
||||||
);
|
);
|
||||||
|
|||||||
+40
-37
@@ -1,25 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use encodify::base64::{LENIENT, STANDARD};
|
use encodify::base64::{LENIENT, STANDARD};
|
||||||
use mockito::Matcher;
|
use inbuxa_migrate::exchange_ews::EwsClient;
|
||||||
use vandelay::exchange_ews::EwsClient;
|
use inbuxa_migrate::exchange_ews::autodiscover::{DiscoverySource, discover};
|
||||||
use vandelay::exchange_ews::autodiscover::{DiscoverySource, discover};
|
use inbuxa_migrate::exchange_ews::error::EwsError;
|
||||||
use vandelay::exchange_ews::error::EwsError;
|
use inbuxa_migrate::exchange_ews::parse::{
|
||||||
use vandelay::exchange_ews::parse::{
|
|
||||||
EnvelopeKind, parse_find_folder_response, parse_find_item_response,
|
EnvelopeKind, parse_find_folder_response, parse_find_item_response,
|
||||||
parse_get_attachment_inline, parse_response_messages, parse_sync_folder_items_response,
|
parse_get_attachment_inline, parse_response_messages, parse_sync_folder_items_response,
|
||||||
read_envelope_summary,
|
read_envelope_summary,
|
||||||
};
|
};
|
||||||
use vandelay::exchange_ews::types::{FolderClass, FolderId, ItemId, ResponseCode, ServerVersion};
|
use inbuxa_migrate::exchange_ews::types::{
|
||||||
use vandelay::exchange_ews::xml::{
|
FolderClass, FolderId, ItemId, ResponseCode, ServerVersion,
|
||||||
|
};
|
||||||
|
use inbuxa_migrate::exchange_ews::xml::{
|
||||||
FolderRef, ItemShape, Traversal, find_folder_body, find_item_body, get_attachment_body,
|
FolderRef, ItemShape, Traversal, find_folder_body, find_item_body, get_attachment_body,
|
||||||
get_item_body, sync_folder_items_body,
|
get_item_body, sync_folder_items_body,
|
||||||
};
|
};
|
||||||
use vandelay::jmap::http::{Auth, RetryPolicy};
|
use inbuxa_migrate::jmap::http::{Auth, RetryPolicy};
|
||||||
|
use mockito::Matcher;
|
||||||
|
|
||||||
const TXT_XML: &str = "text/xml; charset=utf-8";
|
const TXT_XML: &str = "text/xml; charset=utf-8";
|
||||||
const APP_JSON: &str = "application/json";
|
const APP_JSON: &str = "application/json";
|
||||||
@@ -59,7 +62,7 @@ fn autodiscover_v2_returns_global_endpoint() {
|
|||||||
.create();
|
.create();
|
||||||
let _ = server;
|
let _ = server;
|
||||||
let url = "https://outlook.office365.com/EWS/Exchange.asmx";
|
let url = "https://outlook.office365.com/EWS/Exchange.asmx";
|
||||||
assert!(vandelay::exchange_ews::autodiscover::is_fully_qualified_ews_url(url));
|
assert!(inbuxa_migrate::exchange_ews::autodiscover::is_fully_qualified_ews_url(url));
|
||||||
let r = discover(Some(url), None, None, false).unwrap();
|
let r = discover(Some(url), None, None, false).unwrap();
|
||||||
assert_eq!(r.source, DiscoverySource::SuppliedUrl);
|
assert_eq!(r.source, DiscoverySource::SuppliedUrl);
|
||||||
assert_eq!(r.ews_url, url);
|
assert_eq!(r.ews_url, url);
|
||||||
@@ -265,7 +268,7 @@ fn server_busy_with_back_off_triggers_retry_and_eventually_succeeds() {
|
|||||||
let c = client(3);
|
let c = client(3);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -290,7 +293,7 @@ fn http_401_surfaces_as_auth_error() {
|
|||||||
let c = client(0);
|
let c = client(0);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -313,7 +316,7 @@ fn mime_content_round_trips_through_base64_decode() {
|
|||||||
</m:ResponseMessages></m:GetItemResponse>"
|
</m:ResponseMessages></m:GetItemResponse>"
|
||||||
));
|
));
|
||||||
let r = parse_response_messages(body.as_bytes(), "GetItemResponseMessage").unwrap();
|
let r = parse_response_messages(body.as_bytes(), "GetItemResponseMessage").unwrap();
|
||||||
let item = vandelay::exchange_ews::parse::parse_message_item(&r[0].inner_xml).unwrap();
|
let item = inbuxa_migrate::exchange_ews::parse::parse_message_item(&r[0].inner_xml).unwrap();
|
||||||
let s = item.mime_content.unwrap();
|
let s = item.mime_content.unwrap();
|
||||||
let bytes = LENIENT.decode(&s).unwrap();
|
let bytes = LENIENT.decode(&s).unwrap();
|
||||||
assert_eq!(bytes, original);
|
assert_eq!(bytes, original);
|
||||||
@@ -341,7 +344,7 @@ fn get_attachment_inline_decodes_photo_blob() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn calendar_item_master_inlines_modified_and_deleted_occurrences() {
|
fn calendar_item_master_inlines_modified_and_deleted_occurrences() {
|
||||||
let body = "<vandelay-inner xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">\
|
let body = "<inbuxa-migrate-inner xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">\
|
||||||
<t:CalendarItem>\
|
<t:CalendarItem>\
|
||||||
<t:ItemId Id=\"M1\" ChangeKey=\"K1\"/>\
|
<t:ItemId Id=\"M1\" ChangeKey=\"K1\"/>\
|
||||||
<t:Subject>Daily</t:Subject>\
|
<t:Subject>Daily</t:Subject>\
|
||||||
@@ -359,8 +362,8 @@ fn calendar_item_master_inlines_modified_and_deleted_occurrences() {
|
|||||||
<t:DeletedOccurrences>\
|
<t:DeletedOccurrences>\
|
||||||
<t:DeletedOccurrence><t:Start>2025-06-17T14:00:00Z</t:Start></t:DeletedOccurrence>\
|
<t:DeletedOccurrence><t:Start>2025-06-17T14:00:00Z</t:Start></t:DeletedOccurrence>\
|
||||||
</t:DeletedOccurrences>\
|
</t:DeletedOccurrences>\
|
||||||
</t:CalendarItem></vandelay-inner>";
|
</t:CalendarItem></inbuxa-migrate-inner>";
|
||||||
let item = vandelay::exchange_ews::parse::parse_calendar_item(body).unwrap();
|
let item = inbuxa_migrate::exchange_ews::parse::parse_calendar_item(body).unwrap();
|
||||||
assert_eq!(item.id.id, "M1");
|
assert_eq!(item.id.id, "M1");
|
||||||
assert_eq!(item.uid.as_deref(), Some("uid-1"));
|
assert_eq!(item.uid.as_deref(), Some("uid-1"));
|
||||||
assert_eq!(item.modified_occurrences.len(), 1);
|
assert_eq!(item.modified_occurrences.len(), 1);
|
||||||
@@ -373,7 +376,7 @@ fn calendar_item_master_inlines_modified_and_deleted_occurrences() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
|
fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
|
||||||
let body = "<vandelay-inner xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">\
|
let body = "<inbuxa-migrate-inner xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">\
|
||||||
<t:CalendarItem>\
|
<t:CalendarItem>\
|
||||||
<t:ItemId Id=\"M3\" ChangeKey=\"K1\"/>\
|
<t:ItemId Id=\"M3\" ChangeKey=\"K1\"/>\
|
||||||
<t:Subject>Review</t:Subject>\
|
<t:Subject>Review</t:Subject>\
|
||||||
@@ -386,9 +389,9 @@ fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
|
|||||||
<t:RequiredAttendees><t:Attendee><t:Mailbox><t:Name>Kristina Morgental</t:Name>\
|
<t:RequiredAttendees><t:Attendee><t:Mailbox><t:Name>Kristina Morgental</t:Name>\
|
||||||
<t:EmailAddress>/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=bdc77b18152647a29d28ce1188376dc9-kristina</t:EmailAddress>\
|
<t:EmailAddress>/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=bdc77b18152647a29d28ce1188376dc9-kristina</t:EmailAddress>\
|
||||||
<t:RoutingType>EX</t:RoutingType></t:Mailbox><t:ResponseType>Unknown</t:ResponseType></t:Attendee></t:RequiredAttendees>\
|
<t:RoutingType>EX</t:RoutingType></t:Mailbox><t:ResponseType>Unknown</t:ResponseType></t:Attendee></t:RequiredAttendees>\
|
||||||
</t:CalendarItem></vandelay-inner>";
|
</t:CalendarItem></inbuxa-migrate-inner>";
|
||||||
let item = vandelay::exchange_ews::parse::parse_calendar_item(body).unwrap();
|
let item = inbuxa_migrate::exchange_ews::parse::parse_calendar_item(body).unwrap();
|
||||||
let event = vandelay::exchange_ews::calendar_map::to_jscalendar(&item);
|
let event = inbuxa_migrate::exchange_ews::calendar_map::to_jscalendar(&item);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
event.data["organizerCalendarAddress"], "mailto:[email protected]",
|
event.data["organizerCalendarAddress"], "mailto:[email protected]",
|
||||||
@@ -409,7 +412,7 @@ fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
|
|||||||
attendee["calendarAddress"]
|
attendee["calendarAddress"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.starts_with("urn:x-vandelay:attendee:"),
|
.starts_with("urn:x-inbuxa-migrate:attendee:"),
|
||||||
"a legacy directory reference cannot be resolved and stays synthetic"
|
"a legacy directory reference cannot be resolved and stays synthetic"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -420,7 +423,7 @@ fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recurrence_end_date_with_a_timezone_offset_yields_a_bounded_series() {
|
fn recurrence_end_date_with_a_timezone_offset_yields_a_bounded_series() {
|
||||||
let body = "<vandelay-inner xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">\
|
let body = "<inbuxa-migrate-inner xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">\
|
||||||
<t:CalendarItem>\
|
<t:CalendarItem>\
|
||||||
<t:ItemId Id=\"M2\" ChangeKey=\"K1\"/>\
|
<t:ItemId Id=\"M2\" ChangeKey=\"K1\"/>\
|
||||||
<t:Subject>Biweekly</t:Subject>\
|
<t:Subject>Biweekly</t:Subject>\
|
||||||
@@ -432,9 +435,9 @@ fn recurrence_end_date_with_a_timezone_offset_yields_a_bounded_series() {
|
|||||||
<t:WeeklyRecurrence><t:Interval>2</t:Interval><t:DaysOfWeek>Wednesday</t:DaysOfWeek></t:WeeklyRecurrence>\
|
<t:WeeklyRecurrence><t:Interval>2</t:Interval><t:DaysOfWeek>Wednesday</t:DaysOfWeek></t:WeeklyRecurrence>\
|
||||||
<t:EndDateRecurrence><t:StartDate>2021-08-04-06:00</t:StartDate><t:EndDate>2021-09-30-06:00</t:EndDate></t:EndDateRecurrence>\
|
<t:EndDateRecurrence><t:StartDate>2021-08-04-06:00</t:StartDate><t:EndDate>2021-09-30-06:00</t:EndDate></t:EndDateRecurrence>\
|
||||||
</t:Recurrence>\
|
</t:Recurrence>\
|
||||||
</t:CalendarItem></vandelay-inner>";
|
</t:CalendarItem></inbuxa-migrate-inner>";
|
||||||
let item = vandelay::exchange_ews::parse::parse_calendar_item(body).unwrap();
|
let item = inbuxa_migrate::exchange_ews::parse::parse_calendar_item(body).unwrap();
|
||||||
let event = vandelay::exchange_ews::calendar_map::to_jscalendar(&item);
|
let event = inbuxa_migrate::exchange_ews::calendar_map::to_jscalendar(&item);
|
||||||
let rule = &event.data["recurrenceRule"];
|
let rule = &event.data["recurrenceRule"];
|
||||||
assert_eq!(rule["frequency"], "weekly");
|
assert_eq!(rule["frequency"], "weekly");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -486,8 +489,8 @@ fn invalid_sync_state_data_fault_is_surfaced() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn coordinator_diff_classifies_new_vanished_changed_unchanged() {
|
fn coordinator_diff_classifies_new_vanished_changed_unchanged() {
|
||||||
use vandelay::db::exchange_ews_ids::ItemRow;
|
use inbuxa_migrate::db::exchange_ews_ids::ItemRow;
|
||||||
use vandelay::sync::import_exchange_ews::items::{EnumeratedItem, diff};
|
use inbuxa_migrate::sync::import_exchange_ews::items::{EnumeratedItem, diff};
|
||||||
|
|
||||||
let server = vec![
|
let server = vec![
|
||||||
EnumeratedItem {
|
EnumeratedItem {
|
||||||
@@ -532,9 +535,9 @@ fn coordinator_diff_classifies_new_vanished_changed_unchanged() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn source_change_protection_refuses_different_account() {
|
fn source_change_protection_refuses_different_account() {
|
||||||
|
use inbuxa_migrate::db;
|
||||||
|
use inbuxa_migrate::db::sources::SourceKey;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::db;
|
|
||||||
use vandelay::db::sources::SourceKey;
|
|
||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let conn = Connection::open(tmp.path()).unwrap();
|
let conn = Connection::open(tmp.path()).unwrap();
|
||||||
@@ -557,9 +560,9 @@ fn source_change_protection_refuses_different_account() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mailbox_kinds_are_three_separate_sources() {
|
fn mailbox_kinds_are_three_separate_sources() {
|
||||||
|
use inbuxa_migrate::db;
|
||||||
|
use inbuxa_migrate::db::sources::SourceKey;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::db;
|
|
||||||
use vandelay::db::sources::SourceKey;
|
|
||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let conn = Connection::open(tmp.path()).unwrap();
|
let conn = Connection::open(tmp.path()).unwrap();
|
||||||
@@ -653,7 +656,7 @@ fn http_500_with_server_busy_body_is_treated_as_fault_and_retried() {
|
|||||||
let c = client(3);
|
let c = client(3);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -710,7 +713,7 @@ fn invalid_server_version_fault_downgrades_and_succeeds() {
|
|||||||
assert_eq!(c.server_version(), ServerVersion::Exchange2013Sp1);
|
assert_eq!(c.server_version(), ServerVersion::Exchange2013Sp1);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -748,7 +751,7 @@ fn unsupported_version_floor_surfaces_as_soap_fault() {
|
|||||||
let c = client(0);
|
let c = client(0);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -801,7 +804,7 @@ fn server_affinity_cookie_is_captured_and_resent() {
|
|||||||
let c = client(0);
|
let c = client(0);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -823,7 +826,7 @@ fn http_456_surfaces_as_account_locked_auth_error() {
|
|||||||
let c = client(0);
|
let c = client(0);
|
||||||
let body = find_folder_body(
|
let body = find_folder_body(
|
||||||
FolderRef::Distinguished(
|
FolderRef::Distinguished(
|
||||||
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
|
||||||
),
|
),
|
||||||
Traversal::Deep,
|
Traversal::Deep,
|
||||||
);
|
);
|
||||||
@@ -836,8 +839,8 @@ fn http_456_surfaces_as_account_locked_auth_error() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn for_each_fetched_item_streams_every_id_across_windows() {
|
fn for_each_fetched_item_streams_every_id_across_windows() {
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::import_exchange_ews::items::{ItemRunCtx, for_each_fetched_item};
|
use inbuxa_migrate::sync::import_exchange_ews::items::{ItemRunCtx, for_each_fetched_item};
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let url = format!("{}/EWS/Exchange.asmx", server.url());
|
let url = format!("{}/EWS/Exchange.asmx", server.url());
|
||||||
|
|||||||
+150
-146
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -7,21 +8,21 @@
|
|||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
use encodify::base64::URL_SAFE_NO_PAD;
|
use encodify::base64::URL_SAFE_NO_PAD;
|
||||||
use mockito::{Matcher, Server};
|
use inbuxa_migrate::exchange_graph::api::{Endpoints, collect_all_ids, paged_collect};
|
||||||
use serde_json::json;
|
use inbuxa_migrate::exchange_graph::calendar_map::{EventType, classify_event_type, convert_event};
|
||||||
use vandelay::exchange_graph::api::{Endpoints, collect_all_ids, paged_collect};
|
use inbuxa_migrate::exchange_graph::client::{Accept, GraphClient};
|
||||||
use vandelay::exchange_graph::calendar_map::{EventType, classify_event_type, convert_event};
|
use inbuxa_migrate::exchange_graph::contact_map::convert_contact;
|
||||||
use vandelay::exchange_graph::client::{Accept, GraphClient};
|
use inbuxa_migrate::exchange_graph::error::GraphError;
|
||||||
use vandelay::exchange_graph::contact_map::convert_contact;
|
use inbuxa_migrate::exchange_graph::oauth::{
|
||||||
use vandelay::exchange_graph::error::GraphError;
|
|
||||||
use vandelay::exchange_graph::oauth::{
|
|
||||||
DeviceCodeResponse, TokenResponse, parse_device_code_response, parse_token_response,
|
DeviceCodeResponse, TokenResponse, parse_device_code_response, parse_token_response,
|
||||||
run_device_code_polling_against,
|
run_device_code_polling_against,
|
||||||
};
|
};
|
||||||
use vandelay::exchange_graph::recurrence::convert_patterned_recurrence;
|
use inbuxa_migrate::exchange_graph::recurrence::convert_patterned_recurrence;
|
||||||
use vandelay::exchange_graph::retry::{HttpClass, classify_http_status};
|
use inbuxa_migrate::exchange_graph::retry::{HttpClass, classify_http_status};
|
||||||
use vandelay::exchange_graph::types::Surfaces;
|
use inbuxa_migrate::exchange_graph::types::Surfaces;
|
||||||
use vandelay::jmap::http::RetryPolicy;
|
use inbuxa_migrate::jmap::http::RetryPolicy;
|
||||||
|
use mockito::{Matcher, Server};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
@@ -525,7 +526,7 @@ fn contact_minimal_yields_jscontact_card() {
|
|||||||
"emailAddresses": [{"name": "Alice", "address": "[email protected]"}]
|
"emailAddresses": [{"name": "Alice", "address": "[email protected]"}]
|
||||||
});
|
});
|
||||||
let out = convert_contact(&c).unwrap();
|
let out = convert_contact(&c).unwrap();
|
||||||
assert!(out.uid.starts_with("vandelay-graph-"));
|
assert!(out.uid.starts_with("inbuxa-migrate-graph-"));
|
||||||
assert_eq!(out.data["@type"], "Card");
|
assert_eq!(out.data["@type"], "Card");
|
||||||
assert_eq!(out.data["name"]["full"], "Alice Liddell");
|
assert_eq!(out.data["name"]["full"], "Alice Liddell");
|
||||||
let emails = out.data["emails"].as_object().unwrap();
|
let emails = out.data["emails"].as_object().unwrap();
|
||||||
@@ -569,23 +570,23 @@ fn integration_dry_run_against_mock_server_lists_three_surfaces() {
|
|||||||
.with_body(r#"{"value":[{"id":"CON1","displayName":"Contacts"}]}"#)
|
.with_body(r#"{"value":[{"id":"CON1","displayName":"Contacts"}]}"#)
|
||||||
.create();
|
.create();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: tempfile::NamedTempFile::new().unwrap().path().to_owned(),
|
archive: tempfile::NamedTempFile::new().unwrap().path().to_owned(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: true,
|
dry_run: true,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: base.clone(),
|
api_base: base.clone(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: Surfaces::ALL,
|
surfaces: Surfaces::ALL,
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -593,7 +594,7 @@ fn integration_dry_run_against_mock_server_lists_three_surfaces() {
|
|||||||
event_attachments: true,
|
event_attachments: true,
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
let mailbox = summary
|
let mailbox = summary
|
||||||
.per_type
|
.per_type
|
||||||
.iter()
|
.iter()
|
||||||
@@ -681,23 +682,23 @@ fn integration_full_run_mail_only_imports_mime_via_value() {
|
|||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let archive_path = tmp.path().to_owned();
|
let archive_path = tmp.path().to_owned();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive_path.clone(),
|
archive: archive_path.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -706,7 +707,7 @@ fn integration_full_run_mail_only_imports_mime_via_value() {
|
|||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
drop(tmp);
|
drop(tmp);
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
let emails = summary
|
let emails = summary
|
||||||
.per_type
|
.per_type
|
||||||
.iter()
|
.iter()
|
||||||
@@ -780,23 +781,23 @@ fn integration_duplicate_message_id_does_not_abort_run() {
|
|||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let archive_path = tmp.path().to_owned();
|
let archive_path = tmp.path().to_owned();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive_path.clone(),
|
archive: archive_path.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -805,7 +806,7 @@ fn integration_duplicate_message_id_does_not_abort_run() {
|
|||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
drop(tmp);
|
drop(tmp);
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
let emails = summary
|
let emails = summary
|
||||||
.per_type
|
.per_type
|
||||||
.iter()
|
.iter()
|
||||||
@@ -880,15 +881,15 @@ fn integration_full_run_is_convergent_on_second_invocation() {
|
|||||||
|
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let api_base = server.url();
|
let api_base = server.url();
|
||||||
let make_config = || vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let make_config = || inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: api_base.clone(),
|
api_base: api_base.clone(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -896,17 +897,19 @@ fn integration_full_run_is_convergent_on_second_invocation() {
|
|||||||
event_attachments: true,
|
event_attachments: true,
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let make_common = |path: std::path::PathBuf| vandelay::sync::CommonConfig {
|
let make_common = |path: std::path::PathBuf| inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: path,
|
archive: path,
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let first =
|
let first = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
vandelay::sync::import_exchange_graph::run(make_common(archive.clone()), make_config())
|
make_common(archive.clone()),
|
||||||
|
make_config(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let created_first = first
|
let created_first = first
|
||||||
.per_type
|
.per_type
|
||||||
@@ -917,7 +920,8 @@ fn integration_full_run_is_convergent_on_second_invocation() {
|
|||||||
assert_eq!(created_first, 1);
|
assert_eq!(created_first, 1);
|
||||||
|
|
||||||
let second =
|
let second =
|
||||||
vandelay::sync::import_exchange_graph::run(make_common(archive), make_config()).unwrap();
|
inbuxa_migrate::sync::import_exchange_graph::run(make_common(archive), make_config())
|
||||||
|
.unwrap();
|
||||||
let created_second = second
|
let created_second = second
|
||||||
.per_type
|
.per_type
|
||||||
.iter()
|
.iter()
|
||||||
@@ -930,10 +934,10 @@ fn integration_full_run_is_convergent_on_second_invocation() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn source_change_protection_refuses_a_different_account() {
|
fn source_change_protection_refuses_a_different_account() {
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
vandelay::db::sources::upsert_source(
|
inbuxa_migrate::db::sources::upsert_source(
|
||||||
&conn,
|
&conn,
|
||||||
&vandelay::db::sources::SourceKey {
|
&inbuxa_migrate::db::sources::SourceKey {
|
||||||
kind: "exchange_graph".to_owned(),
|
kind: "exchange_graph".to_owned(),
|
||||||
session_url:
|
session_url:
|
||||||
"https://login.microsoftonline.com/common|https://graph.microsoft.com/v1.0"
|
"https://login.microsoftonline.com/common|https://graph.microsoft.com/v1.0"
|
||||||
@@ -954,23 +958,23 @@ fn source_change_protection_refuses_a_different_account() {
|
|||||||
.with_body(r#"{"id":"new-user-id","userPrincipalName":"[email protected]"}"#)
|
.with_body(r#"{"id":"new-user-id","userPrincipalName":"[email protected]"}"#)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive,
|
archive,
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: Surfaces::ALL,
|
surfaces: Surfaces::ALL,
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -978,9 +982,9 @@ fn source_change_protection_refuses_a_different_account() {
|
|||||||
event_attachments: true,
|
event_attachments: true,
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let err = vandelay::sync::import_exchange_graph::run(common, config).unwrap_err();
|
let err = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap_err();
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, vandelay::error::Error::SourceChange(_)),
|
matches!(err, inbuxa_migrate::error::Error::SourceChange(_)),
|
||||||
"expected SourceChange error, got {err:?}"
|
"expected SourceChange error, got {err:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1011,35 +1015,35 @@ fn stub_well_known_folders(server: &mut Server, inbox_id: &str) {
|
|||||||
.create();
|
.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_common(archive: std::path::PathBuf) -> vandelay::sync::CommonConfig {
|
fn make_common(archive: std::path::PathBuf) -> inbuxa_migrate::sync::CommonConfig {
|
||||||
vandelay::sync::CommonConfig {
|
inbuxa_migrate::sync::CommonConfig {
|
||||||
archive,
|
archive,
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn surfaces(list: &str) -> vandelay::exchange_graph::types::Surfaces {
|
fn surfaces(list: &str) -> inbuxa_migrate::exchange_graph::types::Surfaces {
|
||||||
vandelay::exchange_graph::types::Surfaces::parse_list(list).unwrap()
|
inbuxa_migrate::exchange_graph::types::Surfaces::parse_list(list).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_config(
|
fn make_config(
|
||||||
api_base: String,
|
api_base: String,
|
||||||
user_target: Option<String>,
|
user_target: Option<String>,
|
||||||
surfaces: vandelay::exchange_graph::types::Surfaces,
|
surfaces: inbuxa_migrate::exchange_graph::types::Surfaces,
|
||||||
) -> vandelay::sync::import_exchange_graph::GraphImportConfig {
|
) -> inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
vandelay::sync::import_exchange_graph::GraphImportConfig {
|
inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base,
|
api_base,
|
||||||
user_target,
|
user_target,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces,
|
surfaces,
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -1097,15 +1101,15 @@ fn users_upn_routes_through_users_segment_not_me() {
|
|||||||
.expect_at_least(0)
|
.expect_at_least(0)
|
||||||
.create();
|
.create();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: tempfile::NamedTempFile::new().unwrap().path().to_owned(),
|
archive: tempfile::NamedTempFile::new().unwrap().path().to_owned(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: true,
|
dry_run: true,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
common,
|
common,
|
||||||
make_config(base, Some("[email protected]".to_owned()), Surfaces::ALL),
|
make_config(base, Some("[email protected]".to_owned()), Surfaces::ALL),
|
||||||
)
|
)
|
||||||
@@ -1207,7 +1211,7 @@ fn series_master_with_exception_merges_into_recurrence_overrides() {
|
|||||||
.create();
|
.create();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("calendar")),
|
make_config(base, None, surfaces("calendar")),
|
||||||
)
|
)
|
||||||
@@ -1220,7 +1224,7 @@ fn series_master_with_exception_merges_into_recurrence_overrides() {
|
|||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
assert_eq!(events, 1, "exactly one master row, exception merged in");
|
assert_eq!(events, 1, "exactly one master row, exception merged in");
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let row: String = conn
|
let row: String = conn
|
||||||
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
|
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -1312,7 +1316,7 @@ fn occurrence_event_is_skipped_no_row_no_id_mapping() {
|
|||||||
.create();
|
.create();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("calendar")),
|
make_config(base, None, surfaces("calendar")),
|
||||||
)
|
)
|
||||||
@@ -1326,7 +1330,7 @@ fn occurrence_event_is_skipped_no_row_no_id_mapping() {
|
|||||||
assert_eq!(events, 0, "occurrence must not be fetched or stored");
|
assert_eq!(events, 0, "occurrence must not be fetched or stored");
|
||||||
occ_get.assert();
|
occ_get.assert();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let count: i64 = conn
|
let count: i64 = conn
|
||||||
.query_row("SELECT COUNT(*) FROM calendar_events", [], |row| row.get(0))
|
.query_row("SELECT COUNT(*) FROM calendar_events", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -1392,12 +1396,12 @@ fn hidden_mail_folder_has_is_subscribed_zero() {
|
|||||||
stub_well_known_folders(&mut server, "FVISIBLE");
|
stub_well_known_folders(&mut server, "FVISIBLE");
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("mail")),
|
make_config(base, None, surfaces("mail")),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let visible: i64 = conn
|
let visible: i64 = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT is_subscribed FROM mailboxes WHERE name = 'Inbox'",
|
"SELECT is_subscribed FROM mailboxes WHERE name = 'Inbox'",
|
||||||
@@ -1486,12 +1490,12 @@ fn well_known_folder_probes_assign_jmap_roles() {
|
|||||||
}
|
}
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("mail")),
|
make_config(base, None, surfaces("mail")),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let mut stmt = conn
|
let mut stmt = conn
|
||||||
.prepare("SELECT name, role FROM mailboxes ORDER BY name")
|
.prepare("SELECT name, role FROM mailboxes ORDER BY name")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -1563,7 +1567,7 @@ SGVsbG8=\r\n--X--\r\n";
|
|||||||
.create();
|
.create();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive),
|
make_common(archive),
|
||||||
make_config(base, None, surfaces("mail")),
|
make_config(base, None, surfaces("mail")),
|
||||||
)
|
)
|
||||||
@@ -1651,7 +1655,7 @@ fn event_get_carries_outlook_timezone_and_body_content_type_prefer() {
|
|||||||
.create();
|
.create();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive),
|
make_common(archive),
|
||||||
make_config(base, None, surfaces("calendar")),
|
make_config(base, None, surfaces("calendar")),
|
||||||
)
|
)
|
||||||
@@ -1737,23 +1741,23 @@ fn full_run_records_graph_id_in_sync_id_exchange_graph_with_padding() {
|
|||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let archive = tmp.path().to_owned();
|
let archive = tmp.path().to_owned();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -1762,8 +1766,8 @@ fn full_run_records_graph_id_in_sync_id_exchange_graph_with_padding() {
|
|||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
drop(tmp);
|
drop(tmp);
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let (graph_id, type_name): (String, String) = conn
|
let (graph_id, type_name): (String, String) = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT graph_id, type_name FROM sync_id_exchange_graph",
|
"SELECT graph_id, type_name FROM sync_id_exchange_graph",
|
||||||
@@ -1810,23 +1814,23 @@ fn archive_mailbox_kind_encodes_synthetic_suffix_in_account_id() {
|
|||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let archive = tmp.path().to_owned();
|
let archive = tmp.path().to_owned();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Archive,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Archive,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -1835,8 +1839,8 @@ fn archive_mailbox_kind_encodes_synthetic_suffix_in_account_id() {
|
|||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
drop(tmp);
|
drop(tmp);
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let account_id: String = conn
|
let account_id: String = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT account_id FROM sources WHERE kind = 'exchange_graph'",
|
"SELECT account_id FROM sources WHERE kind = 'exchange_graph'",
|
||||||
@@ -1850,10 +1854,10 @@ fn archive_mailbox_kind_encodes_synthetic_suffix_in_account_id() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn allow_source_change_permits_overwriting_a_different_account() {
|
fn allow_source_change_permits_overwriting_a_different_account() {
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
vandelay::db::sources::upsert_source(
|
inbuxa_migrate::db::sources::upsert_source(
|
||||||
&conn,
|
&conn,
|
||||||
&vandelay::db::sources::SourceKey {
|
&inbuxa_migrate::db::sources::SourceKey {
|
||||||
kind: "exchange_graph".to_owned(),
|
kind: "exchange_graph".to_owned(),
|
||||||
session_url: "https://login.microsoftonline.com/common|https://x.example".to_owned(),
|
session_url: "https://login.microsoftonline.com/common|https://x.example".to_owned(),
|
||||||
account_id: "different-uid".to_owned(),
|
account_id: "different-uid".to_owned(),
|
||||||
@@ -1878,23 +1882,23 @@ fn allow_source_change_permits_overwriting_a_different_account() {
|
|||||||
.with_body(r#"{"value":[]}"#)
|
.with_body(r#"{"value":[]}"#)
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -1902,7 +1906,7 @@ fn allow_source_change_permits_overwriting_a_different_account() {
|
|||||||
event_attachments: true,
|
event_attachments: true,
|
||||||
allow_source_change: true,
|
allow_source_change: true,
|
||||||
};
|
};
|
||||||
let result = vandelay::sync::import_exchange_graph::run(common, config);
|
let result = inbuxa_migrate::sync::import_exchange_graph::run(common, config);
|
||||||
assert!(
|
assert!(
|
||||||
result.is_ok(),
|
result.is_ok(),
|
||||||
"--allow-source-change must permit a different account, got {result:?}"
|
"--allow-source-change must permit a different account, got {result:?}"
|
||||||
@@ -1962,23 +1966,23 @@ fn dry_run_makes_no_per_item_get_and_no_sqlite_writes() {
|
|||||||
|
|
||||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||||
let archive = tmp.path().to_owned();
|
let archive = tmp.path().to_owned();
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: true,
|
dry_run: true,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: Surfaces::ALL,
|
surfaces: Surfaces::ALL,
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -1987,10 +1991,10 @@ fn dry_run_makes_no_per_item_get_and_no_sqlite_writes() {
|
|||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
drop(tmp);
|
drop(tmp);
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
no_messages.assert();
|
no_messages.assert();
|
||||||
no_well_known.assert();
|
no_well_known.assert();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let sources: i64 = conn
|
let sources: i64 = conn
|
||||||
.query_row("SELECT count(*) FROM sources", [], |row| row.get(0))
|
.query_row("SELECT count(*) FROM sources", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -2025,10 +2029,10 @@ fn token_response_bad_code_recognised() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn folder_enumeration_failure_skips_vanished_deletion() {
|
fn folder_enumeration_failure_skips_vanished_deletion() {
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let setup_conn = vandelay::db::init::open(&archive).unwrap();
|
let setup_conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let sid = vandelay::db::sources::upsert_source(
|
let sid = inbuxa_migrate::db::sources::upsert_source(
|
||||||
&setup_conn,
|
&setup_conn,
|
||||||
&vandelay::db::sources::SourceKey {
|
&inbuxa_migrate::db::sources::SourceKey {
|
||||||
kind: "exchange_graph".to_owned(),
|
kind: "exchange_graph".to_owned(),
|
||||||
session_url: "stale".to_owned(),
|
session_url: "stale".to_owned(),
|
||||||
account_id: "stale-uid".to_owned(),
|
account_id: "stale-uid".to_owned(),
|
||||||
@@ -2043,10 +2047,10 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
|
|||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
vandelay::db::exchange_graph_ids::insert(
|
inbuxa_migrate::db::exchange_graph_ids::insert(
|
||||||
&setup_conn,
|
&setup_conn,
|
||||||
sid,
|
sid,
|
||||||
vandelay::db::exchange_graph_ids::MAILBOX,
|
inbuxa_migrate::db::exchange_graph_ids::MAILBOX,
|
||||||
"FMAIL",
|
"FMAIL",
|
||||||
42,
|
42,
|
||||||
)
|
)
|
||||||
@@ -2067,10 +2071,10 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
|
|||||||
rusqlite::params![blob_id],
|
rusqlite::params![blob_id],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
vandelay::db::exchange_graph_ids::insert(
|
inbuxa_migrate::db::exchange_graph_ids::insert(
|
||||||
&setup_conn,
|
&setup_conn,
|
||||||
sid,
|
sid,
|
||||||
vandelay::db::exchange_graph_ids::EMAIL,
|
inbuxa_migrate::db::exchange_graph_ids::EMAIL,
|
||||||
"MSG-LOCAL",
|
"MSG-LOCAL",
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
@@ -2133,23 +2137,23 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
|
|||||||
.with_body("transient outage")
|
.with_body("transient outage")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let common = vandelay::sync::CommonConfig {
|
let common = inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 2,
|
threads: 2,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::new(0),
|
logger: inbuxa_migrate::logging::Logger::new(0),
|
||||||
};
|
};
|
||||||
let config = vandelay::sync::import_exchange_graph::GraphImportConfig {
|
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
|
||||||
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
|
||||||
token: make_jwt(9999999999, "[email protected]"),
|
token: make_jwt(9999999999, "[email protected]"),
|
||||||
},
|
},
|
||||||
api_base: server.url(),
|
api_base: server.url(),
|
||||||
user_target: None,
|
user_target: None,
|
||||||
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
|
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
|
||||||
surfaces: surfaces("mail"),
|
surfaces: surfaces("mail"),
|
||||||
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
|
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
|
||||||
graph_connections: 2,
|
graph_connections: 2,
|
||||||
top: 100,
|
top: 100,
|
||||||
exception_window_years: 5,
|
exception_window_years: 5,
|
||||||
@@ -2157,8 +2161,8 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
|
|||||||
event_attachments: true,
|
event_attachments: true,
|
||||||
allow_source_change: true,
|
allow_source_change: true,
|
||||||
};
|
};
|
||||||
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
|
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let remaining: i64 = conn
|
let remaining: i64 = conn
|
||||||
.query_row("SELECT count(*) FROM emails WHERE id = 1", [], |row| {
|
.query_row("SELECT count(*) FROM emails WHERE id = 1", [], |row| {
|
||||||
row.get(0)
|
row.get(0)
|
||||||
@@ -2324,7 +2328,7 @@ fn contacts_surface_imports_only_address_books_and_cards() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
vandelay::sync::import_exchange_graph::run(
|
inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("contacts")),
|
make_config(base, None, surfaces("contacts")),
|
||||||
)
|
)
|
||||||
@@ -2332,7 +2336,7 @@ fn contacts_surface_imports_only_address_books_and_cards() {
|
|||||||
no_mail.assert();
|
no_mail.assert();
|
||||||
no_calendars.assert();
|
no_calendars.assert();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
assert_eq!(row_count(&conn, "address_books"), 1);
|
assert_eq!(row_count(&conn, "address_books"), 1);
|
||||||
assert_eq!(row_count(&conn, "contact_cards"), 1);
|
assert_eq!(row_count(&conn, "contact_cards"), 1);
|
||||||
assert_eq!(row_count(&conn, "mailboxes"), 0);
|
assert_eq!(row_count(&conn, "mailboxes"), 0);
|
||||||
@@ -2368,7 +2372,7 @@ fn mail_surface_imports_only_mailboxes_and_emails() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
vandelay::sync::import_exchange_graph::run(
|
inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("mail")),
|
make_config(base, None, surfaces("mail")),
|
||||||
)
|
)
|
||||||
@@ -2376,7 +2380,7 @@ fn mail_surface_imports_only_mailboxes_and_emails() {
|
|||||||
no_calendars.assert();
|
no_calendars.assert();
|
||||||
no_contact_folders.assert();
|
no_contact_folders.assert();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
assert_eq!(row_count(&conn, "mailboxes"), 1);
|
assert_eq!(row_count(&conn, "mailboxes"), 1);
|
||||||
assert_eq!(row_count(&conn, "emails"), 1);
|
assert_eq!(row_count(&conn, "emails"), 1);
|
||||||
assert_eq!(row_count(&conn, "address_books"), 0);
|
assert_eq!(row_count(&conn, "address_books"), 0);
|
||||||
@@ -2442,7 +2446,7 @@ fn default_contact_folder_is_imported_although_contactfolders_omits_it() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("contacts")),
|
make_config(base, None, surfaces("contacts")),
|
||||||
)
|
)
|
||||||
@@ -2468,7 +2472,7 @@ fn default_contact_folder_is_imported_although_contactfolders_omits_it() {
|
|||||||
"both default-folder contacts import"
|
"both default-folder contacts import"
|
||||||
);
|
);
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let is_default: i64 = conn
|
let is_default: i64 = conn
|
||||||
.query_row("SELECT is_default FROM address_books", [], |row| row.get(0))
|
.query_row("SELECT is_default FROM address_books", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -2518,13 +2522,13 @@ fn default_contact_folder_falls_back_to_parent_of_an_existing_contact() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
vandelay::sync::import_exchange_graph::run(
|
inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("contacts")),
|
make_config(base, None, surfaces("contacts")),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let name: String = conn
|
let name: String = conn
|
||||||
.query_row("SELECT name FROM address_books", [], |row| row.get(0))
|
.query_row("SELECT name FROM address_books", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -2568,7 +2572,7 @@ fn contact_folder_reachable_by_two_paths_is_inserted_once() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("contacts")),
|
make_config(base, None, surfaces("contacts")),
|
||||||
)
|
)
|
||||||
@@ -2638,13 +2642,13 @@ fn message_state_becomes_jmap_keywords() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
vandelay::sync::import_exchange_graph::run(
|
inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("mail")),
|
make_config(base, None, surfaces("mail")),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let mut stmt = conn
|
let mut stmt = conn
|
||||||
.prepare("SELECT keywords FROM emails ORDER BY id")
|
.prepare("SELECT keywords FROM emails ORDER BY id")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -2708,7 +2712,7 @@ fn drive_items_import_as_file_nodes_and_skip_facetless_items() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let summary = vandelay::sync::import_exchange_graph::run(
|
let summary = inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("files")),
|
make_config(base, None, surfaces("files")),
|
||||||
)
|
)
|
||||||
@@ -2725,7 +2729,7 @@ fn drive_items_import_as_file_nodes_and_skip_facetless_items() {
|
|||||||
"one directory and two files; the remoteItem has no file or folder facet and is skipped"
|
"one directory and two files; the remoteItem has no file or folder facet and is skipped"
|
||||||
);
|
);
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let vault: i64 = conn
|
let vault: i64 = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT count(*) FROM file_nodes WHERE name = 'Personal Vault'",
|
"SELECT count(*) FROM file_nodes WHERE name = 'Personal Vault'",
|
||||||
@@ -2844,13 +2848,13 @@ fn a_deleted_occurrence_becomes_an_excluded_override() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
vandelay::sync::import_exchange_graph::run(
|
inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("calendar")),
|
make_config(base, None, surfaces("calendar")),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let row: String = conn
|
let row: String = conn
|
||||||
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
|
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -2910,13 +2914,13 @@ fn event_file_attachments_become_enclosure_links() {
|
|||||||
|
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
vandelay::sync::import_exchange_graph::run(
|
inbuxa_migrate::sync::import_exchange_graph::run(
|
||||||
make_common(archive.clone()),
|
make_common(archive.clone()),
|
||||||
make_config(base, None, surfaces("calendar")),
|
make_config(base, None, surfaces("calendar")),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let row: String = conn
|
let row: String = conn
|
||||||
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
|
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -2985,9 +2989,9 @@ fn contact_photo_categories_and_im_addresses_are_imported() {
|
|||||||
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
|
||||||
let mut config = make_config(base, None, surfaces("contacts"));
|
let mut config = make_config(base, None, surfaces("contacts"));
|
||||||
config.contact_photos = true;
|
config.contact_photos = true;
|
||||||
vandelay::sync::import_exchange_graph::run(make_common(archive.clone()), config).unwrap();
|
inbuxa_migrate::sync::import_exchange_graph::run(make_common(archive.clone()), config).unwrap();
|
||||||
|
|
||||||
let conn = vandelay::db::init::open(&archive).unwrap();
|
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
|
||||||
let row: String = conn
|
let row: String = conn
|
||||||
.query_row("SELECT data FROM contact_cards", [], |row| row.get(0))
|
.query_row("SELECT data FROM contact_cards", [], |row| row.get(0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
+16
-15
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -13,14 +14,14 @@ use std::thread;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use encodify::base64::STANDARD;
|
use encodify::base64::STANDARD;
|
||||||
|
use inbuxa_migrate::db;
|
||||||
|
use inbuxa_migrate::imap::client::{ConnectMode, ImapClient};
|
||||||
|
use inbuxa_migrate::imap::error::ImapError;
|
||||||
|
use inbuxa_migrate::imap::transport::Connector;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
|
use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig, run};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::db;
|
|
||||||
use vandelay::imap::client::{ConnectMode, ImapClient};
|
|
||||||
use vandelay::imap::error::ImapError;
|
|
||||||
use vandelay::imap::transport::Connector;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::CommonConfig;
|
|
||||||
use vandelay::sync::import_imap::{ImapAuth, ImapImportConfig, run};
|
|
||||||
|
|
||||||
type Script = Box<dyn FnOnce(&mut MockConn) -> std::io::Result<()> + Send + 'static>;
|
type Script = Box<dyn FnOnce(&mut MockConn) -> std::io::Result<()> + Send + 'static>;
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ fn connect_mock(server: &MockImap) -> Result<ImapClient, ImapError> {
|
|||||||
fn tempfile(label: &str) -> PathBuf {
|
fn tempfile(label: &str) -> PathBuf {
|
||||||
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
|
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!("vandelay_mock_imap_{label}_{counter}.sqlite"));
|
p.push(format!("inbuxa_migrate_mock_imap_{label}_{counter}.sqlite"));
|
||||||
if p.exists() {
|
if p.exists() {
|
||||||
let _ = std::fs::remove_file(&p);
|
let _ = std::fs::remove_file(&p);
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ fn run_import(
|
|||||||
user: &str,
|
user: &str,
|
||||||
archive: PathBuf,
|
archive: PathBuf,
|
||||||
config_tweak: impl FnOnce(&mut ImapImportConfig),
|
config_tweak: impl FnOnce(&mut ImapImportConfig),
|
||||||
) -> Result<vandelay::sync::Summary, vandelay::error::Error> {
|
) -> Result<inbuxa_migrate::sync::Summary, inbuxa_migrate::error::Error> {
|
||||||
let common = CommonConfig {
|
let common = CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 1,
|
threads: 1,
|
||||||
@@ -364,14 +365,14 @@ fn run_collect_parses_fetch_with_literal_body() {
|
|||||||
.run_collect("UID FETCH 5 (UID BODY.PEEK[])")
|
.run_collect("UID FETCH 5 (UID BODY.PEEK[])")
|
||||||
.expect("fetch");
|
.expect("fetch");
|
||||||
let body = r.untagged.iter().find_map(|u| match u {
|
let body = r.untagged.iter().find_map(|u| match u {
|
||||||
vandelay::imap::response::Untagged::Fetch { items, .. } => Some(items.clone()),
|
inbuxa_migrate::imap::response::Untagged::Fetch { items, .. } => Some(items.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let items = body.expect("fetch items");
|
let items = body.expect("fetch items");
|
||||||
let body_item = items.iter().find(|(n, _)| n == "BODY[]").unwrap();
|
let body_item = items.iter().find(|(n, _)| n == "BODY[]").unwrap();
|
||||||
match &body_item.1 {
|
match &body_item.1 {
|
||||||
vandelay::imap::response::Value::Str(s) => assert_eq!(s, "Hello world"),
|
inbuxa_migrate::imap::response::Value::Str(s) => assert_eq!(s, "Hello world"),
|
||||||
vandelay::imap::response::Value::Bytes(b) => assert_eq!(b, b"Hello world"),
|
inbuxa_migrate::imap::response::Value::Bytes(b) => assert_eq!(b, b"Hello world"),
|
||||||
other => panic!("unexpected body shape: {other:?}"),
|
other => panic!("unexpected body shape: {other:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1094,7 +1095,7 @@ fn coordinator_source_change_detected_on_different_url() {
|
|||||||
let server2 = MockImap::start_scripts(vec![control2]);
|
let server2 = MockImap::start_scripts(vec![control2]);
|
||||||
|
|
||||||
let err = run_import(&server2, "alice", archive.clone(), |_| {}).unwrap_err();
|
let err = run_import(&server2, "alice", archive.clone(), |_| {}).unwrap_err();
|
||||||
assert!(matches!(err, vandelay::error::Error::SourceChange(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::SourceChange(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1483,7 +1484,7 @@ fn coordinator_auth_plain_and_login_both_refused_aborts_run() {
|
|||||||
});
|
});
|
||||||
let archive = tempfile("dual_refuse");
|
let archive = tempfile("dual_refuse");
|
||||||
let err = run_import(&server, "alice", archive, |_| {}).unwrap_err();
|
let err = run_import(&server, "alice", archive, |_| {}).unwrap_err();
|
||||||
assert!(matches!(err, vandelay::error::Error::Connection(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Connection(_)));
|
||||||
assert_eq!(err.exit_code(), 2);
|
assert_eq!(err.exit_code(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1812,7 +1813,7 @@ fn coordinator_authenticationfailed_yields_exit2_connection_error() {
|
|||||||
});
|
});
|
||||||
let archive = tempfile("authfail");
|
let archive = tempfile("authfail");
|
||||||
let err = run_import(&server, "alice", archive, |_| {}).unwrap_err();
|
let err = run_import(&server, "alice", archive, |_| {}).unwrap_err();
|
||||||
assert!(matches!(err, vandelay::error::Error::Connection(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Connection(_)));
|
||||||
assert_eq!(err.exit_code(), 2);
|
assert_eq!(err.exit_code(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-21
@@ -1,22 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use serde_json::json;
|
use inbuxa_migrate::jmap::account::{self, AccountSelector};
|
||||||
use vandelay::jmap::account::{self, AccountSelector};
|
use inbuxa_migrate::jmap::error::JmapError;
|
||||||
use vandelay::jmap::error::JmapError;
|
use inbuxa_migrate::jmap::http::{Auth, HttpClient, RetryPolicy};
|
||||||
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
|
use inbuxa_migrate::jmap::request::{
|
||||||
use vandelay::jmap::request::{
|
|
||||||
self, SetRequest, get_all, get_changes, get_objects, get_state, set_call,
|
self, SetRequest, get_all, get_changes, get_objects, get_state, set_call,
|
||||||
};
|
};
|
||||||
use vandelay::jmap::session::{Limits, Session};
|
use inbuxa_migrate::jmap::session::{Limits, Session};
|
||||||
use vandelay::jmap::wire::JmapId;
|
use inbuxa_migrate::jmap::wire::JmapId;
|
||||||
use vandelay::jmap::wire::identity::Identity;
|
use inbuxa_migrate::jmap::wire::identity::Identity;
|
||||||
use vandelay::jmap::wire::mailbox::Mailbox;
|
use inbuxa_migrate::jmap::wire::mailbox::Mailbox;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
fn client(retries: u32) -> HttpClient {
|
fn client(retries: u32) -> HttpClient {
|
||||||
HttpClient::new(
|
HttpClient::new(
|
||||||
@@ -672,7 +673,7 @@ fn retries_counter_increments_on_429() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn upload_size_precheck_blocks_before_contacting_server() {
|
fn upload_size_precheck_blocks_before_contacting_server() {
|
||||||
use vandelay::jmap::blobxfer;
|
use inbuxa_migrate::jmap::blobxfer;
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let no_hits = server
|
let no_hits = server
|
||||||
@@ -739,7 +740,7 @@ fn concurrent_requests_400_problem_is_retried_then_succeeds() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn concurrent_uploads_400_problem_is_retried_then_succeeds() {
|
fn concurrent_uploads_400_problem_is_retried_then_succeeds() {
|
||||||
use vandelay::jmap::blobxfer;
|
use inbuxa_migrate::jmap::blobxfer;
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
server
|
server
|
||||||
@@ -772,7 +773,7 @@ fn concurrent_uploads_400_problem_is_retried_then_succeeds() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blob_upload_quota_429_with_retry_after_is_honoured() {
|
fn blob_upload_quota_429_with_retry_after_is_honoured() {
|
||||||
use vandelay::jmap::blobxfer;
|
use inbuxa_migrate::jmap::blobxfer;
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
server
|
server
|
||||||
@@ -883,7 +884,7 @@ fn ratelimit_headers_without_retry_after_fall_back_to_backoff() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn upload_extracts_blob_id_and_download_streams_via_download_url() {
|
fn upload_extracts_blob_id_and_download_streams_via_download_url() {
|
||||||
use vandelay::jmap::blobxfer;
|
use inbuxa_migrate::jmap::blobxfer;
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let base = server.url();
|
let base = server.url();
|
||||||
@@ -974,7 +975,7 @@ fn persistent_problem_json_429_without_retry_after_eventually_succeeds_via_share
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn persistent_429_on_download_uses_shared_throttle() {
|
fn persistent_429_on_download_uses_shared_throttle() {
|
||||||
use vandelay::jmap::blobxfer;
|
use inbuxa_migrate::jmap::blobxfer;
|
||||||
|
|
||||||
let mut server = mockito::Server::new();
|
let mut server = mockito::Server::new();
|
||||||
let session = upload_session(&server.url());
|
let session = upload_session(&server.url());
|
||||||
@@ -1207,7 +1208,7 @@ fn archive_path() -> std::path::PathBuf {
|
|||||||
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-mockjmap-{}-{n}.sqlite",
|
"inbuxa-migrate-mockjmap-{}-{n}.sqlite",
|
||||||
std::process::id()
|
std::process::id()
|
||||||
));
|
));
|
||||||
let _ = std::fs::remove_file(&p);
|
let _ = std::fs::remove_file(&p);
|
||||||
@@ -1264,17 +1265,17 @@ fn import_aborts_with_exit_two_when_the_advertised_api_url_is_unreachable() {
|
|||||||
.create();
|
.create();
|
||||||
|
|
||||||
let archive = archive_path();
|
let archive = archive_path();
|
||||||
let err = vandelay::sync::import_jmap::run(
|
let err = inbuxa_migrate::sync::import_jmap::run(
|
||||||
vandelay::sync::CommonConfig {
|
inbuxa_migrate::sync::CommonConfig {
|
||||||
archive: archive.clone(),
|
archive: archive.clone(),
|
||||||
threads: 1,
|
threads: 1,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
max_retries: 0,
|
max_retries: 0,
|
||||||
allow_invalid_certs: false,
|
allow_invalid_certs: false,
|
||||||
logger: vandelay::logging::Logger::from_flags(true, 0),
|
logger: inbuxa_migrate::logging::Logger::from_flags(true, 0),
|
||||||
},
|
},
|
||||||
vandelay::sync::ImportConfig {
|
inbuxa_migrate::sync::ImportConfig {
|
||||||
connect: vandelay::sync::ConnectConfig {
|
connect: inbuxa_migrate::sync::ConnectConfig {
|
||||||
url: session_base.clone(),
|
url: session_base.clone(),
|
||||||
auth: Auth::Basic {
|
auth: Auth::Basic {
|
||||||
user: "u".into(),
|
user: "u".into(),
|
||||||
@@ -1289,7 +1290,7 @@ fn import_aborts_with_exit_two_when_the_advertised_api_url_is_unreachable() {
|
|||||||
.expect_err("an unreachable apiUrl must abort the run");
|
.expect_err("an unreachable apiUrl must abort the run");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, vandelay::error::Error::Connection(_)),
|
matches!(err, inbuxa_migrate::error::Error::Connection(_)),
|
||||||
"a 404 from the advertised apiUrl is a whole-run connection failure, got {err:?}"
|
"a 404 from the advertised apiUrl is a whole-run connection failure, got {err:?}"
|
||||||
);
|
);
|
||||||
assert_eq!(err.exit_code(), 2, "must not report a partial failure");
|
assert_eq!(err.exit_code(), 2, "must not report a partial failure");
|
||||||
|
|||||||
+11
-10
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -8,16 +9,16 @@ use std::collections::HashMap;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
|
use inbuxa_migrate::sync::import_maildir::{MaildirImportConfig, run};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::CommonConfig;
|
|
||||||
use vandelay::sync::import_maildir::{MaildirImportConfig, run};
|
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-mock-maildir-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-mock-maildir-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -530,7 +531,7 @@ fn rejects_path_without_cur_subdir() {
|
|||||||
fs::create_dir_all(td.path().join("new")).unwrap();
|
fs::create_dir_all(td.path().join("new")).unwrap();
|
||||||
let archive = tmp_archive("not-a-maildir");
|
let archive = tmp_archive("not-a-maildir");
|
||||||
let err = run(common(&archive), base_cfg(td.path())).expect_err("should refuse");
|
let err = run(common(&archive), base_cfg(td.path())).expect_err("should refuse");
|
||||||
assert!(matches!(err, vandelay::error::Error::Usage(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Usage(_)));
|
||||||
let _ = fs::remove_file(&archive);
|
let _ = fs::remove_file(&archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,7 +545,7 @@ fn rejects_dovecot_layout_fs_tree() {
|
|||||||
let archive = tmp_archive("layout-fs");
|
let archive = tmp_archive("layout-fs");
|
||||||
let err = run(common(&archive), base_cfg(td.path())).expect_err("should refuse");
|
let err = run(common(&archive), base_cfg(td.path())).expect_err("should refuse");
|
||||||
match err {
|
match err {
|
||||||
vandelay::error::Error::Usage(msg) => {
|
inbuxa_migrate::error::Error::Usage(msg) => {
|
||||||
assert!(msg.contains("Maildir++"), "msg was: {msg}");
|
assert!(msg.contains("Maildir++"), "msg was: {msg}");
|
||||||
}
|
}
|
||||||
other => panic!("expected Usage error, got {other:?}"),
|
other => panic!("expected Usage error, got {other:?}"),
|
||||||
@@ -558,7 +559,7 @@ fn rejects_nonexistent_path() {
|
|||||||
let mut cfg = base_cfg(Path::new("/definitely/not/a/real/maildir"));
|
let mut cfg = base_cfg(Path::new("/definitely/not/a/real/maildir"));
|
||||||
cfg.maildir = PathBuf::from("/definitely/not/a/real/maildir");
|
cfg.maildir = PathBuf::from("/definitely/not/a/real/maildir");
|
||||||
let err = run(common(&archive), cfg).expect_err("should refuse");
|
let err = run(common(&archive), cfg).expect_err("should refuse");
|
||||||
assert!(matches!(err, vandelay::error::Error::Usage(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Usage(_)));
|
||||||
let _ = fs::remove_file(&archive);
|
let _ = fs::remove_file(&archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,7 +573,7 @@ fn source_change_protection_refuses_second_path() {
|
|||||||
let archive = tmp_archive("source-change");
|
let archive = tmp_archive("source-change");
|
||||||
run(common(&archive), base_cfg(td_a.path())).expect("first import");
|
run(common(&archive), base_cfg(td_a.path())).expect("first import");
|
||||||
let err = run(common(&archive), base_cfg(td_b.path())).expect_err("second import refused");
|
let err = run(common(&archive), base_cfg(td_b.path())).expect_err("second import refused");
|
||||||
assert!(matches!(err, vandelay::error::Error::SourceChange(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::SourceChange(_)));
|
||||||
let _ = fs::remove_file(&archive);
|
let _ = fs::remove_file(&archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,7 +602,7 @@ fn folder_and_include_are_mutually_exclusive() {
|
|||||||
cfg.include = vec![regex::Regex::new("^Sent$").unwrap()];
|
cfg.include = vec![regex::Regex::new("^Sent$").unwrap()];
|
||||||
let err = run(common(&archive), cfg).expect_err("mutex");
|
let err = run(common(&archive), cfg).expect_err("mutex");
|
||||||
match err {
|
match err {
|
||||||
vandelay::error::Error::Usage(msg) => {
|
inbuxa_migrate::error::Error::Usage(msg) => {
|
||||||
assert!(
|
assert!(
|
||||||
msg.contains("--folder") && msg.contains("--include"),
|
msg.contains("--folder") && msg.contains("--include"),
|
||||||
"msg was: {msg}"
|
"msg was: {msg}"
|
||||||
@@ -621,7 +622,7 @@ fn folder_and_exclude_are_mutually_exclusive() {
|
|||||||
cfg.folder = vec!["INBOX".to_owned()];
|
cfg.folder = vec!["INBOX".to_owned()];
|
||||||
cfg.exclude = vec![regex::Regex::new("^Trash$").unwrap()];
|
cfg.exclude = vec![regex::Regex::new("^Trash$").unwrap()];
|
||||||
let err = run(common(&archive), cfg).expect_err("mutex");
|
let err = run(common(&archive), cfg).expect_err("mutex");
|
||||||
assert!(matches!(err, vandelay::error::Error::Usage(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Usage(_)));
|
||||||
let _ = fs::remove_file(&archive);
|
let _ = fs::remove_file(&archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -12,10 +13,10 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
|
use inbuxa_migrate::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig, run};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::CommonConfig;
|
|
||||||
use vandelay::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig, run};
|
|
||||||
|
|
||||||
type Script = Box<dyn FnOnce(&mut MockConn) -> std::io::Result<()> + Send + 'static>;
|
type Script = Box<dyn FnOnce(&mut MockConn) -> std::io::Result<()> + Send + 'static>;
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ fn tempfile(label: &str) -> PathBuf {
|
|||||||
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
|
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay_mock_managesieve_{label}_{counter}.sqlite"
|
"inbuxa_migrate_mock_managesieve_{label}_{counter}.sqlite"
|
||||||
));
|
));
|
||||||
if p.exists() {
|
if p.exists() {
|
||||||
let _ = std::fs::remove_file(&p);
|
let _ = std::fs::remove_file(&p);
|
||||||
@@ -133,7 +134,7 @@ fn count(conn: &Connection, table: &str) -> i64 {
|
|||||||
fn run_basic(
|
fn run_basic(
|
||||||
server: &MockSieveServer,
|
server: &MockSieveServer,
|
||||||
archive: &Path,
|
archive: &Path,
|
||||||
) -> Result<vandelay::sync::Summary, vandelay::error::Error> {
|
) -> Result<inbuxa_migrate::sync::Summary, inbuxa_migrate::error::Error> {
|
||||||
let common = CommonConfig {
|
let common = CommonConfig {
|
||||||
archive: archive.to_path_buf(),
|
archive: archive.to_path_buf(),
|
||||||
threads: 1,
|
threads: 1,
|
||||||
@@ -256,7 +257,7 @@ fn auth_no_translates_to_connection_error() {
|
|||||||
let archive = tempfile("auth_fail");
|
let archive = tempfile("auth_fail");
|
||||||
let err = run_basic(&server, &archive).unwrap_err();
|
let err = run_basic(&server, &archive).unwrap_err();
|
||||||
match err {
|
match err {
|
||||||
vandelay::error::Error::Connection(msg) => assert!(
|
inbuxa_migrate::error::Error::Connection(msg) => assert!(
|
||||||
msg.contains("auth failed") || msg.contains("LOGIN"),
|
msg.contains("auth failed") || msg.contains("LOGIN"),
|
||||||
"got {msg}"
|
"got {msg}"
|
||||||
),
|
),
|
||||||
@@ -274,7 +275,7 @@ fn server_lacking_plain_login_for_basic_is_refused() {
|
|||||||
});
|
});
|
||||||
let archive = tempfile("no_basic_mech");
|
let archive = tempfile("no_basic_mech");
|
||||||
let err = run_basic(&server, &archive).unwrap_err();
|
let err = run_basic(&server, &archive).unwrap_err();
|
||||||
assert!(matches!(err, vandelay::error::Error::Connection(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Connection(_)));
|
||||||
let _ = std::fs::remove_file(&archive);
|
let _ = std::fs::remove_file(&archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +424,7 @@ fn referral_aborts_run_with_connection_error() {
|
|||||||
let archive = tempfile("referral");
|
let archive = tempfile("referral");
|
||||||
let err = run_basic(&server, &archive).unwrap_err();
|
let err = run_basic(&server, &archive).unwrap_err();
|
||||||
match err {
|
match err {
|
||||||
vandelay::error::Error::Connection(msg) => assert!(msg.contains("referral"), "{msg}"),
|
inbuxa_migrate::error::Error::Connection(msg) => assert!(msg.contains("referral"), "{msg}"),
|
||||||
other => panic!("expected Connection, got {other:?}"),
|
other => panic!("expected Connection, got {other:?}"),
|
||||||
}
|
}
|
||||||
let _ = std::fs::remove_file(&archive);
|
let _ = std::fs::remove_file(&archive);
|
||||||
@@ -438,7 +439,7 @@ fn seed_then_run(seed: Script, second: Script) -> (MockSieveServer, PathBuf) {
|
|||||||
fn run_against(
|
fn run_against(
|
||||||
server: &MockSieveServer,
|
server: &MockSieveServer,
|
||||||
archive: &Path,
|
archive: &Path,
|
||||||
) -> Result<vandelay::sync::Summary, vandelay::error::Error> {
|
) -> Result<inbuxa_migrate::sync::Summary, inbuxa_migrate::error::Error> {
|
||||||
run_basic(server, archive)
|
run_basic(server, archive)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -935,7 +936,7 @@ fn plain_then_login_both_refused_aborts_run_with_combined_message() {
|
|||||||
let archive = tempfile("plain_and_login_refused");
|
let archive = tempfile("plain_and_login_refused");
|
||||||
let err = run_basic(&server, &archive).unwrap_err();
|
let err = run_basic(&server, &archive).unwrap_err();
|
||||||
match err {
|
match err {
|
||||||
vandelay::error::Error::Connection(msg) => {
|
inbuxa_migrate::error::Error::Connection(msg) => {
|
||||||
assert!(
|
assert!(
|
||||||
msg.contains("LOGIN") && msg.contains("PLAIN"),
|
msg.contains("LOGIN") && msg.contains("PLAIN"),
|
||||||
"expected combined LOGIN/PLAIN error text, got {msg}"
|
"expected combined LOGIN/PLAIN error text, got {msg}"
|
||||||
|
|||||||
+15
-14
@@ -1,26 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use inbuxa_migrate::db;
|
||||||
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
||||||
|
use inbuxa_migrate::types::ObjectType;
|
||||||
use mockito::Matcher;
|
use mockito::Matcher;
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use vandelay::db;
|
|
||||||
use vandelay::jmap::account::AccountSelector;
|
|
||||||
use vandelay::jmap::http::Auth;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
|
||||||
use vandelay::types::ObjectType;
|
|
||||||
|
|
||||||
fn tmp() -> PathBuf {
|
fn tmp() -> PathBuf {
|
||||||
static SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
static SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||||
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-mocksync-{}-{:?}-{n}.sqlite",
|
"inbuxa-migrate-mocksync-{}-{:?}-{n}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::thread::current().id(),
|
std::thread::current().id(),
|
||||||
));
|
));
|
||||||
@@ -1585,8 +1586,8 @@ fn export_missing_target_email_is_created_on_rerun() {
|
|||||||
let raw =
|
let raw =
|
||||||
format!("From: a@x\r\nSubject: m{n}\r\nMessage-ID: <m-{n}@h>\r\n\r\nbody {n}",);
|
format!("From: a@x\r\nSubject: m{n}\r\nMessage-ID: <m-{n}@h>\r\n\r\nbody {n}",);
|
||||||
let blob = db::blobs::intern_blob(&conn, raw.as_bytes()).unwrap();
|
let blob = db::blobs::intern_blob(&conn, raw.as_bytes()).unwrap();
|
||||||
let mm = vandelay::sync::keys::index_to_json(
|
let mm = inbuxa_migrate::sync::keys::index_to_json(
|
||||||
&vandelay::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
|
&inbuxa_migrate::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
|
||||||
);
|
);
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO emails (blob_id,received_at,mailbox_ids,keywords,message_match)
|
"INSERT INTO emails (blob_id,received_at,mailbox_ids,keywords,message_match)
|
||||||
@@ -1700,8 +1701,8 @@ fn export_email_blake3_fallback_matches_when_no_message_id() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let blob = db::blobs::intern_blob(&conn, raw.as_bytes()).unwrap();
|
let blob = db::blobs::intern_blob(&conn, raw.as_bytes()).unwrap();
|
||||||
let mm = vandelay::sync::keys::index_to_json(
|
let mm = inbuxa_migrate::sync::keys::index_to_json(
|
||||||
&vandelay::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
|
&inbuxa_migrate::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
|
||||||
);
|
);
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO emails (blob_id,received_at,mailbox_ids,keywords,message_match)
|
"INSERT INTO emails (blob_id,received_at,mailbox_ids,keywords,message_match)
|
||||||
@@ -1711,7 +1712,7 @@ fn export_email_blake3_fallback_matches_when_no_message_id() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_idx = vandelay::sync::emailmeta::email_index_from_blob(raw.as_bytes());
|
let local_idx = inbuxa_migrate::sync::emailmeta::email_index_from_blob(raw.as_bytes());
|
||||||
assert!(local_idx.mids.is_empty(), "blob must lack Message-ID");
|
assert!(local_idx.mids.is_empty(), "blob must lack Message-ID");
|
||||||
|
|
||||||
let _root = server.mock("GET", "/").with_status(404).create();
|
let _root = server.mock("GET", "/").with_status(404).create();
|
||||||
@@ -4144,7 +4145,7 @@ fn export_aborts_with_exit_two_when_the_advertised_api_url_is_unreachable() {
|
|||||||
.expect_err("an unreachable apiUrl must abort the run");
|
.expect_err("an unreachable apiUrl must abort the run");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, vandelay::error::Error::Connection(_)),
|
matches!(err, inbuxa_migrate::error::Error::Connection(_)),
|
||||||
"a 404 from the advertised apiUrl is a whole-run connection failure, got {err:?}"
|
"a 404 from the advertised apiUrl is a whole-run connection failure, got {err:?}"
|
||||||
);
|
);
|
||||||
assert_eq!(err.exit_code(), 2, "must not report a partial failure");
|
assert_eq!(err.exit_code(), 2, "must not report a partial failure");
|
||||||
@@ -4207,7 +4208,7 @@ fn aborting_import_still_reports_the_types_that_finished() {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("a 404 from the api endpoint aborts the run");
|
.expect("a 404 from the api endpoint aborts the run");
|
||||||
assert!(
|
assert!(
|
||||||
matches!(err, vandelay::error::Error::Connection(_)),
|
matches!(err, inbuxa_migrate::error::Error::Connection(_)),
|
||||||
"the abort must keep its own exit code, got {err:?}"
|
"the abort must keep its own exit code, got {err:?}"
|
||||||
);
|
);
|
||||||
assert_eq!(err.exit_code(), 2);
|
assert_eq!(err.exit_code(), 2);
|
||||||
|
|||||||
+4
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -98,7 +99,9 @@ fn verify_account(label: &str, user: &Jmap, account_id: &str, s: &SeedStats) {
|
|||||||
assert_eq!(list.len(), 2, "{label}: sieve script count");
|
assert_eq!(list.len(), 2, "{label}: sieve script count");
|
||||||
let primary = list
|
let primary = list
|
||||||
.iter()
|
.iter()
|
||||||
.find(|s| s.get("name").and_then(Value::as_str) == Some("vandelay-test-filter"))
|
.find(|s| {
|
||||||
|
s.get("name").and_then(Value::as_str) == Some("inbuxa-migrate-test-filter")
|
||||||
|
})
|
||||||
.expect("primary sieve script present");
|
.expect("primary sieve script present");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
primary.get("isActive").and_then(Value::as_bool),
|
primary.get("isActive").and_then(Value::as_bool),
|
||||||
|
|||||||
+5
-4
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -17,14 +18,14 @@ use seed::{FileSpec, Layout, MailboxSpec};
|
|||||||
|
|
||||||
pub const ADMIN_USER: &str = "admin";
|
pub const ADMIN_USER: &str = "admin";
|
||||||
pub const ADMIN_PASSWORD: &str = "admin";
|
pub const ADMIN_PASSWORD: &str = "admin";
|
||||||
pub const DOMAIN: &str = "vandelay.org";
|
pub const DOMAIN: &str = "inbuxa-migrate.org";
|
||||||
pub const USER_PASSWORD: &str = "VandelayUser#2026";
|
pub const USER_PASSWORD: &str = "InbuxaUser#2026";
|
||||||
pub const ADMIN_ACCOUNT_PASSWORD: &str = "VandelayAdmin#2026";
|
pub const ADMIN_ACCOUNT_PASSWORD: &str = "InbuxaAdmin#2026";
|
||||||
|
|
||||||
pub const SYNC_IN: [&str; 3] = ["test1", "test2", "test3"];
|
pub const SYNC_IN: [&str; 3] = ["test1", "test2", "test3"];
|
||||||
pub const SYNC_OUT: [&str; 3] = ["test4", "test5", "test6"];
|
pub const SYNC_OUT: [&str; 3] = ["test4", "test5", "test6"];
|
||||||
pub const ADMIN_LOCALPART: &str = "vandeladmin";
|
pub const ADMIN_LOCALPART: &str = "vandeladmin";
|
||||||
pub const CUSTOM_IDENTITY_NAME: &str = "Vandelay Test (Custom)";
|
pub const CUSTOM_IDENTITY_NAME: &str = "Inbuxa Test (Custom)";
|
||||||
|
|
||||||
macro_rules! mailbox {
|
macro_rules! mailbox {
|
||||||
($k:expr, $n:expr, $p:expr, $r:expr) => {
|
($k:expr, $n:expr, $p:expr, $r:expr) => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -230,8 +231,8 @@ fn seed_sieve(jmap: &Jmap, account_id: &str, active: bool) -> SeedResult<()> {
|
|||||||
"SieveScript/set",
|
"SieveScript/set",
|
||||||
account_id,
|
account_id,
|
||||||
json!({
|
json!({
|
||||||
"s0": { "name": "vandelay-test-filter", "blobId": primary_blob },
|
"s0": { "name": "inbuxa-migrate-test-filter", "blobId": primary_blob },
|
||||||
"s1": { "name": "vandelay-vacation", "blobId": secondary_blob }
|
"s1": { "name": "inbuxa-migrate-vacation", "blobId": secondary_blob }
|
||||||
}),
|
}),
|
||||||
&extra,
|
&extra,
|
||||||
)?;
|
)?;
|
||||||
@@ -247,8 +248,8 @@ fn seed_identity(jmap: &Jmap, account_id: &str, account_email: &str) -> SeedResu
|
|||||||
"i0": {
|
"i0": {
|
||||||
"name": super::CUSTOM_IDENTITY_NAME,
|
"name": super::CUSTOM_IDENTITY_NAME,
|
||||||
"email": account_email,
|
"email": account_email,
|
||||||
"textSignature": "-- \nVandelay Industries",
|
"textSignature": "-- \nInbuxa Industries",
|
||||||
"htmlSignature": "<p>Vandelay Industries</p>"
|
"htmlSignature": "<p>Inbuxa Industries</p>"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
&[],
|
&[],
|
||||||
@@ -339,7 +340,7 @@ fn seed_contacts_calendars(
|
|||||||
&[CORE, CONTACTS],
|
&[CORE, CONTACTS],
|
||||||
"AddressBook/set",
|
"AddressBook/set",
|
||||||
account_id,
|
account_id,
|
||||||
json!({ "ab": { "name": "Vandelay Work Contacts" } }),
|
json!({ "ab": { "name": "Inbuxa Work Contacts" } }),
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
if let Some(id) = response
|
if let Some(id) = response
|
||||||
@@ -359,7 +360,7 @@ fn seed_contacts_calendars(
|
|||||||
&[CORE, CALENDARS],
|
&[CORE, CALENDARS],
|
||||||
"Calendar/set",
|
"Calendar/set",
|
||||||
account_id,
|
account_id,
|
||||||
json!({ "cal": { "name": "Vandelay Team Calendar", "color": "#3366cc" } }),
|
json!({ "cal": { "name": "Inbuxa Team Calendar", "color": "#3366cc" } }),
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
if let Some(id) = response
|
if let Some(id) = response
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -16,16 +17,16 @@ use rusqlite::Connection;
|
|||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
shared_stalwart().base_url()
|
shared_stalwart().base_url()
|
||||||
}
|
}
|
||||||
use vandelay::jmap::account::AccountSelector;
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
use vandelay::jmap::http::Auth;
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -10,22 +11,22 @@ mod seeder;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
use integration::stalwart::shared as shared_stalwart;
|
use integration::stalwart::shared as shared_stalwart;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use vandelay::jmap::account::AccountSelector;
|
|
||||||
use vandelay::jmap::http::Auth;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
|
|
||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
shared_stalwart().base_url()
|
shared_stalwart().base_url()
|
||||||
}
|
}
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -9,15 +10,15 @@ mod seeder;
|
|||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use inbuxa_migrate::exchange_graph::types::{EventBodyFormat, MailboxKind, Surfaces};
|
||||||
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::import_exchange_graph::{GraphAuth, GraphImportConfig};
|
||||||
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig};
|
||||||
use integration::stalwart::shared as shared_stalwart;
|
use integration::stalwart::shared as shared_stalwart;
|
||||||
use mockito::{Matcher, Server};
|
use mockito::{Matcher, Server};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use vandelay::exchange_graph::types::{EventBodyFormat, MailboxKind, Surfaces};
|
|
||||||
use vandelay::jmap::account::AccountSelector;
|
|
||||||
use vandelay::jmap::http::Auth;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::import_exchange_graph::{GraphAuth, GraphImportConfig};
|
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig};
|
|
||||||
|
|
||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
shared_stalwart().base_url()
|
shared_stalwart().base_url()
|
||||||
@@ -26,7 +27,7 @@ fn base_url() -> &'static str {
|
|||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -96,9 +97,9 @@ fn graph_fixture(server: &mut Server) {
|
|||||||
.with_status(200)
|
.with_status(200)
|
||||||
.with_header("content-type", "text/plain")
|
.with_header("content-type", "text/plain")
|
||||||
.with_body(
|
.with_body(
|
||||||
"From: art@vandelay.example\r\nTo: [email protected]\r\n\
|
"From: art@inbuxa-migrate.example\r\nTo: [email protected]\r\n\
|
||||||
Subject: Graph round trip\r\nDate: Tue, 01 Sep 2026 10:00:00 +0000\r\n\
|
Subject: Graph round trip\r\nDate: Tue, 01 Sep 2026 10:00:00 +0000\r\n\
|
||||||
Message-ID: <graph-rt-1@vandelay.example>\r\n\
|
Message-ID: <graph-rt-1@inbuxa-migrate.example>\r\n\
|
||||||
MIME-Version: 1.0\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n\
|
MIME-Version: 1.0\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n\
|
||||||
Grüße aus Köln 🎉\r\n",
|
Grüße aus Köln 🎉\r\n",
|
||||||
)
|
)
|
||||||
@@ -219,8 +220,8 @@ fn graph_fixture(server: &mut Server) {
|
|||||||
server,
|
server,
|
||||||
"/me/contacts/C1",
|
"/me/contacts/C1",
|
||||||
r#"{"id":"C1","displayName":"Graph Contact","givenName":"Graph","surname":"Contact",
|
r#"{"id":"C1","displayName":"Graph Contact","givenName":"Graph","surname":"Contact",
|
||||||
"categories":["Work","VIP"],"imAddresses":["sip:graph@vandelay.example"],
|
"categories":["Work","VIP"],"imAddresses":["sip:graph@inbuxa-migrate.example"],
|
||||||
"emailAddresses":[{"address":"graph@vandelay.example"}]}"#,
|
"emailAddresses":[{"address":"graph@inbuxa-migrate.example"}]}"#,
|
||||||
);
|
);
|
||||||
server
|
server
|
||||||
.mock("GET", "/me/contacts/C1/photo/$value")
|
.mock("GET", "/me/contacts/C1/photo/$value")
|
||||||
@@ -393,7 +394,7 @@ fn graph_import_survives_a_full_export_to_stalwart() {
|
|||||||
.as_object()
|
.as_object()
|
||||||
.and_then(|m| m.values().next())
|
.and_then(|m| m.values().next())
|
||||||
.and_then(|s| s["uri"].as_str()),
|
.and_then(|s| s["uri"].as_str()),
|
||||||
Some("sip:graph@vandelay.example"),
|
Some("sip:graph@inbuxa-migrate.example"),
|
||||||
"a URI-shaped IM address must land in uri: Stalwart drops an OnlineService \
|
"a URI-shaped IM address must land in uri: Stalwart drops an OnlineService \
|
||||||
that carries only user, even though RFC 9553 permits it"
|
that carries only user, even though RFC 9553 permits it"
|
||||||
);
|
);
|
||||||
|
|||||||
+7
-6
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -22,16 +23,16 @@ fn imaps_url() -> String {
|
|||||||
format!("imaps://{}:{}", s.host, s.imaps_port)
|
format!("imaps://{}:{}", s.host, s.imaps_port)
|
||||||
}
|
}
|
||||||
|
|
||||||
use vandelay::jmap::account::AccountSelector;
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
use vandelay::jmap::http::Auth;
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::import_imap::{ImapAuth, ImapImportConfig};
|
use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig};
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-imap-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-imap-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
|||||||
+40
-39
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -10,15 +11,15 @@ mod seeder;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use encodify::base64::STANDARD;
|
use encodify::base64::STANDARD;
|
||||||
|
use inbuxa_migrate::jmap::account::{self, AccountSelector};
|
||||||
|
use inbuxa_migrate::jmap::http::{Auth, HttpClient, RetryPolicy};
|
||||||
|
use inbuxa_migrate::jmap::request::Request;
|
||||||
|
use inbuxa_migrate::jmap::session::Session;
|
||||||
|
use inbuxa_migrate::logging::Logger;
|
||||||
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
||||||
use integration::stalwart::shared as shared_stalwart;
|
use integration::stalwart::shared as shared_stalwart;
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use serde_json::{Map, Value, json};
|
use serde_json::{Map, Value, json};
|
||||||
use vandelay::jmap::account::{self, AccountSelector};
|
|
||||||
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
|
|
||||||
use vandelay::jmap::request::Request;
|
|
||||||
use vandelay::jmap::session::Session;
|
|
||||||
use vandelay::logging::Logger;
|
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
|
||||||
|
|
||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
shared_stalwart().base_url()
|
shared_stalwart().base_url()
|
||||||
@@ -27,7 +28,7 @@ fn base_url() -> &'static str {
|
|||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -181,7 +182,7 @@ fn import_resolves_account_via_admin_principal_path() {
|
|||||||
},
|
},
|
||||||
account: AccountSelector::Name(target.email.clone()),
|
account: AccountSelector::Name(target.email.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let summary = sync::import_jmap::run(common(&archive, false), cfg)
|
let summary = sync::import_jmap::run(common(&archive, false), cfg)
|
||||||
@@ -390,7 +391,7 @@ fn import_export_deeply_nested_mailbox_tree() {
|
|||||||
auth: basic("test4"),
|
auth: basic("test4"),
|
||||||
account: AccountSelector::Id(src.account_id.clone()),
|
account: AccountSelector::Id(src.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let s = sync::import_jmap::run(common(&archive, false), imp).expect("import");
|
let s = sync::import_jmap::run(common(&archive, false), imp).expect("import");
|
||||||
@@ -432,7 +433,7 @@ fn import_export_deeply_nested_mailbox_tree() {
|
|||||||
auth: basic("test5"),
|
auth: basic("test5"),
|
||||||
account: AccountSelector::Id(tgt.account_id.clone()),
|
account: AccountSelector::Id(tgt.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
sync::import_jmap::run(common(&again_archive, false), imp_again)
|
sync::import_jmap::run(common(&again_archive, false), imp_again)
|
||||||
@@ -470,7 +471,7 @@ fn import_export_deeply_nested_filenode_tree() {
|
|||||||
auth: basic("test4"),
|
auth: basic("test4"),
|
||||||
account: AccountSelector::Id(src.account_id.clone()),
|
account: AccountSelector::Id(src.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::FileNode]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::FileNode]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let s = sync::import_jmap::run(common(&archive, false), imp).expect("import");
|
let s = sync::import_jmap::run(common(&archive, false), imp).expect("import");
|
||||||
@@ -514,7 +515,7 @@ fn import_export_deeply_nested_filenode_tree() {
|
|||||||
auth: basic("test5"),
|
auth: basic("test5"),
|
||||||
account: AccountSelector::Id(tgt.account_id.clone()),
|
account: AccountSelector::Id(tgt.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::FileNode]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::FileNode]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -554,7 +555,7 @@ fn prune_multilevel_mailbox_tree_destroys_leaf_first() {
|
|||||||
auth: basic("test4"),
|
auth: basic("test4"),
|
||||||
account: AccountSelector::Id(src.account_id.clone()),
|
account: AccountSelector::Id(src.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -567,7 +568,7 @@ fn prune_multilevel_mailbox_tree_destroys_leaf_first() {
|
|||||||
|
|
||||||
let arch_empty = tmp_archive("prune_deep_empty");
|
let arch_empty = tmp_archive("prune_deep_empty");
|
||||||
{
|
{
|
||||||
let _ = vandelay::db::init::open(&arch_empty).expect("init empty archive");
|
let _ = inbuxa_migrate::db::init::open(&arch_empty).expect("init empty archive");
|
||||||
}
|
}
|
||||||
|
|
||||||
let small_jmap = jmap_for(&fx.account("test6").expect("test6").localpart);
|
let small_jmap = jmap_for(&fx.account("test6").expect("test6").localpart);
|
||||||
@@ -595,7 +596,7 @@ fn prune_multilevel_mailbox_tree_destroys_leaf_first() {
|
|||||||
auth: basic("test6"),
|
auth: basic("test6"),
|
||||||
account: AccountSelector::Id(fx.account("test6").unwrap().account_id.clone()),
|
account: AccountSelector::Id(fx.account("test6").unwrap().account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -644,8 +645,8 @@ fn prune_non_tree_type_contact_card() {
|
|||||||
account: AccountSelector::Id(src.account_id.clone()),
|
account: AccountSelector::Id(src.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![
|
objects: Some(vec![
|
||||||
vandelay::types::ObjectType::AddressBook,
|
inbuxa_migrate::types::ObjectType::AddressBook,
|
||||||
vandelay::types::ObjectType::ContactCard,
|
inbuxa_migrate::types::ObjectType::ContactCard,
|
||||||
]),
|
]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
},
|
},
|
||||||
@@ -659,7 +660,7 @@ fn prune_non_tree_type_contact_card() {
|
|||||||
|
|
||||||
let arch_empty = tmp_archive("prune_cc_empty");
|
let arch_empty = tmp_archive("prune_cc_empty");
|
||||||
{
|
{
|
||||||
let conn = vandelay::db::init::open(&arch_empty).expect("init empty archive");
|
let conn = inbuxa_migrate::db::init::open(&arch_empty).expect("init empty archive");
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO address_books (id,name,is_default) VALUES (1,'AB',1)",
|
"INSERT INTO address_books (id,name,is_default) VALUES (1,'AB',1)",
|
||||||
[],
|
[],
|
||||||
@@ -690,8 +691,8 @@ fn prune_non_tree_type_contact_card() {
|
|||||||
seeder::teardown(base_url()).expect("teardown");
|
seeder::teardown(base_url()).expect("teardown");
|
||||||
}
|
}
|
||||||
|
|
||||||
const ISSUE30_CARD_UID: &str = "vandelay-issue30-card";
|
const ISSUE30_CARD_UID: &str = "inbuxa-migrate-issue30-card";
|
||||||
const ISSUE30_EVENT_UID: &str = "vandelay-issue30-event";
|
const ISSUE30_EVENT_UID: &str = "inbuxa-migrate-issue30-event";
|
||||||
|
|
||||||
fn data_uri_bytes(resource: &Value, uri_key: &str, expect_media_type: &str) -> Vec<u8> {
|
fn data_uri_bytes(resource: &Value, uri_key: &str, expect_media_type: &str) -> Vec<u8> {
|
||||||
let uri = resource
|
let uri = resource
|
||||||
@@ -716,10 +717,10 @@ fn export_inlines_contact_and_event_blobs_instead_of_blob_ids() {
|
|||||||
let tgt = fx.account("test6").expect("test6");
|
let tgt = fx.account("test6").expect("test6");
|
||||||
let archive = tmp_archive("issue30");
|
let archive = tmp_archive("issue30");
|
||||||
|
|
||||||
let photo: &[u8] = b"\x89PNG\r\n\x1a\nvandelay issue 30 contact photo bytes";
|
let photo: &[u8] = b"\x89PNG\r\n\x1a\ninbuxa-migrate issue 30 contact photo bytes";
|
||||||
let agenda: &[u8] = b"vandelay issue 30 calendar enclosure bytes";
|
let agenda: &[u8] = b"inbuxa-migrate issue 30 calendar enclosure bytes";
|
||||||
{
|
{
|
||||||
let conn = vandelay::db::init::open(&archive).expect("init archive");
|
let conn = inbuxa_migrate::db::init::open(&archive).expect("init archive");
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"INSERT INTO address_books (id,name,is_default) VALUES (1,'Issue30 Book',1)",
|
"INSERT INTO address_books (id,name,is_default) VALUES (1,'Issue30 Book',1)",
|
||||||
[],
|
[],
|
||||||
@@ -730,8 +731,8 @@ fn export_inlines_contact_and_event_blobs_instead_of_blob_ids() {
|
|||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let photo_blob = vandelay::db::blobs::intern_blob(&conn, photo).unwrap();
|
let photo_blob = inbuxa_migrate::db::blobs::intern_blob(&conn, photo).unwrap();
|
||||||
let agenda_blob = vandelay::db::blobs::intern_blob(&conn, agenda).unwrap();
|
let agenda_blob = inbuxa_migrate::db::blobs::intern_blob(&conn, agenda).unwrap();
|
||||||
let card = json!({
|
let card = json!({
|
||||||
"@type": "Card",
|
"@type": "Card",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
@@ -944,7 +945,7 @@ fn export_prune_destroys_unmatched() {
|
|||||||
auth: basic("test1"),
|
auth: basic("test1"),
|
||||||
account: AccountSelector::Id(big.account_id.clone()),
|
account: AccountSelector::Id(big.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -964,7 +965,7 @@ fn export_prune_destroys_unmatched() {
|
|||||||
auth: basic("test3"),
|
auth: basic("test3"),
|
||||||
account: AccountSelector::Id(small.account_id.clone()),
|
account: AccountSelector::Id(small.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::Mailbox]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -1004,7 +1005,7 @@ fn import_resume_converges_after_partial() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut first = mk();
|
let mut first = mk();
|
||||||
first.objects = Some(vec![vandelay::types::ObjectType::Mailbox]);
|
first.objects = Some(vec![inbuxa_migrate::types::ObjectType::Mailbox]);
|
||||||
sync::import_jmap::run(common(&archive, false), first).expect("partial import");
|
sync::import_jmap::run(common(&archive, false), first).expect("partial import");
|
||||||
|
|
||||||
let conn = Connection::open(&archive).unwrap();
|
let conn = Connection::open(&archive).unwrap();
|
||||||
@@ -1038,10 +1039,10 @@ fn import_resume_converges_after_partial() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore = "requires Docker"]
|
#[ignore = "requires Docker"]
|
||||||
fn live_burst_exceeds_concurrent_requests_and_recovers() {
|
fn live_burst_exceeds_concurrent_requests_and_recovers() {
|
||||||
|
use inbuxa_migrate::jmap::http::{HttpClient, RetryPolicy};
|
||||||
|
use inbuxa_migrate::jmap::request::{Request, check_method_error};
|
||||||
|
use inbuxa_migrate::jmap::session::{Limits, Session};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vandelay::jmap::http::{HttpClient, RetryPolicy};
|
|
||||||
use vandelay::jmap::request::{Request, check_method_error};
|
|
||||||
use vandelay::jmap::session::{Limits, Session};
|
|
||||||
|
|
||||||
let fx = seeder::provision(base_url()).expect("provision");
|
let fx = seeder::provision(base_url()).expect("provision");
|
||||||
let acc = fx.account("test1").expect("test1");
|
let acc = fx.account("test1").expect("test1");
|
||||||
@@ -1131,7 +1132,7 @@ fn live_burst_exceeds_concurrent_requests_and_recovers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct JmapSettingsGuard {
|
struct JmapSettingsGuard {
|
||||||
admin: vandelay::jmap::http::HttpClient,
|
admin: inbuxa_migrate::jmap::http::HttpClient,
|
||||||
admin_api: String,
|
admin_api: String,
|
||||||
admin_account: String,
|
admin_account: String,
|
||||||
previous: serde_json::Map<String, serde_json::Value>,
|
previous: serde_json::Map<String, serde_json::Value>,
|
||||||
@@ -1139,8 +1140,8 @@ struct JmapSettingsGuard {
|
|||||||
|
|
||||||
impl JmapSettingsGuard {
|
impl JmapSettingsGuard {
|
||||||
fn override_settings(updates: serde_json::Map<String, serde_json::Value>) -> Self {
|
fn override_settings(updates: serde_json::Map<String, serde_json::Value>) -> Self {
|
||||||
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
|
use inbuxa_migrate::jmap::http::{Auth, HttpClient, RetryPolicy};
|
||||||
use vandelay::jmap::session::Session;
|
use inbuxa_migrate::jmap::session::Session;
|
||||||
let admin = HttpClient::new(
|
let admin = HttpClient::new(
|
||||||
Auth::Basic {
|
Auth::Basic {
|
||||||
user: seeder::ADMIN_USER.to_owned(),
|
user: seeder::ADMIN_USER.to_owned(),
|
||||||
@@ -1188,7 +1189,7 @@ impl Drop for JmapSettingsGuard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_jmap_settings(
|
fn read_jmap_settings(
|
||||||
admin: &vandelay::jmap::http::HttpClient,
|
admin: &inbuxa_migrate::jmap::http::HttpClient,
|
||||||
api: &str,
|
api: &str,
|
||||||
account: &str,
|
account: &str,
|
||||||
properties: &[&str],
|
properties: &[&str],
|
||||||
@@ -1217,7 +1218,7 @@ fn read_jmap_settings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn apply_jmap_settings(
|
fn apply_jmap_settings(
|
||||||
admin: &vandelay::jmap::http::HttpClient,
|
admin: &inbuxa_migrate::jmap::http::HttpClient,
|
||||||
api: &str,
|
api: &str,
|
||||||
account: &str,
|
account: &str,
|
||||||
updates: &serde_json::Map<String, serde_json::Value>,
|
updates: &serde_json::Map<String, serde_json::Value>,
|
||||||
@@ -1252,9 +1253,9 @@ fn apply_jmap_settings(
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore = "requires Docker"]
|
#[ignore = "requires Docker"]
|
||||||
fn live_blob_quota_429_triggers_retry_after_then_succeeds() {
|
fn live_blob_quota_429_triggers_retry_after_then_succeeds() {
|
||||||
use vandelay::jmap::blobxfer;
|
use inbuxa_migrate::jmap::blobxfer;
|
||||||
use vandelay::jmap::http::{HttpClient, RetryPolicy};
|
use inbuxa_migrate::jmap::http::{HttpClient, RetryPolicy};
|
||||||
use vandelay::jmap::session::Session;
|
use inbuxa_migrate::jmap::session::Session;
|
||||||
|
|
||||||
let fx = seeder::provision(base_url()).expect("provision");
|
let fx = seeder::provision(base_url()).expect("provision");
|
||||||
let acc = fx.account("test1").expect("test1");
|
let acc = fx.account("test1").expect("test1");
|
||||||
|
|||||||
+11
-10
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -19,16 +20,16 @@ use rusqlite::Connection;
|
|||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
shared_stalwart().base_url()
|
shared_stalwart().base_url()
|
||||||
}
|
}
|
||||||
use vandelay::jmap::account::AccountSelector;
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
use vandelay::jmap::http::Auth;
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::import_maildir::{MaildirImportConfig, run as run_maildir};
|
use inbuxa_migrate::sync::import_maildir::{MaildirImportConfig, run as run_maildir};
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-sync-maildir-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-sync-maildir-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -551,8 +552,8 @@ fn maildir_and_jmap_imports_share_blob_bytes() {
|
|||||||
account: AccountSelector::Id(acc.account_id.clone()),
|
account: AccountSelector::Id(acc.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![
|
objects: Some(vec![
|
||||||
vandelay::types::ObjectType::Mailbox,
|
inbuxa_migrate::types::ObjectType::Mailbox,
|
||||||
vandelay::types::ObjectType::Email,
|
inbuxa_migrate::types::ObjectType::Email,
|
||||||
]),
|
]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
@@ -627,8 +628,8 @@ fn maildir_message_count_matches_jmap_for_same_corpus() {
|
|||||||
account: AccountSelector::Id(acc.account_id.clone()),
|
account: AccountSelector::Id(acc.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![
|
objects: Some(vec![
|
||||||
vandelay::types::ObjectType::Mailbox,
|
inbuxa_migrate::types::ObjectType::Mailbox,
|
||||||
vandelay::types::ObjectType::Email,
|
inbuxa_migrate::types::ObjectType::Email,
|
||||||
]),
|
]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
|
|||||||
+14
-13
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -25,16 +26,16 @@ fn sieves_url() -> String {
|
|||||||
let s = shared_stalwart();
|
let s = shared_stalwart();
|
||||||
format!("sieves://{}:{}", s.host, s.sieve_port)
|
format!("sieves://{}:{}", s.host, s.sieve_port)
|
||||||
}
|
}
|
||||||
use vandelay::jmap::account::AccountSelector;
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
use vandelay::jmap::http::Auth;
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig};
|
use inbuxa_migrate::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig};
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-managesieve-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-managesieve-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
@@ -226,7 +227,7 @@ fn managesieve_and_jmap_imports_share_blob_bytes() {
|
|||||||
},
|
},
|
||||||
account: AccountSelector::Id(acc.account_id.clone()),
|
account: AccountSelector::Id(acc.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::SieveScript]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::SieveScript]),
|
||||||
allow_source_change: false,
|
allow_source_change: false,
|
||||||
};
|
};
|
||||||
let jmap_common = CommonConfig {
|
let jmap_common = CommonConfig {
|
||||||
@@ -319,7 +320,7 @@ fn managesieve_source_change_protection_refuses_second_account() {
|
|||||||
|
|
||||||
let err = sync::import_managesieve::run(common(&archive), basic_config(&acc2.localpart))
|
let err = sync::import_managesieve::run(common(&archive), basic_config(&acc2.localpart))
|
||||||
.expect_err("should refuse the second source without override");
|
.expect_err("should refuse the second source without override");
|
||||||
assert!(matches!(err, vandelay::error::Error::SourceChange(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::SourceChange(_)));
|
||||||
|
|
||||||
let _ = std::fs::remove_file(&archive);
|
let _ = std::fs::remove_file(&archive);
|
||||||
seeder::teardown(base_url()).expect("teardown");
|
seeder::teardown(base_url()).expect("teardown");
|
||||||
@@ -336,7 +337,7 @@ fn managesieve_implicit_tls_path_succeeds_when_offered() {
|
|||||||
cfg.url = sieves_url();
|
cfg.url = sieves_url();
|
||||||
let result = sync::import_managesieve::run(common(&archive), cfg);
|
let result = sync::import_managesieve::run(common(&archive), cfg);
|
||||||
|
|
||||||
if let Err(vandelay::error::Error::Connection(msg)) = &result {
|
if let Err(inbuxa_migrate::error::Error::Connection(msg)) = &result {
|
||||||
eprintln!("(expected on cleartext-only deployments) {msg}");
|
eprintln!("(expected on cleartext-only deployments) {msg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +383,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
|
|||||||
allow_invalid_certs: true,
|
allow_invalid_certs: true,
|
||||||
logger: Logger::from_flags(false, 0),
|
logger: Logger::from_flags(false, 0),
|
||||||
};
|
};
|
||||||
let export_cfg = vandelay::sync::ExportConfig {
|
let export_cfg = inbuxa_migrate::sync::ExportConfig {
|
||||||
connect: ConnectConfig {
|
connect: ConnectConfig {
|
||||||
url: fx.base_url.clone(),
|
url: fx.base_url.clone(),
|
||||||
auth: Auth::Basic {
|
auth: Auth::Basic {
|
||||||
@@ -391,7 +392,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
|
|||||||
},
|
},
|
||||||
account: AccountSelector::Id(dst.account_id.clone()),
|
account: AccountSelector::Id(dst.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::SieveScript]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::SieveScript]),
|
||||||
prune: false,
|
prune: false,
|
||||||
yes: false,
|
yes: false,
|
||||||
};
|
};
|
||||||
@@ -416,7 +417,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
|
|||||||
allow_invalid_certs: true,
|
allow_invalid_certs: true,
|
||||||
logger: Logger::from_flags(false, 0),
|
logger: Logger::from_flags(false, 0),
|
||||||
};
|
};
|
||||||
let export_cfg2 = vandelay::sync::ExportConfig {
|
let export_cfg2 = inbuxa_migrate::sync::ExportConfig {
|
||||||
connect: ConnectConfig {
|
connect: ConnectConfig {
|
||||||
url: fx.base_url.clone(),
|
url: fx.base_url.clone(),
|
||||||
auth: Auth::Basic {
|
auth: Auth::Basic {
|
||||||
@@ -425,7 +426,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
|
|||||||
},
|
},
|
||||||
account: AccountSelector::Id(dst.account_id.clone()),
|
account: AccountSelector::Id(dst.account_id.clone()),
|
||||||
},
|
},
|
||||||
objects: Some(vec![vandelay::types::ObjectType::SieveScript]),
|
objects: Some(vec![inbuxa_migrate::types::ObjectType::SieveScript]),
|
||||||
prune: false,
|
prune: false,
|
||||||
yes: false,
|
yes: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -11,9 +12,9 @@ use std::path::{Path, PathBuf};
|
|||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::CommonConfig;
|
use inbuxa_migrate::sync::CommonConfig;
|
||||||
use vandelay::sync::import_takeout::{TakeoutImportConfig, run};
|
use inbuxa_migrate::sync::import_takeout::{TakeoutImportConfig, run};
|
||||||
|
|
||||||
const RESOURCES: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/resources");
|
const RESOURCES: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/resources");
|
||||||
|
|
||||||
@@ -230,7 +231,7 @@ fn empty_directory_fails_with_usage() {
|
|||||||
let archive = td.path().join("a.sqlite");
|
let archive = td.path().join("a.sqlite");
|
||||||
let err = run(common_for(&archive), config_for(td.path().to_path_buf())).unwrap_err();
|
let err = run(common_for(&archive), config_for(td.path().to_path_buf())).unwrap_err();
|
||||||
assert!(format!("{err}").contains("no .mbox"));
|
assert!(format!("{err}").contains("no .mbox"));
|
||||||
assert!(matches!(err, vandelay::error::Error::Usage(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Usage(_)));
|
||||||
assert_eq!(err.exit_code(), 1);
|
assert_eq!(err.exit_code(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ fn nonexistent_path_fails_with_usage() {
|
|||||||
let archive = td.path().join("a.sqlite");
|
let archive = td.path().join("a.sqlite");
|
||||||
let missing = td.path().join("does-not-exist");
|
let missing = td.path().join("does-not-exist");
|
||||||
let err = run(common_for(&archive), config_for(missing)).unwrap_err();
|
let err = run(common_for(&archive), config_for(missing)).unwrap_err();
|
||||||
assert!(matches!(err, vandelay::error::Error::Usage(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::Usage(_)));
|
||||||
assert_eq!(err.exit_code(), 1);
|
assert_eq!(err.exit_code(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +451,7 @@ fn contacts_dedup_by_uid_across_two_vcf_files() {
|
|||||||
assert_eq!(with_uid, 2);
|
assert_eq!(with_uid, 2);
|
||||||
let synthetic_uids: i64 = conn
|
let synthetic_uids: i64 = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT COUNT(*) FROM contact_cards WHERE uid LIKE 'vandelay-syn-%'",
|
"SELECT COUNT(*) FROM contact_cards WHERE uid LIKE 'inbuxa-migrate-syn-%'",
|
||||||
[],
|
[],
|
||||||
|r| r.get(0),
|
|r| r.get(0),
|
||||||
)
|
)
|
||||||
@@ -543,7 +544,7 @@ fn source_change_protection_refuses_different_path() {
|
|||||||
let archive = td.path().join("a.sqlite");
|
let archive = td.path().join("a.sqlite");
|
||||||
run(common_for(&archive), config_for(a.clone())).unwrap();
|
run(common_for(&archive), config_for(a.clone())).unwrap();
|
||||||
let err = run(common_for(&archive), config_for(b.clone())).unwrap_err();
|
let err = run(common_for(&archive), config_for(b.clone())).unwrap_err();
|
||||||
assert!(matches!(err, vandelay::error::Error::SourceChange(_)));
|
assert!(matches!(err, inbuxa_migrate::error::Error::SourceChange(_)));
|
||||||
|
|
||||||
let mut cfg2 = config_for(b);
|
let mut cfg2 = config_for(b);
|
||||||
cfg2.allow_source_change = true;
|
cfg2.allow_source_change = true;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||||
|
* SPDX-FileCopyrightText: 2026 John Coffey <johnellis@linux.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
*/
|
*/
|
||||||
@@ -16,16 +17,16 @@ use rusqlite::Connection;
|
|||||||
fn base_url() -> &'static str {
|
fn base_url() -> &'static str {
|
||||||
shared_stalwart().base_url()
|
shared_stalwart().base_url()
|
||||||
}
|
}
|
||||||
use vandelay::jmap::account::AccountSelector;
|
use inbuxa_migrate::jmap::account::AccountSelector;
|
||||||
use vandelay::jmap::http::Auth;
|
use inbuxa_migrate::jmap::http::Auth;
|
||||||
use vandelay::logging::Logger;
|
use inbuxa_migrate::logging::Logger;
|
||||||
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
|
||||||
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
|
||||||
|
|
||||||
fn tmp_archive(tag: &str) -> PathBuf {
|
fn tmp_archive(tag: &str) -> PathBuf {
|
||||||
let mut p = std::env::temp_dir();
|
let mut p = std::env::temp_dir();
|
||||||
p.push(format!(
|
p.push(format!(
|
||||||
"vandelay-{tag}-{}-{}.sqlite",
|
"inbuxa-migrate-{tag}-{}-{}.sqlite",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
|||||||
Reference in New Issue
Block a user