Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions src/symbols/exists.ts

This file was deleted.

42 changes: 15 additions & 27 deletions src/symbols/s3-api-client/s3-api-client.spec.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,64 @@
import * as ExistsModule from '../exists';
import { S3ApiClient } from './s3-api-client';

describe('S3ApiClient', () => {
describe('uploadFileToPresignedUrl', () => {
let s3ApiClient;
let fakeReadStream;
let s3ApiClient: S3ApiClient;
let fakeSuccessResponse;

beforeEach(() => {
fakeReadStream = '🦦';
fakeSuccessResponse = { status: 200 };
spyOn(ExistsModule, 'exists').and.returnValue(true);
s3ApiClient = new S3ApiClient();
s3ApiClient._fs = jasmine.createSpyObj('fs', ['createReadStream']);
s3ApiClient._fs.createReadStream.and.returnValue(fakeReadStream);
s3ApiClient._fetch = jasmine.createSpy();
s3ApiClient._fetch.and.resolveTo(fakeSuccessResponse);
});

it('should throw if file does not exist', async () => {
const path = '/file/not/found';
(<jasmine.Spy>ExistsModule.exists).and.returnValue(false);
await expectAsync(s3ApiClient.uploadFileToPresignedUrl('url', path)).toBeRejectedWithError(`File does not exist at path: ${path}!`);
(s3ApiClient as any)._fetch = jasmine.createSpy();
(s3ApiClient as any)._fetch.and.resolveTo(fakeSuccessResponse);
});

it('should call fetch with presignedUrl', async () => {
const url = 'https://bugsplat.com';
const path = '/some/fake/path';
const file = '🐛.txt' as any;

await s3ApiClient.uploadFileToPresignedUrl(url, path);
await s3ApiClient.uploadFileToPresignedUrl(url, file, 1);

expect(s3ApiClient._fetch).toHaveBeenCalledWith(url, jasmine.anything());
expect((s3ApiClient as any)._fetch).toHaveBeenCalledWith(url, jasmine.anything());
});

it('should call fetch with init containing method and headers', async () => {
const url = 'https://bugsplat.com';
const path = '/some/fake/path';
const file = '🐛.txt' as any;
const size = 1337;

await s3ApiClient.uploadFileToPresignedUrl(url, path, size);
await s3ApiClient.uploadFileToPresignedUrl(url, file, size);

expect(s3ApiClient._fetch).toHaveBeenCalledWith(
expect((s3ApiClient as any)._fetch).toHaveBeenCalledWith(
jasmine.anything(),
jasmine.objectContaining({
method: 'PUT',
headers: {
'content-type': 'application/octet-stream',
'content-length': `${size}`
},
body: fakeReadStream
body: file
})
);
});

it('should return response', async () => {
const url = 'https://bugsplat.com';
const path = '/some/fake/path';
const file = '🐛.txt' as any;
const size = 1337;

const response = await s3ApiClient.uploadFileToPresignedUrl(url, path, size);
const response = await s3ApiClient.uploadFileToPresignedUrl(url, file, size);

expect(response).toEqual(fakeSuccessResponse);
});

describe('error', () => {
it('should throw if response status is not 200', async () => {
const url = 'https://bugsplat.com';
const path = '/some/fake/path';
const file = '🐛.txt' as any;
const size = 1337;
s3ApiClient._fetch.and.resolveTo({ status: 500 });
(s3ApiClient as any)._fetch.and.resolveTo({ status: 500 });

await expectAsync(s3ApiClient.uploadFileToPresignedUrl(url, path, size)).toBeRejectedWithError(`Error uploading ${path} to presignedUrl`);
await expectAsync(s3ApiClient.uploadFileToPresignedUrl(url, file, size)).toBeRejectedWithError(`Error uploading to presignedUrl ${url}`);
});
});
});
Expand Down
15 changes: 4 additions & 11 deletions src/symbols/s3-api-client/s3-api-client.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import fetchPonyfill from 'fetch-ponyfill';
import fs from 'fs';
import { exists } from '../exists';
import type fs from 'fs';

export class S3ApiClient {

private _fetch = fetchPonyfill().fetch;
private _fs = fs;

async uploadFileToPresignedUrl(presignedUrl: string, file: string, size: number): Promise<Response> {
if (!exists(file)) {
throw new Error(`File does not exist at path: ${file}!`);
}

async uploadFileToPresignedUrl(presignedUrl: string, file: File | fs.ReadStream, size: number): Promise<Response> {
const response = await this._fetch(presignedUrl, {
method: 'PUT',
headers: {
'content-type': 'application/octet-stream',
'content-length': `${size}`
},
body: <any>this._fs.createReadStream(file),
body: file as BodyInit
});

if (response.status !== 200) {
throw new Error(`Error uploading ${file} to presignedUrl`);
throw new Error(`Error uploading to presignedUrl ${presignedUrl}`);
}

return response;
Expand Down
11 changes: 10 additions & 1 deletion src/symbols/symbols-api-client/symbols-api-client.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import fs from "fs";
import path from 'path';
import { config } from "../../../spec/config";
import { BugSplatApiClient } from "../../common";
import { SymbolsApiClient } from "./symbols-api-client";
Expand Down Expand Up @@ -32,7 +34,14 @@ describe('SymbolsApiClient', () => {

describe('post', () => {
it('should return 200 for post with valid database, application, version and files', async () => {
const file = './dist/cjs/index.js.map';
const filePath = './dist/cjs/index.js.map';
const name = path.basename(filePath);
const size = fs.statSync(filePath).size;
const file = {
name,
size,
file: fs.createReadStream(filePath)
};
const response = await client.post(
database,
application,
Expand Down
33 changes: 8 additions & 25 deletions src/symbols/symbols-api-client/symbols-api-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import path from 'path';
import { createFakeBugSplatApiClient } from '../../../spec/fakes/common/bugsplat-api-client';
import { createFakeFormData } from '../../../spec/fakes/common/form-data';
import { createFakeResponseBody } from '../../../spec/fakes/common/response';
import * as ExistsModule from '../exists';
import { SymbolsApiClient } from './symbols-api-client';
import * as S3ApiClientModule from '../s3-api-client/s3-api-client';
import { of } from 'rxjs';
Expand Down Expand Up @@ -87,22 +86,17 @@ describe('SymbolsApiClient', () => {
let fakeS3ApiClient;
let files;
let result;
let stat;
let size;
let timer;

beforeEach(async () => {
files = ['file/📄'];
size = 1337;
stat = jasmine.createSpy();
stat.and.returnValue({ size });
files = [{
name: '📄.sym',
size: 1337
}];
timer = jasmine.createSpy();
timer.and.returnValue(of(0));
(<any>symbolsApiClient)._stat = stat;
(<any>symbolsApiClient)._timer = timer;

spyOn(ExistsModule, 'exists').and.returnValue(true);

fakeS3ApiClient = jasmine.createSpyObj('S3ApiClient', ['uploadFileToPresignedUrl']);
fakeS3ApiClient.uploadFileToPresignedUrl.and.resolveTo(fakeSuccessResponse);
spyOn(S3ApiClientModule, 'S3ApiClient').and.returnValue(fakeS3ApiClient);
Expand All @@ -115,23 +109,12 @@ describe('SymbolsApiClient', () => {
);
});

it('should throw if file does not exist', async () => {
(<jasmine.Spy>ExistsModule.exists).and.returnValue(false);

await expectAsync(symbolsApiClient.post(
database,
application,
version,
files
)).toBeRejectedWithError(`File does not exist at path: ${files[0]}!`);
});

it('should append dbName, appName, appVersion, size and symFileName to FormData', () => {
expect(fakeFormData.append).toHaveBeenCalledWith('dbName', database);
expect(fakeFormData.append).toHaveBeenCalledWith('appName', application);
expect(fakeFormData.append).toHaveBeenCalledWith('appVersion', version);
expect(fakeFormData.append).toHaveBeenCalledWith('size', size.toString());
expect(fakeFormData.append).toHaveBeenCalledWith('symFileName', path.basename(files[0]));
expect(fakeFormData.append).toHaveBeenCalledWith('size', files[0].size.toString());
expect(fakeFormData.append).toHaveBeenCalledWith('symFileName', path.basename(files[0].name));
});

it('should call fetch with correct route', () => {
Expand All @@ -153,7 +136,7 @@ describe('SymbolsApiClient', () => {
});

it('should call uploadFileToPresignedUrl with url, file and size', () => {
expect(fakeS3ApiClient.uploadFileToPresignedUrl).toHaveBeenCalledWith(url, files[0], size);
expect(fakeS3ApiClient.uploadFileToPresignedUrl).toHaveBeenCalledWith(url, files[0].file, files[0].size);
});

it('should sleep between requests', () => {
Expand All @@ -176,7 +159,7 @@ describe('SymbolsApiClient', () => {
application,
version,
files
)).toBeRejectedWithError(`Error getting presignedUrl for ${path.basename(files[0])}`);
)).toBeRejectedWithError(`Error getting presignedUrl for ${files[0].name}`);
});

it('should throw if response json Status is \'Failed\'', async () => {
Expand Down
21 changes: 6 additions & 15 deletions src/symbols/symbols-api-client/symbols-api-client.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import fs from 'fs';
import path from 'path';
import type fs from 'fs';
import { lastValueFrom, timer } from 'rxjs';
import util from 'util';
import { ApiClient, BugSplatResponse } from '../../common';
import { exists } from '../exists';
import { S3ApiClient } from '../s3-api-client/s3-api-client';
const stat = util.promisify(fs.stat);

export class SymbolsApiClient {

private readonly route = '/api/symbols';
private _stat = stat;

private _timer = timer;

constructor(private _client: ApiClient) { }
Expand Down Expand Up @@ -45,17 +41,12 @@ export class SymbolsApiClient {
database: string,
application: string,
version: string,
files: Array<string>
files: Array<{ name: string, size: number, file: File | fs.ReadStream }>
): Promise<Array<BugSplatResponse>> {
const promises = files
.map(async (file) => {
if (!exists(file)) {
throw new Error(`File does not exist at path: ${file}!`);
}

const stats = await this._stat(file);
const size = stats.size;
const name = path.basename(file);
const name = file.name;
const size = file.size;
const presignedUrl = await this.getPresignedUrl(
database,
application,
Expand All @@ -65,7 +56,7 @@ export class SymbolsApiClient {
);

const s3Client = new S3ApiClient();
const response = s3Client.uploadFileToPresignedUrl(presignedUrl, file, size);
const response = s3Client.uploadFileToPresignedUrl(presignedUrl, file.file, size);
await lastValueFrom(this._timer(1000));

return response;
Expand Down