Skip to content
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
12 changes: 12 additions & 0 deletions packages/cli-repl/src/cli-repl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ describe('CliRepl', () => {
]);
});

it('fails when trying to overwrite mongosh-owned config settings', async() => {
output = '';
input.write('config.set("userId", "foo")\n');
await waitEval(cliRepl.bus);
expect(output).to.include('Option "userId" is not available in this environment');

output = '';
input.write('config.get("userId")\n');
await waitEval(cliRepl.bus);
expect(output).to.match(/^[a-z0-9]{24}\n> $/);
});

context('loading JS files from disk', () => {
it('allows loading a file from the disk', async() => {
const filenameA = path.resolve(__dirname, '..', 'test', 'fixtures', 'load', 'a.js');
Expand Down
4 changes: 3 additions & 1 deletion packages/cli-repl/src/mongosh-repl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { MongoshCommandFailed } from '@mongosh/errors';
import { bson, ServiceProvider } from '@mongosh/service-provider-core';
import { ADMIN_DB } from '@mongosh/shell-api/lib/enums';
import { CliUserConfig } from '@mongosh/types';
import { EventEmitter, once } from 'events';
import path from 'path';
import { Duplex, PassThrough } from 'stream';
Expand Down Expand Up @@ -37,11 +38,12 @@ describe('MongoshNodeRepl', () => {
outputStream.setEncoding('utf8').on('data', (chunk) => { output += chunk; });
bus = new EventEmitter();

config = {};
config = new CliUserConfig();
const cp = stubInterface<MongoshIOProvider>();
cp.getHistoryFilePath.returns(path.join(tmpdir.path, 'history'));
cp.getConfig.callsFake(async(key: string) => config[key]);
cp.setConfig.callsFake(async(key: string, value: any) => { config[key] = value; return 'success'; });
cp.listConfigOptions.callsFake(() => Object.keys(config));
cp.exit.callsFake(((code) => bus.emit('test-exit-event', code)) as any);

ioProvider = cp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ describe('worker', () => {
},
getConfig() {},
setConfig() {},
listConfigOptions() { return []; },
listConfigOptions() { return ['batchSize']; },
onRunInterruptible() {}
};

Expand Down Expand Up @@ -555,8 +555,8 @@ describe('worker', () => {

await init('mongodb://nodb/', {}, { nodb: true });

await evaluate('config.set("key", "value")');
expect(evalListener.setConfig).to.have.been.calledWith('key', 'value');
await evaluate('config.set("batchSize", 200)');
expect(evalListener.setConfig).to.have.been.calledWith('batchSize', 200);
});
});

Expand Down
8 changes: 6 additions & 2 deletions packages/shell-api/src/shell-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -622,9 +622,9 @@ describe('ShellApi', () => {

beforeEach(() => {
config = internalState.context.config;
store = {};
store = { somekey: '' };
evaluationListener.setConfig.callsFake(async(key, value) => {
if (key === 'unavailable' as any) return 'ignored';
if (key === 'ignoreme' as any) return 'ignored';
store[key] = value;
return 'success';
});
Expand All @@ -647,6 +647,10 @@ describe('ShellApi', () => {
it('rejects setting unavailable config keys', async() => {
expect(await config.set('unavailable', 'value')).to.equal('Option "unavailable" is not available in this environment');
});

it('rejects setting explicitly ignored config keys', async() => {
expect(await config.set('ignoreme', 'value')).to.equal('Option "ignoreme" is not available in this environment');
});
});

context('with a no-config evaluation listener', () => {
Expand Down
12 changes: 8 additions & 4 deletions packages/shell-api/src/shell-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class ShellConfig extends ShellApiClass {
async set<K extends keyof ShellUserConfig>(key: K, value: ShellUserConfig[K]): Promise<string> {
assertArgsDefinedType([key], ['string'], 'config.set');
const { evaluationListener } = this._internalState;
const result = await evaluationListener.setConfig?.(key, value);
// Only allow known config keys here:
const result = (await this._allKeys()).includes(key) && await evaluationListener.setConfig?.(key, value);
if (result !== 'success') {
return `Option "${key}" is not available in this environment`;
}
Expand All @@ -57,12 +58,15 @@ class ShellConfig extends ShellApiClass {
return await evaluationListener.getConfig?.(key) ?? this.defaults[key];
}

async [asPrintable](): Promise<Map<keyof ShellUserConfig, ShellUserConfig[keyof ShellUserConfig]>> {
async _allKeys(): Promise<(keyof ShellUserConfig)[]> {
const { evaluationListener } = this._internalState;
const keys = (await evaluationListener.listConfigOptions?.() ?? Object.keys(this.defaults)) as (keyof ShellUserConfig)[];
return (await evaluationListener.listConfigOptions?.() ?? Object.keys(this.defaults)) as (keyof ShellUserConfig)[];
}

async [asPrintable](): Promise<Map<keyof ShellUserConfig, ShellUserConfig[keyof ShellUserConfig]>> {
return new Map(
await Promise.all(
keys.map(
(await this._allKeys()).map(
async key => [key, await this.get(key)] as const)));
}
}
Expand Down