Path: blob/main/src/vs/platform/configuration/test/common/configurationService.test.ts
5243 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { VSBuffer } from '../../../../base/common/buffer.js';7import { Event } from '../../../../base/common/event.js';8import { Schemas } from '../../../../base/common/network.js';9import { URI } from '../../../../base/common/uri.js';10import { runWithFakedTimers } from '../../../../base/test/common/timeTravelScheduler.js';11import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';12import { ConfigurationTarget, isConfigured } from '../../common/configuration.js';13import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from '../../common/configurationRegistry.js';14import { ConfigurationService } from '../../common/configurationService.js';15import { IFileService } from '../../../files/common/files.js';16import { FileService } from '../../../files/common/fileService.js';17import { InMemoryFileSystemProvider } from '../../../files/common/inMemoryFilesystemProvider.js';18import { NullLogService } from '../../../log/common/log.js';19import { FilePolicyService } from '../../../policy/common/filePolicyService.js';20import { NullPolicyService } from '../../../policy/common/policy.js';21import { Registry } from '../../../registry/common/platform.js';22import { PolicyCategory } from '../../../../base/common/policy.js';2324suite('ConfigurationService.test.ts', () => {2526const disposables = ensureNoDisposablesAreLeakedInTestSuite();2728let fileService: IFileService;29let settingsResource: URI;3031setup(async () => {32fileService = disposables.add(new FileService(new NullLogService()));33const diskFileSystemProvider = disposables.add(new InMemoryFileSystemProvider());34disposables.add(fileService.registerProvider(Schemas.file, diskFileSystemProvider));35settingsResource = URI.file('settings.json');36});3738test('simple', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {39await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));40const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));41await testObject.initialize();42const config = testObject.getValue<{43foo: string;44}>();4546assert.ok(config);47assert.strictEqual(config.foo, 'bar');48}));4950test('config gets flattened', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {51await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }'));5253const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));54await testObject.initialize();55const config = testObject.getValue<{56testworkbench: {57editor: {58tabs: boolean;59};60};61}>();6263assert.ok(config);64assert.ok(config.testworkbench);65assert.ok(config.testworkbench.editor);66assert.strictEqual(config.testworkbench.editor.tabs, true);67}));6869test('error case does not explode', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {70await fileService.writeFile(settingsResource, VSBuffer.fromString(',,,,'));7172const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));73await testObject.initialize();74const config = testObject.getValue<{75foo: string;76}>();7778assert.ok(config);79}));8081test('missing file does not explode', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {82const testObject = disposables.add(new ConfigurationService(URI.file('__testFile'), fileService, new NullPolicyService(), new NullLogService()));83await testObject.initialize();8485const config = testObject.getValue<{ foo: string }>();8687assert.ok(config);88}));8990test('trigger configuration change event when file does not exist', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {91const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));92await testObject.initialize();93return new Promise<void>((c, e) => {94disposables.add(Event.filter(testObject.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(() => {95assert.strictEqual(testObject.getValue('foo'), 'bar');96c();97}));98fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }')).catch(e);99});100101}));102103test('trigger configuration change event when file exists', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {104const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));105await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));106await testObject.initialize();107108return new Promise<void>((c) => {109disposables.add(Event.filter(testObject.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {110assert.strictEqual(testObject.getValue('foo'), 'barz');111c();112}));113fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "barz" }'));114});115}));116117test('reloadConfiguration', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {118await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));119120const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));121await testObject.initialize();122let config = testObject.getValue<{123foo: string;124}>();125assert.ok(config);126assert.strictEqual(config.foo, 'bar');127await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "changed" }'));128129// force a reload to get latest130await testObject.reloadConfiguration();131config = testObject.getValue<{132foo: string;133}>();134assert.ok(config);135assert.strictEqual(config.foo, 'changed');136}));137138test('model defaults', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {139interface ITestSetting {140configuration: {141service: {142testSetting: string;143};144};145}146147const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);148configurationRegistry.registerConfiguration({149'id': '_test',150'type': 'object',151'properties': {152'configuration.service.testSetting': {153'type': 'string',154'default': 'isSet'155}156}157});158159let testObject = disposables.add(new ConfigurationService(URI.file('__testFile'), fileService, new NullPolicyService(), new NullLogService()));160await testObject.initialize();161let setting = testObject.getValue<ITestSetting>();162163assert.ok(setting);164assert.strictEqual(setting.configuration.service.testSetting, 'isSet');165166await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }'));167testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));168await testObject.initialize();169170setting = testObject.getValue<ITestSetting>();171172assert.ok(setting);173assert.strictEqual(setting.configuration.service.testSetting, 'isSet');174175await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "configuration.service.testSetting": "isChanged" }'));176177await testObject.reloadConfiguration();178setting = testObject.getValue<ITestSetting>();179assert.ok(setting);180assert.strictEqual(setting.configuration.service.testSetting, 'isChanged');181}));182183test('lookup', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {184const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);185configurationRegistry.registerConfiguration({186'id': '_test',187'type': 'object',188'properties': {189'lookup.service.testSetting': {190'type': 'string',191'default': 'isSet'192}193}194});195196const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));197await testObject.initialize();198199let res = testObject.inspect('something.missing');200assert.strictEqual(res.value, undefined);201assert.strictEqual(res.defaultValue, undefined);202assert.strictEqual(res.userValue, undefined);203assert.strictEqual(isConfigured(res), false);204205res = testObject.inspect('lookup.service.testSetting');206assert.strictEqual(res.defaultValue, 'isSet');207assert.strictEqual(res.value, 'isSet');208assert.strictEqual(res.userValue, undefined);209assert.strictEqual(isConfigured(res), false);210211await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "lookup.service.testSetting": "bar" }'));212213await testObject.reloadConfiguration();214res = testObject.inspect('lookup.service.testSetting');215assert.strictEqual(res.defaultValue, 'isSet');216assert.strictEqual(res.userValue, 'bar');217assert.strictEqual(res.value, 'bar');218assert.strictEqual(isConfigured(res), true);219220}));221222test('lookup with null', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {223const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);224configurationRegistry.registerConfiguration({225'id': '_testNull',226'type': 'object',227'properties': {228'lookup.service.testNullSetting': {229'type': 'null',230}231}232});233234const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));235await testObject.initialize();236237let res = testObject.inspect('lookup.service.testNullSetting');238assert.strictEqual(res.defaultValue, null);239assert.strictEqual(res.value, null);240assert.strictEqual(res.userValue, undefined);241242await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "lookup.service.testNullSetting": null }'));243244await testObject.reloadConfiguration();245246res = testObject.inspect('lookup.service.testNullSetting');247assert.strictEqual(res.defaultValue, null);248assert.strictEqual(res.value, null);249assert.strictEqual(res.userValue, null);250}));251252test('update configuration', async () => {253const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);254configurationRegistry.registerConfiguration({255'id': '_test',256'type': 'object',257'properties': {258'configurationService.testSetting': {259'type': 'string',260'default': 'isSet'261}262}263});264const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));265await testObject.initialize();266267await testObject.updateValue('configurationService.testSetting', 'value');268assert.strictEqual(testObject.getValue('configurationService.testSetting'), 'value');269});270271test('update configuration when exist', async () => {272const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);273configurationRegistry.registerConfiguration({274'id': '_test',275'type': 'object',276'properties': {277'configurationService.testSetting': {278'type': 'string',279'default': 'isSet'280}281}282});283const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));284await testObject.initialize();285286await testObject.updateValue('configurationService.testSetting', 'value');287await testObject.updateValue('configurationService.testSetting', 'updatedValue');288assert.strictEqual(testObject.getValue('configurationService.testSetting'), 'updatedValue');289});290291test('update configuration to default value should remove', async () => {292const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);293configurationRegistry.registerConfiguration({294'id': '_test',295'type': 'object',296'properties': {297'configurationService.testSetting': {298'type': 'string',299'default': 'isSet'300}301}302});303const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));304await testObject.initialize();305306await testObject.updateValue('configurationService.testSetting', 'value');307await testObject.updateValue('configurationService.testSetting', 'isSet');308const inspect = testObject.inspect('configurationService.testSetting');309310assert.strictEqual(inspect.userValue, undefined);311});312313test('update configuration should remove when undefined is passed', async () => {314const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);315configurationRegistry.registerConfiguration({316'id': '_test',317'type': 'object',318'properties': {319'configurationService.testSetting': {320'type': 'string',321'default': 'isSet'322}323}324});325const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));326await testObject.initialize();327328await testObject.updateValue('configurationService.testSetting', 'value');329await testObject.updateValue('configurationService.testSetting', undefined);330const inspect = testObject.inspect('configurationService.testSetting');331332assert.strictEqual(inspect.userValue, undefined);333});334335test('update unknown configuration', async () => {336const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));337await testObject.initialize();338339await testObject.updateValue('configurationService.unknownSetting', 'value');340assert.strictEqual(testObject.getValue('configurationService.unknownSetting'), 'value');341});342343test('update configuration in non user target throws error', async () => {344const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);345configurationRegistry.registerConfiguration({346'id': '_test',347'type': 'object',348'properties': {349'configurationService.testSetting': {350'type': 'string',351'default': 'isSet'352}353}354});355const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, new NullPolicyService(), new NullLogService()));356await testObject.initialize();357358try {359await testObject.updateValue('configurationService.testSetting', 'value', ConfigurationTarget.WORKSPACE);360assert.fail('Should fail with error');361} catch (e) {362// succeess363}364});365366test('update configuration throws error for policy setting', async () => {367const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);368configurationRegistry.registerConfiguration({369'id': '_test',370'type': 'object',371'properties': {372'configurationService.policySetting': {373'type': 'string',374'default': 'isSet',375policy: {376name: 'configurationService.policySetting',377category: PolicyCategory.Extensions,378minimumVersion: '1.0.0',379localization: { description: { key: '', value: '' }, }380}381}382}383});384385const logService = new NullLogService();386const policyFile = URI.file('policies.json');387await fileService.writeFile(policyFile, VSBuffer.fromString('{ "configurationService.policySetting": "policyValue" }'));388const policyService = disposables.add(new FilePolicyService(policyFile, fileService, logService));389const testObject = disposables.add(new ConfigurationService(settingsResource, fileService, policyService, logService));390await testObject.initialize();391392try {393await testObject.updateValue('configurationService.policySetting', 'value');394assert.fail('Should throw error');395} catch (error) {396// succeess397}398});399});400401402