mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-10-24 01:53:20 +00:00
Migrate LiveSync flows to provider-owned resources
This commit is contained in:
1 parent
f7206b1a6e
commit
db70b4c2b6
34 files changed
+1830
-365
No files matched your search
@@ -0,0 +1,174 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { ObsidianLiveSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/types";
|
||||
import { createNewVaultSettings } from "@vrtmrz/livesync-commonlib/settings";
|
||||
import {
|
||||
getCouchDBReplicatorConfigurationIdentity,
|
||||
getObjectStorageReplicatorConfigurationIdentity,
|
||||
} from "./replicatorConfigurationIdentity";
|
||||
|
||||
describe("active Replicator configuration identity", () => {
|
||||
function configuredSettings(overrides: Partial<ObsidianLiveSyncSettings> = {}): ObsidianLiveSyncSettings {
|
||||
return Object.assign(createNewVaultSettings(), {
|
||||
activeConfigurationId: "profile-a",
|
||||
couchDB_URI: "https://couch.example.test/base",
|
||||
couchDB_USER: "alice",
|
||||
couchDB_PASSWORD: "secret-a",
|
||||
couchDB_DBNAME: "vault",
|
||||
couchDB_CustomHeaders: "X-Second: two\nX-First: one",
|
||||
endpoint: "https://objects.example.test/base",
|
||||
accessKey: "alice",
|
||||
secretKey: "secret-a",
|
||||
bucket: "vault",
|
||||
bucketPrefix: "notes/",
|
||||
region: "auto",
|
||||
bucketCustomHeaders: "X-Second: two\nX-First: one",
|
||||
encrypt: true,
|
||||
passphrase: "encryption-a",
|
||||
useDynamicIterationCount: false,
|
||||
permitEmptyPassphrase: false,
|
||||
enableCompression: false,
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
|
||||
it.each([
|
||||
["couchDB_URI", "https://other.example.test/base"],
|
||||
["couchDB_DBNAME", "other-vault"],
|
||||
["couchDB_USER", "bob"],
|
||||
["couchDB_PASSWORD", "secret-b"],
|
||||
["couchDB_CustomHeaders", "X-First: changed"],
|
||||
["useRequestAPI", true],
|
||||
["disableRequestURI", true],
|
||||
["encrypt", false],
|
||||
["passphrase", "encryption-b"],
|
||||
["useDynamicIterationCount", true],
|
||||
["E2EEAlgorithm", ""],
|
||||
["permitEmptyPassphrase", true],
|
||||
["enableCompression", true],
|
||||
] satisfies Array<[keyof ObsidianLiveSyncSettings, ObsidianLiveSyncSettings[keyof ObsidianLiveSyncSettings]]>)(
|
||||
"detects a CouchDB %s change",
|
||||
(key, value) => {
|
||||
const settings = configuredSettings();
|
||||
expect(getCouchDBReplicatorConfigurationIdentity({ ...settings, [key]: value })).not.toBe(
|
||||
getCouchDBReplicatorConfigurationIdentity(settings)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it("ignores persisted central profile identity when the effective connection settings match", () => {
|
||||
const settings = configuredSettings({ activeConfigurationId: "profile-a" });
|
||||
const otherProfile = { ...settings, activeConfigurationId: "profile-b" };
|
||||
|
||||
expect(getCouchDBReplicatorConfigurationIdentity(otherProfile)).toBe(
|
||||
getCouchDBReplicatorConfigurationIdentity(settings)
|
||||
);
|
||||
expect(getObjectStorageReplicatorConfigurationIdentity(otherProfile)).toBe(
|
||||
getObjectStorageReplicatorConfigurationIdentity(settings)
|
||||
);
|
||||
});
|
||||
|
||||
it("projects only the active CouchDB authentication mode", () => {
|
||||
const basic = configuredSettings({ useJWT: false, jwtKey: "inactive-a" });
|
||||
expect(getCouchDBReplicatorConfigurationIdentity({ ...basic, jwtKey: "inactive-b" })).toBe(
|
||||
getCouchDBReplicatorConfigurationIdentity(basic)
|
||||
);
|
||||
|
||||
const jwt = configuredSettings({
|
||||
useJWT: true,
|
||||
jwtAlgorithm: "HS256",
|
||||
jwtKey: "jwt-a",
|
||||
jwtKid: "kid-a",
|
||||
jwtSub: "subject-a",
|
||||
jwtExpDuration: 5,
|
||||
});
|
||||
expect(getCouchDBReplicatorConfigurationIdentity({ ...jwt, couchDB_PASSWORD: "inactive" })).toBe(
|
||||
getCouchDBReplicatorConfigurationIdentity(jwt)
|
||||
);
|
||||
expect(getCouchDBReplicatorConfigurationIdentity({ ...jwt, jwtKey: "jwt-b" })).not.toBe(
|
||||
getCouchDBReplicatorConfigurationIdentity(jwt)
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["endpoint", "https://other.example.test/base"],
|
||||
["bucket", "other-vault"],
|
||||
["bucketPrefix", "archive/"],
|
||||
["region", "eu-west-1"],
|
||||
["accessKey", "bob"],
|
||||
["secretKey", "secret-b"],
|
||||
["forcePathStyle", false],
|
||||
["useCustomRequestHandler", true],
|
||||
["bucketCustomHeaders", "X-First: changed"],
|
||||
["encrypt", false],
|
||||
["passphrase", "encryption-b"],
|
||||
["useDynamicIterationCount", true],
|
||||
["E2EEAlgorithm", ""],
|
||||
["permitEmptyPassphrase", true],
|
||||
] satisfies Array<[keyof ObsidianLiveSyncSettings, ObsidianLiveSyncSettings[keyof ObsidianLiveSyncSettings]]>)(
|
||||
"detects an Object Storage %s change",
|
||||
(key, value) => {
|
||||
const settings = configuredSettings();
|
||||
expect(getObjectStorageReplicatorConfigurationIdentity({ ...settings, [key]: value })).not.toBe(
|
||||
getObjectStorageReplicatorConfigurationIdentity(settings)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
it("normalises endpoint and header representation without using the setup URI grammar", () => {
|
||||
const settings = configuredSettings();
|
||||
const couchIdentity = getCouchDBReplicatorConfigurationIdentity(settings);
|
||||
const objectStorageIdentity = getObjectStorageReplicatorConfigurationIdentity(settings);
|
||||
|
||||
expect(
|
||||
getCouchDBReplicatorConfigurationIdentity({
|
||||
...settings,
|
||||
couchDB_URI: "https://couch.example.test:443/base/",
|
||||
couchDB_CustomHeaders: "X-First: one\nX-Second: two",
|
||||
})
|
||||
).toBe(couchIdentity);
|
||||
expect(
|
||||
getObjectStorageReplicatorConfigurationIdentity({
|
||||
...settings,
|
||||
endpoint: "https://objects.example.test:443/base/",
|
||||
bucketCustomHeaders: "X-First: one\nX-Second: two",
|
||||
})
|
||||
).toBe(objectStorageIdentity);
|
||||
});
|
||||
|
||||
it("ignores inactive remote-security credentials", () => {
|
||||
const settings = configuredSettings({ encrypt: false, passphrase: "inactive-a" });
|
||||
|
||||
expect(
|
||||
getCouchDBReplicatorConfigurationIdentity({
|
||||
...settings,
|
||||
passphrase: "inactive-b",
|
||||
useDynamicIterationCount: !settings.useDynamicIterationCount,
|
||||
E2EEAlgorithm: "",
|
||||
permitEmptyPassphrase: !settings.permitEmptyPassphrase,
|
||||
})
|
||||
).toBe(getCouchDBReplicatorConfigurationIdentity(settings));
|
||||
expect(
|
||||
getObjectStorageReplicatorConfigurationIdentity({
|
||||
...settings,
|
||||
passphrase: "inactive-b",
|
||||
useDynamicIterationCount: !settings.useDynamicIterationCount,
|
||||
E2EEAlgorithm: "",
|
||||
permitEmptyPassphrase: !settings.permitEmptyPassphrase,
|
||||
})
|
||||
).toBe(getObjectStorageReplicatorConfigurationIdentity(settings));
|
||||
});
|
||||
|
||||
it("keeps malformed endpoints deterministic and scoped", () => {
|
||||
const settings = configuredSettings({ couchDB_URI: "not a URL", endpoint: "also not a URL" });
|
||||
|
||||
expect(() => getCouchDBReplicatorConfigurationIdentity(settings)).not.toThrow();
|
||||
expect(() => getObjectStorageReplicatorConfigurationIdentity(settings)).not.toThrow();
|
||||
expect(
|
||||
getCouchDBReplicatorConfigurationIdentity({ ...settings, couchDB_URI: "different invalid URL" })
|
||||
).not.toBe(getCouchDBReplicatorConfigurationIdentity(settings));
|
||||
const unrelatedPluginChange = { ...settings, displayLanguage: "ja" };
|
||||
expect(getObjectStorageReplicatorConfigurationIdentity(unrelatedPluginChange)).toBe(
|
||||
getObjectStorageReplicatorConfigurationIdentity(settings)
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user