提交 1063f59d 编写于 作者: S Sandeep Somavarapu

Fix #97555

上级 e4e1099f
...@@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; ...@@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService, IFileContent, FileChangesEvent, FileOperationResult, FileOperationError } from 'vs/platform/files/common/files'; import { IFileService, IFileContent, FileChangesEvent, FileOperationResult, FileOperationError } from 'vs/platform/files/common/files';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { SyncResource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService, Conflict, ISyncResourceHandle, USER_DATA_SYNC_SCHEME, ISyncPreviewResult } from 'vs/platform/userDataSync/common/userDataSync'; import { SyncResource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService, Conflict, ISyncResourceHandle, USER_DATA_SYNC_SCHEME, ISyncPreviewResult, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { joinPath, dirname, isEqual, basename } from 'vs/base/common/resources'; import { joinPath, dirname, isEqual, basename } from 'vs/base/common/resources';
import { CancelablePromise } from 'vs/base/common/async'; import { CancelablePromise } from 'vs/base/common/async';
...@@ -108,7 +108,7 @@ export abstract class AbstractSynchroniser extends Disposable { ...@@ -108,7 +108,7 @@ export abstract class AbstractSynchroniser extends Disposable {
protected isEnabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resource); } protected isEnabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resource); }
async sync(ref?: string): Promise<void> { async sync(manifest: IUserDataManifest | null): Promise<void> {
if (!this.isEnabled()) { if (!this.isEnabled()) {
if (this.status !== SyncStatus.Idle) { if (this.status !== SyncStatus.Idle) {
await this.stop(); await this.stop();
...@@ -129,7 +129,7 @@ export abstract class AbstractSynchroniser extends Disposable { ...@@ -129,7 +129,7 @@ export abstract class AbstractSynchroniser extends Disposable {
this.setStatus(SyncStatus.Syncing); this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData(); const lastSyncUserData = await this.getLastSyncUserData();
const remoteUserData = ref && lastSyncUserData && lastSyncUserData.ref === ref ? lastSyncUserData : await this.getRemoteUserData(lastSyncUserData); const remoteUserData = await this.getLatestRemoteUserData(manifest, lastSyncUserData);
let status: SyncStatus = SyncStatus.Idle; let status: SyncStatus = SyncStatus.Idle;
try { try {
...@@ -144,6 +144,24 @@ export abstract class AbstractSynchroniser extends Disposable { ...@@ -144,6 +144,24 @@ export abstract class AbstractSynchroniser extends Disposable {
} }
} }
private async getLatestRemoteUserData(manifest: IUserDataManifest | null, lastSyncUserData: IRemoteUserData | null): Promise<IRemoteUserData> {
if (lastSyncUserData) {
const latestRef = manifest && manifest.latest ? manifest.latest[this.resource] : undefined;
// Last time synced resource and latest resource on server are same
if (lastSyncUserData.ref === latestRef) {
return lastSyncUserData;
}
// There is no resource on server and last time it was synced with no resource
if (latestRef === undefined && lastSyncUserData.syncData === null) {
return lastSyncUserData;
}
}
return this.getRemoteUserData(lastSyncUserData);
}
async getSyncPreview(): Promise<ISyncPreviewResult> { async getSyncPreview(): Promise<ISyncPreviewResult> {
if (!this.isEnabled()) { if (!this.isEnabled()) {
return { hasLocalChanged: false, hasRemoteChanged: false }; return { hasLocalChanged: false, hasRemoteChanged: false };
...@@ -225,15 +243,19 @@ export abstract class AbstractSynchroniser extends Disposable { ...@@ -225,15 +243,19 @@ export abstract class AbstractSynchroniser extends Disposable {
} catch (e) { /* ignore */ } } catch (e) { /* ignore */ }
} }
protected async getLastSyncUserData<T extends IRemoteUserData>(): Promise<T | null> { async getLastSyncUserData<T extends IRemoteUserData>(): Promise<T | null> {
try { try {
const content = await this.fileService.readFile(this.lastSyncResource); const content = await this.fileService.readFile(this.lastSyncResource);
const parsed = JSON.parse(content.value.toString()); const parsed = JSON.parse(content.value.toString());
let syncData: ISyncData = JSON.parse(parsed.content); const userData: IUserData = parsed as IUserData;
if (userData.content === null) {
return { ref: parsed.ref, syncData: null } as T;
}
let syncData: ISyncData = JSON.parse(userData.content);
// Migration from old content to sync data // Migration from old content to sync data
if (!isSyncData(syncData)) { if (!isSyncData(syncData)) {
syncData = { version: this.version, content: parsed.content }; syncData = { version: this.version, content: userData.content };
} }
return { ...parsed, ...{ syncData, content: undefined } }; return { ...parsed, ...{ syncData, content: undefined } };
...@@ -247,11 +269,11 @@ export abstract class AbstractSynchroniser extends Disposable { ...@@ -247,11 +269,11 @@ export abstract class AbstractSynchroniser extends Disposable {
} }
protected async updateLastSyncUserData(lastSyncRemoteUserData: IRemoteUserData, additionalProps: IStringDictionary<any> = {}): Promise<void> { protected async updateLastSyncUserData(lastSyncRemoteUserData: IRemoteUserData, additionalProps: IStringDictionary<any> = {}): Promise<void> {
const lastSyncUserData: IUserData = { ref: lastSyncRemoteUserData.ref, content: JSON.stringify(lastSyncRemoteUserData.syncData), ...additionalProps }; const lastSyncUserData: IUserData = { ref: lastSyncRemoteUserData.ref, content: lastSyncRemoteUserData.syncData ? JSON.stringify(lastSyncRemoteUserData.syncData) : null, ...additionalProps };
await this.fileService.writeFile(this.lastSyncResource, VSBuffer.fromString(JSON.stringify(lastSyncUserData))); await this.fileService.writeFile(this.lastSyncResource, VSBuffer.fromString(JSON.stringify(lastSyncUserData)));
} }
protected async getRemoteUserData(lastSyncData: IRemoteUserData | null): Promise<IRemoteUserData> { async getRemoteUserData(lastSyncData: IRemoteUserData | null): Promise<IRemoteUserData> {
const { ref, content } = await this.getUserData(lastSyncData); const { ref, content } = await this.getUserData(lastSyncData);
let syncData: ISyncData | null = null; let syncData: ISyncData | null = null;
if (content !== null) { if (content !== null) {
......
...@@ -21,11 +21,12 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync ...@@ -21,11 +21,12 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
const updated: ISyncExtension[] = []; const updated: ISyncExtension[] = [];
if (!remoteExtensions) { if (!remoteExtensions) {
const remote = localExtensions.filter(({ identifier }) => ignoredExtensions.every(id => id.toLowerCase() !== identifier.id.toLowerCase()));
return { return {
added, added,
removed, removed,
updated, updated,
remote: localExtensions.filter(({ identifier }) => ignoredExtensions.every(id => id.toLowerCase() !== identifier.id.toLowerCase())) remote: remote.length > 0 ? remote : null
}; };
} }
......
...@@ -18,7 +18,7 @@ export interface IMergeResult { ...@@ -18,7 +18,7 @@ export interface IMergeResult {
export function merge(localStorage: IStringDictionary<IStorageValue>, remoteStorage: IStringDictionary<IStorageValue> | null, baseStorage: IStringDictionary<IStorageValue> | null, storageKeys: ReadonlyArray<IStorageKey>, previouslySkipped: string[], logService: ILogService): IMergeResult { export function merge(localStorage: IStringDictionary<IStorageValue>, remoteStorage: IStringDictionary<IStorageValue> | null, baseStorage: IStringDictionary<IStorageValue> | null, storageKeys: ReadonlyArray<IStorageKey>, previouslySkipped: string[], logService: ILogService): IMergeResult {
if (!remoteStorage) { if (!remoteStorage) {
return { remote: localStorage, local: { added: {}, removed: [], updated: {} }, skipped: [] }; return { remote: Object.keys(localStorage).length > 0 ? localStorage : null, local: { added: {}, removed: [], updated: {} }, skipped: [] };
} }
const localToRemote = compare(localStorage, remoteStorage); const localToRemote = compare(localStorage, remoteStorage);
......
...@@ -248,10 +248,10 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem ...@@ -248,10 +248,10 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing keybindings.`); this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing keybindings.`);
} }
if (lastSyncUserData?.ref !== remoteUserData.ref && (content !== null || fileContent !== null)) { if (lastSyncUserData?.ref !== remoteUserData.ref) {
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized keybindings...`); this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized keybindings...`);
const lastSyncContent = this.toSyncContent(content !== null ? content : fileContent!.value.toString(), null); const lastSyncContent = content !== null || fileContent !== null ? this.toSyncContent(content !== null ? content : fileContent!.value.toString(), null) : null;
await this.updateLastSyncUserData({ ref: remoteUserData.ref, syncData: { version: remoteUserData.syncData!.version, content: lastSyncContent } }); await this.updateLastSyncUserData({ ref: remoteUserData.ref, syncData: lastSyncContent ? { version: remoteUserData.syncData!.version, content: lastSyncContent } : null });
this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized keybindings`); this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized keybindings`);
} }
...@@ -315,7 +315,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem ...@@ -315,7 +315,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts }; return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts };
} }
private getKeybindingsContentFromSyncContent(syncContent: string): string | null { getKeybindingsContentFromSyncContent(syncContent: string): string | null {
try { try {
const parsed = <ISyncContent>JSON.parse(syncContent); const parsed = <ISyncContent>JSON.parse(syncContent);
if (!this.configurationService.getValue<boolean>('sync.keybindingsPerPlatform')) { if (!this.configurationService.getValue<boolean>('sync.keybindingsPerPlatform')) {
......
...@@ -357,7 +357,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser { ...@@ -357,7 +357,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser {
return remoteUserData.syncData ? this.parseSettingsSyncContent(remoteUserData.syncData.content) : null; return remoteUserData.syncData ? this.parseSettingsSyncContent(remoteUserData.syncData.content) : null;
} }
private parseSettingsSyncContent(syncContent: string): ISettingsSyncContent | null { parseSettingsSyncContent(syncContent: string): ISettingsSyncContent | null {
try { try {
const parsed = <ISettingsSyncContent>JSON.parse(syncContent); const parsed = <ISettingsSyncContent>JSON.parse(syncContent);
return isSettingsSyncContent(parsed) ? parsed : /* migrate */ { settings: syncContent }; return isSettingsSyncContent(parsed) ? parsed : /* migrate */ { settings: syncContent };
......
...@@ -26,7 +26,7 @@ export function merge(local: IStringDictionary<string>, remote: IStringDictionar ...@@ -26,7 +26,7 @@ export function merge(local: IStringDictionary<string>, remote: IStringDictionar
removed: values(removed), removed: values(removed),
updated, updated,
conflicts: [], conflicts: [],
remote: local remote: Object.keys(local).length > 0 ? local : null
}; };
} }
......
...@@ -285,7 +285,7 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD ...@@ -285,7 +285,7 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
private async doGeneratePreview(local: IStringDictionary<IFileContent>, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resolvedConflicts: IStringDictionary<string | null> = {}, token: CancellationToken = CancellationToken.None): Promise<ISinppetsSyncPreviewResult> { private async doGeneratePreview(local: IStringDictionary<IFileContent>, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resolvedConflicts: IStringDictionary<string | null> = {}, token: CancellationToken = CancellationToken.None): Promise<ISinppetsSyncPreviewResult> {
const localSnippets = this.toSnippetsContents(local); const localSnippets = this.toSnippetsContents(local);
const remoteSnippets: IStringDictionary<string> | null = remoteUserData.syncData ? this.parseSnippets(remoteUserData.syncData) : null; const remoteSnippets: IStringDictionary<string> | null = remoteUserData.syncData ? this.parseSnippets(remoteUserData.syncData) : null;
const lastSyncSnippets: IStringDictionary<string> | null = lastSyncUserData ? this.parseSnippets(lastSyncUserData.syncData!) : null; const lastSyncSnippets: IStringDictionary<string> | null = lastSyncUserData && lastSyncUserData.syncData ? this.parseSnippets(lastSyncUserData.syncData) : null;
if (remoteSnippets) { if (remoteSnippets) {
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote snippets with local snippets...`); this.logService.trace(`${this.syncResourceLogLabel}: Merging remote snippets with local snippets...`);
......
...@@ -274,7 +274,7 @@ export interface IUserDataSynchroniser { ...@@ -274,7 +274,7 @@ export interface IUserDataSynchroniser {
pull(): Promise<void>; pull(): Promise<void>;
push(): Promise<void>; push(): Promise<void>;
sync(ref?: string): Promise<void>; sync(manifest: IUserDataManifest | null): Promise<void>;
stop(): Promise<void>; stop(): Promise<void>;
getSyncPreview(): Promise<ISyncPreviewResult> getSyncPreview(): Promise<ISyncPreviewResult>
......
...@@ -136,7 +136,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ ...@@ -136,7 +136,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
for (const synchroniser of this.synchronisers) { for (const synchroniser of this.synchronisers) {
try { try {
await synchroniser.sync(manifest && manifest.latest ? manifest.latest[synchroniser.resource] : undefined); await synchroniser.sync(manifest);
} catch (e) { } catch (e) {
this.handleSyncError(e, synchroniser.resource); this.handleSyncError(e, synchroniser.resource);
this._syncErrors.push([synchroniser.resource, UserDataSyncError.toUserDataSyncError(e)]); this._syncErrors.push([synchroniser.resource, UserDataSyncError.toUserDataSyncError(e)]);
......
...@@ -44,11 +44,58 @@ suite('GlobalStateSync', () => { ...@@ -44,11 +44,58 @@ suite('GlobalStateSync', () => {
teardown(() => disposableStore.clear()); teardown(() => disposableStore.clear());
test('when global state does not exist', async () => {
assert.deepEqual(await testObject.getLastSyncUserData(), null);
let manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'GET', url: `${server.url}/v1/resource/${testObject.resource}/latest`, headers: {} },
]);
const lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.equal(lastSyncUserData!.syncData, null);
manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
});
test('when global state is created after first sync', async () => {
await testObject.sync(await testClient.manifest());
updateStorage('a', 'value1', testClient);
let lastSyncUserData = await testObject.getLastSyncUserData();
const manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': lastSyncUserData?.ref } },
]);
lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.deepEqual(JSON.parse(lastSyncUserData!.syncData!.content).storage, { 'a': { version: 1, value: 'value1' } });
});
test('first time sync - outgoing to server (no state)', async () => { test('first time sync - outgoing to server (no state)', async () => {
updateStorage('a', 'value1', testClient); updateStorage('a', 'value1', testClient);
await updateLocale(testClient); await updateLocale(testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -63,7 +110,7 @@ suite('GlobalStateSync', () => { ...@@ -63,7 +110,7 @@ suite('GlobalStateSync', () => {
await updateLocale(client2); await updateLocale(client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -76,7 +123,7 @@ suite('GlobalStateSync', () => { ...@@ -76,7 +123,7 @@ suite('GlobalStateSync', () => {
await client2.sync(); await client2.sync();
updateStorage('b', 'value2', testClient); updateStorage('b', 'value2', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -94,7 +141,7 @@ suite('GlobalStateSync', () => { ...@@ -94,7 +141,7 @@ suite('GlobalStateSync', () => {
await client2.sync(); await client2.sync();
updateStorage('a', 'value2', client2); updateStorage('a', 'value2', client2);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -109,10 +156,10 @@ suite('GlobalStateSync', () => { ...@@ -109,10 +156,10 @@ suite('GlobalStateSync', () => {
test('sync adding a storage value', async () => { test('sync adding a storage value', async () => {
updateStorage('a', 'value1', testClient); updateStorage('a', 'value1', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
updateStorage('b', 'value2', testClient); updateStorage('b', 'value2', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -127,10 +174,10 @@ suite('GlobalStateSync', () => { ...@@ -127,10 +174,10 @@ suite('GlobalStateSync', () => {
test('sync updating a storage value', async () => { test('sync updating a storage value', async () => {
updateStorage('a', 'value1', testClient); updateStorage('a', 'value1', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
updateStorage('a', 'value2', testClient); updateStorage('a', 'value2', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -145,10 +192,10 @@ suite('GlobalStateSync', () => { ...@@ -145,10 +192,10 @@ suite('GlobalStateSync', () => {
test('sync removing a storage value', async () => { test('sync removing a storage value', async () => {
updateStorage('a', 'value1', testClient); updateStorage('a', 'value1', testClient);
updateStorage('b', 'value2', testClient); updateStorage('b', 'value2', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
removeStorage('b', testClient); removeStorage('b', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IUserDataSyncStoreService, IUserDataSyncService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
import { IFileService } from 'vs/platform/files/common/files';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { KeybindingsSynchroniser } from 'vs/platform/userDataSync/common/keybindingsSync';
import { VSBuffer } from 'vs/base/common/buffer';
suite('KeybindingsSync', () => {
const disposableStore = new DisposableStore();
const server = new UserDataSyncTestServer();
let client: UserDataSyncClient;
let testObject: KeybindingsSynchroniser;
setup(async () => {
client = disposableStore.add(new UserDataSyncClient(server));
await client.setUp(true);
testObject = (client.instantiationService.get(IUserDataSyncService) as UserDataSyncService).getSynchroniser(SyncResource.Keybindings) as KeybindingsSynchroniser;
disposableStore.add(toDisposable(() => client.instantiationService.get(IUserDataSyncStoreService).clear()));
});
teardown(() => disposableStore.clear());
test('when keybindings file does not exist', async () => {
const fileService = client.instantiationService.get(IFileService);
const keybindingsResource = client.instantiationService.get(IEnvironmentService).keybindingsResource;
assert.deepEqual(await testObject.getLastSyncUserData(), null);
let manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'GET', url: `${server.url}/v1/resource/${testObject.resource}/latest`, headers: {} },
]);
assert.ok(!await fileService.exists(keybindingsResource));
const lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.equal(lastSyncUserData!.syncData, null);
manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
});
test('when keybindings file is created after first sync', async () => {
const fileService = client.instantiationService.get(IFileService);
const keybindingsResource = client.instantiationService.get(IEnvironmentService).keybindingsResource;
await testObject.sync(await client.manifest());
await fileService.createFile(keybindingsResource, VSBuffer.fromString('[]'));
let lastSyncUserData = await testObject.getLastSyncUserData();
const manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': lastSyncUserData?.ref } },
]);
lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.equal(testObject.getKeybindingsContentFromSyncContent(lastSyncUserData!.syncData!.content!), '[]');
});
});
...@@ -43,13 +43,67 @@ suite('SettingsSync', () => { ...@@ -43,13 +43,67 @@ suite('SettingsSync', () => {
setup(async () => { setup(async () => {
client = disposableStore.add(new UserDataSyncClient(server)); client = disposableStore.add(new UserDataSyncClient(server));
await client.setUp(); await client.setUp(true);
testObject = (client.instantiationService.get(IUserDataSyncService) as UserDataSyncService).getSynchroniser(SyncResource.Settings) as SettingsSynchroniser; testObject = (client.instantiationService.get(IUserDataSyncService) as UserDataSyncService).getSynchroniser(SyncResource.Settings) as SettingsSynchroniser;
disposableStore.add(toDisposable(() => client.instantiationService.get(IUserDataSyncStoreService).clear())); disposableStore.add(toDisposable(() => client.instantiationService.get(IUserDataSyncStoreService).clear()));
}); });
teardown(() => disposableStore.clear()); teardown(() => disposableStore.clear());
test('when settings file does not exist', async () => {
const fileService = client.instantiationService.get(IFileService);
const settingResource = client.instantiationService.get(IEnvironmentService).settingsResource;
assert.deepEqual(await testObject.getLastSyncUserData(), null);
let manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'GET', url: `${server.url}/v1/resource/${testObject.resource}/latest`, headers: {} },
]);
assert.ok(!await fileService.exists(settingResource));
const lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.equal(lastSyncUserData!.syncData, null);
manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
});
test('when settings file is created after first sync', async () => {
const fileService = client.instantiationService.get(IFileService);
const settingsResource = client.instantiationService.get(IEnvironmentService).settingsResource;
await testObject.sync(await client.manifest());
await fileService.createFile(settingsResource, VSBuffer.fromString('{}'));
let lastSyncUserData = await testObject.getLastSyncUserData();
const manifest = await client.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': lastSyncUserData?.ref } },
]);
lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.equal(testObject.parseSettingsSyncContent(lastSyncUserData!.syncData!.content!)?.settings, '{}');
});
test('sync for first time to the server', async () => { test('sync for first time to the server', async () => {
const expected = const expected =
`{ `{
...@@ -75,7 +129,7 @@ suite('SettingsSync', () => { ...@@ -75,7 +129,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(expected); await updateSettings(expected);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -99,7 +153,7 @@ suite('SettingsSync', () => { ...@@ -99,7 +153,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -130,7 +184,7 @@ suite('SettingsSync', () => { ...@@ -130,7 +184,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -161,7 +215,7 @@ suite('SettingsSync', () => { ...@@ -161,7 +215,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -185,7 +239,7 @@ suite('SettingsSync', () => { ...@@ -185,7 +239,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -203,7 +257,7 @@ suite('SettingsSync', () => { ...@@ -203,7 +257,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -237,7 +291,7 @@ suite('SettingsSync', () => { ...@@ -237,7 +291,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -285,7 +339,7 @@ suite('SettingsSync', () => { ...@@ -285,7 +339,7 @@ suite('SettingsSync', () => {
}`; }`;
await updateSettings(settingsContent); await updateSettings(settingsContent);
await testObject.sync(); await testObject.sync(await client.manifest());
const { content } = await client.read(testObject.resource); const { content } = await client.read(testObject.resource);
assert.ok(content !== null); assert.ok(content !== null);
...@@ -333,7 +387,7 @@ suite('SettingsSync', () => { ...@@ -333,7 +387,7 @@ suite('SettingsSync', () => {
await updateSettings(expected); await updateSettings(expected);
try { try {
await testObject.sync(); await testObject.sync(await client.manifest());
assert.fail('should fail with invalid content error'); assert.fail('should fail with invalid content error');
} catch (e) { } catch (e) {
assert.ok(e instanceof UserDataSyncError); assert.ok(e instanceof UserDataSyncError);
......
...@@ -167,11 +167,62 @@ suite('SnippetsSync', () => { ...@@ -167,11 +167,62 @@ suite('SnippetsSync', () => {
teardown(() => disposableStore.clear()); teardown(() => disposableStore.clear());
test('when snippets does not exist', async () => {
const fileService = testClient.instantiationService.get(IFileService);
const snippetsResource = testClient.instantiationService.get(IEnvironmentService).snippetsHome;
assert.deepEqual(await testObject.getLastSyncUserData(), null);
let manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'GET', url: `${server.url}/v1/resource/${testObject.resource}/latest`, headers: {} },
]);
assert.ok(!await fileService.exists(snippetsResource));
const lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.equal(lastSyncUserData!.syncData, null);
manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, []);
});
test('when snippet is created after first sync', async () => {
await testObject.sync(await testClient.manifest());
await updateSnippet('html.json', htmlSnippet1, testClient);
let lastSyncUserData = await testObject.getLastSyncUserData();
const manifest = await testClient.manifest();
server.reset();
await testObject.sync(manifest);
assert.deepEqual(server.requests, [
{ type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': lastSyncUserData?.ref } },
]);
lastSyncUserData = await testObject.getLastSyncUserData();
const remoteUserData = await testObject.getRemoteUserData(null);
assert.deepEqual(lastSyncUserData!.ref, remoteUserData.ref);
assert.deepEqual(lastSyncUserData!.syncData, remoteUserData.syncData);
assert.deepEqual(lastSyncUserData!.syncData!.content, JSON.stringify({ 'html.json': htmlSnippet1 }));
});
test('first time sync - outgoing to server (no snippets)', async () => { test('first time sync - outgoing to server (no snippets)', async () => {
await updateSnippet('html.json', htmlSnippet1, testClient); await updateSnippet('html.json', htmlSnippet1, testClient);
await updateSnippet('typescript.json', tsSnippet1, testClient); await updateSnippet('typescript.json', tsSnippet1, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -186,7 +237,7 @@ suite('SnippetsSync', () => { ...@@ -186,7 +237,7 @@ suite('SnippetsSync', () => {
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -201,7 +252,7 @@ suite('SnippetsSync', () => { ...@@ -201,7 +252,7 @@ suite('SnippetsSync', () => {
await client2.sync(); await client2.sync();
await updateSnippet('typescript.json', tsSnippet1, testClient); await updateSnippet('typescript.json', tsSnippet1, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -221,7 +272,7 @@ suite('SnippetsSync', () => { ...@@ -221,7 +272,7 @@ suite('SnippetsSync', () => {
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.HasConflicts); assert.equal(testObject.status, SyncStatus.HasConflicts);
const environmentService = testClient.instantiationService.get(IEnvironmentService); const environmentService = testClient.instantiationService.get(IEnvironmentService);
...@@ -234,7 +285,7 @@ suite('SnippetsSync', () => { ...@@ -234,7 +285,7 @@ suite('SnippetsSync', () => {
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
const conflicts = testObject.conflicts; const conflicts = testObject.conflicts;
await testObject.acceptConflict(conflicts[0].local, htmlSnippet1); await testObject.acceptConflict(conflicts[0].local, htmlSnippet1);
...@@ -259,7 +310,7 @@ suite('SnippetsSync', () => { ...@@ -259,7 +310,7 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await updateSnippet('typescript.json', tsSnippet2, testClient); await updateSnippet('typescript.json', tsSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.HasConflicts); assert.equal(testObject.status, SyncStatus.HasConflicts);
const environmentService = testClient.instantiationService.get(IEnvironmentService); const environmentService = testClient.instantiationService.get(IEnvironmentService);
...@@ -278,7 +329,7 @@ suite('SnippetsSync', () => { ...@@ -278,7 +329,7 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await updateSnippet('typescript.json', tsSnippet2, testClient); await updateSnippet('typescript.json', tsSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
let conflicts = testObject.conflicts; let conflicts = testObject.conflicts;
await testObject.acceptConflict(conflicts[0].local, htmlSnippet2); await testObject.acceptConflict(conflicts[0].local, htmlSnippet2);
...@@ -299,7 +350,7 @@ suite('SnippetsSync', () => { ...@@ -299,7 +350,7 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await updateSnippet('typescript.json', tsSnippet2, testClient); await updateSnippet('typescript.json', tsSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
const conflicts = testObject.conflicts; const conflicts = testObject.conflicts;
await testObject.acceptConflict(conflicts[0].local, htmlSnippet2); await testObject.acceptConflict(conflicts[0].local, htmlSnippet2);
...@@ -324,10 +375,10 @@ suite('SnippetsSync', () => { ...@@ -324,10 +375,10 @@ suite('SnippetsSync', () => {
test('sync adding a snippet', async () => { test('sync adding a snippet', async () => {
await updateSnippet('html.json', htmlSnippet1, testClient); await updateSnippet('html.json', htmlSnippet1, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('typescript.json', tsSnippet1, testClient); await updateSnippet('typescript.json', tsSnippet1, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -345,12 +396,12 @@ suite('SnippetsSync', () => { ...@@ -345,12 +396,12 @@ suite('SnippetsSync', () => {
test('sync adding a snippet - accept', async () => { test('sync adding a snippet - accept', async () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -362,10 +413,10 @@ suite('SnippetsSync', () => { ...@@ -362,10 +413,10 @@ suite('SnippetsSync', () => {
test('sync updating a snippet', async () => { test('sync updating a snippet', async () => {
await updateSnippet('html.json', htmlSnippet1, testClient); await updateSnippet('html.json', htmlSnippet1, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -381,12 +432,12 @@ suite('SnippetsSync', () => { ...@@ -381,12 +432,12 @@ suite('SnippetsSync', () => {
test('sync updating a snippet - accept', async () => { test('sync updating a snippet - accept', async () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('html.json', htmlSnippet2, client2); await updateSnippet('html.json', htmlSnippet2, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -397,13 +448,13 @@ suite('SnippetsSync', () => { ...@@ -397,13 +448,13 @@ suite('SnippetsSync', () => {
test('sync updating a snippet - conflict', async () => { test('sync updating a snippet - conflict', async () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('html.json', htmlSnippet2, client2); await updateSnippet('html.json', htmlSnippet2, client2);
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet3, testClient); await updateSnippet('html.json', htmlSnippet3, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.HasConflicts); assert.equal(testObject.status, SyncStatus.HasConflicts);
const environmentService = testClient.instantiationService.get(IEnvironmentService); const environmentService = testClient.instantiationService.get(IEnvironmentService);
const local = joinPath(environmentService.userDataSyncHome, testObject.resource, PREVIEW_DIR_NAME, 'html.json'); const local = joinPath(environmentService.userDataSyncHome, testObject.resource, PREVIEW_DIR_NAME, 'html.json');
...@@ -413,13 +464,13 @@ suite('SnippetsSync', () => { ...@@ -413,13 +464,13 @@ suite('SnippetsSync', () => {
test('sync updating a snippet - resolve conflict', async () => { test('sync updating a snippet - resolve conflict', async () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('html.json', htmlSnippet2, client2); await updateSnippet('html.json', htmlSnippet2, client2);
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet3, testClient); await updateSnippet('html.json', htmlSnippet3, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
await testObject.acceptConflict(testObject.conflicts[0].local, htmlSnippet2); await testObject.acceptConflict(testObject.conflicts[0].local, htmlSnippet2);
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
...@@ -437,10 +488,10 @@ suite('SnippetsSync', () => { ...@@ -437,10 +488,10 @@ suite('SnippetsSync', () => {
test('sync removing a snippet', async () => { test('sync removing a snippet', async () => {
await updateSnippet('html.json', htmlSnippet1, testClient); await updateSnippet('html.json', htmlSnippet1, testClient);
await updateSnippet('typescript.json', tsSnippet1, testClient); await updateSnippet('typescript.json', tsSnippet1, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
await removeSnippet('html.json', testClient); await removeSnippet('html.json', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -459,12 +510,12 @@ suite('SnippetsSync', () => { ...@@ -459,12 +510,12 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await removeSnippet('html.json', client2); await removeSnippet('html.json', client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -478,13 +529,13 @@ suite('SnippetsSync', () => { ...@@ -478,13 +529,13 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await updateSnippet('html.json', htmlSnippet2, client2); await updateSnippet('html.json', htmlSnippet2, client2);
await client2.sync(); await client2.sync();
await removeSnippet('html.json', testClient); await removeSnippet('html.json', testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -499,13 +550,13 @@ suite('SnippetsSync', () => { ...@@ -499,13 +550,13 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await removeSnippet('html.json', client2); await removeSnippet('html.json', client2);
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.HasConflicts); assert.equal(testObject.status, SyncStatus.HasConflicts);
const environmentService = testClient.instantiationService.get(IEnvironmentService); const environmentService = testClient.instantiationService.get(IEnvironmentService);
...@@ -517,13 +568,13 @@ suite('SnippetsSync', () => { ...@@ -517,13 +568,13 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await removeSnippet('html.json', client2); await removeSnippet('html.json', client2);
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
await testObject.acceptConflict(testObject.conflicts[0].local, htmlSnippet3); await testObject.acceptConflict(testObject.conflicts[0].local, htmlSnippet3);
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
...@@ -544,13 +595,13 @@ suite('SnippetsSync', () => { ...@@ -544,13 +595,13 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
await removeSnippet('html.json', client2); await removeSnippet('html.json', client2);
await client2.sync(); await client2.sync();
await updateSnippet('html.json', htmlSnippet2, testClient); await updateSnippet('html.json', htmlSnippet2, testClient);
await testObject.sync(); await testObject.sync(await testClient.manifest());
await testObject.acceptConflict(testObject.conflicts[0].local, ''); await testObject.acceptConflict(testObject.conflicts[0].local, '');
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
...@@ -601,7 +652,7 @@ suite('SnippetsSync', () => { ...@@ -601,7 +652,7 @@ suite('SnippetsSync', () => {
await updateSnippet('html.json', htmlSnippet1, client2); await updateSnippet('html.json', htmlSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
...@@ -622,7 +673,7 @@ suite('SnippetsSync', () => { ...@@ -622,7 +673,7 @@ suite('SnippetsSync', () => {
await updateSnippet('typescript.json', tsSnippet1, client2); await updateSnippet('typescript.json', tsSnippet1, client2);
await client2.sync(); await client2.sync();
await testObject.sync(); await testObject.sync(await testClient.manifest());
assert.equal(testObject.status, SyncStatus.Idle); assert.equal(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []); assert.deepEqual(testObject.conflicts, []);
......
...@@ -79,7 +79,7 @@ suite('TestSynchronizer', () => { ...@@ -79,7 +79,7 @@ suite('TestSynchronizer', () => {
const promise = Event.toPromise(testObject.onDoSyncCall.event); const promise = Event.toPromise(testObject.onDoSyncCall.event);
testObject.sync(); testObject.sync(await client.manifest());
await promise; await promise;
assert.deepEqual(actual, [SyncStatus.Syncing]); assert.deepEqual(actual, [SyncStatus.Syncing]);
...@@ -94,7 +94,7 @@ suite('TestSynchronizer', () => { ...@@ -94,7 +94,7 @@ suite('TestSynchronizer', () => {
const actual: SyncStatus[] = []; const actual: SyncStatus[] = [];
disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status)));
await testObject.sync(); await testObject.sync(await client.manifest());
assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]); assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]);
assert.deepEqual(testObject.status, SyncStatus.Idle); assert.deepEqual(testObject.status, SyncStatus.Idle);
...@@ -107,7 +107,7 @@ suite('TestSynchronizer', () => { ...@@ -107,7 +107,7 @@ suite('TestSynchronizer', () => {
const actual: SyncStatus[] = []; const actual: SyncStatus[] = [];
disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status)));
await testObject.sync(); await testObject.sync(await client.manifest());
assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.HasConflicts]); assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.HasConflicts]);
assert.deepEqual(testObject.status, SyncStatus.HasConflicts); assert.deepEqual(testObject.status, SyncStatus.HasConflicts);
...@@ -122,7 +122,7 @@ suite('TestSynchronizer', () => { ...@@ -122,7 +122,7 @@ suite('TestSynchronizer', () => {
disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status)));
try { try {
await testObject.sync(); await testObject.sync(await client.manifest());
assert.fail('Should fail'); assert.fail('Should fail');
} catch (e) { } catch (e) {
assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]); assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]);
...@@ -134,12 +134,12 @@ suite('TestSynchronizer', () => { ...@@ -134,12 +134,12 @@ suite('TestSynchronizer', () => {
const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncResource.Settings); const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncResource.Settings);
const promise = Event.toPromise(testObject.onDoSyncCall.event); const promise = Event.toPromise(testObject.onDoSyncCall.event);
testObject.sync(); testObject.sync(await client.manifest());
await promise; await promise;
const actual: SyncStatus[] = []; const actual: SyncStatus[] = [];
disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status)));
await testObject.sync(); await testObject.sync(await client.manifest());
assert.deepEqual(actual, []); assert.deepEqual(actual, []);
assert.deepEqual(testObject.status, SyncStatus.Syncing); assert.deepEqual(testObject.status, SyncStatus.Syncing);
...@@ -154,7 +154,7 @@ suite('TestSynchronizer', () => { ...@@ -154,7 +154,7 @@ suite('TestSynchronizer', () => {
const actual: SyncStatus[] = []; const actual: SyncStatus[] = [];
disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status)));
await testObject.sync(); await testObject.sync(await client.manifest());
assert.deepEqual(actual, []); assert.deepEqual(actual, []);
assert.deepEqual(testObject.status, SyncStatus.Idle); assert.deepEqual(testObject.status, SyncStatus.Idle);
...@@ -164,11 +164,11 @@ suite('TestSynchronizer', () => { ...@@ -164,11 +164,11 @@ suite('TestSynchronizer', () => {
const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncResource.Settings); const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncResource.Settings);
testObject.syncResult = { status: SyncStatus.HasConflicts }; testObject.syncResult = { status: SyncStatus.HasConflicts };
testObject.syncBarrier.open(); testObject.syncBarrier.open();
await testObject.sync(); await testObject.sync(await client.manifest());
const actual: SyncStatus[] = []; const actual: SyncStatus[] = [];
disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status)));
await testObject.sync(); await testObject.sync(await client.manifest());
assert.deepEqual(actual, []); assert.deepEqual(actual, []);
assert.deepEqual(testObject.status, SyncStatus.HasConflicts); assert.deepEqual(testObject.status, SyncStatus.HasConflicts);
...@@ -178,7 +178,7 @@ suite('TestSynchronizer', () => { ...@@ -178,7 +178,7 @@ suite('TestSynchronizer', () => {
const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncResource.Settings); const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncResource.Settings);
// Sync once // Sync once
testObject.syncBarrier.open(); testObject.syncBarrier.open();
await testObject.sync(); await testObject.sync(await client.manifest());
testObject.syncBarrier = new Barrier(); testObject.syncBarrier = new Barrier();
// update remote data before syncing so that 412 is thrown by server // update remote data before syncing so that 412 is thrown by server
...@@ -190,8 +190,9 @@ suite('TestSynchronizer', () => { ...@@ -190,8 +190,9 @@ suite('TestSynchronizer', () => {
}); });
// Start sycing // Start sycing
const { ref } = await userDataSyncStoreService.read(testObject.resource, null); const manifest = await client.manifest();
await testObject.sync(ref); const ref = manifest!.latest![testObject.resource];
await testObject.sync(await client.manifest());
assert.deepEqual(server.requests, [ assert.deepEqual(server.requests, [
{ type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': ref } }, { type: 'POST', url: `${server.url}/v1/resource/${testObject.resource}`, headers: { 'If-Match': ref } },
......
...@@ -124,6 +124,10 @@ export class UserDataSyncClient extends Disposable { ...@@ -124,6 +124,10 @@ export class UserDataSyncClient extends Disposable {
return this.instantiationService.get(IUserDataSyncStoreService).read(resource, null); return this.instantiationService.get(IUserDataSyncStoreService).read(resource, null);
} }
manifest(): Promise<IUserDataManifest | null> {
return this.instantiationService.get(IUserDataSyncStoreService).manifest();
}
} }
export class UserDataSyncTestServer implements IRequestService { export class UserDataSyncTestServer implements IRequestService {
......
...@@ -45,7 +45,6 @@ suite('UserDataSyncService', () => { ...@@ -45,7 +45,6 @@ suite('UserDataSyncService', () => {
{ type: 'POST', url: `${target.url}/v1/resource/globalState`, headers: { 'If-Match': '0' } }, { type: 'POST', url: `${target.url}/v1/resource/globalState`, headers: { 'If-Match': '0' } },
// Extensions // Extensions
{ type: 'GET', url: `${target.url}/v1/resource/extensions/latest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/resource/extensions/latest`, headers: {} },
{ type: 'POST', url: `${target.url}/v1/resource/extensions`, headers: { 'If-Match': '0' } },
// Manifest // Manifest
{ type: 'GET', url: `${target.url}/v1/manifest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/manifest`, headers: {} },
]); ]);
...@@ -71,13 +70,10 @@ suite('UserDataSyncService', () => { ...@@ -71,13 +70,10 @@ suite('UserDataSyncService', () => {
{ type: 'GET', url: `${target.url}/v1/resource/keybindings/latest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/resource/keybindings/latest`, headers: {} },
// Snippets // Snippets
{ type: 'GET', url: `${target.url}/v1/resource/snippets/latest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/resource/snippets/latest`, headers: {} },
{ type: 'POST', url: `${target.url}/v1/resource/snippets`, headers: { 'If-Match': '0' } },
// Global state // Global state
{ type: 'GET', url: `${target.url}/v1/resource/globalState/latest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/resource/globalState/latest`, headers: {} },
{ type: 'POST', url: `${target.url}/v1/resource/globalState`, headers: { 'If-Match': '0' } },
// Extensions // Extensions
{ type: 'GET', url: `${target.url}/v1/resource/extensions/latest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/resource/extensions/latest`, headers: {} },
{ type: 'POST', url: `${target.url}/v1/resource/extensions`, headers: { 'If-Match': '0' } },
// Manifest // Manifest
{ type: 'GET', url: `${target.url}/v1/manifest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/manifest`, headers: {} },
]); ]);
...@@ -384,7 +380,6 @@ suite('UserDataSyncService', () => { ...@@ -384,7 +380,6 @@ suite('UserDataSyncService', () => {
{ type: 'POST', url: `${target.url}/v1/resource/globalState`, headers: { 'If-Match': '0' } }, { type: 'POST', url: `${target.url}/v1/resource/globalState`, headers: { 'If-Match': '0' } },
// Extensions // Extensions
{ type: 'GET', url: `${target.url}/v1/resource/extensions/latest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/resource/extensions/latest`, headers: {} },
{ type: 'POST', url: `${target.url}/v1/resource/extensions`, headers: { 'If-Match': '0' } },
// Manifest // Manifest
{ type: 'GET', url: `${target.url}/v1/manifest`, headers: {} }, { type: 'GET', url: `${target.url}/v1/manifest`, headers: {} },
]); ]);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册