Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: lazy preference proxy #9169

Merged
merged 1 commit into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
321 changes: 193 additions & 128 deletions packages/core/src/browser/preferences/preference-proxy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,167 +73,232 @@ describe('Preference Proxy', () => {
getProvider(PreferenceScope.User).markReady();
getProvider(PreferenceScope.Workspace).markReady();
getProvider(PreferenceScope.Folder).markReady();
console.log('before ready');
try {
await prefService.ready;
} catch (e) {
console.error(e);
}
console.log('done');
});

afterEach(() => {
});

// Actually run the test suite with different parameters:
testPreferenceProxy('Synchronous Schema Definition', { asyncSchema: false });
testPreferenceProxy('Asynchronous Schema Definition (1s delay)', { asyncSchema: true });

function getProvider(scope: PreferenceScope): MockPreferenceProvider {
return testContainer.getNamed(PreferenceProvider, scope) as MockPreferenceProvider;
}

function getProxy(schema?: PreferenceSchema, options?: PreferenceProxyOptions): PreferenceProxy<{ [key: string]: any }> {
const s: PreferenceSchema = schema || {
properties: {
'my.pref': {
type: 'string',
defaultValue: 'foo'
}
}
};
prefSchema.setSchema(s);
return createPreferenceProxy(prefService, s, options);
}
function testPreferenceProxy(testDescription: string, testOptions: { asyncSchema: boolean }): void {

it('by default, it should get provide access in flat style but not deep', () => {
const proxy = getProxy();
expect(proxy['my.pref']).to.equal('foo');
expect(proxy.my).to.equal(undefined);
expect(Object.keys(proxy).join()).to.equal(['my.pref'].join());
});
describe(testDescription, () => {

it('it should get provide access in deep style but not flat', () => {
const proxy = getProxy(undefined, { style: 'deep' });
expect(proxy['my.pref']).to.equal(undefined);
expect(proxy.my.pref).to.equal('foo');
expect(Object.keys(proxy).join()).to.equal(['my'].join());
});
function getProxy(schema?: PreferenceSchema, options?: PreferenceProxyOptions): {
proxy: PreferenceProxy<{ [key: string]: any }>,
/** Only set if we are using a schema asynchronously. */
promisedSchema?: Promise<PreferenceSchema>
} {
const s: PreferenceSchema = schema || {
properties: {
'my.pref': {
type: 'string',
defaultValue: 'foo'
}
}
};
if (testOptions.asyncSchema) {
const promisedSchema = new Promise<PreferenceSchema>(resolve => setTimeout(() => {
prefSchema.setSchema(s);
resolve(s);
}, 1000));
const proxy = createPreferenceProxy(prefService, promisedSchema, options);
return { proxy, promisedSchema };
} else {
prefSchema.setSchema(s);
const proxy = createPreferenceProxy(prefService, s, options);
return { proxy };
}
}

it('it should get provide access in to both styles', () => {
const proxy = getProxy(undefined, { style: 'both' });
expect(proxy['my.pref']).to.equal('foo');
expect(proxy.my.pref).to.equal('foo');
expect(Object.keys(proxy).join()).to.equal(['my', 'my.pref'].join());
});
if (testOptions.asyncSchema) {
it('using the proxy before the schema is set should be no-op', async () => {
const { proxy, promisedSchema } = getProxy();
let changed = 0;
proxy.onPreferenceChanged(event => {
changed += 1;
});
expect(proxy['my.pref']).to.equal(undefined);
expect(Object.keys(proxy).length).to.equal(0);
// The proxy doesn't know the schema, so events shouldn't be forwarded:
await getProvider(PreferenceScope.User).setPreference('my.pref', 'bar');
expect(changed).to.equal(0);
expect(proxy['my.pref']).to.equal(undefined);
expect(Object.keys(proxy).length).to.equal(0);
// Once the schema is resolved, operations should be working:
await promisedSchema!;
expect(proxy['my.pref']).to.equal('bar');
expect(Object.keys(proxy)).members(['my.pref']);
await getProvider(PreferenceScope.User).setPreference('my.pref', 'fizz');
expect(changed).to.equal(1);
expect(proxy['my.pref']).to.equal('fizz');

it('it should forward change events', async () => {
const proxy = getProxy(undefined, { style: 'both' });
let theChange: PreferenceChangeEvent<{ [key: string]: any }>;
proxy.onPreferenceChanged(change => {
expect(theChange).to.equal(undefined);
theChange = change;
});
let theSecondChange: PreferenceChangeEvent<{ [key: string]: any }>;
(proxy.my as PreferenceProxy<{ [key: string]: any }>).onPreferenceChanged(change => {
expect(theSecondChange).to.equal(undefined);
theSecondChange = change;
});
});
}

await getProvider(PreferenceScope.User).setPreference('my.pref', 'bar');
it('by default, it should get provide access in flat style but not deep', async () => {
const { proxy, promisedSchema } = getProxy();
if (promisedSchema) {
await promisedSchema;
}
expect(proxy['my.pref']).to.equal('foo');
expect(proxy.my).to.equal(undefined);
expect(Object.keys(proxy).join()).to.equal(['my.pref'].join());
});

expect(theChange!.newValue).to.equal('bar');
expect(theChange!.oldValue).to.equal(undefined);
expect(theChange!.preferenceName).to.equal('my.pref');
expect(theSecondChange!.newValue).to.equal('bar');
expect(theSecondChange!.oldValue).to.equal(undefined);
expect(theSecondChange!.preferenceName).to.equal('my.pref');
});
it('it should get provide access in deep style but not flat', async () => {
const { proxy, promisedSchema } = getProxy(undefined, { style: 'deep' });
if (promisedSchema) {
await promisedSchema;
}
expect(proxy['my.pref']).to.equal(undefined);
expect(proxy.my.pref).to.equal('foo');
expect(Object.keys(proxy).join()).to.equal(['my'].join());
});

it('toJSON with deep', () => {
const proxy = getProxy({
properties: {
'foo.baz': {
type: 'number',
default: 4
},
'foo.bar.x': {
type: 'boolean',
default: true
},
'foo.bar.y': {
type: 'boolean',
default: false
},
'a': {
type: 'string',
default: 'a'
it('it should get provide access in to both styles', async () => {
const { proxy, promisedSchema } = getProxy(undefined, { style: 'both' });
if (promisedSchema) {
await promisedSchema;
}
}
}, { style: 'deep' });
assert.deepStrictEqual(JSON.stringify(proxy, undefined, 2), JSON.stringify({
foo: {
baz: 4,
bar: {
x: true,
y: false
expect(proxy['my.pref']).to.equal('foo');
expect(proxy.my.pref).to.equal('foo');
expect(Object.keys(proxy).join()).to.equal(['my', 'my.pref'].join());
});

it('it should forward change events', async () => {
const { proxy, promisedSchema } = getProxy(undefined, { style: 'both' });
if (promisedSchema) {
await promisedSchema;
}
},
a: 'a'
}, undefined, 2), 'there should not be foo.bar.x to avoid sending excessive data to remote clients');
});
let theChange: PreferenceChangeEvent<{ [key: string]: any }>;
proxy.onPreferenceChanged(change => {
expect(theChange).to.equal(undefined);
theChange = change;
});
let theSecondChange: PreferenceChangeEvent<{ [key: string]: any }>;
(proxy.my as PreferenceProxy<{ [key: string]: any }>).onPreferenceChanged(change => {
expect(theSecondChange).to.equal(undefined);
theSecondChange = change;
});

await getProvider(PreferenceScope.User).setPreference('my.pref', 'bar');

it('get nested default', () => {
const proxy = getProxy({
properties: {
'foo': {
'anyOf': [
{
'enum': [
false
]
expect(theChange!.newValue).to.equal('bar');
expect(theChange!.oldValue).to.equal(undefined);
expect(theChange!.preferenceName).to.equal('my.pref');
expect(theSecondChange!.newValue).to.equal('bar');
expect(theSecondChange!.oldValue).to.equal(undefined);
expect(theSecondChange!.preferenceName).to.equal('my.pref');
});

it('toJSON with deep', async () => {
const { proxy, promisedSchema } = getProxy({
properties: {
'foo.baz': {
type: 'number',
default: 4
},
{
'properties': {
'bar': {
'anyOf': [
{
'enum': [
false
]
},
{
'properties': {
'x': {
type: 'boolean'
'foo.bar.x': {
type: 'boolean',
default: true
},
'foo.bar.y': {
type: 'boolean',
default: false
},
'a': {
type: 'string',
default: 'a'
}
}
}, { style: 'deep' });
if (promisedSchema) {
await promisedSchema;
}
assert.deepStrictEqual(JSON.stringify(proxy, undefined, 2), JSON.stringify({
foo: {
baz: 4,
bar: {
x: true,
y: false
}
},
a: 'a'
}, undefined, 2), 'there should not be foo.bar.x to avoid sending excessive data to remote clients');
});

it('get nested default', async () => {
const { proxy, promisedSchema } = getProxy({
properties: {
'foo': {
'anyOf': [
{
'enum': [
false
]
},
{
'properties': {
'bar': {
'anyOf': [
{
'enum': [
false
]
},
'y': {
type: 'boolean'
{
'properties': {
'x': {
type: 'boolean'
},
'y': {
type: 'boolean'
}
}
}
}
]
}
]
}
}
],
default: {
bar: {
x: true,
y: false
}
}
}
],
default: {
bar: {
x: true,
y: false
}
}
}, { style: 'both' });
if (promisedSchema) {
await promisedSchema;
}
}
}, { style: 'both' });
assert.deepStrictEqual(proxy['foo'], {
bar: {
x: true,
y: false
}
});
assert.deepStrictEqual(proxy['foo.bar'], {
x: true,
y: false
assert.deepStrictEqual(proxy['foo'], {
bar: {
x: true,
y: false
}
});
assert.deepStrictEqual(proxy['foo.bar'], {
x: true,
y: false
});
assert.strictEqual(proxy['foo.bar.x'], true);
assert.strictEqual(proxy['foo.bar.y'], false);
});
});
assert.strictEqual(proxy['foo.bar.x'], true);
assert.strictEqual(proxy['foo.bar.y'], false);
});
}

});
Loading