Skip to content

Commit fd38ba4

Browse files
author
Akos Kitta
committed
test: added compiler + build output path test
Signed-off-by: Akos Kitta <[email protected]>
1 parent 2d85902 commit fd38ba4

File tree

3 files changed

+319
-8
lines changed

3 files changed

+319
-8
lines changed

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,7 @@ export class CoreClientProvider {
136136
this.toDisposeOnCloseClient.pushAll([
137137
Disposable.create(() => client.client.close()),
138138
Disposable.create(() => {
139-
this.ready.reject(
140-
new Error(
141-
`Disposed. Creating a new gRPC core client on address ${address}.`
142-
)
143-
);
139+
this.ready.resolve();
144140
this.ready = new Deferred();
145141
}),
146142
]);

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
SketchContainer,
1919
SketchesError,
2020
} from '../common/protocol/sketches-service';
21-
import { NotificationServiceServerImpl } from './notification-service-server';
21+
import { NotificationServiceServer } from '../common/protocol';
2222
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
2323
import { CoreClientAware } from './core-client-provider';
2424
import {
@@ -76,8 +76,8 @@ export class SketchesServiceImpl
7676
@inject(ConfigServiceImpl)
7777
private readonly configService: ConfigServiceImpl;
7878

79-
@inject(NotificationServiceServerImpl)
80-
private readonly notificationService: NotificationServiceServerImpl;
79+
@inject(NotificationServiceServer)
80+
private readonly notificationService: NotificationServiceServer;
8181

8282
@inject(EnvVariablesServer)
8383
private readonly envVariableServer: EnvVariablesServer;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
2+
import {
3+
CommandContribution,
4+
CommandRegistry,
5+
CommandService,
6+
} from '@theia/core/lib/common/command';
7+
import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider';
8+
import { Disposable } from '@theia/core/lib/common/disposable';
9+
import { EnvVariablesServer as TheiaEnvVariablesServer } from '@theia/core/lib/common/env-variables';
10+
import { ILogger } from '@theia/core/lib/common/logger';
11+
import { isWindows } from '@theia/core/lib/common/os';
12+
import { waitForEvent } from '@theia/core/lib/common/promise-util';
13+
import { MockLogger } from '@theia/core/lib/common/test/mock-logger';
14+
import { BackendApplicationConfigProvider } from '@theia/core/lib/node/backend-application-config-provider';
15+
import { FileUri } from '@theia/core/lib/node/file-uri';
16+
import {
17+
Container,
18+
ContainerModule,
19+
injectable,
20+
} from '@theia/core/shared/inversify';
21+
import { expect } from 'chai';
22+
import {
23+
ArduinoDaemon,
24+
AttachedBoardsChangeEvent,
25+
AvailablePorts,
26+
BoardsPackage,
27+
BoardsService,
28+
ConfigService,
29+
ConfigState,
30+
CoreService,
31+
IndexUpdateDidCompleteParams,
32+
IndexUpdateDidFailParams,
33+
IndexUpdateParams,
34+
LibraryPackage,
35+
NotificationServiceClient,
36+
NotificationServiceServer,
37+
OutputMessage,
38+
ProgressMessage,
39+
ResponseService,
40+
Sketch,
41+
SketchesService,
42+
} from '../../common/protocol';
43+
import { ArduinoDaemonImpl } from '../../node/arduino-daemon-impl';
44+
import { BoardDiscovery } from '../../node/board-discovery';
45+
import { BoardsServiceImpl } from '../../node/boards-service-impl';
46+
import { ConfigServiceImpl } from '../../node/config-service-impl';
47+
import { CoreClientProvider } from '../../node/core-client-provider';
48+
import { CoreServiceImpl } from '../../node/core-service-impl';
49+
import { IsTempSketch } from '../../node/is-temp-sketch';
50+
import { MonitorManager } from '../../node/monitor-manager';
51+
import { MonitorService } from '../../node/monitor-service';
52+
import {
53+
MonitorServiceFactory,
54+
MonitorServiceFactoryOptions,
55+
} from '../../node/monitor-service-factory';
56+
import { SketchesServiceImpl } from '../../node/sketches-service-impl';
57+
import { EnvVariablesServer } from '../../node/theia/env-variables/env-variables-server';
58+
59+
const timeout = 50_000;
60+
const avr = 'arduino:avr';
61+
const uno = 'arduino:avr:uno';
62+
63+
describe('core-service-impl', () => {
64+
let container: Container;
65+
let toDispose: Disposable[];
66+
67+
before(() => {
68+
BackendApplicationConfigProvider.set({ configDirName: 'testArduinoIDE' });
69+
});
70+
71+
beforeEach(async function () {
72+
this.timeout(timeout);
73+
toDispose = [];
74+
container = createContainer();
75+
await start(container, toDispose);
76+
});
77+
78+
afterEach(() => {
79+
let disposable = toDispose.pop();
80+
while (disposable) {
81+
try {
82+
disposable?.dispose();
83+
} catch {}
84+
disposable = toDispose.pop();
85+
}
86+
});
87+
88+
describe('compile', () => {
89+
it('should execute a command with the build path', async function () {
90+
this.timeout(timeout);
91+
const coreService = container.get<CoreService>(CoreService);
92+
const sketchesService = container.get<SketchesService>(SketchesService);
93+
const commandService =
94+
container.get<TestCommandRegistry>(TestCommandRegistry);
95+
const sketch = await sketchesService.createNewSketch();
96+
97+
await coreService.compile({
98+
fqbn: uno,
99+
sketch,
100+
optimizeForDebug: false,
101+
sourceOverride: {},
102+
verbose: true,
103+
});
104+
105+
const executedBuildDidCompleteCommands =
106+
commandService.executedCommands.filter(
107+
([command]) =>
108+
command === 'arduino.languageserver.notifyBuildDidComplete'
109+
);
110+
expect(executedBuildDidCompleteCommands.length).to.be.equal(1);
111+
const [, args] = executedBuildDidCompleteCommands[0];
112+
expect(args.length).to.be.equal(1);
113+
const arg = args[0];
114+
expect(typeof arg).to.be.equal('object');
115+
expect('buildOutputUri' in arg).to.be.true;
116+
expect(arg.buildOutputUri).to.be.not.undefined;
117+
118+
const tempBuildPaths = await sketchesService.tempBuildPath(sketch);
119+
if (isWindows) {
120+
expect(tempBuildPaths.length).to.be.greaterThan(1);
121+
} else {
122+
expect(tempBuildPaths.length).to.be.equal(1);
123+
}
124+
125+
const { buildOutputUri } = arg;
126+
const buildOutputPath = FileUri.fsPath(buildOutputUri).toString();
127+
expect(tempBuildPaths.includes(buildOutputPath)).to.be.true;
128+
});
129+
});
130+
});
131+
132+
async function start(
133+
container: Container,
134+
toDispose: Disposable[]
135+
): Promise<void> {
136+
const daemon = container.get<ArduinoDaemonImpl>(ArduinoDaemonImpl);
137+
const configService = container.get<ConfigServiceImpl>(ConfigServiceImpl);
138+
toDispose.push(Disposable.create(() => daemon.stop()));
139+
configService.onStart();
140+
daemon.onStart();
141+
await waitForEvent(daemon.onDaemonStarted, timeout);
142+
const boardService = container.get<BoardsServiceImpl>(BoardsServiceImpl);
143+
const searchResults = await boardService.search({ query: avr });
144+
const platform = searchResults.find(({ id }) => id === avr);
145+
if (!platform) {
146+
throw new Error(`Could not find platform: ${avr}`);
147+
}
148+
await boardService.install({ item: platform });
149+
}
150+
151+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
152+
function createContainer(): Container {
153+
const container = new Container({ defaultScope: 'Singleton' });
154+
const module = new ContainerModule((bind) => {
155+
bind(CoreClientProvider).toSelf().inSingletonScope();
156+
bind(CoreServiceImpl).toSelf().inSingletonScope();
157+
bind(CoreService).toService(CoreServiceImpl);
158+
bind(BoardsServiceImpl).toSelf().inSingletonScope();
159+
bind(BoardsService).toService(BoardsServiceImpl);
160+
bind(TestResponseService).toSelf().inSingletonScope();
161+
bind(ResponseService).toService(TestResponseService);
162+
bind(MonitorManager).toSelf().inSingletonScope();
163+
bind(MonitorServiceFactory).toFactory(
164+
({ container }) =>
165+
(options: MonitorServiceFactoryOptions) => {
166+
const child = container.createChild();
167+
child
168+
.bind<MonitorServiceFactoryOptions>(MonitorServiceFactoryOptions)
169+
.toConstantValue({
170+
...options,
171+
});
172+
child.bind(MonitorService).toSelf();
173+
return child.get<MonitorService>(MonitorService);
174+
}
175+
);
176+
bind(EnvVariablesServer).toSelf().inSingletonScope();
177+
bind(TheiaEnvVariablesServer).toService(EnvVariablesServer);
178+
bind(ArduinoDaemonImpl).toSelf().inSingletonScope();
179+
bind(ArduinoDaemon).toService(ArduinoDaemonImpl);
180+
bind(MockLogger).toSelf().inSingletonScope();
181+
bind(ILogger).toService(MockLogger);
182+
bind(TestNotificationServiceServer).toSelf().inSingletonScope();
183+
bind(NotificationServiceServer).toService(TestNotificationServiceServer);
184+
bind(ConfigServiceImpl).toSelf().inSingletonScope();
185+
bind(ConfigService).toService(ConfigServiceImpl);
186+
bind(TestCommandRegistry).toSelf().inSingletonScope();
187+
bind(CommandRegistry).toService(TestCommandRegistry);
188+
bind(CommandService).toService(CommandRegistry);
189+
bindContributionProvider(bind, CommandContribution);
190+
bind(TestBoardDiscovery).toSelf().inSingletonScope();
191+
bind(BoardDiscovery).toService(TestBoardDiscovery);
192+
bind(IsTempSketch).toSelf().inSingletonScope();
193+
bind(SketchesServiceImpl).toSelf().inSingletonScope();
194+
bind(SketchesService).toService(SketchesServiceImpl);
195+
});
196+
container.load(module);
197+
return container;
198+
}
199+
200+
@injectable()
201+
class TestResponseService implements ResponseService {
202+
readonly outputMessages: OutputMessage[] = [];
203+
readonly progressMessages: ProgressMessage[] = [];
204+
205+
appendToOutput(message: OutputMessage): void {
206+
this.outputMessages.push(message);
207+
}
208+
reportProgress(message: ProgressMessage): void {
209+
this.progressMessages.push(message);
210+
}
211+
}
212+
213+
@injectable()
214+
class TestNotificationServiceServer implements NotificationServiceServer {
215+
readonly events: string[] = [];
216+
217+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
218+
disposeClient(client: NotificationServiceClient): void {
219+
this.events.push('disposeClient:');
220+
}
221+
notifyDidReinitialize(): void {
222+
this.events.push('notifyDidReinitialize:');
223+
}
224+
notifyIndexUpdateWillStart(params: IndexUpdateParams): void {
225+
this.events.push(`notifyIndexUpdateWillStart:${JSON.stringify(params)}`);
226+
}
227+
notifyIndexUpdateDidProgress(progressMessage: ProgressMessage): void {
228+
this.events.push(
229+
`notifyIndexUpdateDidProgress:${JSON.stringify(progressMessage)}`
230+
);
231+
}
232+
notifyIndexUpdateDidComplete(params: IndexUpdateDidCompleteParams): void {
233+
this.events.push(`notifyIndexUpdateDidComplete:${JSON.stringify(params)}`);
234+
}
235+
notifyIndexUpdateDidFail(params: IndexUpdateDidFailParams): void {
236+
this.events.push(`notifyIndexUpdateDidFail:${JSON.stringify(params)}`);
237+
}
238+
notifyDaemonDidStart(port: string): void {
239+
this.events.push(`notifyDaemonDidStart:${port}`);
240+
}
241+
notifyDaemonDidStop(): void {
242+
this.events.push('notifyDaemonDidStop:');
243+
}
244+
notifyConfigDidChange(event: ConfigState): void {
245+
this.events.push(`notifyConfigDidChange:${JSON.stringify(event)}`);
246+
}
247+
notifyPlatformDidInstall(event: { item: BoardsPackage }): void {
248+
this.events.push(`notifyPlatformDidInstall:${JSON.stringify(event)}`);
249+
}
250+
notifyPlatformDidUninstall(event: { item: BoardsPackage }): void {
251+
this.events.push(`notifyPlatformDidUninstall:${JSON.stringify(event)}`);
252+
}
253+
notifyLibraryDidInstall(event: {
254+
item: LibraryPackage | 'zip-install';
255+
}): void {
256+
this.events.push(`notifyLibraryDidInstall:${JSON.stringify(event)}`);
257+
}
258+
notifyLibraryDidUninstall(event: { item: LibraryPackage }): void {
259+
this.events.push(`notifyLibraryDidUninstall:${JSON.stringify(event)}`);
260+
}
261+
notifyAttachedBoardsDidChange(event: AttachedBoardsChangeEvent): void {
262+
this.events.push(`notifyAttachedBoardsDidChange:${JSON.stringify(event)}`);
263+
}
264+
notifyRecentSketchesDidChange(event: { sketches: Sketch[] }): void {
265+
this.events.push(`notifyRecentSketchesDidChange:${JSON.stringify(event)}`);
266+
}
267+
dispose(): void {
268+
this.events.push('dispose');
269+
}
270+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
271+
setClient(client: NotificationServiceClient | undefined): void {
272+
this.events.push('setClient:');
273+
}
274+
}
275+
276+
@injectable()
277+
class TestBoardDiscovery extends BoardDiscovery {
278+
mutableAvailablePorts: AvailablePorts = {};
279+
280+
override async start(): Promise<void> {
281+
// NOOP
282+
}
283+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
284+
override async stop(restart?: boolean): Promise<void> {
285+
// NOOP
286+
}
287+
override get availablePorts(): AvailablePorts {
288+
return this.mutableAvailablePorts;
289+
}
290+
}
291+
292+
@injectable()
293+
class TestCommandRegistry extends CommandRegistry {
294+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
295+
readonly executedCommands: [string, any[]][] = [];
296+
297+
override async executeCommand<T>(
298+
commandId: string,
299+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
300+
...args: any[]
301+
): Promise<T | undefined> {
302+
const { token } = new CancellationTokenSource();
303+
this.onWillExecuteCommandEmitter.fire({
304+
commandId,
305+
args,
306+
token,
307+
waitUntil: () => {
308+
// NOOP
309+
},
310+
});
311+
this.executedCommands.push([commandId, args]);
312+
this.onDidExecuteCommandEmitter.fire({ commandId, args });
313+
return undefined;
314+
}
315+
}

0 commit comments

Comments
 (0)