Update test
This commit is contained in:
parent
e493b98a24
commit
dc31afd907
2 changed files with 59 additions and 27 deletions
|
|
@ -5,11 +5,14 @@ import type { RelativePath, SyncSettings } from "sync-client";
|
||||||
import { LogLevel } from "sync-client";
|
import { LogLevel } from "sync-client";
|
||||||
import { MockClient } from "./mock-client";
|
import { MockClient } from "./mock-client";
|
||||||
import { sleep } from "../utils/sleep";
|
import { sleep } from "../utils/sleep";
|
||||||
|
import type { LogLine } from "sync-client/dist/types/tracing/logger";
|
||||||
|
|
||||||
export class MockAgent extends MockClient {
|
export class MockAgent extends MockClient {
|
||||||
private readonly writtenContents: string[] = [];
|
private readonly writtenContents: string[] = [];
|
||||||
private readonly pendingActions: Promise<unknown>[] = [];
|
private readonly pendingActions: Promise<unknown>[] = [];
|
||||||
private doNotTouch: string[] = [];
|
|
||||||
|
// The renamed file finding algorithm isn't too smart so we can't both update and rename the same file
|
||||||
|
private doNotTouchWhileOffline: string[] = [];
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
initialSettings: Partial<SyncSettings>,
|
initialSettings: Partial<SyncSettings>,
|
||||||
|
|
@ -23,6 +26,11 @@ export class MockAgent extends MockClient {
|
||||||
public async init(): Promise<void> {
|
public async init(): Promise<void> {
|
||||||
await super.init();
|
await super.init();
|
||||||
|
|
||||||
|
assert(
|
||||||
|
(await this.client.checkConnection()).isSuccessful,
|
||||||
|
"Connection check failed"
|
||||||
|
);
|
||||||
|
|
||||||
this.client.fetchImplementation = async (
|
this.client.fetchImplementation = async (
|
||||||
input: string | URL | globalThis.Request,
|
input: string | URL | globalThis.Request,
|
||||||
init?: RequestInit
|
init?: RequestInit
|
||||||
|
|
@ -33,9 +41,12 @@ export class MockAgent extends MockClient {
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client.logger.addOnMessageListener((message) => {
|
this.client.logger.addOnMessageListener((logLine: LogLine) => {
|
||||||
const formatted = `[${this.name}] ${message.timestamp.toISOString()} ${message.level} ${message.message}`;
|
const state = this.client.settings.getSettings().isSyncEnabled
|
||||||
switch (message.level) {
|
? "(online) "
|
||||||
|
: "(offline)";
|
||||||
|
const formatted = `[${this.name} ${state}] ${logLine.timestamp.toISOString()} ${logLine.level} ${logLine.message}`;
|
||||||
|
switch (logLine.level) {
|
||||||
case LogLevel.ERROR:
|
case LogLevel.ERROR:
|
||||||
console.error(formatted);
|
console.error(formatted);
|
||||||
// Let's not ignore errors
|
// Let's not ignore errors
|
||||||
|
|
@ -45,6 +56,17 @@ export class MockAgent extends MockClient {
|
||||||
console.warn(formatted);
|
console.warn(formatted);
|
||||||
break;
|
break;
|
||||||
case LogLevel.INFO:
|
case LogLevel.INFO:
|
||||||
|
// HACK: we have to ensure the file has been synced if we want to change it offline without data loss
|
||||||
|
const result = /.*History entry: (.*.md).*/.exec(
|
||||||
|
logLine.message
|
||||||
|
);
|
||||||
|
if (result) {
|
||||||
|
this.doNotTouchWhileOffline =
|
||||||
|
this.doNotTouchWhileOffline.filter(
|
||||||
|
(file) => file !== result[1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
console.info(formatted);
|
console.info(formatted);
|
||||||
break;
|
break;
|
||||||
case LogLevel.DEBUG:
|
case LogLevel.DEBUG:
|
||||||
|
|
@ -59,11 +81,18 @@ export class MockAgent extends MockClient {
|
||||||
public async act(): Promise<void> {
|
public async act(): Promise<void> {
|
||||||
const options: (() => Promise<unknown>)[] = [
|
const options: (() => Promise<unknown>)[] = [
|
||||||
this.createFileAction.bind(this),
|
this.createFileAction.bind(this),
|
||||||
this.changeFetchChangesUpdateIntervalMsAction.bind(this),
|
this.changeFetchChangesUpdateIntervalMsAction.bind(this)
|
||||||
this.disableSyncAction.bind(this),
|
|
||||||
this.enableSyncAction.bind(this)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.client.settings.getSettings().isSyncEnabled &&
|
||||||
|
this.doNotTouchWhileOffline.length === 0
|
||||||
|
) {
|
||||||
|
options.push(this.disableSyncAction.bind(this));
|
||||||
|
} else {
|
||||||
|
options.push(this.enableSyncAction.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
const files = await this.listAllFiles();
|
const files = await this.listAllFiles();
|
||||||
|
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
|
|
@ -195,7 +224,11 @@ export class MockAgent extends MockClient {
|
||||||
private async createFileAction(): Promise<void> {
|
private async createFileAction(): Promise<void> {
|
||||||
const file = this.getFileName();
|
const file = this.getFileName();
|
||||||
|
|
||||||
if (this.doNotTouch.includes(file) || (await this.exists(file))) {
|
if (
|
||||||
|
(!this.client.settings.getSettings().isSyncEnabled &&
|
||||||
|
this.doNotTouchWhileOffline.includes(file)) ||
|
||||||
|
(await this.exists(file))
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,15 +261,17 @@ export class MockAgent extends MockClient {
|
||||||
private async enableSyncAction(): Promise<void> {
|
private async enableSyncAction(): Promise<void> {
|
||||||
this.client.logger.info(`Decided to enable sync`);
|
this.client.logger.info(`Decided to enable sync`);
|
||||||
await this.client.settings.setSetting("isSyncEnabled", true);
|
await this.client.settings.setSetting("isSyncEnabled", true);
|
||||||
this.doNotTouch = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async renameFileAction(files: RelativePath[]): Promise<void> {
|
private async renameFileAction(files: RelativePath[]): Promise<void> {
|
||||||
const file = choose(files);
|
const file = choose(files);
|
||||||
|
|
||||||
// We can't edit files offline that have been renamed while offline.
|
// We can't edit files offline that have been updated while offline.
|
||||||
// Otherwise, the resolution logic couldn't handle it.
|
// Otherwise, the resolution logic couldn't handle it.
|
||||||
if (this.doNotTouch.includes(file)) {
|
if (
|
||||||
|
!this.client.settings.getSettings().isSyncEnabled &&
|
||||||
|
this.doNotTouchWhileOffline.includes(file)
|
||||||
|
) {
|
||||||
this.client.logger.info(
|
this.client.logger.info(
|
||||||
`Skipping file ${file} because it has been updated while offline`
|
`Skipping file ${file} because it has been updated while offline`
|
||||||
);
|
);
|
||||||
|
|
@ -245,14 +280,16 @@ export class MockAgent extends MockClient {
|
||||||
|
|
||||||
const newName = this.getFileName();
|
const newName = this.getFileName();
|
||||||
|
|
||||||
if (this.doNotTouch.includes(newName) || (await this.exists(newName))) {
|
if (
|
||||||
|
(!this.client.settings.getSettings().isSyncEnabled &&
|
||||||
|
this.doNotTouchWhileOffline.includes(newName)) ||
|
||||||
|
(await this.exists(newName))
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client.logger.info(`Decided to rename file ${file} to ${newName}`);
|
this.client.logger.info(`Decided to rename file ${file} to ${newName}`);
|
||||||
if (!this.client.settings.getSettings().isSyncEnabled) {
|
this.doNotTouchWhileOffline.push(file, newName);
|
||||||
this.doNotTouch.push(file, newName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.rename(file, newName);
|
return this.rename(file, newName);
|
||||||
}
|
}
|
||||||
|
|
@ -260,11 +297,14 @@ export class MockAgent extends MockClient {
|
||||||
private async updateFileAction(files: RelativePath[]): Promise<void> {
|
private async updateFileAction(files: RelativePath[]): Promise<void> {
|
||||||
const file = choose(files);
|
const file = choose(files);
|
||||||
|
|
||||||
// We can't edit files offline that have been renamed while offline.
|
// We can't edit files offline that have been updated while offline.
|
||||||
// Otherwise, the resolution logic couldn't handle it.
|
// Otherwise, the resolution logic couldn't handle it.
|
||||||
if (this.doNotTouch.includes(file)) {
|
if (
|
||||||
|
!this.client.settings.getSettings().isSyncEnabled &&
|
||||||
|
this.doNotTouchWhileOffline.includes(file)
|
||||||
|
) {
|
||||||
this.client.logger.info(
|
this.client.logger.info(
|
||||||
`Skipping file ${file} because it has been renamed while offline`
|
`Skipping file ${file} because it has been updated while offline`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -273,9 +313,7 @@ export class MockAgent extends MockClient {
|
||||||
this.client.logger.info(
|
this.client.logger.info(
|
||||||
`Decided to update file ${file} with ${content}`
|
`Decided to update file ${file} with ${content}`
|
||||||
);
|
);
|
||||||
if (!this.client.settings.getSettings().isSyncEnabled) {
|
this.doNotTouchWhileOffline.push(file);
|
||||||
this.doNotTouch.push(file);
|
|
||||||
}
|
|
||||||
await this.atomicUpdateText(file, (old) => old + ` |${content}| `);
|
await this.atomicUpdateText(file, (old) => old + ` |${content}| `);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import type {
|
||||||
SyncSettings
|
SyncSettings
|
||||||
} from "sync-client";
|
} from "sync-client";
|
||||||
import { SyncClient } from "sync-client";
|
import { SyncClient } from "sync-client";
|
||||||
import { assert } from "../utils/assert";
|
|
||||||
|
|
||||||
export class MockClient implements FileSystemOperations {
|
export class MockClient implements FileSystemOperations {
|
||||||
protected readonly localFiles = new Map<string, Uint8Array>();
|
protected readonly localFiles = new Map<string, Uint8Array>();
|
||||||
|
|
@ -29,11 +28,6 @@ export class MockClient implements FileSystemOperations {
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(
|
|
||||||
(await this.client.checkConnection()).isSuccessful,
|
|
||||||
"Connection check failed"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listAllFiles(): Promise<RelativePath[]> {
|
public async listAllFiles(): Promise<RelativePath[]> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue