mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-13 07:36:32 +00:00
fix: flaky compiler test
- The gRPC core client provider requires an initialized config service when processing the error message received during the `InitRequest` - Additional logging in the config service. - The tests log into the console. Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
658f117e93
commit
f5621db85d
@ -136,8 +136,10 @@ export class ConfigServiceImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async initConfig(): Promise<void> {
|
private async initConfig(): Promise<void> {
|
||||||
|
this.logger.info('>>> Initializing CLI configuration...');
|
||||||
try {
|
try {
|
||||||
const cliConfig = await this.loadCliConfig();
|
const cliConfig = await this.loadCliConfig();
|
||||||
|
this.logger.info('Loaded the CLI configuration.');
|
||||||
this.cliConfig = cliConfig;
|
this.cliConfig = cliConfig;
|
||||||
const [config] = await Promise.all([
|
const [config] = await Promise.all([
|
||||||
this.mapCliConfigToAppConfig(this.cliConfig),
|
this.mapCliConfigToAppConfig(this.cliConfig),
|
||||||
@ -153,10 +155,16 @@ export class ConfigServiceImpl
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
this.config.config = config;
|
this.config.config = config;
|
||||||
|
this.logger.info(
|
||||||
|
`Mapped the CLI configuration: ${JSON.stringify(this.config.config)}`
|
||||||
|
);
|
||||||
|
this.logger.info('Validating the CLI configuration...');
|
||||||
await this.validateCliConfig(this.cliConfig);
|
await this.validateCliConfig(this.cliConfig);
|
||||||
delete this.config.messages;
|
delete this.config.messages;
|
||||||
|
this.logger.info('The CLI config is valid.');
|
||||||
if (config) {
|
if (config) {
|
||||||
this.ready.resolve();
|
this.ready.resolve();
|
||||||
|
this.logger.info('<<< Initialized the CLI configuration.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
@ -173,18 +181,35 @@ export class ConfigServiceImpl
|
|||||||
): Promise<DefaultCliConfig> {
|
): Promise<DefaultCliConfig> {
|
||||||
const cliConfigFileUri = await this.getCliConfigFileUri();
|
const cliConfigFileUri = await this.getCliConfigFileUri();
|
||||||
const cliConfigPath = FileUri.fsPath(cliConfigFileUri);
|
const cliConfigPath = FileUri.fsPath(cliConfigFileUri);
|
||||||
|
this.logger.info(`Loading CLI configuration from ${cliConfigPath}...`);
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(cliConfigPath, {
|
const content = await fs.readFile(cliConfigPath, {
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
});
|
});
|
||||||
const model = (yaml.safeLoad(content) || {}) as DefaultCliConfig;
|
const model = (yaml.safeLoad(content) || {}) as DefaultCliConfig;
|
||||||
|
this.logger.info(`Loaded CLI configuration: ${JSON.stringify(model)}`);
|
||||||
if (model.directories.data && model.directories.user) {
|
if (model.directories.data && model.directories.user) {
|
||||||
|
this.logger.info(
|
||||||
|
"'directories.data' and 'directories.user' are set in the CLI configuration model."
|
||||||
|
);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
// The CLI can run with partial (missing `port`, `directories`), the IDE2 cannot.
|
// The CLI can run with partial (missing `port`, `directories`), the IDE2 cannot.
|
||||||
// We merge the default CLI config with the partial user's config.
|
// We merge the default CLI config with the partial user's config.
|
||||||
|
this.logger.info(
|
||||||
|
"Loading fallback CLI configuration to get 'directories.data' and 'directories.user'"
|
||||||
|
);
|
||||||
const fallbackModel = await this.getFallbackCliConfig();
|
const fallbackModel = await this.getFallbackCliConfig();
|
||||||
return deepmerge(fallbackModel, model) as DefaultCliConfig;
|
this.logger.info(
|
||||||
|
`Loaded fallback CLI configuration: ${JSON.stringify(fallbackModel)}`
|
||||||
|
);
|
||||||
|
const mergedModel = deepmerge(fallbackModel, model) as DefaultCliConfig;
|
||||||
|
this.logger.info(
|
||||||
|
`Merged CLI configuration with the fallback: ${JSON.stringify(
|
||||||
|
mergedModel
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
return mergedModel;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (ErrnoException.isENOENT(error)) {
|
if (ErrnoException.isENOENT(error)) {
|
||||||
if (initializeIfAbsent) {
|
if (initializeIfAbsent) {
|
||||||
|
@ -254,8 +254,8 @@ export class CoreClientProvider {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('error', reject)
|
.on('error', reject)
|
||||||
.on('end', () => {
|
.on('end', async () => {
|
||||||
const error = this.evaluateErrorStatus(errors);
|
const error = await this.evaluateErrorStatus(errors);
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
return;
|
return;
|
||||||
@ -265,7 +265,10 @@ export class CoreClientProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private evaluateErrorStatus(status: RpcStatus[]): Error | undefined {
|
private async evaluateErrorStatus(
|
||||||
|
status: RpcStatus[]
|
||||||
|
): Promise<Error | undefined> {
|
||||||
|
await this.configService.getConfiguration(); // to ensure the CLI config service has been initialized.
|
||||||
const { cliConfiguration } = this.configService;
|
const { cliConfiguration } = this.configService;
|
||||||
if (!cliConfiguration) {
|
if (!cliConfiguration) {
|
||||||
// If the CLI config is not available, do not even try to guess what went wrong.
|
// If the CLI config is not available, do not even try to guess what went wrong.
|
||||||
|
@ -7,7 +7,8 @@ import {
|
|||||||
import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider';
|
import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider';
|
||||||
import { Disposable } from '@theia/core/lib/common/disposable';
|
import { Disposable } from '@theia/core/lib/common/disposable';
|
||||||
import { EnvVariablesServer as TheiaEnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
import { EnvVariablesServer as TheiaEnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||||
import { ILogger } from '@theia/core/lib/common/logger';
|
import { ILogger, Loggable } from '@theia/core/lib/common/logger';
|
||||||
|
import { LogLevel } from '@theia/core/lib/common/logger-protocol';
|
||||||
import { isWindows } from '@theia/core/lib/common/os';
|
import { isWindows } from '@theia/core/lib/common/os';
|
||||||
import { waitForEvent } from '@theia/core/lib/common/promise-util';
|
import { waitForEvent } from '@theia/core/lib/common/promise-util';
|
||||||
import { MockLogger } from '@theia/core/lib/common/test/mock-logger';
|
import { MockLogger } from '@theia/core/lib/common/test/mock-logger';
|
||||||
@ -66,7 +67,7 @@ describe('core-service-impl', () => {
|
|||||||
let toDispose: Disposable[];
|
let toDispose: Disposable[];
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
BackendApplicationConfigProvider.set({ configDirName: 'testArduinoIDE' });
|
BackendApplicationConfigProvider.set({ configDirName: '.testArduinoIDE' });
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
@ -175,10 +176,11 @@ function createContainer(): Container {
|
|||||||
);
|
);
|
||||||
bind(EnvVariablesServer).toSelf().inSingletonScope();
|
bind(EnvVariablesServer).toSelf().inSingletonScope();
|
||||||
bind(TheiaEnvVariablesServer).toService(EnvVariablesServer);
|
bind(TheiaEnvVariablesServer).toService(EnvVariablesServer);
|
||||||
bind(ArduinoDaemonImpl).toSelf().inSingletonScope();
|
bind(SilentArduinoDaemon).toSelf().inSingletonScope();
|
||||||
bind(ArduinoDaemon).toService(ArduinoDaemonImpl);
|
bind(ArduinoDaemon).toService(SilentArduinoDaemon);
|
||||||
bind(MockLogger).toSelf().inSingletonScope();
|
bind(ArduinoDaemonImpl).toService(SilentArduinoDaemon);
|
||||||
bind(ILogger).toService(MockLogger);
|
bind(ConsoleLogger).toSelf().inSingletonScope();
|
||||||
|
bind(ILogger).toService(ConsoleLogger);
|
||||||
bind(TestNotificationServiceServer).toSelf().inSingletonScope();
|
bind(TestNotificationServiceServer).toSelf().inSingletonScope();
|
||||||
bind(NotificationServiceServer).toService(TestNotificationServiceServer);
|
bind(NotificationServiceServer).toService(TestNotificationServiceServer);
|
||||||
bind(ConfigServiceImpl).toSelf().inSingletonScope();
|
bind(ConfigServiceImpl).toSelf().inSingletonScope();
|
||||||
@ -312,3 +314,88 @@ class TestCommandRegistry extends CommandRegistry {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
class ConsoleLogger extends MockLogger {
|
||||||
|
override log(
|
||||||
|
logLevel: number,
|
||||||
|
arg2: string | Loggable | Error,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
...params: any[]
|
||||||
|
): Promise<void> {
|
||||||
|
if (arg2 instanceof Error) {
|
||||||
|
return this.error(String(arg2), params);
|
||||||
|
}
|
||||||
|
switch (logLevel) {
|
||||||
|
case LogLevel.INFO:
|
||||||
|
return this.info(arg2, params);
|
||||||
|
case LogLevel.WARN:
|
||||||
|
return this.warn(arg2, params);
|
||||||
|
case LogLevel.TRACE:
|
||||||
|
return this.trace(arg2, params);
|
||||||
|
case LogLevel.ERROR:
|
||||||
|
return this.error(arg2, params);
|
||||||
|
case LogLevel.FATAL:
|
||||||
|
return this.fatal(arg2, params);
|
||||||
|
default:
|
||||||
|
return this.info(arg2, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
override async info(arg: string | Loggable, ...params: any[]): Promise<void> {
|
||||||
|
if (params.length) {
|
||||||
|
console.info(arg, ...params);
|
||||||
|
} else {
|
||||||
|
console.info(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override async trace(
|
||||||
|
arg: string | Loggable,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
...params: any[]
|
||||||
|
): Promise<void> {
|
||||||
|
if (params.length) {
|
||||||
|
console.trace(arg, ...params);
|
||||||
|
} else {
|
||||||
|
console.trace(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
override async warn(arg: string | Loggable, ...params: any[]): Promise<void> {
|
||||||
|
if (params.length) {
|
||||||
|
console.warn(arg, ...params);
|
||||||
|
} else {
|
||||||
|
console.warn(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override async error(
|
||||||
|
arg: string | Loggable,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
...params: any[]
|
||||||
|
): Promise<void> {
|
||||||
|
if (params.length) {
|
||||||
|
console.error(arg, ...params);
|
||||||
|
} else {
|
||||||
|
console.error(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override async fatal(
|
||||||
|
arg: string | Loggable,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
...params: any[]
|
||||||
|
): Promise<void> {
|
||||||
|
return this.error(arg, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
class SilentArduinoDaemon extends ArduinoDaemonImpl {
|
||||||
|
protected override onData(): void {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user