Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c18f23e

Browse files
author
Akos Kitta
committed
fix: can unset network#proxy in the CLI config
An empty object (`{}`) must be used to correctly unset the CLI config value to its default. Closes #2184 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent 405b4fe commit c18f23e

File tree

2 files changed

+179
-1
lines changed

2 files changed

+179
-1
lines changed

‎arduino-ide-extension/src/node/config-service-impl.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export class ConfigServiceImpl
9595
};
9696
copyDefaultCliConfig.locale = locale || 'en';
9797
const proxy = Network.stringify(network);
98-
copyDefaultCliConfig.network = { proxy };
98+
copyDefaultCliConfig.network = proxy ? { proxy } : {};// must be an empty object to unset the default prop with the `WriteRequest`.
9999

100100
// always use the port of the daemon
101101
const port = await this.daemon.getPort();
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import {
2+
Disposable,
3+
DisposableCollection,
4+
} from '@theia/core/lib/common/disposable';
5+
import { deepClone } from '@theia/core/lib/common/objects';
6+
import type { MaybePromise, Mutable } from '@theia/core/lib/common/types';
7+
import type { Container } from '@theia/core/shared/inversify';
8+
import { expect } from 'chai';
9+
import { load as parseYaml } from 'js-yaml';
10+
import { promises as fs } from 'node:fs';
11+
import { join } from 'node:path';
12+
import temp from 'temp';
13+
import {
14+
Config,
15+
Network,
16+
ProxySettings,
17+
} from '../../common/protocol/config-service';
18+
import { CLI_CONFIG, DefaultCliConfig } from '../../node/cli-config';
19+
import { ConfigServiceImpl } from '../../node/config-service-impl';
20+
import { ConfigDirUriProvider } from '../../node/theia/env-variables/env-variables-server';
21+
import {
22+
createBaseContainer,
23+
createCliConfig,
24+
startDaemon,
25+
} from './node-test-bindings';
26+
27+
describe('config-service-impl', () => {
28+
const noProxy = 'none';
29+
const manualProxy: ProxySettings = {
30+
protocol: 'http',
31+
hostname: 'hostname',
32+
password: 'secret',
33+
username: 'username',
34+
port: '1234',
35+
};
36+
37+
describe('setConfiguration', () => {
38+
let configService: ConfigServiceImpl;
39+
let toDispose: DisposableCollection;
40+
let cliConfigPath: string;
41+
42+
beforeEach(async () => {
43+
const container = await createBaseContainer();
44+
toDispose = new DisposableCollection();
45+
await startDaemon(container, toDispose);
46+
configService = container.get<ConfigServiceImpl>(ConfigServiceImpl);
47+
cliConfigPath = getCliConfigPath(container);
48+
});
49+
50+
afterEach(() => toDispose.dispose());
51+
52+
it("should detect 'none' proxy with th default config", async () => {
53+
const state = await configService.getConfiguration();
54+
expect(state.config).to.be.not.undefined;
55+
const config = <Config>state.config;
56+
expect(config.network).to.be.equal(noProxy);
57+
expect(Network.stringify(config.network)).is.undefined;
58+
await assertRawConfigModel(cliConfigPath, (actualModel) => {
59+
expect(actualModel.network).to.be.undefined;
60+
});
61+
});
62+
63+
it('should ignore noop changes', async () => {
64+
const beforeState = await configService.getConfiguration();
65+
const config = <Mutable<Config>>deepClone(beforeState).config;
66+
let eventCounter = 0;
67+
toDispose.push(configService.onConfigChange(() => eventCounter++));
68+
await configService.setConfiguration(config);
69+
const afterState = await configService.getConfiguration();
70+
expect(beforeState.config).to.be.deep.equal(afterState.config);
71+
expect(eventCounter).to.be.equal(0);
72+
});
73+
74+
it('should set the manual proxy', async () => {
75+
const beforeState = await configService.getConfiguration();
76+
const config = <Mutable<Config>>deepClone(beforeState).config;
77+
config.network = manualProxy;
78+
let eventCounter = 0;
79+
toDispose.push(configService.onConfigChange(() => eventCounter++));
80+
await configService.setConfiguration(config);
81+
const afterState = await configService.getConfiguration();
82+
expect(beforeState.config).to.be.not.deep.equal(afterState.config);
83+
expect(afterState.config?.network).to.be.deep.equal(manualProxy);
84+
expect(eventCounter).to.be.equal(1);
85+
await assertRawConfigModel(cliConfigPath, (actualModel) => {
86+
expect(actualModel.network?.proxy).to.be.equal(
87+
Network.stringify(manualProxy)
88+
);
89+
});
90+
});
91+
92+
it('should unset the manual proxy', async () => {
93+
const initialState = await configService.getConfiguration();
94+
const config = <Mutable<Config>>deepClone(initialState).config;
95+
config.network = manualProxy;
96+
let eventCounter = 0;
97+
toDispose.push(configService.onConfigChange(() => eventCounter++));
98+
await configService.setConfiguration(config);
99+
const beforeState = await configService.getConfiguration();
100+
const config2 = <Mutable<Config>>deepClone(config);
101+
config2.network = noProxy;
102+
await configService.setConfiguration(config2);
103+
const afterState = await configService.getConfiguration();
104+
expect(beforeState.config).to.be.not.deep.equal(afterState.config);
105+
expect(afterState.config?.network).to.be.deep.equal(noProxy);
106+
expect(eventCounter).to.be.equal(2);
107+
await assertRawConfigModel(cliConfigPath, (actualModel) => {
108+
expect(actualModel.network?.proxy).to.be.undefined;
109+
});
110+
});
111+
});
112+
113+
describe('setConfiguration (multiple CLI daemon sessions)', () => {
114+
let tracked: typeof temp;
115+
let toDispose: DisposableCollection;
116+
117+
before(() => {
118+
tracked = temp.track();
119+
toDispose = new DisposableCollection(
120+
Disposable.create(() => tracked.cleanupSync())
121+
);
122+
});
123+
124+
after(() => toDispose.dispose());
125+
126+
it("should unset the 'network#proxy' config value between daemon sessions", async () => {
127+
const configDirPath = tracked.mkdirSync();
128+
const cliConfigPath = join(configDirPath, CLI_CONFIG);
129+
const cliConfig = await createCliConfig(configDirPath);
130+
const setupContainer = await createBaseContainer({
131+
cliConfig,
132+
configDirPath,
133+
});
134+
const toDisposeAfterFirstStart = new DisposableCollection();
135+
toDispose.push(toDisposeAfterFirstStart);
136+
await startDaemon(setupContainer, toDisposeAfterFirstStart);
137+
toDisposeAfterFirstStart.dispose();
138+
139+
// second startup when the indexes are all downloaded and the daemon is initialized with the network#proxy
140+
cliConfig.network = { proxy: Network.stringify(manualProxy) };
141+
const container = await createBaseContainer({ cliConfig, configDirPath });
142+
await startDaemon(container, toDispose);
143+
const configService = container.get<ConfigServiceImpl>(ConfigServiceImpl);
144+
let eventCounter = 0;
145+
toDispose.push(configService.onConfigChange(() => eventCounter++));
146+
147+
const beforeState = await configService.getConfiguration();
148+
const config = <Mutable<Config>>deepClone(beforeState.config);
149+
config.network = noProxy;
150+
await configService.setConfiguration(config);
151+
const afterState = await configService.getConfiguration();
152+
expect(beforeState.config).to.be.not.deep.equal(afterState.config);
153+
expect(afterState.config?.network).to.be.deep.equal(noProxy);
154+
expect(eventCounter).to.be.equal(1);
155+
await assertRawConfigModel(cliConfigPath, (actualModel) => {
156+
expect(actualModel.network?.proxy).to.be.undefined; // currently fails due to arduino/arduino-cli#2275
157+
});
158+
});
159+
});
160+
161+
async function assertRawConfigModel(
162+
cliConfigPath: string,
163+
assert: (actual: DefaultCliConfig) => MaybePromise<void>
164+
): Promise<void> {
165+
const raw = await fs.readFile(cliConfigPath, { encoding: 'utf8' });
166+
const model = parseYaml(raw);
167+
await assert(model);
168+
}
169+
170+
function getCliConfigPath(container: Container): string {
171+
const configDirUriProvider =
172+
container.get<ConfigDirUriProvider>(ConfigDirUriProvider);
173+
return configDirUriProvider
174+
.configDirUri()
175+
.resolve(CLI_CONFIG)
176+
.path.fsPath();
177+
}
178+
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /