Skip to content

Commit 51f69f6

Browse files
Akos Kittakittaakos
Akos Kitta
authored andcommitted
test: gRPC core client init integration test
- Copied the env-variable server from Theia and made it possible to customize it for the tests. Each test has its own `data` folder. - Relaxed the primary package and library index error detection. This should make the init error detection locale independent. - Kill the daemon process subtree when stopping the daemon. Signed-off-by: Akos Kitta <[email protected]>
1 parent 097c92d commit 51f69f6

13 files changed

+596
-91
lines changed

Diff for: arduino-ide-extension/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"cpy": "^8.1.2",
6969
"cross-fetch": "^3.1.5",
7070
"dateformat": "^3.0.3",
71-
"deepmerge": "2.0.1",
71+
"deepmerge": "^4.2.2",
7272
"electron-updater": "^4.6.5",
7373
"fast-json-stable-stringify": "^2.1.0",
7474
"fast-safe-stringify": "^2.1.1",

Diff for: arduino-ide-extension/src/browser/create/create-api.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ export class CreateApi {
512512
const result = await resultProvider(response);
513513
const parseEnd = performance.now();
514514
console.debug(
515-
`HTTP ${fetchCount} ${method} ${url} [fetch: ${(
515+
`HTTP ${fetchCount} ${method}${url} [fetch: ${(
516516
fetchEnd - fetchStart
517517
).toFixed(2)} ms, parse: ${(parseEnd - parseStart).toFixed(
518518
2

Diff for: arduino-ide-extension/src/node/arduino-daemon-impl.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ArduinoDaemon, NotificationServiceServer } from '../common/protocol';
1616
import { CLI_CONFIG } from './cli-config';
1717
import { getExecPath } from './exec-util';
1818
import { SettingsReader } from './settings-reader';
19+
import { ProcessUtils } from '@theia/core/lib/node/process-utils';
1920

2021
@injectable()
2122
export class ArduinoDaemonImpl
@@ -34,6 +35,9 @@ export class ArduinoDaemonImpl
3435
@inject(SettingsReader)
3536
private readonly settingsReader: SettingsReader;
3637

38+
@inject(ProcessUtils)
39+
private readonly processUtils: ProcessUtils;
40+
3741
private readonly toDispose = new DisposableCollection();
3842
private readonly onDaemonStartedEmitter = new Emitter<string>();
3943
private readonly onDaemonStoppedEmitter = new Emitter<void>();
@@ -84,8 +88,16 @@ export class ArduinoDaemonImpl
8488
).unref();
8589

8690
this.toDispose.pushAll([
87-
Disposable.create(() => daemon.kill()),
88-
Disposable.create(() => this.fireDaemonStopped()),
91+
Disposable.create(() => {
92+
if (daemon.pid) {
93+
this.processUtils.terminateProcessTree(daemon.pid);
94+
this.fireDaemonStopped();
95+
} else {
96+
throw new Error(
97+
'The CLI Daemon process does not have a PID. IDE2 could not stop the CLI daemon.'
98+
);
99+
}
100+
}),
89101
]);
90102
this.fireDaemonStarted(port);
91103
this.onData('Daemon is running.');

Diff for: arduino-ide-extension/src/node/arduino-ide-backend-module.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ import {
4141
} from '../common/protocol/arduino-daemon';
4242
import { ConfigServiceImpl } from './config-service-impl';
4343
import { EnvVariablesServer as TheiaEnvVariablesServer } from '@theia/core/lib/common/env-variables';
44-
import { EnvVariablesServer } from './theia/env-variables/env-variables-server';
44+
import {
45+
ConfigDirUriProvider,
46+
EnvVariablesServer,
47+
} from './theia/env-variables/env-variables-server';
4548
import { NodeFileSystemExt } from './node-filesystem-ext';
4649
import {
4750
FileSystemExt,
@@ -236,6 +239,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
236239
bind(DefaultWorkspaceServer).toSelf().inSingletonScope();
237240
rebind(TheiaWorkspaceServer).toService(DefaultWorkspaceServer);
238241

242+
bind(ConfigDirUriProvider).toSelf().inSingletonScope();
239243
bind(EnvVariablesServer).toSelf().inSingletonScope();
240244
rebind(TheiaEnvVariablesServer).toService(EnvVariablesServer);
241245

Diff for: arduino-ide-extension/src/node/core-client-provider.ts

-3
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,6 @@ function isPrimaryPackageIndexMissingStatus(
530530
{ directories: { data } }: DefaultCliConfig
531531
): boolean {
532532
const predicate = ({ message }: RpcStatus.AsObject) =>
533-
message.includes('loading json index file') &&
534533
message.includes(join(data, 'package_index.json'));
535534
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
536535
return evaluate(status, predicate);
@@ -551,8 +550,6 @@ function isLibraryIndexMissingStatus(
551550
{ directories: { data } }: DefaultCliConfig
552551
): boolean {
553552
const predicate = ({ message }: RpcStatus.AsObject) =>
554-
message.includes('index file') &&
555-
message.includes('reading') &&
556553
message.includes(join(data, 'library_index.json'));
557554
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
558555
return evaluate(status, predicate);
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,112 @@
1-
import { join } from 'path';
2-
import { homedir } from 'os';
3-
import { injectable } from '@theia/core/shared/inversify';
4-
import { FileUri } from '@theia/core/lib/node/file-uri';
1+
import {
2+
EnvVariable,
3+
EnvVariablesServer as TheiaEnvVariablesServer,
4+
} from '@theia/core/lib/common/env-variables/env-variables-protocol';
5+
import { isWindows } from '@theia/core/lib/common/os';
6+
import URI from '@theia/core/lib/common/uri';
57
import { BackendApplicationConfigProvider } from '@theia/core/lib/node/backend-application-config-provider';
6-
import { EnvVariablesServerImpl as TheiaEnvVariablesServerImpl } from '@theia/core/lib/node/env-variables/env-variables-server';
8+
import { FileUri } from '@theia/core/lib/node/file-uri';
9+
import {
10+
inject,
11+
injectable,
12+
postConstruct,
13+
} from '@theia/core/shared/inversify';
14+
import { list as listDrives } from 'drivelist';
15+
import { homedir } from 'os';
16+
import { join } from 'path';
17+
18+
@injectable()
19+
export class ConfigDirUriProvider {
20+
private uri: URI | undefined;
21+
22+
configDirUri(): URI {
23+
if (!this.uri) {
24+
this.uri = FileUri.create(
25+
join(homedir(), BackendApplicationConfigProvider.get().configDirName)
26+
);
27+
}
28+
return this.uri;
29+
}
30+
}
731

32+
// Copy-pasted from https://github.com/eclipse-theia/theia/blob/v1.31.1/packages/core/src/node/env-variables/env-variables-server.ts
33+
// to simplify the binding of the config directory location for tests.
834
@injectable()
9-
export class EnvVariablesServer extends TheiaEnvVariablesServerImpl {
10-
protected override readonly configDirUri = Promise.resolve(
11-
FileUri.create(
12-
join(homedir(), BackendApplicationConfigProvider.get().configDirName)
13-
).toString()
14-
);
35+
export class EnvVariablesServer implements TheiaEnvVariablesServer {
36+
@inject(ConfigDirUriProvider)
37+
private readonly configDirUriProvider: ConfigDirUriProvider;
38+
39+
private readonly envs: { [key: string]: EnvVariable } = {};
40+
private readonly homeDirUri = FileUri.create(homedir()).toString();
41+
42+
constructor() {
43+
const prEnv = process.env;
44+
Object.keys(prEnv).forEach((key: string) => {
45+
let keyName = key;
46+
if (isWindows) {
47+
keyName = key.toLowerCase();
48+
}
49+
this.envs[keyName] = { name: keyName, value: prEnv[key] };
50+
});
51+
}
52+
53+
@postConstruct()
54+
protected init(): void {
55+
console.log(
56+
`Configuration directory URI: '${this.configDirUriProvider
57+
.configDirUri()
58+
.toString()}'`
59+
);
60+
}
61+
62+
async getExecPath(): Promise<string> {
63+
return process.execPath;
64+
}
65+
66+
async getVariables(): Promise<EnvVariable[]> {
67+
return Object.keys(this.envs).map((key) => this.envs[key]);
68+
}
69+
70+
async getValue(key: string): Promise<EnvVariable | undefined> {
71+
if (isWindows) {
72+
key = key.toLowerCase();
73+
}
74+
return this.envs[key];
75+
}
76+
77+
async getConfigDirUri(): Promise<string> {
78+
return this.configDirUriProvider.configDirUri().toString();
79+
}
80+
81+
async getHomeDirUri(): Promise<string> {
82+
return this.homeDirUri;
83+
}
84+
85+
async getDrives(): Promise<string[]> {
86+
const uris: string[] = [];
87+
const drives = await listDrives();
88+
for (const drive of drives) {
89+
for (const mountpoint of drive.mountpoints) {
90+
if (this.filterHiddenPartitions(mountpoint.path)) {
91+
uris.push(FileUri.create(mountpoint.path).toString());
92+
}
93+
}
94+
}
95+
return uris;
96+
}
97+
98+
/**
99+
* Filters hidden and system partitions.
100+
*/
101+
private filterHiddenPartitions(path: string): boolean {
102+
// OS X: This is your sleep-image. When your Mac goes to sleep it writes the contents of its memory to the hard disk. (https://bit.ly/2R6cztl)
103+
if (path === '/private/var/vm') {
104+
return false;
105+
}
106+
// Ubuntu: This system partition is simply the boot partition created when the computers mother board runs UEFI rather than BIOS. (https://bit.ly/2N5duHr)
107+
if (path === '/boot/efi') {
108+
return false;
109+
}
110+
return true;
111+
}
15112
}

Diff for: arduino-ide-extension/src/test/node/boards-service-impl.slow-test.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,16 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
22
import { Container } from '@theia/core/shared/inversify';
33
import { expect } from 'chai';
44
import { BoardSearch, BoardsService } from '../../common/protocol';
5-
import {
6-
configureBackendApplicationConfigProvider,
7-
createBaseContainer,
8-
startDaemon,
9-
} from './test-bindings';
5+
import { createBaseContainer, startDaemon } from './test-bindings';
106

117
describe('boards-service-impl', () => {
128
let boardService: BoardsService;
139
let toDispose: DisposableCollection;
1410

1511
before(async function () {
16-
configureBackendApplicationConfigProvider();
1712
this.timeout(20_000);
1813
toDispose = new DisposableCollection();
19-
const container = createContainer();
14+
const container = await createContainer();
2015
await start(container, toDispose);
2116
boardService = container.get<BoardsService>(BoardsService);
2217
});
@@ -94,7 +89,7 @@ describe('boards-service-impl', () => {
9489
});
9590
});
9691

97-
function createContainer(): Container {
92+
async function createContainer(): Promise<Container> {
9893
return createBaseContainer();
9994
}
10095

0 commit comments

Comments
 (0)