mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-08 03:46:33 +00:00
fix: reduced unnecessary GET /sketches
request
Ref: #1849 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
b451e2db8c
commit
097c92d904
@ -86,26 +86,25 @@ export class CreateApi {
|
|||||||
url.searchParams.set('user_id', 'me');
|
url.searchParams.set('user_id', 'me');
|
||||||
url.searchParams.set('limit', limit.toString());
|
url.searchParams.set('limit', limit.toString());
|
||||||
const headers = await this.headers();
|
const headers = await this.headers();
|
||||||
const result: { sketches: Create.Sketch[] } = { sketches: [] };
|
const allSketches: Create.Sketch[] = [];
|
||||||
|
|
||||||
let partialSketches: Create.Sketch[] = [];
|
|
||||||
let currentOffset = 0;
|
let currentOffset = 0;
|
||||||
do {
|
while (true) {
|
||||||
url.searchParams.set('offset', currentOffset.toString());
|
url.searchParams.set('offset', currentOffset.toString());
|
||||||
partialSketches = (
|
const { sketches } = await this.run<{ sketches: Create.Sketch[] }>(url, {
|
||||||
await this.run<{ sketches: Create.Sketch[] }>(url, {
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers,
|
headers,
|
||||||
})
|
});
|
||||||
).sketches;
|
allSketches.push(...sketches);
|
||||||
if (partialSketches.length !== 0) {
|
if (sketches.length < limit) {
|
||||||
result.sketches = result.sketches.concat(partialSketches);
|
break;
|
||||||
}
|
}
|
||||||
currentOffset = currentOffset + limit;
|
currentOffset += limit;
|
||||||
} while (partialSketches.length !== 0);
|
// The create API doc show that there is `next` and `prev` pages, but it does not work
|
||||||
|
// https://api2.arduino.cc/create/docs#!/sketches95v2/sketches_v2_search
|
||||||
result.sketches.forEach((sketch) => this.sketchCache.addSketch(sketch));
|
// IF sketchCount mod limit === 0, an extra fetch must happen to detect the end of the pagination.
|
||||||
return result.sketches;
|
}
|
||||||
|
allSketches.forEach((sketch) => this.sketchCache.addSketch(sketch));
|
||||||
|
return allSketches;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createSketch(
|
async createSketch(
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import { Container, ContainerModule } from '@theia/core/shared/inversify';
|
import {
|
||||||
|
Container,
|
||||||
|
ContainerModule,
|
||||||
|
injectable,
|
||||||
|
} from '@theia/core/shared/inversify';
|
||||||
import { assert, expect } from 'chai';
|
import { assert, expect } from 'chai';
|
||||||
import fetch from 'cross-fetch';
|
import fetch from 'cross-fetch';
|
||||||
import { posix } from 'path';
|
import { posix } from 'path';
|
||||||
@ -19,13 +23,14 @@ import queryString = require('query-string');
|
|||||||
const timeout = 60 * 1_000;
|
const timeout = 60 * 1_000;
|
||||||
|
|
||||||
describe('create-api', () => {
|
describe('create-api', () => {
|
||||||
let createApi: CreateApi;
|
let createApi: TestCreateApi;
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(timeout);
|
this.timeout(timeout);
|
||||||
try {
|
try {
|
||||||
const accessToken = await login();
|
const accessToken = await login();
|
||||||
createApi = createContainer(accessToken).get<CreateApi>(CreateApi);
|
createApi =
|
||||||
|
createContainer(accessToken).get<TestCreateApi>(TestCreateApi);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof LoginFailed) {
|
if (err instanceof LoginFailed) {
|
||||||
return this.skip();
|
return this.skip();
|
||||||
@ -43,7 +48,7 @@ describe('create-api', () => {
|
|||||||
const container = new Container({ defaultScope: 'Singleton' });
|
const container = new Container({ defaultScope: 'Singleton' });
|
||||||
container.load(
|
container.load(
|
||||||
new ContainerModule((bind) => {
|
new ContainerModule((bind) => {
|
||||||
bind(CreateApi).toSelf().inSingletonScope();
|
bind(TestCreateApi).toSelf().inSingletonScope();
|
||||||
bind(SketchCache).toSelf().inSingletonScope();
|
bind(SketchCache).toSelf().inSingletonScope();
|
||||||
bind(AuthenticationClientService).toConstantValue(<
|
bind(AuthenticationClientService).toConstantValue(<
|
||||||
AuthenticationClientService
|
AuthenticationClientService
|
||||||
@ -224,6 +229,47 @@ describe('create-api', () => {
|
|||||||
expect(findByName(otherName, sketches)).to.be.not.undefined;
|
expect(findByName(otherName, sketches)).to.be.not.undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
[-1, 1],
|
||||||
|
[0, 2],
|
||||||
|
[1, 2],
|
||||||
|
].forEach(([diff, expected]) =>
|
||||||
|
it(`should not run unnecessary fetches when retrieving all sketches (sketch count ${
|
||||||
|
diff < 0 ? '<' : diff > 0 ? '>' : '='
|
||||||
|
} limit)`, async () => {
|
||||||
|
const content = 'void setup(){} void loop(){}';
|
||||||
|
const maxLimit = 50; // https://github.com/arduino/arduino-ide/pull/875
|
||||||
|
const sketchCount = maxLimit + diff;
|
||||||
|
const sketchNames = [...Array(sketchCount).keys()].map(() => v4());
|
||||||
|
|
||||||
|
await sketchNames
|
||||||
|
.map((name) => createApi.createSketch(toPosix(name), content))
|
||||||
|
.reduce(async (acc, curr) => {
|
||||||
|
await acc;
|
||||||
|
return curr;
|
||||||
|
}, Promise.resolve() as Promise<unknown>);
|
||||||
|
|
||||||
|
createApi.resetRequestRecording();
|
||||||
|
const sketches = await createApi.sketches();
|
||||||
|
const allRequests = createApi.requestRecording.slice();
|
||||||
|
|
||||||
|
expect(sketches.length).to.be.equal(sketchCount);
|
||||||
|
sketchNames.forEach(
|
||||||
|
(name) => expect(findByName(name, sketches)).to.be.not.undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(allRequests.length).to.be.equal(expected);
|
||||||
|
const getSketchesRequests = allRequests.filter(
|
||||||
|
(description) =>
|
||||||
|
description.method === 'GET' &&
|
||||||
|
description.pathname === '/create/v2/sketches' &&
|
||||||
|
description.query &&
|
||||||
|
description.query.includes(`limit=${maxLimit}`)
|
||||||
|
);
|
||||||
|
expect(getSketchesRequests.length).to.be.equal(expected);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
['.', '-', '_'].map((char) => {
|
['.', '-', '_'].map((char) => {
|
||||||
it(`should create a new sketch with '${char}' in the sketch folder name although it's disallowed from the Create Editor`, async () => {
|
it(`should create a new sketch with '${char}' in the sketch folder name although it's disallowed from the Create Editor`, async () => {
|
||||||
const name = `sketch${char}`;
|
const name = `sketch${char}`;
|
||||||
@ -332,3 +378,44 @@ class LoginFailed extends Error {
|
|||||||
Object.setPrototypeOf(this, LoginFailed.prototype);
|
Object.setPrototypeOf(this, LoginFailed.prototype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
class TestCreateApi extends CreateApi {
|
||||||
|
private _recording: RequestDescription[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const originalRun = this['run'];
|
||||||
|
this['run'] = (url, init, resultProvider) => {
|
||||||
|
this._recording.push(createRequestDescription(url, init));
|
||||||
|
return originalRun.bind(this)(url, init, resultProvider);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
resetRequestRecording(): void {
|
||||||
|
this._recording = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
get requestRecording(): RequestDescription[] {
|
||||||
|
return this._recording;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RequestDescription {
|
||||||
|
readonly origin: string;
|
||||||
|
readonly pathname: string;
|
||||||
|
readonly query?: string;
|
||||||
|
|
||||||
|
readonly method?: string | undefined;
|
||||||
|
readonly serializedBody?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRequestDescription(
|
||||||
|
url: URL,
|
||||||
|
init?: RequestInit | undefined
|
||||||
|
): RequestDescription {
|
||||||
|
const { origin, pathname, search: query } = url;
|
||||||
|
const method = init?.method;
|
||||||
|
const serializedBody = init?.body?.toString();
|
||||||
|
return { origin, pathname, query, method, serializedBody };
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user