diff --git a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts index 4f9c272f2ec05805585f9fcdd305234bb0ec5fbb..252d31728a9ddd9ae04854bada97ba2d9f36dcd3 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts @@ -297,7 +297,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn } -class RequestsSession { +export class RequestsSession { private count: number = 0; private startTime: Date | undefined = undefined; diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts index e46525cf2d9b2d92df93cb0bf532a1d7a4684752..eca683222d79c680cc801273235beaef73a29ab4 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts @@ -4,11 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IUserDataSyncStoreService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; +import { IUserDataSyncStoreService, SyncResource, UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; import { isWeb } from 'vs/base/common/platform'; +import { RequestsSession } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; +import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { newWriteableBufferStream } from 'vs/base/common/buffer'; +import { timeout } from 'vs/base/common/async'; suite('UserDataSyncStoreService', () => { @@ -316,5 +322,49 @@ suite('UserDataSyncStoreService', () => { assert.notEqual(target.requestsWithAllHeaders[0].headers!['X-User-Session-Id'], undefined); }); +}); + +suite('UserDataSyncRequestsSession', () => { + + const requestService: IRequestService = { + _serviceBrand: undefined, + async request() { return { res: { headers: {} }, stream: newWriteableBufferStream() }; }, + async resolveProxy() { return undefined; } + }; + + test('too many requests are thrown when limit exceeded', () => { + const testObject = new RequestsSession(1, 100, requestService, NullTelemetryService); + testObject.request({}, CancellationToken.None); + + try { + testObject.request({}, CancellationToken.None); + assert.fail('Should fail with limit exceeded'); + } catch (error) { + assert.ok(error instanceof UserDataSyncStoreError); + assert.equal((error).code, UserDataSyncErrorCode.LocalTooManyRequests); + } + }); + + test('requests are handled after session is expired', async () => { + const testObject = new RequestsSession(1, 100, requestService, NullTelemetryService); + testObject.request({}, CancellationToken.None); + await timeout(100); + testObject.request({}, CancellationToken.None); + }); + + test('too many requests are thrown after session is expired', async () => { + const testObject = new RequestsSession(1, 100, requestService, NullTelemetryService); + testObject.request({}, CancellationToken.None); + await timeout(100); + testObject.request({}, CancellationToken.None); + + try { + testObject.request({}, CancellationToken.None); + assert.fail('Should fail with limit exceeded'); + } catch (error) { + assert.ok(error instanceof UserDataSyncStoreError); + assert.equal((error).code, UserDataSyncErrorCode.LocalTooManyRequests); + } + }); });