Skip to content

Commit edd94ce

Browse files
committed
add settings sync tests
1 parent efbb8ae commit edd94ce

4 files changed

Lines changed: 366 additions & 8 deletions

File tree

src/vs/platform/userDataSync/common/settingsSync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
2323
import { URI } from 'vs/base/common/uri';
2424
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
2525

26-
interface ISettingsSyncContent {
26+
export interface ISettingsSyncContent {
2727
settings: string;
2828
}
2929

src/vs/platform/userDataSync/common/userDataSyncService.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -302,13 +302,8 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
302302
return this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts).map(s => s.source);
303303
}
304304

305-
private getSynchroniser(source: SyncSource): IUserDataSynchroniser {
306-
switch (source) {
307-
case SyncSource.Settings: return this.settingsSynchroniser;
308-
case SyncSource.Keybindings: return this.keybindingsSynchroniser;
309-
case SyncSource.Extensions: return this.extensionsSynchroniser;
310-
case SyncSource.GlobalState: return this.globalStateSynchroniser;
311-
}
305+
getSynchroniser(source: SyncSource): IUserDataSynchroniser {
306+
return this.synchronisers.filter(s => s.source === source)[0];
312307
}
313308

314309
private async checkEnablement(): Promise<void> {
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as assert from 'assert';
7+
import { IUserDataSyncStoreService, IUserDataSyncService, SyncSource, UserDataSyncError, UserDataSyncErrorCode } from 'vs/platform/userDataSync/common/userDataSync';
8+
import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient';
9+
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
10+
import { SettingsSynchroniser, ISettingsSyncContent } from 'vs/platform/userDataSync/common/settingsSync';
11+
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
12+
import { IFileService } from 'vs/platform/files/common/files';
13+
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
14+
import { VSBuffer } from 'vs/base/common/buffer';
15+
import { ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
16+
import { Registry } from 'vs/platform/registry/common/platform';
17+
import { IConfigurationRegistry, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
18+
19+
suite('SettingsSync', () => {
20+
21+
const disposableStore = new DisposableStore();
22+
const server = new UserDataSyncTestServer();
23+
let client: UserDataSyncClient;
24+
25+
let testObject: SettingsSynchroniser;
26+
27+
suiteSetup(() => {
28+
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
29+
'id': 'settingsSync',
30+
'type': 'object',
31+
'properties': {
32+
'settingsSync.machine': {
33+
'type': 'string',
34+
'scope': ConfigurationScope.MACHINE
35+
},
36+
'settingsSync.machineOverridable': {
37+
'type': 'string',
38+
'scope': ConfigurationScope.MACHINE_OVERRIDABLE
39+
}
40+
}
41+
});
42+
});
43+
44+
setup(async () => {
45+
client = disposableStore.add(new UserDataSyncClient(server));
46+
await client.setUp();
47+
testObject = (client.instantiationService.get(IUserDataSyncService) as UserDataSyncService).getSynchroniser(SyncSource.Settings) as SettingsSynchroniser;
48+
disposableStore.add(toDisposable(() => client.instantiationService.get(IUserDataSyncStoreService).clear()));
49+
});
50+
51+
teardown(() => disposableStore.clear());
52+
53+
test('sync for first time to the server', async () => {
54+
const expected =
55+
`{
56+
// Always
57+
"files.autoSave": "afterDelay",
58+
"files.simpleDialog.enable": true,
59+
60+
// Workbench
61+
"workbench.colorTheme": "GitHub Sharp",
62+
"workbench.tree.indent": 20,
63+
"workbench.colorCustomizations": {
64+
"editorLineNumber.activeForeground": "#ff0000",
65+
"[GitHub Sharp]": {
66+
"statusBarItem.remoteBackground": "#24292E",
67+
"editorPane.background": "#f3f1f11a"
68+
}
69+
},
70+
71+
"gitBranch.base": "remote-repo/master",
72+
73+
// Experimental
74+
"workbench.view.experimental.allowMovingToNewContainer": true,
75+
}`;
76+
77+
await updateSettings(expected);
78+
await testObject.sync();
79+
80+
const { content } = await client.read(testObject.resourceKey);
81+
assert.ok(content !== null);
82+
const actual = parseSettings(content!);
83+
assert.deepEqual(actual, expected);
84+
});
85+
86+
test('do not sync machine settings', async () => {
87+
const settingsContent =
88+
`{
89+
// Always
90+
"files.autoSave": "afterDelay",
91+
"files.simpleDialog.enable": true,
92+
93+
// Workbench
94+
"workbench.colorTheme": "GitHub Sharp",
95+
96+
// Machine
97+
"settingsSync.machine": "someValue",
98+
"settingsSync.machineOverridable": "someValue"
99+
}`;
100+
await updateSettings(settingsContent);
101+
102+
await testObject.sync();
103+
104+
const { content } = await client.read(testObject.resourceKey);
105+
assert.ok(content !== null);
106+
const actual = parseSettings(content!);
107+
assert.deepEqual(actual, `{
108+
// Always
109+
"files.autoSave": "afterDelay",
110+
"files.simpleDialog.enable": true,
111+
112+
// Workbench
113+
"workbench.colorTheme": "GitHub Sharp"
114+
}`);
115+
});
116+
117+
test('do not sync machine settings when spread across file', async () => {
118+
const settingsContent =
119+
`{
120+
// Always
121+
"files.autoSave": "afterDelay",
122+
"settingsSync.machine": "someValue",
123+
"files.simpleDialog.enable": true,
124+
125+
// Workbench
126+
"workbench.colorTheme": "GitHub Sharp",
127+
128+
// Machine
129+
"settingsSync.machineOverridable": "someValue"
130+
}`;
131+
await updateSettings(settingsContent);
132+
133+
await testObject.sync();
134+
135+
const { content } = await client.read(testObject.resourceKey);
136+
assert.ok(content !== null);
137+
const actual = parseSettings(content!);
138+
assert.deepEqual(actual, `{
139+
// Always
140+
"files.autoSave": "afterDelay",
141+
"files.simpleDialog.enable": true,
142+
143+
// Workbench
144+
"workbench.colorTheme": "GitHub Sharp"
145+
}`);
146+
});
147+
148+
test('do not sync machine settings when spread across file - 2', async () => {
149+
const settingsContent =
150+
`{
151+
// Always
152+
"files.autoSave": "afterDelay",
153+
"settingsSync.machine": "someValue",
154+
155+
// Workbench
156+
"workbench.colorTheme": "GitHub Sharp",
157+
158+
// Machine
159+
"settingsSync.machineOverridable": "someValue",
160+
"files.simpleDialog.enable": true,
161+
}`;
162+
await updateSettings(settingsContent);
163+
164+
await testObject.sync();
165+
166+
const { content } = await client.read(testObject.resourceKey);
167+
assert.ok(content !== null);
168+
const actual = parseSettings(content!);
169+
assert.deepEqual(actual, `{
170+
// Always
171+
"files.autoSave": "afterDelay",
172+
173+
// Workbench
174+
"workbench.colorTheme": "GitHub Sharp",
175+
"files.simpleDialog.enable": true,
176+
}`);
177+
});
178+
179+
test('sync when all settings are machine settings', async () => {
180+
const settingsContent =
181+
`{
182+
// Machine
183+
"settingsSync.machine": "someValue",
184+
"settingsSync.machineOverridable": "someValue"
185+
}`;
186+
await updateSettings(settingsContent);
187+
188+
await testObject.sync();
189+
190+
const { content } = await client.read(testObject.resourceKey);
191+
assert.ok(content !== null);
192+
const actual = parseSettings(content!);
193+
assert.deepEqual(actual, `{
194+
}`);
195+
});
196+
197+
test('sync when all settings are machine settings with trailing comma', async () => {
198+
const settingsContent =
199+
`{
200+
// Machine
201+
"settingsSync.machine": "someValue",
202+
"settingsSync.machineOverridable": "someValue",
203+
}`;
204+
await updateSettings(settingsContent);
205+
206+
await testObject.sync();
207+
208+
const { content } = await client.read(testObject.resourceKey);
209+
assert.ok(content !== null);
210+
const actual = parseSettings(content!);
211+
assert.deepEqual(actual, `{
212+
,
213+
}`);
214+
});
215+
216+
test('do not sync ignored settings', async () => {
217+
const settingsContent =
218+
`{
219+
// Always
220+
"files.autoSave": "afterDelay",
221+
"files.simpleDialog.enable": true,
222+
223+
// Editor
224+
"editor.fontFamily": "Fira Code",
225+
226+
// Terminal
227+
"terminal.integrated.shell.osx": "some path",
228+
229+
// Workbench
230+
"workbench.colorTheme": "GitHub Sharp",
231+
232+
// Ignored
233+
"sync.ignoredSettings": [
234+
"editor.fontFamily",
235+
"terminal.integrated.shell.osx"
236+
]
237+
}`;
238+
await updateSettings(settingsContent);
239+
240+
await testObject.sync();
241+
242+
const { content } = await client.read(testObject.resourceKey);
243+
assert.ok(content !== null);
244+
const actual = parseSettings(content!);
245+
assert.deepEqual(actual, `{
246+
// Always
247+
"files.autoSave": "afterDelay",
248+
"files.simpleDialog.enable": true,
249+
250+
// Workbench
251+
"workbench.colorTheme": "GitHub Sharp",
252+
253+
// Ignored
254+
"sync.ignoredSettings": [
255+
"editor.fontFamily",
256+
"terminal.integrated.shell.osx"
257+
]
258+
}`);
259+
});
260+
261+
test('do not sync ignored and machine settings', async () => {
262+
const settingsContent =
263+
`{
264+
// Always
265+
"files.autoSave": "afterDelay",
266+
"files.simpleDialog.enable": true,
267+
268+
// Editor
269+
"editor.fontFamily": "Fira Code",
270+
271+
// Terminal
272+
"terminal.integrated.shell.osx": "some path",
273+
274+
// Workbench
275+
"workbench.colorTheme": "GitHub Sharp",
276+
277+
// Ignored
278+
"sync.ignoredSettings": [
279+
"editor.fontFamily",
280+
"terminal.integrated.shell.osx"
281+
],
282+
283+
// Machine
284+
"settingsSync.machine": "someValue",
285+
}`;
286+
await updateSettings(settingsContent);
287+
288+
await testObject.sync();
289+
290+
const { content } = await client.read(testObject.resourceKey);
291+
assert.ok(content !== null);
292+
const actual = parseSettings(content!);
293+
assert.deepEqual(actual, `{
294+
// Always
295+
"files.autoSave": "afterDelay",
296+
"files.simpleDialog.enable": true,
297+
298+
// Workbench
299+
"workbench.colorTheme": "GitHub Sharp",
300+
301+
// Ignored
302+
"sync.ignoredSettings": [
303+
"editor.fontFamily",
304+
"terminal.integrated.shell.osx"
305+
],
306+
}`);
307+
});
308+
309+
test('sync throws invalid content error', async () => {
310+
const expected =
311+
`{
312+
// Always
313+
"files.autoSave": "afterDelay",
314+
"files.simpleDialog.enable": true,
315+
316+
// Workbench
317+
"workbench.colorTheme": "GitHub Sharp",
318+
"workbench.tree.indent": 20,
319+
"workbench.colorCustomizations": {
320+
"editorLineNumber.activeForeground": "#ff0000",
321+
"[GitHub Sharp]": {
322+
"statusBarItem.remoteBackground": "#24292E",
323+
"editorPane.background": "#f3f1f11a"
324+
}
325+
}
326+
327+
"gitBranch.base": "remote-repo/master",
328+
329+
// Experimental
330+
"workbench.view.experimental.allowMovingToNewContainer": true,
331+
}`;
332+
333+
await updateSettings(expected);
334+
335+
try {
336+
await testObject.sync();
337+
assert.fail('should fail with invalid content error');
338+
} catch (e) {
339+
assert.ok(e instanceof UserDataSyncError);
340+
assert.deepEqual((<UserDataSyncError>e).code, UserDataSyncErrorCode.LocalInvalidContent);
341+
}
342+
});
343+
344+
function parseSettings(content: string): string {
345+
const syncData: ISyncData = JSON.parse(content);
346+
const settingsSyncContent: ISettingsSyncContent = JSON.parse(syncData.content);
347+
return settingsSyncContent.settings;
348+
}
349+
350+
async function updateSettings(content: string): Promise<void> {
351+
await client.instantiationService.get(IFileService).writeFile(client.instantiationService.get(IEnvironmentService).settingsResource, VSBuffer.fromString(content));
352+
}
353+
354+
355+
});

src/vs/platform/userDataSync/test/common/userDataSyncClient.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ export class UserDataSyncClient extends Disposable {
114114
await configurationService.reloadConfiguration();
115115
}
116116

117+
sync(): Promise<void> {
118+
return this.instantiationService.get(IUserDataSyncService).sync();
119+
}
120+
121+
read(key: ResourceKey): Promise<IUserData> {
122+
return this.instantiationService.get(IUserDataSyncStoreService).read(key, null);
123+
}
124+
117125
}
118126

119127
export class UserDataSyncTestServer implements IRequestService {

0 commit comments

Comments
 (0)