Skip to content

Commit

Permalink
fix: handle missing additional info (#122)
Browse files Browse the repository at this point in the history
* fix: handle missing additional info

* chore: remove rxjs dependency

* fix: build paths
  • Loading branch information
bobbyg603 authored Apr 20, 2024
1 parent 6afb88f commit ea3af3c
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 78 deletions.
29 changes: 1 addition & 28 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
]
},
"dependencies": {
"argument-contracts": "^1.2.3",
"rxjs": "^7.1.0"
"argument-contracts": "^1.2.3"
},
"devDependencies": {
"@commitlint/cli": "^17.6.1",
Expand Down
6 changes: 3 additions & 3 deletions spec/files/native/post-native-crash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { BugSplatApiClient } from '@common';
import { CrashApiClient } from '@crash';
import { CrashPostClient, CrashType } from '@post';
import { VersionsApiClient } from '@versions';
import { firstValueFrom, timer } from 'rxjs';
import { PostCrashResponse } from 'src/post/post-crash-response';
import { createUploadableFile } from '../create-bugsplat-file';
import { createSymbolFile } from '../create-symbol-file';
import { delay } from '../../../src/common/delay';

export async function postNativeCrashAndSymbols(
authenticatedClient: BugSplatApiClient,
Expand Down Expand Up @@ -34,7 +34,7 @@ export async function postNativeCrash(
): Promise<PostCrashResponse> {
const crashFile = await createUploadableFile('./spec/files/native/myConsoleCrasher.zip');
const crashPostClient = new CrashPostClient(database);
await firstValueFrom(timer(2000)); // Prevent rate-limiting
await delay(2000); // Prevent rate-limiting
const postCrashResult = await crashPostClient.postCrash(
application,
version,
Expand Down Expand Up @@ -75,7 +75,7 @@ export async function postNativeCrashAndWaitForCrashToProcess(
if (stackKeyId > 0) {
break;
}
await firstValueFrom(timer(3000));
await delay(3000);
}

return {
Expand Down
3 changes: 3 additions & 0 deletions src/common/delay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export async function delay(millis: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, millis));
}
6 changes: 6 additions & 0 deletions src/crash/additional-info/additional-info.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ describe('AdditionalInfo', () => {

expect(result.threads).toEqual([]);
});

it('should not throw if exception is undefined', () => {
apiResponse.process.exception = undefined;

expect(() => AdditionalInfo.fromRawResponse(apiResponse)).not.toThrow();
});
});
});

Expand Down
40 changes: 22 additions & 18 deletions src/crash/additional-info/additional-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import { ModuleResponseObject } from '../module/module';
const ATTRIBUTES = '@attributes';

export interface AdditionalInfoConstructorOptions {
os: string;
debuggerOutput: string;
registers: Array<Register>;
modules: Array<Module>;
threads: Array<ThreadCollection>;
os?: string;
debuggerOutput?: string;
registers?: Array<Register>;
modules?: Array<Module>;
threads?: Array<ThreadCollection>;
}

export interface AdditionalInfoResponseObject {
os: string;
process: {
DebugOutput: {
DebugOutput?: {
DbgEngOutput: string;
},
exception: {
exception?: {
registers: Record<string, string>;
},
threads: {
threads?: {
thread: ThreadResponseObject | Array<ThreadResponseObject>;
},
modules: {
modules?: {
module: Array<ModuleResponseObject>;
}
};
Expand All @@ -45,7 +45,7 @@ export interface ThreadResponseObject {
frame: FrameResponseObject | Array<FrameResponseObject>
}

export class AdditionalInfo implements AdditionalInfoConstructorOptions {
export class AdditionalInfo implements Required<AdditionalInfoConstructorOptions> {
os: string;
debuggerOutput: string;
registers: Array<Register>;
Expand Down Expand Up @@ -78,19 +78,19 @@ export class AdditionalInfo implements AdditionalInfoConstructorOptions {
const os = response.os || '';

const debuggerOutput = !isEmpty(response.process.DebugOutput)
? response.process.DebugOutput.DbgEngOutput
? response.process.DebugOutput?.DbgEngOutput
: '';

const registers = !isEmpty(response.process.exception.registers)
? createRegistersArray(response.process.exception.registers)
const registers = !isEmpty(response.process.exception?.registers)
? createRegistersArray(response.process.exception?.registers)
: [];

const threads = !isEmpty(response.process.threads)
? createThreadCollectionArray(response.process.threads.thread)
? createThreadCollectionArray(response.process.threads?.thread)
: [];

const modules = !isEmpty(response.process.modules)
? createModulesArray(response.process.modules.module)
? createModulesArray(response.process.modules?.module)
: [];

return new AdditionalInfo({
Expand All @@ -103,7 +103,7 @@ export class AdditionalInfo implements AdditionalInfoConstructorOptions {
}
}

function createModulesArray(modules: Array<ModuleResponseObject>): Array<Module> {
function createModulesArray(modules?: Array<ModuleResponseObject>): Array<Module> {
if (!modules) {
modules = [];
}
Expand All @@ -115,11 +115,15 @@ function createModulesArray(modules: Array<ModuleResponseObject>): Array<Module>
return modules.map(module => Module.fromResponseObject(module));
}

function createRegistersArray(registers: Record<string, string>): Array<Register> {
function createRegistersArray(registers?: Record<string, string>): Array<Register> {
if (!registers) {
return [];
}

return Register.fromResponseObject(registers);
}

function createThreadCollectionArray(threads: ThreadResponseObject | Array<ThreadResponseObject>): Array<ThreadCollection> {
function createThreadCollectionArray(threads?: ThreadResponseObject | Array<ThreadResponseObject>): Array<ThreadCollection> {
if (!threads) {
threads = [];
}
Expand Down
6 changes: 3 additions & 3 deletions src/post/crash-post-client.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { CrashPostClient, CrashType } from '@post';
import { config } from '@spec/config';
import { createUploadableFile } from '@spec/files/create-bugsplat-file';
import { firstValueFrom, timer } from 'rxjs';
import { delay } from '../common/delay';

describe('CrashPostClient', () => {
beforeEach(async () => firstValueFrom(timer(2000))); // Prevent rate-limiting
beforeEach(async () => delay(2000)); // Prevent rate-limiting

describe('postCrash', () => {
it('should post crash to BugSplat and return 200', async () => {
const application = 'myConsoleCrasher';
Expand Down
8 changes: 4 additions & 4 deletions src/summary/summary-api-client/summary-api-client.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { BugSplatApiClient } from '@common';
import { config } from '@spec/config';
import { postNativeCrashAndSymbols } from '@spec/files/native/post-native-crash';
import { firstValueFrom, timer } from 'rxjs';
import { SummaryApiClient } from './summary-api-client';
import { delay } from '../../common/delay';

describe('SummaryApiClient', () => {
let summaryClient: SummaryApiClient;
Expand All @@ -25,7 +25,7 @@ describe('SummaryApiClient', () => {

describe('getSummary', () => {
it('should return 200 and array of stack keys', async () => {
const stackKey = 'myConsoleCrasher!MemoryException(150)';
const stackKey = 'myConsoleCrasher!MemoryException(150)';
const database = config.database;
const applications = [application];
const versions = [version];
Expand All @@ -45,9 +45,9 @@ describe('SummaryApiClient', () => {
break;
}

await firstValueFrom(timer(2000));
await delay(2000);
}

const row = result.rows.find(row => row.stackKey === stackKey);
expect(result.rows).toBeTruthy();
expect(result.rows.length).toEqual(pageSize);
Expand Down
3 changes: 1 addition & 2 deletions src/symbols/symbols-api-client/symbols-api-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ApiClient } from '@common';
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 { of } from 'rxjs';
import { SymbolsApiClient } from './symbols-api-client';

describe('SymbolsApiClient', () => {
Expand Down Expand Up @@ -35,7 +34,7 @@ describe('SymbolsApiClient', () => {
symbolsApiClient = new SymbolsApiClient(apiClient);

fakeTimer = jasmine.createSpy('timer');
fakeTimer.and.returnValue(of(0));
fakeTimer.and.resolveTo(0);
fakeUploadResponse = createFakeResponseBody(200, { Status: 'Success' });
(symbolsApiClient as any)._s3ApiClient = jasmine.createSpyObj('S3ApiClient', ['uploadFileToPresignedUrl']);
(symbolsApiClient as any)._s3ApiClient.uploadFileToPresignedUrl.and.resolveTo(fakeUploadResponse);
Expand Down
16 changes: 8 additions & 8 deletions src/symbols/symbols-api-client/symbols-api-client.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ApiClient, BugSplatResponse, GZippedSymbolFile, S3ApiClient } from '@common';
import { lastValueFrom, timer } from 'rxjs';
import { delay } from '../../common/delay';

export class SymbolsApiClient {
private readonly uploadUrl = '/symsrv/uploadUrl';
private readonly uploadCompleteUrl = '/symsrv/uploadComplete';
private _s3ApiClient = new S3ApiClient();
private _timer = timer;
private _timer = delay;

constructor(private _client: ApiClient) { }

Expand All @@ -15,7 +15,7 @@ export class SymbolsApiClient {
database: string,
application: string,
version: string,
files: Array<GZippedSymbolFile>
files: Array<GZippedSymbolFile>
): Promise<Array<BugSplatResponse>> {
const promises = files
.map(async (file) => {
Expand All @@ -40,21 +40,21 @@ export class SymbolsApiClient {
const additionalHeaders = {
'content-encoding': 'gzip'
};

const uploadResponse = await this._s3ApiClient.uploadFileToPresignedUrl(presignedUrl, file, additionalHeaders);

await this.postUploadComplete(
database,
application,
version,
file
);
await lastValueFrom(this._timer(1000));

await this._timer(1000);

return uploadResponse;
});

return Promise.all(promises);
}

Expand Down
5 changes: 2 additions & 3 deletions src/versions/versions-api-client/versions-api-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { createFakeFormData } from '@spec/fakes/common/form-data';
import { createFakeResponseBody } from '@spec/fakes/common/response';
import { VersionsApiClient } from '@versions';
import path from 'path';
import { of } from 'rxjs';
import * as S3ApiClientModule from '../../common/client/s3-api-client/s3-api-client';
import * as TableDataClientModule from '../../common/data/table-data/table-data-client/table-data-client';
import { VersionsApiRow } from '../versions-api-row/versions-api-row';
Expand Down Expand Up @@ -232,7 +231,7 @@ describe('VersionsApiClient', () => {
size: 1337
}];
timer = jasmine.createSpy();
timer.and.returnValue(of(0));
timer.and.resolveTo(0);
(<any>versionsApiClient)._timer = timer;

result = await versionsApiClient.postSymbols(
Expand Down Expand Up @@ -295,7 +294,7 @@ describe('VersionsApiClient', () => {
files
)).toBeRejectedWithError('Error getting presigned URL, invalid credentials');
});

it('should throw if response status is not 200, or 403', async () => {
const fakeErrorResponse = createFakeResponseBody(400);
fakeBugSplatApiClient.fetch.and.resolveTo(fakeErrorResponse);
Expand Down
Loading

0 comments on commit ea3af3c

Please sign in to comment.