Rename to inbuxa-migrate

The crate, binary, library path and every name the tool writes or reads
become inbuxa-migrate: the CLI name and about text, the HTTP user agent,
the credential variables (INBUXA_MIGRATE_PASSWORD, _TOKEN,
_EWS_CLIENT_SECRET and _GRAPH_TOKEN, with no fallback to the old names),
thread names, synthesized UIDs and calendar addresses
(urn:x-inbuxa-migrate:attendee:), and the Maildir file suffix used by the
export script. This is a new tool, so archives written by Vandelay are not
read back.

The version moves to the date scheme the release tags use (2026.9.30), and
the package metadata points at the inbuxa-migrate repository. The cargo-dist
and MSI metadata goes with the release tooling it served.

Modified files carry an added copyright line; the original notices stay.
This commit is contained in:
2026-09-30 10:09:10 -07:00
parent 486a384712
commit 5931b06392
54 changed files with 719 additions and 644 deletions
+5 -4
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -34,7 +35,7 @@ const BAIKAL_YAML: &str = "system:
timezone: 'UTC'
card_enabled: true
cal_enabled: true
invite_from: 'noreply@vandelay.test'
invite_from: 'noreply@inbuxa-migrate.test'
dav_auth_type: 'Basic'
admin_passwordhash: '004b53ae84286ba6003b34e8ef404826'
failed_access_message: 'user %u authentication failure for Baikal'
@@ -64,7 +65,7 @@ impl Baikal {
pub fn start() -> ContainerResult<Self> {
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_data(BAIKAL_YAML.as_bytes().to_vec(), "baikal.yaml")
.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}")))?;
let uri = format!("principals/{name}");
let email = format!("{name}@vandelay.test");
let display = format!("Vandelay {name}");
let email = format!("{name}@inbuxa-migrate.test");
let display = format!("Inbuxa {name}");
conn.execute(
"INSERT INTO principals (uri, email, displayname) VALUES (?1, ?2, ?3)",
params![uri, email, display],
+11 -7
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -142,7 +143,7 @@ pub struct Cyrus {
impl Cyrus {
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_data(IMAPD_CONF.as_bytes().to_vec(), "imapd.conf")
.with_data(CYRUS_CONF.as_bytes().to_vec(), "cyrus.conf")
@@ -313,10 +314,13 @@ impl Cyrus {
) -> ContainerResult<(Vec<u8>, String)> {
let mut client = ImapSeed::connect(&self.imap.host, self.imap.port)?;
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!(
"From: cyrus-added-{tag}@vandelay.test\r\n\
To: {}@vandelay.test\r\n\
"From: cyrus-added-{tag}@inbuxa-migrate.test\r\n\
To: {}@inbuxa-migrate.test\r\n\
Subject: Cyrus added probe {tag}\r\n\
Message-ID: {message_id}\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> {
let body = "From: probe-flags@vandelay.test\r\n\
To: user@vandelay.test\r\n\
let body = "From: probe-flags@inbuxa-migrate.test\r\n\
To: user@inbuxa-migrate.test\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\
\r\n\
Cyrus flag probe body.\r\n";
+45 -44
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* 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);
for i in 0..n {
let body = format!(
"From: sender{i}@vandelay.test\r\n\
To: user@vandelay.test\r\n\
"From: sender{i}@inbuxa-migrate.test\r\n\
To: user@inbuxa-migrate.test\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\
MIME-Version: 1.0\r\n\
Content-Type: text/plain; charset=utf-8\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 {
raw: body.into_bytes(),
@@ -135,10 +136,10 @@ fn vcard_v3_basic(i: usize) -> String {
format!(
"BEGIN:VCARD\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\
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"
)
}
@@ -147,14 +148,14 @@ fn vcard_v3_full(i: usize) -> String {
format!(
"BEGIN:VCARD\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\
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\
ORG:Vandelay Test\r\n\
ORG:Inbuxa Test\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\
END:VCARD\r\n"
)
@@ -164,11 +165,11 @@ fn vcard_v3_multi_email(i: usize) -> String {
format!(
"BEGIN:VCARD\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\
N:Contact{i};MultiEmail;;;\r\n\
EMAIL;TYPE=INTERNET;TYPE=HOME:multi-{i}-home@vandelay.test\r\n\
EMAIL;TYPE=INTERNET;TYPE=WORK:multi-{i}-work@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@inbuxa-migrate.test\r\n\
END:VCARD\r\n"
)
}
@@ -177,12 +178,12 @@ fn vcard_v3_org_and_title(i: usize) -> String {
format!(
"BEGIN:VCARD\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\
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\
EMAIL;TYPE=INTERNET:org-{i}@vandelay.test\r\n\
EMAIL;TYPE=INTERNET:org-{i}@inbuxa-migrate.test\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\
FN:V4 Basic {i}\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"
)
}
@@ -206,7 +207,7 @@ fn vcard_v4_with_address(i: usize) -> String {
UID:urn:uuid:00000000-0000-4000-b000-0000{i:08x}\r\n\
FN:V4 Address {i}\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\
END:VCARD\r\n"
)
@@ -220,7 +221,7 @@ fn vcard_v4_nickname(i: usize) -> String {
FN:V4 Nick {i}\r\n\
N:Contact{i};V4Nick;;;\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"
)
}
@@ -236,7 +237,7 @@ fn vcard_v4_birthday(i: usize) -> String {
FN:V4 Birthday {i}\r\n\
N:Contact{i};V4Birthday;;;\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"
)
}
@@ -245,10 +246,10 @@ fn vcard_v3_apple_item_labels(i: usize) -> String {
format!(
"BEGIN:VCARD\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\
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\
ITEM2.X-ABLABEL:Name2\r\n\
ITEM1.X-ABDATE:20171111\r\n\
@@ -287,9 +288,9 @@ fn ical_simple_dt(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-simple-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-simple-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\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\
@@ -307,9 +308,9 @@ fn ical_all_day(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-allday-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-allday-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART;VALUE=DATE:2025{month:02}{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!(
"BEGIN:VCALENDAR\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\
UID:vandelay-multiday-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-multiday-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART:2025{month:02}{day:02}T090000Z\r\n\
DTEND:2025{month:02}{day:02}T170000Z\r\n\
@@ -344,16 +345,16 @@ fn ical_with_organizer_attendees(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-meeting-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-meeting-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART:2025{month:02}{day:02}T140000Z\r\n\
DTEND:2025{month:02}{day:02}T150000Z\r\n\
SUMMARY:Sync meeting {i}\r\n\
ORGANIZER;CN=Organiser:mailto:organiser-{i}@vandelay.test\r\n\
ATTENDEE;CN=Alice;PARTSTAT=ACCEPTED:mailto:alice-{i}@vandelay.test\r\n\
ATTENDEE;CN=Bob;PARTSTAT=NEEDS-ACTION:mailto:bob-{i}@vandelay.test\r\n\
ORGANIZER;CN=Organiser:mailto:organiser-{i}@inbuxa-migrate.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}@inbuxa-migrate.test\r\n\
END:VEVENT\r\n\
END:VCALENDAR\r\n"
)
@@ -365,15 +366,15 @@ fn ical_with_categories_location(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-cat-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-cat-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART:2025{month:02}{day:02}T100000Z\r\n\
DTEND:2025{month:02}{day:02}T110000Z\r\n\
SUMMARY:Categorised event {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:VCALENDAR\r\n"
)
@@ -385,9 +386,9 @@ fn ical_recurring_daily(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-daily-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-daily-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART:2025{month:02}{day:02}T070000Z\r\n\
DTEND:2025{month:02}{day:02}T073000Z\r\n\
@@ -405,9 +406,9 @@ fn ical_recurring_weekly_until(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-weekly-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-weekly-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART:2025{month:02}{day:02}T160000Z\r\n\
DTEND:2025{month:02}{day:02}T170000Z\r\n\
@@ -424,9 +425,9 @@ fn ical_with_alarm(i: usize) -> String {
format!(
"BEGIN:VCALENDAR\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\
UID:vandelay-alarm-{i}@vandelay.test\r\n\
UID:inbuxa-migrate-alarm-{i}@inbuxa-migrate.test\r\n\
DTSTAMP:20250101T120000Z\r\n\
DTSTART:2025{month:02}{day:02}T080000Z\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!(
"BEGIN:VCALENDAR\r\n\
VERSION:2.0\r\n\
PRODID:-//vandelay//broken//EN\r\n\
PRODID:-//inbuxa-migrate//broken//EN\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\
DTSTART:NOT-A-DATE\r\n\
RRULE:FREQ=BOGUS;INTERVAL=oops\r\n\
+13 -12
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -126,7 +127,7 @@ pub struct Dovecot {
impl Dovecot {
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_data(DOVECOT_CONF.as_bytes().to_vec(), "dovecot.conf")
.with_data(users_file().into_bytes(), "users")
@@ -374,10 +375,10 @@ impl Dovecot {
) -> ContainerResult<(Vec<u8>, String)> {
let mut client = ImapSeed::connect(&self.imap.host, self.imap.port)?;
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!(
"From: added-{tag}@vandelay.test\r\n\
To: {}@vandelay.test\r\n\
"From: added-{tag}@inbuxa-migrate.test\r\n\
To: {}@inbuxa-migrate.test\r\n\
Subject: Added probe {tag}\r\n\
Message-ID: {message_id}\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> {
let body = "From: probe-flags@vandelay.test\r\n\
To: user@vandelay.test\r\n\
let body = "From: probe-flags@inbuxa-migrate.test\r\n\
To: user@inbuxa-migrate.test\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\
\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> {
let body = "From: nomid@vandelay.test\r\n\
To: user@vandelay.test\r\n\
let body = "From: nomid@inbuxa-migrate.test\r\n\
To: user@inbuxa-migrate.test\r\n\
Subject: No Message-ID probe\r\n\
Date: Wed, 01 Jan 2025 12:00:00 +0000\r\n\
\r\n\
@@ -467,10 +468,10 @@ pub fn no_message_id_probe() -> Vec<u8> {
}
pub fn shared_message_id_probe() -> Vec<u8> {
let body = "From: shared@vandelay.test\r\n\
To: user@vandelay.test\r\n\
let body = "From: shared@inbuxa-migrate.test\r\n\
To: user@inbuxa-migrate.test\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\
\r\n\
Shared MID body.\r\n";
+2 -1
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -63,7 +64,7 @@ pub const ACCOUNT1: &str = "user1";
pub const ACCOUNT2: &str = "user2";
pub const ACCOUNT3: &str = "user3";
pub const PASSWORD: &str = "VandelayUser#2026";
pub const PASSWORD: &str = "InbuxaUser#2026";
pub static MAILBOXES_DEEP: &[MailboxSpec] = &[
mailbox!("proj", "Projects", None),
+2 -1
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -22,7 +23,7 @@ pub mod webdav;
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;
+4 -3
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -9,13 +10,13 @@ use std::path::{Path, PathBuf};
use rusqlite::Connection;
use vandelay::logging::Logger;
use vandelay::sync::CommonConfig;
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::CommonConfig;
pub fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-container-{tag}-{}-{}.sqlite",
"inbuxa-migrate-container-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
+2 -1
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -137,7 +138,7 @@ pub struct WebDav {
impl WebDav {
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_data(APACHE_CONF.as_bytes().to_vec(), "apache.conf")
.with_data(htpasswd_for_test().into_bytes(), "htpasswd")
+4 -3
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -16,11 +17,11 @@ use integration::validate::{
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 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 {
let path = match kind {
+7 -6
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -16,9 +17,9 @@ use integration::validate::{
};
use integration::{Account, Endpoint};
use vandelay::error::Error;
use vandelay::sync::import_imap;
use vandelay::sync::import_imap::{ImapAuth, ImapImportConfig};
use inbuxa_migrate::error::Error;
use inbuxa_migrate::sync::import_imap;
use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig};
fn imap_config(account: &Account, imap: &Endpoint) -> ImapImportConfig {
ImapImportConfig {
@@ -327,10 +328,10 @@ fn cyrus_non_ascii_mailbox_names_round_trip() {
let mutf7_name = "Envoy&AOk-s";
let utf8_name = "Envoyés";
let message = b"From: accents@vandelay.test\r\n\
To: user1@vandelay.test\r\n\
let message = b"From: accents@inbuxa-migrate.test\r\n\
To: user1@inbuxa-migrate.test\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\
\r\n\
Accented folder probe.\r\n";
+11 -10
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* 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,
};
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 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 {
ImapImportConfig {
@@ -526,10 +527,10 @@ fn dovecot_non_ascii_mailbox_names_round_trip() {
let mutf7_name = "Envoy&AOk-s";
let utf8_name = "Envoyés";
let message = b"From: accents@vandelay.test\r\n\
To: user1@vandelay.test\r\n\
let message = b"From: accents@inbuxa-migrate.test\r\n\
To: user1@inbuxa-migrate.test\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\
\r\n\
Accented folder probe.\r\n";
+4 -3
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -16,11 +17,11 @@ use integration::validate::{
};
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 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 {
DavImportConfig {
+5 -4
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -15,9 +16,9 @@ use integration::validate::{
use integration::webdav::{AccountSeed, WebDav};
use integration::{Account, Endpoint};
use vandelay::error::Error;
use vandelay::sync::import_dav;
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use inbuxa_migrate::error::Error;
use inbuxa_migrate::sync::import_dav;
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
fn webdav_config(account: &Account, http: &Endpoint) -> DavImportConfig {
DavImportConfig {
@@ -319,7 +320,7 @@ fn webdav_starts_seeds_and_imports() {
drop(conn);
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
);
let new_payload_bytes = new_payload.as_bytes().to_vec();
+4 -3
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -7,10 +8,10 @@
mod integration;
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 vandelay::jmap::account::{self, AccountSelector};
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
use vandelay::jmap::session::Session;
fn admin_client() -> HttpClient {
HttpClient::new(
+66 -51
View File
@@ -1,17 +1,18 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
use std::io::Cursor;
use vandelay::dav::client::DavClient;
use vandelay::dav::discover::{DavKind, discover};
use vandelay::dav::parse::{parse_multistatus, strip_ascii_control_chars};
use vandelay::dav::xml;
use vandelay::jmap::error::JmapError;
use vandelay::jmap::http::{Auth, RetryPolicy};
use inbuxa_migrate::dav::client::DavClient;
use inbuxa_migrate::dav::discover::{DavKind, discover};
use inbuxa_migrate::dav::parse::{parse_multistatus, strip_ascii_control_chars};
use inbuxa_migrate::dav::xml;
use inbuxa_migrate::jmap::error::JmapError;
use inbuxa_migrate::jmap::http::{Auth, RetryPolicy};
fn client(retries: u32) -> DavClient {
DavClient::new(
@@ -75,7 +76,7 @@ fn discovery_resolves_per_user_principal_even_when_url_lists_collections() {
r#"<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<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:prop>
<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:propstat>
<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:status>HTTP/1.1 200 OK</d:status>
</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.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"
);
}
@@ -212,7 +213,7 @@ fn discovery_returns_not_found_when_no_collections() {
let err = discover(&c, DavKind::Caldav, &server.url()).unwrap_err();
assert!(matches!(
err,
vandelay::dav::discover::DiscoveryError::NotFound { .. }
inbuxa_migrate::dav::discover::DiscoveryError::NotFound { .. }
));
}
@@ -489,14 +490,14 @@ fn webdav_listing_returns_collection_and_file() {
#[test]
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"}]}}"#;
assert_eq!(classify(403, body), DavOutcome::Retryable);
}
#[test]
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);
}
@@ -801,7 +802,7 @@ fn webdav_cycle_breaks_on_lex_smallest() {
#[test]
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);
}
@@ -893,8 +894,8 @@ fn streaming_propfind_404_returns_empty_responses() {
#[test]
fn source_change_protection_rejects_different_account_id() {
use inbuxa_migrate::db::{init, sources};
use rusqlite::Connection;
use vandelay::db::{init, sources};
let conn = Connection::open_in_memory().unwrap();
init::apply_schema(&conn).unwrap();
@@ -1049,15 +1050,15 @@ fn webdav_discovery_keeps_only_self_row_as_root() {
#[test]
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 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 url = server.url();
@@ -1336,10 +1337,10 @@ fn webdav_display_or_basename_test_via_parser_keeps_basename_semantics() {
#[test]
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 vandelay::logging::Logger;
use vandelay::sync::CommonConfig;
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg, run};
let mut server = mockito::Server::new();
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 archive: PathBuf = std::env::temp_dir().join(format!(
"vandelay-dryrun-{}-{}.sqlite",
"inbuxa-migrate-dryrun-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
@@ -1449,10 +1450,10 @@ fn dry_run_writes_nothing_but_emits_per_collection_counts() {
#[test]
fn dav_source_change_protection_fires_across_users_on_same_root() {
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 vandelay::logging::Logger;
use vandelay::sync::CommonConfig;
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg, run};
let mut server = mockito::Server::new();
let url = server.url();
@@ -1499,8 +1500,14 @@ fn dav_source_change_protection_fires_across_users_on_same_root() {
.with_body(&empty_items)
.create();
let auth_a = format!("Basic {}", STANDARD.encode("[email protected]:passA"));
let auth_b = format!("Basic {}", STANDARD.encode("[email protected]:passB"));
let auth_a = format!(
"Basic {}",
STANDARD.encode("[email protected]:passA")
);
let auth_b = format!(
"Basic {}",
STANDARD.encode("[email protected]:passB")
);
let principal = |who: &str| {
format!(
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())
.with_status(207)
.with_header("content-type", "application/xml; charset=utf-8")
.with_body(principal("secondary@vandelay.org"))
.with_body(principal("secondary@inbuxa-migrate.org"))
.create();
let _pb = server
.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())
.with_status(207)
.with_header("content-type", "application/xml; charset=utf-8")
.with_body(principal("tertiary@vandelay.org"))
.with_body(principal("tertiary@inbuxa-migrate.org"))
.create();
let archive: PathBuf = std::env::temp_dir().join(format!(
"vandelay-dav-srcchange-{}-{}.sqlite",
"inbuxa-migrate-dav-srcchange-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.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,
};
run(common(&archive), config("[email protected]", "passA")).expect("user A import ok");
let err = run(common(&archive), config("[email protected]", "passB")).unwrap_err();
run(
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);
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:?}"
);
}
#[test]
fn source_change_protection_rejects_different_session_url_same_account() {
use inbuxa_migrate::db::{init, sources};
use rusqlite::Connection;
use vandelay::db::{init, sources};
let conn = Connection::open_in_memory().unwrap();
init::apply_schema(&conn).unwrap();
@@ -1627,8 +1642,8 @@ fn etag_missing_in_enumeration_propagates_to_storage_layer() {
#[test]
fn mixed_source_archive_allows_distinct_kinds_against_same_url() {
use inbuxa_migrate::db::{init, sources};
use rusqlite::Connection;
use vandelay::db::{init, sources};
let conn = Connection::open_in_memory().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 mut p = std::env::temp_dir();
p.push(format!(
"vandelay-mockdav-{}-{:?}-{n}.sqlite",
"inbuxa-migrate-mockdav-{}-{:?}-{n}.sqlite",
std::process::id(),
std::thread::current().id(),
));
@@ -1671,11 +1686,11 @@ fn dav_archive() -> std::path::PathBuf {
p
}
fn caldav_import_config(url: &str) -> vandelay::sync::import_dav::DavImportConfig {
vandelay::sync::import_dav::DavImportConfig {
kind: vandelay::sync::import_dav::DavKindArg::Caldav,
fn caldav_import_config(url: &str) -> inbuxa_migrate::sync::import_dav::DavImportConfig {
inbuxa_migrate::sync::import_dav::DavImportConfig {
kind: inbuxa_migrate::sync::import_dav::DavKindArg::Caldav,
url: url.to_owned(),
auth: vandelay::sync::import_dav::DavAuth::Basic {
auth: inbuxa_migrate::sync::import_dav::DavAuth::Basic {
user: "u".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 {
vandelay::sync::CommonConfig {
fn dav_common(archive: &std::path::Path) -> inbuxa_migrate::sync::CommonConfig {
inbuxa_migrate::sync::CommonConfig {
archive: archive.to_path_buf(),
threads: 1,
dry_run: false,
max_retries: 0,
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();
let archive = dav_archive();
let summary = vandelay::sync::import_dav::run(
let summary = inbuxa_migrate::sync::import_dav::run(
dav_common(&archive),
caldav_import_config(&format!("{url}/dav/cal/u/")),
)
@@ -1828,14 +1843,14 @@ fn credentials_rejected_during_discovery_still_aborts_the_run() {
.create();
let archive = dav_archive();
let err = vandelay::sync::import_dav::run(
let err = inbuxa_migrate::sync::import_dav::run(
dav_common(&archive),
caldav_import_config(&format!("{url}/dav/cal/u/")),
)
.expect_err("credentials rejected for the principal aborts the run");
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:?}"
);
assert_eq!(err.exit_code(), 2);
@@ -1871,7 +1886,7 @@ fn dav_import_reports_both_phases_when_every_collection_fails() {
.create();
let archive = dav_archive();
let outcome = vandelay::sync::import_dav::run_reporting(
let outcome = inbuxa_migrate::sync::import_dav::run_reporting(
dav_common(&archive),
caldav_import_config(&format!("{url}/dav/cal/u/")),
);
+40 -37
View File
@@ -1,25 +1,28 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
use encodify::base64::{LENIENT, STANDARD};
use mockito::Matcher;
use vandelay::exchange_ews::EwsClient;
use vandelay::exchange_ews::autodiscover::{DiscoverySource, discover};
use vandelay::exchange_ews::error::EwsError;
use vandelay::exchange_ews::parse::{
use inbuxa_migrate::exchange_ews::EwsClient;
use inbuxa_migrate::exchange_ews::autodiscover::{DiscoverySource, discover};
use inbuxa_migrate::exchange_ews::error::EwsError;
use inbuxa_migrate::exchange_ews::parse::{
EnvelopeKind, parse_find_folder_response, parse_find_item_response,
parse_get_attachment_inline, parse_response_messages, parse_sync_folder_items_response,
read_envelope_summary,
};
use vandelay::exchange_ews::types::{FolderClass, FolderId, ItemId, ResponseCode, ServerVersion};
use vandelay::exchange_ews::xml::{
use inbuxa_migrate::exchange_ews::types::{
FolderClass, FolderId, ItemId, ResponseCode, ServerVersion,
};
use inbuxa_migrate::exchange_ews::xml::{
FolderRef, ItemShape, Traversal, find_folder_body, find_item_body, get_attachment_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 APP_JSON: &str = "application/json";
@@ -59,7 +62,7 @@ fn autodiscover_v2_returns_global_endpoint() {
.create();
let _ = server;
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();
assert_eq!(r.source, DiscoverySource::SuppliedUrl);
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 body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -290,7 +293,7 @@ fn http_401_surfaces_as_auth_error() {
let c = client(0);
let body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -313,7 +316,7 @@ fn mime_content_round_trips_through_base64_decode() {
</m:ResponseMessages></m:GetItemResponse>"
));
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 bytes = LENIENT.decode(&s).unwrap();
assert_eq!(bytes, original);
@@ -341,7 +344,7 @@ fn get_attachment_inline_decodes_photo_blob() {
#[test]
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:ItemId Id=\"M1\" ChangeKey=\"K1\"/>\
<t:Subject>Daily</t:Subject>\
@@ -359,8 +362,8 @@ fn calendar_item_master_inlines_modified_and_deleted_occurrences() {
<t:DeletedOccurrences>\
<t:DeletedOccurrence><t:Start>2025-06-17T14:00:00Z</t:Start></t:DeletedOccurrence>\
</t:DeletedOccurrences>\
</t:CalendarItem></vandelay-inner>";
let item = vandelay::exchange_ews::parse::parse_calendar_item(body).unwrap();
</t:CalendarItem></inbuxa-migrate-inner>";
let item = inbuxa_migrate::exchange_ews::parse::parse_calendar_item(body).unwrap();
assert_eq!(item.id.id, "M1");
assert_eq!(item.uid.as_deref(), Some("uid-1"));
assert_eq!(item.modified_occurrences.len(), 1);
@@ -373,7 +376,7 @@ fn calendar_item_master_inlines_modified_and_deleted_occurrences() {
#[test]
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:ItemId Id=\"M3\" ChangeKey=\"K1\"/>\
<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: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:CalendarItem></vandelay-inner>";
let item = vandelay::exchange_ews::parse::parse_calendar_item(body).unwrap();
let event = vandelay::exchange_ews::calendar_map::to_jscalendar(&item);
</t:CalendarItem></inbuxa-migrate-inner>";
let item = inbuxa_migrate::exchange_ews::parse::parse_calendar_item(body).unwrap();
let event = inbuxa_migrate::exchange_ews::calendar_map::to_jscalendar(&item);
assert_eq!(
event.data["organizerCalendarAddress"], "mailto:[email protected]",
@@ -409,7 +412,7 @@ fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
attendee["calendarAddress"]
.as_str()
.unwrap()
.starts_with("urn:x-vandelay:attendee:"),
.starts_with("urn:x-inbuxa-migrate:attendee:"),
"a legacy directory reference cannot be resolved and stays synthetic"
);
assert!(
@@ -420,7 +423,7 @@ fn organizer_and_attendee_addresses_survive_an_ex_routing_type() {
#[test]
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:ItemId Id=\"M2\" ChangeKey=\"K1\"/>\
<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:EndDateRecurrence><t:StartDate>2021-08-04-06:00</t:StartDate><t:EndDate>2021-09-30-06:00</t:EndDate></t:EndDateRecurrence>\
</t:Recurrence>\
</t:CalendarItem></vandelay-inner>";
let item = vandelay::exchange_ews::parse::parse_calendar_item(body).unwrap();
let event = vandelay::exchange_ews::calendar_map::to_jscalendar(&item);
</t:CalendarItem></inbuxa-migrate-inner>";
let item = inbuxa_migrate::exchange_ews::parse::parse_calendar_item(body).unwrap();
let event = inbuxa_migrate::exchange_ews::calendar_map::to_jscalendar(&item);
let rule = &event.data["recurrenceRule"];
assert_eq!(rule["frequency"], "weekly");
assert_eq!(
@@ -486,8 +489,8 @@ fn invalid_sync_state_data_fault_is_surfaced() {
#[test]
fn coordinator_diff_classifies_new_vanished_changed_unchanged() {
use vandelay::db::exchange_ews_ids::ItemRow;
use vandelay::sync::import_exchange_ews::items::{EnumeratedItem, diff};
use inbuxa_migrate::db::exchange_ews_ids::ItemRow;
use inbuxa_migrate::sync::import_exchange_ews::items::{EnumeratedItem, diff};
let server = vec![
EnumeratedItem {
@@ -532,9 +535,9 @@ fn coordinator_diff_classifies_new_vanished_changed_unchanged() {
#[test]
fn source_change_protection_refuses_different_account() {
use inbuxa_migrate::db;
use inbuxa_migrate::db::sources::SourceKey;
use rusqlite::Connection;
use vandelay::db;
use vandelay::db::sources::SourceKey;
let tmp = tempfile::NamedTempFile::new().unwrap();
let conn = Connection::open(tmp.path()).unwrap();
@@ -557,9 +560,9 @@ fn source_change_protection_refuses_different_account() {
#[test]
fn mailbox_kinds_are_three_separate_sources() {
use inbuxa_migrate::db;
use inbuxa_migrate::db::sources::SourceKey;
use rusqlite::Connection;
use vandelay::db;
use vandelay::db::sources::SourceKey;
let tmp = tempfile::NamedTempFile::new().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 body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -710,7 +713,7 @@ fn invalid_server_version_fault_downgrades_and_succeeds() {
assert_eq!(c.server_version(), ServerVersion::Exchange2013Sp1);
let body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -748,7 +751,7 @@ fn unsupported_version_floor_surfaces_as_soap_fault() {
let c = client(0);
let body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -801,7 +804,7 @@ fn server_affinity_cookie_is_captured_and_resent() {
let c = client(0);
let body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -823,7 +826,7 @@ fn http_456_surfaces_as_account_locked_auth_error() {
let c = client(0);
let body = find_folder_body(
FolderRef::Distinguished(
vandelay::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
inbuxa_migrate::exchange_ews::types::DistinguishedFolderId::MsgFolderRoot,
),
Traversal::Deep,
);
@@ -836,8 +839,8 @@ fn http_456_surfaces_as_account_locked_auth_error() {
#[test]
fn for_each_fetched_item_streams_every_id_across_windows() {
use vandelay::logging::Logger;
use vandelay::sync::import_exchange_ews::items::{ItemRunCtx, for_each_fetched_item};
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::import_exchange_ews::items::{ItemRunCtx, for_each_fetched_item};
let mut server = mockito::Server::new();
let url = format!("{}/EWS/Exchange.asmx", server.url());
+151 -147
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -7,21 +8,21 @@
use std::sync::Once;
use encodify::base64::URL_SAFE_NO_PAD;
use mockito::{Matcher, Server};
use serde_json::json;
use vandelay::exchange_graph::api::{Endpoints, collect_all_ids, paged_collect};
use vandelay::exchange_graph::calendar_map::{EventType, classify_event_type, convert_event};
use vandelay::exchange_graph::client::{Accept, GraphClient};
use vandelay::exchange_graph::contact_map::convert_contact;
use vandelay::exchange_graph::error::GraphError;
use vandelay::exchange_graph::oauth::{
use inbuxa_migrate::exchange_graph::api::{Endpoints, collect_all_ids, paged_collect};
use inbuxa_migrate::exchange_graph::calendar_map::{EventType, classify_event_type, convert_event};
use inbuxa_migrate::exchange_graph::client::{Accept, GraphClient};
use inbuxa_migrate::exchange_graph::contact_map::convert_contact;
use inbuxa_migrate::exchange_graph::error::GraphError;
use inbuxa_migrate::exchange_graph::oauth::{
DeviceCodeResponse, TokenResponse, parse_device_code_response, parse_token_response,
run_device_code_polling_against,
};
use vandelay::exchange_graph::recurrence::convert_patterned_recurrence;
use vandelay::exchange_graph::retry::{HttpClass, classify_http_status};
use vandelay::exchange_graph::types::Surfaces;
use vandelay::jmap::http::RetryPolicy;
use inbuxa_migrate::exchange_graph::recurrence::convert_patterned_recurrence;
use inbuxa_migrate::exchange_graph::retry::{HttpClass, classify_http_status};
use inbuxa_migrate::exchange_graph::types::Surfaces;
use inbuxa_migrate::jmap::http::RetryPolicy;
use mockito::{Matcher, Server};
use serde_json::json;
static INIT: Once = Once::new();
@@ -525,7 +526,7 @@ fn contact_minimal_yields_jscontact_card() {
"emailAddresses": [{"name": "Alice", "address": "[email protected]"}]
});
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["name"]["full"], "Alice Liddell");
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"}]}"#)
.create();
let base = server.url();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: tempfile::NamedTempFile::new().unwrap().path().to_owned(),
threads: 2,
dry_run: true,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: base.clone(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -593,7 +594,7 @@ fn integration_dry_run_against_mock_server_lists_three_surfaces() {
event_attachments: true,
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
.per_type
.iter()
@@ -681,23 +682,23 @@ fn integration_full_run_mail_only_imports_mime_via_value() {
let tmp = tempfile::NamedTempFile::new().unwrap();
let archive_path = tmp.path().to_owned();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive_path.clone(),
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -706,7 +707,7 @@ fn integration_full_run_mail_only_imports_mime_via_value() {
allow_source_change: false,
};
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
.per_type
.iter()
@@ -780,23 +781,23 @@ fn integration_duplicate_message_id_does_not_abort_run() {
let tmp = tempfile::NamedTempFile::new().unwrap();
let archive_path = tmp.path().to_owned();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive_path.clone(),
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -805,7 +806,7 @@ fn integration_duplicate_message_id_does_not_abort_run() {
allow_source_change: false,
};
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
.per_type
.iter()
@@ -880,15 +881,15 @@ fn integration_full_run_is_convergent_on_second_invocation() {
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
let api_base = server.url();
let make_config = || vandelay::sync::import_exchange_graph::GraphImportConfig {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let make_config = || inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: api_base.clone(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -896,18 +897,20 @@ fn integration_full_run_is_convergent_on_second_invocation() {
event_attachments: true,
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,
threads: 2,
dry_run: false,
max_retries: 0,
allow_invalid_certs: false,
logger: vandelay::logging::Logger::new(0),
logger: inbuxa_migrate::logging::Logger::new(0),
};
let first =
vandelay::sync::import_exchange_graph::run(make_common(archive.clone()), make_config())
.unwrap();
let first = inbuxa_migrate::sync::import_exchange_graph::run(
make_common(archive.clone()),
make_config(),
)
.unwrap();
let created_first = first
.per_type
.iter()
@@ -917,7 +920,8 @@ fn integration_full_run_is_convergent_on_second_invocation() {
assert_eq!(created_first, 1);
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
.per_type
.iter()
@@ -930,10 +934,10 @@ fn integration_full_run_is_convergent_on_second_invocation() {
#[test]
fn source_change_protection_refuses_a_different_account() {
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
let conn = vandelay::db::init::open(&archive).unwrap();
vandelay::db::sources::upsert_source(
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
inbuxa_migrate::db::sources::upsert_source(
&conn,
&vandelay::db::sources::SourceKey {
&inbuxa_migrate::db::sources::SourceKey {
kind: "exchange_graph".to_owned(),
session_url:
"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]"}"#)
.create();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive,
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -978,9 +982,9 @@ fn source_change_protection_refuses_a_different_account() {
event_attachments: true,
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!(
matches!(err, vandelay::error::Error::SourceChange(_)),
matches!(err, inbuxa_migrate::error::Error::SourceChange(_)),
"expected SourceChange error, got {err:?}"
);
}
@@ -1011,35 +1015,35 @@ fn stub_well_known_folders(server: &mut Server, inbox_id: &str) {
.create();
}
fn make_common(archive: std::path::PathBuf) -> vandelay::sync::CommonConfig {
vandelay::sync::CommonConfig {
fn make_common(archive: std::path::PathBuf) -> inbuxa_migrate::sync::CommonConfig {
inbuxa_migrate::sync::CommonConfig {
archive,
threads: 2,
dry_run: false,
max_retries: 0,
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 {
vandelay::exchange_graph::types::Surfaces::parse_list(list).unwrap()
fn surfaces(list: &str) -> inbuxa_migrate::exchange_graph::types::Surfaces {
inbuxa_migrate::exchange_graph::types::Surfaces::parse_list(list).unwrap()
}
fn make_config(
api_base: String,
user_target: Option<String>,
surfaces: vandelay::exchange_graph::types::Surfaces,
) -> vandelay::sync::import_exchange_graph::GraphImportConfig {
vandelay::sync::import_exchange_graph::GraphImportConfig {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
surfaces: inbuxa_migrate::exchange_graph::types::Surfaces,
) -> inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base,
user_target,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
surfaces,
event_body_format: vandelay::exchange_graph::types::EventBodyFormat::Text,
event_body_format: inbuxa_migrate::exchange_graph::types::EventBodyFormat::Text,
graph_connections: 2,
top: 100,
exception_window_years: 5,
@@ -1097,15 +1101,15 @@ fn users_upn_routes_through_users_segment_not_me() {
.expect_at_least(0)
.create();
let base = server.url();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: tempfile::NamedTempFile::new().unwrap().path().to_owned(),
threads: 2,
dry_run: true,
max_retries: 0,
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,
make_config(base, Some("[email protected]".to_owned()), Surfaces::ALL),
)
@@ -1207,7 +1211,7 @@ fn series_master_with_exception_merges_into_recurrence_overrides() {
.create();
let base = server.url();
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_config(base, None, surfaces("calendar")),
)
@@ -1220,7 +1224,7 @@ fn series_master_with_exception_merges_into_recurrence_overrides() {
.unwrap_or(0);
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
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
.unwrap();
@@ -1312,7 +1316,7 @@ fn occurrence_event_is_skipped_no_row_no_id_mapping() {
.create();
let base = server.url();
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_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");
occ_get.assert();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let count: i64 = conn
.query_row("SELECT COUNT(*) FROM calendar_events", [], |row| row.get(0))
.unwrap();
@@ -1392,12 +1396,12 @@ fn hidden_mail_folder_has_is_subscribed_zero() {
stub_well_known_folders(&mut server, "FVISIBLE");
let base = server.url();
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_config(base, None, surfaces("mail")),
)
.unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let visible: i64 = conn
.query_row(
"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 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_config(base, None, surfaces("mail")),
)
.unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let mut stmt = conn
.prepare("SELECT name, role FROM mailboxes ORDER BY name")
.unwrap();
@@ -1563,7 +1567,7 @@ SGVsbG8=\r\n--X--\r\n";
.create();
let base = server.url();
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_config(base, None, surfaces("mail")),
)
@@ -1651,7 +1655,7 @@ fn event_get_carries_outlook_timezone_and_body_content_type_prefer() {
.create();
let base = server.url();
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_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 archive = tmp.path().to_owned();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive.clone(),
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
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,
};
drop(tmp);
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let (graph_id, type_name): (String, String) = conn
.query_row(
"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 archive = tmp.path().to_owned();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive.clone(),
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Archive,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Archive,
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,
top: 100,
exception_window_years: 5,
@@ -1835,8 +1839,8 @@ fn archive_mailbox_kind_encodes_synthetic_suffix_in_account_id() {
allow_source_change: false,
};
drop(tmp);
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let account_id: String = conn
.query_row(
"SELECT account_id FROM sources WHERE kind = 'exchange_graph'",
@@ -1850,10 +1854,10 @@ fn archive_mailbox_kind_encodes_synthetic_suffix_in_account_id() {
#[test]
fn allow_source_change_permits_overwriting_a_different_account() {
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
let conn = vandelay::db::init::open(&archive).unwrap();
vandelay::db::sources::upsert_source(
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
inbuxa_migrate::db::sources::upsert_source(
&conn,
&vandelay::db::sources::SourceKey {
&inbuxa_migrate::db::sources::SourceKey {
kind: "exchange_graph".to_owned(),
session_url: "https://login.microsoftonline.com/common|https://x.example".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":[]}"#)
.create();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive.clone(),
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -1902,7 +1906,7 @@ fn allow_source_change_permits_overwriting_a_different_account() {
event_attachments: 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!(
result.is_ok(),
"--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 archive = tmp.path().to_owned();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive.clone(),
threads: 2,
dry_run: true,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -1987,10 +1991,10 @@ fn dry_run_makes_no_per_item_get_and_no_sqlite_writes() {
allow_source_change: false,
};
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_well_known.assert();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let sources: i64 = conn
.query_row("SELECT count(*) FROM sources", [], |row| row.get(0))
.unwrap();
@@ -2025,10 +2029,10 @@ fn token_response_bad_code_recognised() {
#[test]
fn folder_enumeration_failure_skips_vanished_deletion() {
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
let setup_conn = vandelay::db::init::open(&archive).unwrap();
let sid = vandelay::db::sources::upsert_source(
let setup_conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let sid = inbuxa_migrate::db::sources::upsert_source(
&setup_conn,
&vandelay::db::sources::SourceKey {
&inbuxa_migrate::db::sources::SourceKey {
kind: "exchange_graph".to_owned(),
session_url: "stale".to_owned(),
account_id: "stale-uid".to_owned(),
@@ -2043,10 +2047,10 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
[],
)
.unwrap();
vandelay::db::exchange_graph_ids::insert(
inbuxa_migrate::db::exchange_graph_ids::insert(
&setup_conn,
sid,
vandelay::db::exchange_graph_ids::MAILBOX,
inbuxa_migrate::db::exchange_graph_ids::MAILBOX,
"FMAIL",
42,
)
@@ -2067,10 +2071,10 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
rusqlite::params![blob_id],
)
.unwrap();
vandelay::db::exchange_graph_ids::insert(
inbuxa_migrate::db::exchange_graph_ids::insert(
&setup_conn,
sid,
vandelay::db::exchange_graph_ids::EMAIL,
inbuxa_migrate::db::exchange_graph_ids::EMAIL,
"MSG-LOCAL",
1,
)
@@ -2133,23 +2137,23 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
.with_body("transient outage")
.create();
let common = vandelay::sync::CommonConfig {
let common = inbuxa_migrate::sync::CommonConfig {
archive: archive.clone(),
threads: 2,
dry_run: false,
max_retries: 0,
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 {
auth: vandelay::sync::import_exchange_graph::GraphAuth::PreAcquired {
let config = inbuxa_migrate::sync::import_exchange_graph::GraphImportConfig {
auth: inbuxa_migrate::sync::import_exchange_graph::GraphAuth::PreAcquired {
token: make_jwt(9999999999, "[email protected]"),
},
api_base: server.url(),
user_target: None,
mailbox_kind: vandelay::exchange_graph::types::MailboxKind::Primary,
mailbox_kind: inbuxa_migrate::exchange_graph::types::MailboxKind::Primary,
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,
top: 100,
exception_window_years: 5,
@@ -2157,8 +2161,8 @@ fn folder_enumeration_failure_skips_vanished_deletion() {
event_attachments: true,
allow_source_change: true,
};
let _ = vandelay::sync::import_exchange_graph::run(common, config).unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let _ = inbuxa_migrate::sync::import_exchange_graph::run(common, config).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let remaining: i64 = conn
.query_row("SELECT count(*) FROM emails WHERE id = 1", [], |row| {
row.get(0)
@@ -2324,7 +2328,7 @@ fn contacts_surface_imports_only_address_books_and_cards() {
let base = server.url();
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_config(base, None, surfaces("contacts")),
)
@@ -2332,7 +2336,7 @@ fn contacts_surface_imports_only_address_books_and_cards() {
no_mail.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, "contact_cards"), 1);
assert_eq!(row_count(&conn, "mailboxes"), 0);
@@ -2368,7 +2372,7 @@ fn mail_surface_imports_only_mailboxes_and_emails() {
let base = server.url();
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_config(base, None, surfaces("mail")),
)
@@ -2376,7 +2380,7 @@ fn mail_surface_imports_only_mailboxes_and_emails() {
no_calendars.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, "emails"), 1);
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 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_config(base, None, surfaces("contacts")),
)
@@ -2468,7 +2472,7 @@ fn default_contact_folder_is_imported_although_contactfolders_omits_it() {
"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
.query_row("SELECT is_default FROM address_books", [], |row| row.get(0))
.unwrap();
@@ -2518,13 +2522,13 @@ fn default_contact_folder_falls_back_to_parent_of_an_existing_contact() {
let base = server.url();
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_config(base, None, surfaces("contacts")),
)
.unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let name: String = conn
.query_row("SELECT name FROM address_books", [], |row| row.get(0))
.unwrap();
@@ -2568,7 +2572,7 @@ fn contact_folder_reachable_by_two_paths_is_inserted_once() {
let base = server.url();
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_config(base, None, surfaces("contacts")),
)
@@ -2638,13 +2642,13 @@ fn message_state_becomes_jmap_keywords() {
let base = server.url();
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_config(base, None, surfaces("mail")),
)
.unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let mut stmt = conn
.prepare("SELECT keywords FROM emails ORDER BY id")
.unwrap();
@@ -2708,7 +2712,7 @@ fn drive_items_import_as_file_nodes_and_skip_facetless_items() {
let base = server.url();
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_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"
);
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let vault: i64 = conn
.query_row(
"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 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_config(base, None, surfaces("calendar")),
)
.unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let row: String = conn
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
.unwrap();
@@ -2910,13 +2914,13 @@ fn event_file_attachments_become_enclosure_links() {
let base = server.url();
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_config(base, None, surfaces("calendar")),
)
.unwrap();
let conn = vandelay::db::init::open(&archive).unwrap();
let conn = inbuxa_migrate::db::init::open(&archive).unwrap();
let row: String = conn
.query_row("SELECT data FROM calendar_events", [], |row| row.get(0))
.unwrap();
@@ -2985,9 +2989,9 @@ fn contact_photo_categories_and_im_addresses_are_imported() {
let archive = tempfile::NamedTempFile::new().unwrap().path().to_owned();
let mut config = make_config(base, None, surfaces("contacts"));
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
.query_row("SELECT data FROM contact_cards", [], |row| row.get(0))
.unwrap();
+16 -15
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -13,14 +14,14 @@ use std::thread;
use std::time::Duration;
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 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>;
@@ -129,7 +130,7 @@ fn connect_mock(server: &MockImap) -> Result<ImapClient, ImapError> {
fn tempfile(label: &str) -> PathBuf {
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
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() {
let _ = std::fs::remove_file(&p);
}
@@ -143,7 +144,7 @@ fn run_import(
user: &str,
archive: PathBuf,
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 {
archive: archive.clone(),
threads: 1,
@@ -364,14 +365,14 @@ fn run_collect_parses_fetch_with_literal_body() {
.run_collect("UID FETCH 5 (UID BODY.PEEK[])")
.expect("fetch");
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,
});
let items = body.expect("fetch items");
let body_item = items.iter().find(|(n, _)| n == "BODY[]").unwrap();
match &body_item.1 {
vandelay::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::Str(s) => assert_eq!(s, "Hello world"),
inbuxa_migrate::imap::response::Value::Bytes(b) => assert_eq!(b, b"Hello world"),
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 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]
@@ -1483,7 +1484,7 @@ fn coordinator_auth_plain_and_login_both_refused_aborts_run() {
});
let archive = tempfile("dual_refuse");
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);
}
@@ -1812,7 +1813,7 @@ fn coordinator_authenticationfailed_yields_exit2_connection_error() {
});
let archive = tempfile("authfail");
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);
}
+22 -21
View File
@@ -1,22 +1,23 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
use std::time::Instant;
use serde_json::json;
use vandelay::jmap::account::{self, AccountSelector};
use vandelay::jmap::error::JmapError;
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
use vandelay::jmap::request::{
use inbuxa_migrate::jmap::account::{self, AccountSelector};
use inbuxa_migrate::jmap::error::JmapError;
use inbuxa_migrate::jmap::http::{Auth, HttpClient, RetryPolicy};
use inbuxa_migrate::jmap::request::{
self, SetRequest, get_all, get_changes, get_objects, get_state, set_call,
};
use vandelay::jmap::session::{Limits, Session};
use vandelay::jmap::wire::JmapId;
use vandelay::jmap::wire::identity::Identity;
use vandelay::jmap::wire::mailbox::Mailbox;
use inbuxa_migrate::jmap::session::{Limits, Session};
use inbuxa_migrate::jmap::wire::JmapId;
use inbuxa_migrate::jmap::wire::identity::Identity;
use inbuxa_migrate::jmap::wire::mailbox::Mailbox;
use serde_json::json;
fn client(retries: u32) -> HttpClient {
HttpClient::new(
@@ -672,7 +673,7 @@ fn retries_counter_increments_on_429() {
#[test]
fn upload_size_precheck_blocks_before_contacting_server() {
use vandelay::jmap::blobxfer;
use inbuxa_migrate::jmap::blobxfer;
let mut server = mockito::Server::new();
let no_hits = server
@@ -739,7 +740,7 @@ fn concurrent_requests_400_problem_is_retried_then_succeeds() {
#[test]
fn concurrent_uploads_400_problem_is_retried_then_succeeds() {
use vandelay::jmap::blobxfer;
use inbuxa_migrate::jmap::blobxfer;
let mut server = mockito::Server::new();
server
@@ -772,7 +773,7 @@ fn concurrent_uploads_400_problem_is_retried_then_succeeds() {
#[test]
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();
server
@@ -883,7 +884,7 @@ fn ratelimit_headers_without_retry_after_fall_back_to_backoff() {
#[test]
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 base = server.url();
@@ -974,7 +975,7 @@ fn persistent_problem_json_429_without_retry_after_eventually_succeeds_via_share
#[test]
fn persistent_429_on_download_uses_shared_throttle() {
use vandelay::jmap::blobxfer;
use inbuxa_migrate::jmap::blobxfer;
let mut server = mockito::Server::new();
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 mut p = std::env::temp_dir();
p.push(format!(
"vandelay-mockjmap-{}-{n}.sqlite",
"inbuxa-migrate-mockjmap-{}-{n}.sqlite",
std::process::id()
));
let _ = std::fs::remove_file(&p);
@@ -1264,17 +1265,17 @@ fn import_aborts_with_exit_two_when_the_advertised_api_url_is_unreachable() {
.create();
let archive = archive_path();
let err = vandelay::sync::import_jmap::run(
vandelay::sync::CommonConfig {
let err = inbuxa_migrate::sync::import_jmap::run(
inbuxa_migrate::sync::CommonConfig {
archive: archive.clone(),
threads: 1,
dry_run: false,
max_retries: 0,
allow_invalid_certs: false,
logger: vandelay::logging::Logger::from_flags(true, 0),
logger: inbuxa_migrate::logging::Logger::from_flags(true, 0),
},
vandelay::sync::ImportConfig {
connect: vandelay::sync::ConnectConfig {
inbuxa_migrate::sync::ImportConfig {
connect: inbuxa_migrate::sync::ConnectConfig {
url: session_base.clone(),
auth: Auth::Basic {
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");
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:?}"
);
assert_eq!(err.exit_code(), 2, "must not report a partial failure");
+11 -10
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -8,16 +9,16 @@ use std::collections::HashMap;
use std::fs;
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 tempfile::TempDir;
use vandelay::logging::Logger;
use vandelay::sync::CommonConfig;
use vandelay::sync::import_maildir::{MaildirImportConfig, run};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-mock-maildir-{tag}-{}-{}.sqlite",
"inbuxa-migrate-mock-maildir-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.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();
let archive = tmp_archive("not-a-maildir");
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);
}
@@ -544,7 +545,7 @@ fn rejects_dovecot_layout_fs_tree() {
let archive = tmp_archive("layout-fs");
let err = run(common(&archive), base_cfg(td.path())).expect_err("should refuse");
match err {
vandelay::error::Error::Usage(msg) => {
inbuxa_migrate::error::Error::Usage(msg) => {
assert!(msg.contains("Maildir++"), "msg was: {msg}");
}
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"));
cfg.maildir = PathBuf::from("/definitely/not/a/real/maildir");
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);
}
@@ -572,7 +573,7 @@ fn source_change_protection_refuses_second_path() {
let archive = tmp_archive("source-change");
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");
assert!(matches!(err, vandelay::error::Error::SourceChange(_)));
assert!(matches!(err, inbuxa_migrate::error::Error::SourceChange(_)));
let _ = fs::remove_file(&archive);
}
@@ -601,7 +602,7 @@ fn folder_and_include_are_mutually_exclusive() {
cfg.include = vec![regex::Regex::new("^Sent$").unwrap()];
let err = run(common(&archive), cfg).expect_err("mutex");
match err {
vandelay::error::Error::Usage(msg) => {
inbuxa_migrate::error::Error::Usage(msg) => {
assert!(
msg.contains("--folder") && msg.contains("--include"),
"msg was: {msg}"
@@ -621,7 +622,7 @@ fn folder_and_exclude_are_mutually_exclusive() {
cfg.folder = vec!["INBOX".to_owned()];
cfg.exclude = vec![regex::Regex::new("^Trash$").unwrap()];
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);
}
+11 -10
View File
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -12,10 +13,10 @@ use std::sync::atomic::{AtomicU32, Ordering};
use std::thread;
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 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>;
@@ -117,7 +118,7 @@ fn tempfile(label: &str) -> PathBuf {
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay_mock_managesieve_{label}_{counter}.sqlite"
"inbuxa_migrate_mock_managesieve_{label}_{counter}.sqlite"
));
if p.exists() {
let _ = std::fs::remove_file(&p);
@@ -133,7 +134,7 @@ fn count(conn: &Connection, table: &str) -> i64 {
fn run_basic(
server: &MockSieveServer,
archive: &Path,
) -> Result<vandelay::sync::Summary, vandelay::error::Error> {
) -> Result<inbuxa_migrate::sync::Summary, inbuxa_migrate::error::Error> {
let common = CommonConfig {
archive: archive.to_path_buf(),
threads: 1,
@@ -256,7 +257,7 @@ fn auth_no_translates_to_connection_error() {
let archive = tempfile("auth_fail");
let err = run_basic(&server, &archive).unwrap_err();
match err {
vandelay::error::Error::Connection(msg) => assert!(
inbuxa_migrate::error::Error::Connection(msg) => assert!(
msg.contains("auth failed") || msg.contains("LOGIN"),
"got {msg}"
),
@@ -274,7 +275,7 @@ fn server_lacking_plain_login_for_basic_is_refused() {
});
let archive = tempfile("no_basic_mech");
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);
}
@@ -423,7 +424,7 @@ fn referral_aborts_run_with_connection_error() {
let archive = tempfile("referral");
let err = run_basic(&server, &archive).unwrap_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:?}"),
}
let _ = std::fs::remove_file(&archive);
@@ -438,7 +439,7 @@ fn seed_then_run(seed: Script, second: Script) -> (MockSieveServer, PathBuf) {
fn run_against(
server: &MockSieveServer,
archive: &Path,
) -> Result<vandelay::sync::Summary, vandelay::error::Error> {
) -> Result<inbuxa_migrate::sync::Summary, inbuxa_migrate::error::Error> {
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 err = run_basic(&server, &archive).unwrap_err();
match err {
vandelay::error::Error::Connection(msg) => {
inbuxa_migrate::error::Error::Connection(msg) => {
assert!(
msg.contains("LOGIN") && msg.contains("PLAIN"),
"expected combined LOGIN/PLAIN error text, got {msg}"
+15 -14
View File
@@ -1,26 +1,27 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 John Coffey <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
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 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 {
static SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-mocksync-{}-{:?}-{n}.sqlite",
"inbuxa-migrate-mocksync-{}-{:?}-{n}.sqlite",
std::process::id(),
std::thread::current().id(),
));
@@ -1585,8 +1586,8 @@ fn export_missing_target_email_is_created_on_rerun() {
let raw =
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 mm = vandelay::sync::keys::index_to_json(
&vandelay::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
let mm = inbuxa_migrate::sync::keys::index_to_json(
&inbuxa_migrate::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
);
conn.execute(
"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();
let blob = db::blobs::intern_blob(&conn, raw.as_bytes()).unwrap();
let mm = vandelay::sync::keys::index_to_json(
&vandelay::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
let mm = inbuxa_migrate::sync::keys::index_to_json(
&inbuxa_migrate::sync::emailmeta::email_index_from_blob(raw.as_bytes()),
);
conn.execute(
"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();
}
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");
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");
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:?}"
);
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()
.expect("a 404 from the api endpoint aborts the run");
assert!(
matches!(err, vandelay::error::Error::Connection(_)),
matches!(err, inbuxa_migrate::error::Error::Connection(_)),
"the abort must keep its own exit code, got {err:?}"
);
assert_eq!(err.exit_code(), 2);
+4 -1
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -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");
let primary = list
.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");
assert_eq!(
primary.get("isActive").and_then(Value::as_bool),
+5 -4
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -17,14 +18,14 @@ use seed::{FileSpec, Layout, MailboxSpec};
pub const ADMIN_USER: &str = "admin";
pub const ADMIN_PASSWORD: &str = "admin";
pub const DOMAIN: &str = "vandelay.org";
pub const USER_PASSWORD: &str = "VandelayUser#2026";
pub const ADMIN_ACCOUNT_PASSWORD: &str = "VandelayAdmin#2026";
pub const DOMAIN: &str = "inbuxa-migrate.org";
pub const USER_PASSWORD: &str = "InbuxaUser#2026";
pub const ADMIN_ACCOUNT_PASSWORD: &str = "InbuxaAdmin#2026";
pub const SYNC_IN: [&str; 3] = ["test1", "test2", "test3"];
pub const SYNC_OUT: [&str; 3] = ["test4", "test5", "test6"];
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 {
($k:expr, $n:expr, $p:expr, $r:expr) => {
+7 -6
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -230,8 +231,8 @@ fn seed_sieve(jmap: &Jmap, account_id: &str, active: bool) -> SeedResult<()> {
"SieveScript/set",
account_id,
json!({
"s0": { "name": "vandelay-test-filter", "blobId": primary_blob },
"s1": { "name": "vandelay-vacation", "blobId": secondary_blob }
"s0": { "name": "inbuxa-migrate-test-filter", "blobId": primary_blob },
"s1": { "name": "inbuxa-migrate-vacation", "blobId": secondary_blob }
}),
&extra,
)?;
@@ -247,8 +248,8 @@ fn seed_identity(jmap: &Jmap, account_id: &str, account_email: &str) -> SeedResu
"i0": {
"name": super::CUSTOM_IDENTITY_NAME,
"email": account_email,
"textSignature": "-- \nVandelay Industries",
"htmlSignature": "<p>Vandelay Industries</p>"
"textSignature": "-- \nInbuxa Industries",
"htmlSignature": "<p>Inbuxa Industries</p>"
}
}),
&[],
@@ -339,7 +340,7 @@ fn seed_contacts_calendars(
&[CORE, CONTACTS],
"AddressBook/set",
account_id,
json!({ "ab": { "name": "Vandelay Work Contacts" } }),
json!({ "ab": { "name": "Inbuxa Work Contacts" } }),
&[],
)?;
if let Some(id) = response
@@ -359,7 +360,7 @@ fn seed_contacts_calendars(
&[CORE, CALENDARS],
"Calendar/set",
account_id,
json!({ "cal": { "name": "Vandelay Team Calendar", "color": "#3366cc" } }),
json!({ "cal": { "name": "Inbuxa Team Calendar", "color": "#3366cc" } }),
&[],
)?;
if let Some(id) = response
+7 -6
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -16,16 +17,16 @@ use rusqlite::Connection;
fn base_url() -> &'static str {
shared_stalwart().base_url()
}
use vandelay::jmap::account::AccountSelector;
use vandelay::jmap::http::Auth;
use vandelay::logging::Logger;
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
use inbuxa_migrate::jmap::account::AccountSelector;
use inbuxa_migrate::jmap::http::Auth;
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-{tag}-{}-{}.sqlite",
"inbuxa-migrate-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
+7 -6
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -10,22 +11,22 @@ mod seeder;
use std::collections::HashSet;
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 rusqlite::Connection;
use vandelay::jmap::account::AccountSelector;
use vandelay::jmap::http::Auth;
use vandelay::logging::Logger;
fn base_url() -> &'static str {
shared_stalwart().base_url()
}
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-{tag}-{}-{}.sqlite",
"inbuxa-migrate-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
+13 -12
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -9,15 +10,15 @@ mod seeder;
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 mockito::{Matcher, Server};
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 {
shared_stalwart().base_url()
@@ -26,7 +27,7 @@ fn base_url() -> &'static str {
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-{tag}-{}-{}.sqlite",
"inbuxa-migrate-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
@@ -96,9 +97,9 @@ fn graph_fixture(server: &mut Server) {
.with_status(200)
.with_header("content-type", "text/plain")
.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\
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\
Grüße aus Köln 🎉\r\n",
)
@@ -219,8 +220,8 @@ fn graph_fixture(server: &mut Server) {
server,
"/me/contacts/C1",
r#"{"id":"C1","displayName":"Graph Contact","givenName":"Graph","surname":"Contact",
"categories":["Work","VIP"],"imAddresses":["sip:graph@vandelay.example"],
"emailAddresses":[{"address":"graph@vandelay.example"}]}"#,
"categories":["Work","VIP"],"imAddresses":["sip:graph@inbuxa-migrate.example"],
"emailAddresses":[{"address":"graph@inbuxa-migrate.example"}]}"#,
);
server
.mock("GET", "/me/contacts/C1/photo/$value")
@@ -393,7 +394,7 @@ fn graph_import_survives_a_full_export_to_stalwart() {
.as_object()
.and_then(|m| m.values().next())
.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 \
that carries only user, even though RFC 9553 permits it"
);
+7 -6
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -22,16 +23,16 @@ fn imaps_url() -> String {
format!("imaps://{}:{}", s.host, s.imaps_port)
}
use vandelay::jmap::account::AccountSelector;
use vandelay::jmap::http::Auth;
use vandelay::logging::Logger;
use vandelay::sync::import_imap::{ImapAuth, ImapImportConfig};
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
use inbuxa_migrate::jmap::account::AccountSelector;
use inbuxa_migrate::jmap::http::Auth;
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::import_imap::{ImapAuth, ImapImportConfig};
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-imap-{tag}-{}-{}.sqlite",
"inbuxa-migrate-imap-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
+40 -39
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -10,15 +11,15 @@ mod seeder;
use std::path::{Path, PathBuf};
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 rusqlite::Connection;
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 {
shared_stalwart().base_url()
@@ -27,7 +28,7 @@ fn base_url() -> &'static str {
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-{tag}-{}-{}.sqlite",
"inbuxa-migrate-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
@@ -181,7 +182,7 @@ fn import_resolves_account_via_admin_principal_path() {
},
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,
};
let summary = sync::import_jmap::run(common(&archive, false), cfg)
@@ -390,7 +391,7 @@ fn import_export_deeply_nested_mailbox_tree() {
auth: basic("test4"),
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,
};
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"),
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,
};
sync::import_jmap::run(common(&again_archive, false), imp_again)
@@ -470,7 +471,7 @@ fn import_export_deeply_nested_filenode_tree() {
auth: basic("test4"),
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,
};
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"),
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,
},
)
@@ -554,7 +555,7 @@ fn prune_multilevel_mailbox_tree_destroys_leaf_first() {
auth: basic("test4"),
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,
},
)
@@ -567,7 +568,7 @@ fn prune_multilevel_mailbox_tree_destroys_leaf_first() {
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);
@@ -595,7 +596,7 @@ fn prune_multilevel_mailbox_tree_destroys_leaf_first() {
auth: basic("test6"),
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,
},
)
@@ -644,8 +645,8 @@ fn prune_non_tree_type_contact_card() {
account: AccountSelector::Id(src.account_id.clone()),
},
objects: Some(vec![
vandelay::types::ObjectType::AddressBook,
vandelay::types::ObjectType::ContactCard,
inbuxa_migrate::types::ObjectType::AddressBook,
inbuxa_migrate::types::ObjectType::ContactCard,
]),
allow_source_change: false,
},
@@ -659,7 +660,7 @@ fn prune_non_tree_type_contact_card() {
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(
"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");
}
const ISSUE30_CARD_UID: &str = "vandelay-issue30-card";
const ISSUE30_EVENT_UID: &str = "vandelay-issue30-event";
const ISSUE30_CARD_UID: &str = "inbuxa-migrate-issue30-card";
const ISSUE30_EVENT_UID: &str = "inbuxa-migrate-issue30-event";
fn data_uri_bytes(resource: &Value, uri_key: &str, expect_media_type: &str) -> Vec<u8> {
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 archive = tmp_archive("issue30");
let photo: &[u8] = b"\x89PNG\r\n\x1a\nvandelay issue 30 contact photo bytes";
let agenda: &[u8] = b"vandelay issue 30 calendar enclosure bytes";
let photo: &[u8] = b"\x89PNG\r\n\x1a\ninbuxa-migrate issue 30 contact photo 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(
"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();
let photo_blob = vandelay::db::blobs::intern_blob(&conn, photo).unwrap();
let agenda_blob = vandelay::db::blobs::intern_blob(&conn, agenda).unwrap();
let photo_blob = inbuxa_migrate::db::blobs::intern_blob(&conn, photo).unwrap();
let agenda_blob = inbuxa_migrate::db::blobs::intern_blob(&conn, agenda).unwrap();
let card = json!({
"@type": "Card",
"version": "1.0",
@@ -944,7 +945,7 @@ fn export_prune_destroys_unmatched() {
auth: basic("test1"),
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,
},
)
@@ -964,7 +965,7 @@ fn export_prune_destroys_unmatched() {
auth: basic("test3"),
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,
},
)
@@ -1004,7 +1005,7 @@ fn import_resume_converges_after_partial() {
};
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");
let conn = Connection::open(&archive).unwrap();
@@ -1038,10 +1039,10 @@ fn import_resume_converges_after_partial() {
#[test]
#[ignore = "requires Docker"]
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 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 acc = fx.account("test1").expect("test1");
@@ -1131,7 +1132,7 @@ fn live_burst_exceeds_concurrent_requests_and_recovers() {
}
struct JmapSettingsGuard {
admin: vandelay::jmap::http::HttpClient,
admin: inbuxa_migrate::jmap::http::HttpClient,
admin_api: String,
admin_account: String,
previous: serde_json::Map<String, serde_json::Value>,
@@ -1139,8 +1140,8 @@ struct JmapSettingsGuard {
impl JmapSettingsGuard {
fn override_settings(updates: serde_json::Map<String, serde_json::Value>) -> Self {
use vandelay::jmap::http::{Auth, HttpClient, RetryPolicy};
use vandelay::jmap::session::Session;
use inbuxa_migrate::jmap::http::{Auth, HttpClient, RetryPolicy};
use inbuxa_migrate::jmap::session::Session;
let admin = HttpClient::new(
Auth::Basic {
user: seeder::ADMIN_USER.to_owned(),
@@ -1188,7 +1189,7 @@ impl Drop for JmapSettingsGuard {
}
fn read_jmap_settings(
admin: &vandelay::jmap::http::HttpClient,
admin: &inbuxa_migrate::jmap::http::HttpClient,
api: &str,
account: &str,
properties: &[&str],
@@ -1217,7 +1218,7 @@ fn read_jmap_settings(
}
fn apply_jmap_settings(
admin: &vandelay::jmap::http::HttpClient,
admin: &inbuxa_migrate::jmap::http::HttpClient,
api: &str,
account: &str,
updates: &serde_json::Map<String, serde_json::Value>,
@@ -1252,9 +1253,9 @@ fn apply_jmap_settings(
#[test]
#[ignore = "requires Docker"]
fn live_blob_quota_429_triggers_retry_after_then_succeeds() {
use vandelay::jmap::blobxfer;
use vandelay::jmap::http::{HttpClient, RetryPolicy};
use vandelay::jmap::session::Session;
use inbuxa_migrate::jmap::blobxfer;
use inbuxa_migrate::jmap::http::{HttpClient, RetryPolicy};
use inbuxa_migrate::jmap::session::Session;
let fx = seeder::provision(base_url()).expect("provision");
let acc = fx.account("test1").expect("test1");
+11 -10
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -19,16 +20,16 @@ use rusqlite::Connection;
fn base_url() -> &'static str {
shared_stalwart().base_url()
}
use vandelay::jmap::account::AccountSelector;
use vandelay::jmap::http::Auth;
use vandelay::logging::Logger;
use vandelay::sync::import_maildir::{MaildirImportConfig, run as run_maildir};
use vandelay::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
use inbuxa_migrate::jmap::account::AccountSelector;
use inbuxa_migrate::jmap::http::Auth;
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::import_maildir::{MaildirImportConfig, run as run_maildir};
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-sync-maildir-{tag}-{}-{}.sqlite",
"inbuxa-migrate-sync-maildir-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.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()),
},
objects: Some(vec![
vandelay::types::ObjectType::Mailbox,
vandelay::types::ObjectType::Email,
inbuxa_migrate::types::ObjectType::Mailbox,
inbuxa_migrate::types::ObjectType::Email,
]),
allow_source_change: false,
};
@@ -627,8 +628,8 @@ fn maildir_message_count_matches_jmap_for_same_corpus() {
account: AccountSelector::Id(acc.account_id.clone()),
},
objects: Some(vec![
vandelay::types::ObjectType::Mailbox,
vandelay::types::ObjectType::Email,
inbuxa_migrate::types::ObjectType::Mailbox,
inbuxa_migrate::types::ObjectType::Email,
]),
allow_source_change: false,
};
+14 -13
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -25,16 +26,16 @@ fn sieves_url() -> String {
let s = shared_stalwart();
format!("sieves://{}:{}", s.host, s.sieve_port)
}
use vandelay::jmap::account::AccountSelector;
use vandelay::jmap::http::Auth;
use vandelay::logging::Logger;
use vandelay::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig};
use vandelay::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
use inbuxa_migrate::jmap::account::AccountSelector;
use inbuxa_migrate::jmap::http::Auth;
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::import_managesieve::{ManageSieveAuth, ManageSieveImportConfig};
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ImportConfig};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-managesieve-{tag}-{}-{}.sqlite",
"inbuxa-migrate-managesieve-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.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()),
},
objects: Some(vec![vandelay::types::ObjectType::SieveScript]),
objects: Some(vec![inbuxa_migrate::types::ObjectType::SieveScript]),
allow_source_change: false,
};
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))
.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);
seeder::teardown(base_url()).expect("teardown");
@@ -336,7 +337,7 @@ fn managesieve_implicit_tls_path_succeeds_when_offered() {
cfg.url = sieves_url();
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}");
}
@@ -382,7 +383,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
allow_invalid_certs: true,
logger: Logger::from_flags(false, 0),
};
let export_cfg = vandelay::sync::ExportConfig {
let export_cfg = inbuxa_migrate::sync::ExportConfig {
connect: ConnectConfig {
url: fx.base_url.clone(),
auth: Auth::Basic {
@@ -391,7 +392,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
},
account: AccountSelector::Id(dst.account_id.clone()),
},
objects: Some(vec![vandelay::types::ObjectType::SieveScript]),
objects: Some(vec![inbuxa_migrate::types::ObjectType::SieveScript]),
prune: false,
yes: false,
};
@@ -416,7 +417,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
allow_invalid_certs: true,
logger: Logger::from_flags(false, 0),
};
let export_cfg2 = vandelay::sync::ExportConfig {
let export_cfg2 = inbuxa_migrate::sync::ExportConfig {
connect: ConnectConfig {
url: fx.base_url.clone(),
auth: Auth::Basic {
@@ -425,7 +426,7 @@ fn managesieve_round_trip_via_jmap_export_converges() {
},
account: AccountSelector::Id(dst.account_id.clone()),
},
objects: Some(vec![vandelay::types::ObjectType::SieveScript]),
objects: Some(vec![inbuxa_migrate::types::ObjectType::SieveScript]),
prune: false,
yes: false,
};
+8 -7
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -11,9 +12,9 @@ use std::path::{Path, PathBuf};
use rusqlite::Connection;
use tempfile::TempDir;
use vandelay::logging::Logger;
use vandelay::sync::CommonConfig;
use vandelay::sync::import_takeout::{TakeoutImportConfig, run};
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::CommonConfig;
use inbuxa_migrate::sync::import_takeout::{TakeoutImportConfig, run};
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 err = run(common_for(&archive), config_for(td.path().to_path_buf())).unwrap_err();
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);
}
@@ -240,7 +241,7 @@ fn nonexistent_path_fails_with_usage() {
let archive = td.path().join("a.sqlite");
let missing = td.path().join("does-not-exist");
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);
}
@@ -450,7 +451,7 @@ fn contacts_dedup_by_uid_across_two_vcf_files() {
assert_eq!(with_uid, 2);
let synthetic_uids: i64 = conn
.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),
)
@@ -543,7 +544,7 @@ fn source_change_protection_refuses_different_path() {
let archive = td.path().join("a.sqlite");
run(common_for(&archive), config_for(a.clone())).unwrap();
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);
cfg2.allow_source_change = true;
+7 -6
View File
@@ -1,5 +1,6 @@
/*
* 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
*/
@@ -16,16 +17,16 @@ use rusqlite::Connection;
fn base_url() -> &'static str {
shared_stalwart().base_url()
}
use vandelay::jmap::account::AccountSelector;
use vandelay::jmap::http::Auth;
use vandelay::logging::Logger;
use vandelay::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use vandelay::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
use inbuxa_migrate::jmap::account::AccountSelector;
use inbuxa_migrate::jmap::http::Auth;
use inbuxa_migrate::logging::Logger;
use inbuxa_migrate::sync::import_dav::{DavAuth, DavImportConfig, DavKindArg};
use inbuxa_migrate::sync::{self, CommonConfig, ConnectConfig, ExportConfig, ImportConfig};
fn tmp_archive(tag: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!(
"vandelay-{tag}-{}-{}.sqlite",
"inbuxa-migrate-{tag}-{}-{}.sqlite",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)