mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-18 01:56:34 +00:00
Made the CLI schema validation bit more relaxed.
Both `metrics` and `telemetry` are generated by `config dump`. Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
c6b125011e
commit
66b711f43c
@ -103,18 +103,18 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"telemetry": {
|
||||
"metrics": {
|
||||
"type": "object",
|
||||
"description": "Telemetry Configuration",
|
||||
"description": "Metrics Configuration",
|
||||
"properties": {
|
||||
"addr": {
|
||||
"type": "string",
|
||||
"description": "Address to the telemetry endpoint. Must be a full address with host, address, and port. For instance, ':9090' represents 'localhost:9090'",
|
||||
"description": "Address to the metrics endpoint. Must be a full address with host, address, and port. For instance, ':9090' represents 'localhost:9090'",
|
||||
"pattern": "^(.*)$"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the telemetry is enabled or not."
|
||||
"description": "Whether the metrics is enabled or not."
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
@ -132,6 +132,5 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
|
@ -1,318 +0,0 @@
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import * as os from '@theia/core/lib/common/os';
|
||||
import { Container, injectable } from 'inversify';
|
||||
import { Event } from '@theia/core/lib/common/event';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { MockLogger } from '@theia/core/lib/common/test/mock-logger';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { MessageClient } from '@theia/core/lib/common/message-service-protocol';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { StorageService } from '@theia/core/lib/browser/storage-service';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { BoardsService, Board, Port, BoardsPackage, BoardDetails } from '../../common/protocol';
|
||||
import { BoardsServiceProvider, AvailableBoard } from '../../browser/boards/boards-service-provider';
|
||||
import { BoardsConfig } from '../../browser/boards/boards-config';
|
||||
import { NotificationCenter } from '../../browser/notification-center';
|
||||
|
||||
// tslint:disable: no-unused-expression
|
||||
|
||||
describe('boards-service-client-impl', () => {
|
||||
|
||||
describe('onAvailableBoardsChanged', () => {
|
||||
|
||||
const ESP8266: Port = { protocol: 'serial', address: '/dev/cu.SLAB_USBtoUART' };
|
||||
const UNO: Board = { name: 'Arduino Uno', fqbn: 'arduino:avr:uno', port: { protocol: 'serial', address: '/dev/cu.usbmodem14501' } };
|
||||
const MKR1000: Board = { name: 'Arduino MKR1000', fqbn: 'arduino:samd:mkr1000', port: { protocol: 'serial', address: '/dev/cu.usbmodem14601' } };
|
||||
const NANO: Board = { name: 'Arduino Nano', fqbn: 'arduino:avr:nano' };
|
||||
|
||||
const recognized = AvailableBoard.State.recognized;
|
||||
const guessed = AvailableBoard.State.guessed;
|
||||
const incomplete = AvailableBoard.State.incomplete;
|
||||
|
||||
let stub: sinon.SinonStub;
|
||||
|
||||
let server: MockBoardsService;
|
||||
let client: BoardsServiceProvider;
|
||||
let notificationCenter: NotificationCenter;
|
||||
|
||||
beforeEach(() => {
|
||||
stub = sinon.stub(os, 'isOSX').value(true);
|
||||
const container = init();
|
||||
server = container.get(MockBoardsService);
|
||||
client = container.get(BoardsServiceProvider);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
stub.reset();
|
||||
});
|
||||
|
||||
it('should have no available boards by default', () => {
|
||||
expect(client.availableBoards).to.have.length(0);
|
||||
});
|
||||
|
||||
it('should be notified when a board is attached', async () => {
|
||||
await attach(MKR1000);
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(recognized);
|
||||
expect(!!availableBoards()[0].selected).to.be.false;
|
||||
});
|
||||
|
||||
it('should be notified when a unknown board is attached', async () => {
|
||||
await attach(ESP8266);
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(incomplete);
|
||||
});
|
||||
|
||||
it('should be notified when a board is detached', async () => {
|
||||
await attach(MKR1000, UNO, ESP8266);
|
||||
expect(availableBoards()).to.have.length(3);
|
||||
await detach(MKR1000);
|
||||
expect(availableBoards()).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should be notified when an unknown board is detached', async () => {
|
||||
await attach(MKR1000, UNO, ESP8266);
|
||||
expect(availableBoards()).to.have.length(3);
|
||||
await detach(ESP8266);
|
||||
expect(availableBoards()).to.have.length(2);
|
||||
});
|
||||
|
||||
it('should recognize boards config as an available board', async () => {
|
||||
await configureBoards({ selectedBoard: NANO });
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(incomplete);
|
||||
expect(availableBoards()[0].selected).to.be.true;
|
||||
});
|
||||
|
||||
it('should discard the boards config port when corresponding board is detached', async () => {
|
||||
await attach(MKR1000);
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(recognized);
|
||||
expect(availableBoards()[0].selected).to.be.false;
|
||||
|
||||
await configureBoards({ selectedBoard: MKR1000, selectedPort: server.portFor(MKR1000) });
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(recognized);
|
||||
expect(availableBoards()[0].selected).to.be.true;
|
||||
|
||||
await detach(MKR1000);
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(incomplete);
|
||||
expect(availableBoards()[0].selected).to.be.true;
|
||||
});
|
||||
|
||||
it("should consider selected unknown boards as 'guessed'", async () => {
|
||||
await attach(ESP8266);
|
||||
await configureBoards({ selectedBoard: { name: 'guessed' }, selectedPort: ESP8266 });
|
||||
expect(availableBoards()).to.have.length(1);
|
||||
expect(availableBoards()[0].state).to.be.equal(guessed);
|
||||
expect(availableBoards()[0].name).to.be.equal('guessed');
|
||||
expect(availableBoards()[0].fqbn).to.be.undefined;
|
||||
expect(client.canVerify(client.boardsConfig)).to.be.true;
|
||||
});
|
||||
|
||||
it('should not reconnect last valid selected if port is gone', async () => {
|
||||
await attach(ESP8266, UNO);
|
||||
await configureBoards({ selectedBoard: { name: 'NodeMCU 0.9 (ESP-12 Module)', fqbn: 'esp8266:esp8266:nodemcu' }, selectedPort: ESP8266 });
|
||||
await detach(ESP8266);
|
||||
expect(availableBoards()).to.have.length(2);
|
||||
const selected = availableBoards().find(({ selected }) => selected);
|
||||
expect(selected).to.be.not.undefined;
|
||||
expect(selected!.port).to.be.undefined;
|
||||
expect(selected!.name).to.be.equal('NodeMCU 0.9 (ESP-12 Module)');
|
||||
});
|
||||
|
||||
function availableBoards(): AvailableBoard[] {
|
||||
return client.availableBoards.slice();
|
||||
}
|
||||
|
||||
async function configureBoards(config: BoardsConfig.Config): Promise<void> {
|
||||
return awaitAll(() => { client.boardsConfig = config; }, client.onAvailableBoardsChanged);
|
||||
}
|
||||
|
||||
async function detach(...toDetach: Array<Board | Port>): Promise<void> {
|
||||
return awaitAll(() => server.detach(...toDetach), client.onAttachedBoardsChanged, client.onAvailableBoardsChanged);
|
||||
}
|
||||
|
||||
async function attach(...toAttach: Array<Board | Port>): Promise<void> {
|
||||
return awaitAll(() => server.attach(...toAttach), client.onAttachedBoardsChanged, client.onAvailableBoardsChanged);
|
||||
}
|
||||
|
||||
async function awaitAll(exec: () => MaybePromise<void>, ...waitFor: Event<any>[]): Promise<void> {
|
||||
return new Promise<void>(async resolve => {
|
||||
const toDispose = new DisposableCollection();
|
||||
const promises = waitFor.map(event => {
|
||||
const deferred = new Deferred<void>();
|
||||
toDispose.push(event(() => deferred.resolve()));
|
||||
return deferred.promise;
|
||||
});
|
||||
await exec();
|
||||
await Promise.all(promises);
|
||||
toDispose.dispose();
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function init(): Container {
|
||||
const container = new Container({ defaultScope: 'Singleton' });
|
||||
container.bind(MockBoardsService).toSelf();
|
||||
container.bind(MockLogger).toSelf();
|
||||
container.bind(ILogger).toService(MockLogger);
|
||||
container.bind(MockStorageService).toSelf();
|
||||
container.bind(StorageService).toService(MockStorageService);
|
||||
container.bind(BoardsServiceProvider).toSelf();
|
||||
container.bind(MessageClient).toSelf().inSingletonScope();
|
||||
container.bind(MessageService).toSelf().inSingletonScope();
|
||||
return container;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class MockBoardsService implements BoardsService {
|
||||
|
||||
private client: BoardsServiceClient | undefined;
|
||||
|
||||
boards: Board[] = [];
|
||||
ports: Port[] = [];
|
||||
|
||||
attach(...toAttach: Array<Board | Port>): void {
|
||||
const oldState = { boards: this.boards.slice(), ports: this.ports.slice() };
|
||||
for (const what of toAttach) {
|
||||
if (Board.is(what)) {
|
||||
if (what.port) {
|
||||
this.ports.push(what.port);
|
||||
}
|
||||
this.boards.push(what);
|
||||
} else {
|
||||
this.ports.push(what);
|
||||
}
|
||||
}
|
||||
const newState = { boards: this.boards, ports: this.ports };
|
||||
if (this.client) {
|
||||
this.client.notifyAttachedBoardsChanged({ oldState, newState });
|
||||
}
|
||||
}
|
||||
|
||||
detach(...toRemove: Array<Board | Port>): void {
|
||||
const oldState = { boards: this.boards.slice(), ports: this.ports.slice() };
|
||||
for (const what of toRemove) {
|
||||
if (Board.is(what)) {
|
||||
const index = this.boards.indexOf(what);
|
||||
if (index === -1) {
|
||||
throw new Error(`${what} board is not attached. Boards were: ${JSON.stringify(oldState.boards)}`);
|
||||
}
|
||||
this.boards.splice(index, 1);
|
||||
if (what.port) {
|
||||
const portIndex = this.ports.findIndex(port => Port.sameAs(what.port, port));
|
||||
if (portIndex === -1) {
|
||||
throw new Error(`${what} port is not available. Ports were: ${JSON.stringify(oldState.ports)}`);
|
||||
}
|
||||
this.ports.splice(portIndex, 1);
|
||||
}
|
||||
} else {
|
||||
const index = this.ports.indexOf(what);
|
||||
if (index === -1) {
|
||||
throw new Error(`${what} port is not available. Ports were: ${JSON.stringify(oldState.ports)}`);
|
||||
}
|
||||
this.ports.splice(index, 1);
|
||||
}
|
||||
}
|
||||
const newState = { boards: this.boards, ports: this.ports };
|
||||
if (this.client) {
|
||||
this.client.notifyAttachedBoardsChanged({ oldState, newState });
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.setState({ boards: [], ports: [], silent: true });
|
||||
}
|
||||
|
||||
setState({ boards, ports, silent }: { boards: Board[], ports: Port[], silent?: boolean }): void {
|
||||
const oldState = { boards: this.boards, ports: this.ports };
|
||||
const newState = { boards, ports };
|
||||
if (this.client && !silent) {
|
||||
this.client.notifyAttachedBoardsChanged({ oldState, newState });
|
||||
}
|
||||
}
|
||||
|
||||
portFor(board: Board): Port {
|
||||
if (!board.port) {
|
||||
throw new Error(`${JSON.stringify(board)} does not have a port.`);
|
||||
}
|
||||
const port = this.ports.find(port => Port.sameAs(port, board.port));
|
||||
if (!port) {
|
||||
throw new Error(`Could not find port for board: ${JSON.stringify(board)}. Ports were: ${JSON.stringify(this.ports)}.`);
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
// BoardsService API
|
||||
|
||||
async getAttachedBoards(): Promise<Board[]> {
|
||||
return this.boards;
|
||||
}
|
||||
|
||||
async getAvailablePorts(): Promise<Port[]> {
|
||||
throw this.ports;
|
||||
}
|
||||
|
||||
async getBoardDetails(): Promise<BoardDetails> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getBoardPackage(): Promise<BoardsPackage> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getContainerBoardPackage(): Promise<BoardsPackage> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
allBoards(): Promise<Array<Board & { packageName: string; }>> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
install(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
uninstall(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
search(): Promise<BoardsPackage[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.reset();
|
||||
this.client = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@injectable()
|
||||
class MockStorageService implements StorageService {
|
||||
|
||||
private store: Map<string, any> = new Map();
|
||||
|
||||
reset(): void {
|
||||
this.store.clear();
|
||||
}
|
||||
|
||||
async setData<T>(key: string, data: T): Promise<void> {
|
||||
this.store.set(key, data);
|
||||
}
|
||||
|
||||
async getData<T>(key: string): Promise<T | undefined>;
|
||||
async getData<T>(key: string, defaultValue?: T): Promise<T | undefined> {
|
||||
const data = this.store.get(key);
|
||||
return data ? data : defaultValue;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user