Skip to content

Commit 6385b36

Browse files
authored
feat: crash status (#134)
* feat: crash status * fix: crashes status * fix: summary status * feat: post success
1 parent dcddfe8 commit 6385b36

File tree

10 files changed

+131
-17
lines changed

10 files changed

+131
-17
lines changed

spec/fakes/crash/crash-api-response.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { GroupableThreadCollection, ProcessingStatus } from '@crash';
22
import { EventType } from '@events';
33
import { createFakeEvents } from '@spec/fakes/events/events';
4-
import { CrashDetailsRawResponse } from 'src/crash/crash-details/crash-details';
4+
import { CrashDetailsRawResponse, CrashStatus } from 'src/crash/crash-details/crash-details';
55

66
export const createFakeCrashApiResponse = () => ({
77
processed: ProcessingStatus.Complete as number,
@@ -27,6 +27,7 @@ export const createFakeCrashApiResponse = () => ({
2727
platform: 'NES',
2828
previousCrashId: 998,
2929
processor: 'Pentium 4',
30+
status: CrashStatus.Open,
3031
stackKey: 'myConsoleCrasher(1337)',
3132
stackKeyComment: 'hello world!',
3233
stackKeyId: 117,

src/crash/crash-api-client/crash-api-client.e2e.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
import { BugSplatApiClient } from '@common';
2-
import { CrashApiClient } from '@crash';
2+
import { CrashApiClient, CrashStatus } from '@crash';
33
import { config } from '@spec/config';
4-
import { postNativeCrashAndSymbols } from '@spec/files/native/post-native-crash';
4+
import { postNativeCrashAndWaitForCrashToProcess } from '@spec/files/native/post-native-crash';
55

66
describe('CrashApiClient', () => {
77
let crashClient: CrashApiClient;
88
let application: string;
99
let version: string;
1010
let id: number;
11+
let stackKeyId: number;
1112

1213
beforeEach(async () => {
1314
const { host, email, password } = config;
1415
const bugsplatApiClient = await BugSplatApiClient.createAuthenticatedClientForNode(email, password, host);
1516
application = 'myConsoleCrasher';
1617
version = `${Math.random() * 1000000}`;
17-
const result = await postNativeCrashAndSymbols(
18+
crashClient = new CrashApiClient(bugsplatApiClient);
19+
const result = await postNativeCrashAndWaitForCrashToProcess(
1820
bugsplatApiClient,
21+
crashClient,
1922
config.database,
2023
application,
2124
version
2225
);
2326
id = result.crashId;
24-
25-
crashClient = new CrashApiClient(bugsplatApiClient);
27+
stackKeyId = result.stackKeyId;
2628
});
2729

2830
describe('getCrashById', () => {
@@ -39,7 +41,15 @@ describe('CrashApiClient', () => {
3941
it('should return 200 for a recent crash that has symbols', async () => {
4042
const response = await crashClient.reprocessCrash(config.database, id);
4143

42-
expect(response.success).toEqual(true);
44+
expect(response.status).toEqual('success');
45+
});
46+
});
47+
48+
describe('postStatus', () => {
49+
it('should return 200', async () => {
50+
const response = await crashClient.postStatus(config.database, stackKeyId, CrashStatus.Open);
51+
52+
expect(response.status).toEqual('success');
4353
});
4454
});
45-
});
55+
});

src/crash/crash-api-client/crash-api-client.spec.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createFakeBugSplatApiClient } from '@spec/fakes/common/bugsplat-api-cli
33
import { createFakeFormData } from '@spec/fakes/common/form-data';
44
import { createFakeResponseBody } from '@spec/fakes/common/response';
55
import { createFakeCrashApiResponse } from '@spec/fakes/crash/crash-api-response';
6-
import { createCrashDetails } from '../crash-details/crash-details';
6+
import { CrashStatus, createCrashDetails } from '../crash-details/crash-details';
77

88
describe('CrashApiClient', () => {
99
const database = 'fred';
@@ -170,4 +170,59 @@ describe('CrashApiClient', () => {
170170
}
171171
});
172172
});
173-
});
173+
174+
describe('postStatus', () => {
175+
let client: CrashApiClient;
176+
let fakePostStatusApiResponse;
177+
let fakeBugSplatApiClient;
178+
let result;
179+
180+
beforeEach(async () => {
181+
fakePostStatusApiResponse = { success: true };
182+
const fakeResponse = createFakeResponseBody(200, fakePostStatusApiResponse);
183+
fakeBugSplatApiClient = createFakeBugSplatApiClient(fakeFormData, fakeResponse);
184+
client = new CrashApiClient(fakeBugSplatApiClient);
185+
186+
result = await client.postStatus(database, id, CrashStatus.Closed);
187+
});
188+
189+
it('should call fetch with correct route', () => {
190+
expect(fakeBugSplatApiClient.fetch).toHaveBeenCalledWith('/api/crash/status', jasmine.anything());
191+
});
192+
193+
it('should call fetch with formData containing database, id and status', () => {
194+
expect(fakeFormData.append).toHaveBeenCalledWith('database', database);
195+
expect(fakeFormData.append).toHaveBeenCalledWith('groupId', id.toString());
196+
expect(fakeFormData.append).toHaveBeenCalledWith('status', CrashStatus.Closed.toString());
197+
});
198+
199+
it('should return response json', () => {
200+
expect(result).toEqual(fakePostStatusApiResponse);
201+
});
202+
203+
it('should throw if status is not 200', async () => {
204+
const message = 'Bad request';
205+
206+
try {
207+
const fakePostStatusErrorBody = { message };
208+
const fakeResponse = createFakeResponseBody(400, fakePostStatusErrorBody, false);
209+
const fakeBugSplatApiClient = createFakeBugSplatApiClient(fakeFormData, fakeResponse);
210+
const client = new CrashApiClient(fakeBugSplatApiClient);
211+
212+
await client.postStatus(database, id, CrashStatus.Closed);
213+
fail('postStatus was supposed to throw!');
214+
} catch (error: any) {
215+
expect(error.message).toEqual(message);
216+
}
217+
});
218+
219+
it('should throw if database is falsy', async () => {
220+
try {
221+
await client.postStatus('', id, CrashStatus.Closed);
222+
fail('postStatus was supposed to throw!');
223+
} catch (error: any) {
224+
expect(error.message).toMatch(/to be a non white space string/);
225+
}
226+
});
227+
});
228+
});

src/crash/crash-api-client/crash-api-client.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ApiClient } from '@common';
22
import { CrashDetails } from '@crash';
33
import ac from 'argument-contracts';
4-
import { CrashDetailsRawResponse, createCrashDetails } from '../crash-details/crash-details';
4+
import { CrashDetailsRawResponse, CrashStatus, createCrashDetails } from '../crash-details/crash-details';
55

66
export class CrashApiClient {
77

@@ -75,9 +75,38 @@ export class CrashApiClient {
7575

7676
return json as SuccessResponse;
7777
}
78+
79+
async postStatus(database: string, groupId: number, status: CrashStatus): Promise<SuccessResponse> {
80+
ac.assertNonWhiteSpaceString(database, 'database');
81+
ac.assertNumber(groupId, 'groupId');
82+
ac.assertNumber(status, 'status');
83+
84+
const formData = this._client.createFormData();
85+
formData.append('database', database);
86+
formData.append('groupId', groupId.toString());
87+
formData.append('status', status.toString());
88+
const init = {
89+
method: 'POST',
90+
body: formData,
91+
cache: 'no-cache',
92+
credentials: 'include',
93+
redirect: 'follow',
94+
duplex: 'half'
95+
} as RequestInit;
96+
97+
const response = await this._client.fetch<PostStatusResponse>('/api/crash/status', init);
98+
const json = await response.json();
99+
100+
if (response.status !== 200) {
101+
throw new Error((json as ErrorResponse).message);
102+
}
103+
104+
return json as SuccessResponse;
105+
}
78106
}
79107

80-
type SuccessResponse = { success: boolean };
108+
type SuccessResponse = { status: 'success' };
81109
type ErrorResponse = { message: string };
82110
type GetCrashByIdResponse = CrashDetailsRawResponse | ErrorResponse;
83111
type ReprocessCrashResponse = SuccessResponse | ErrorResponse;
112+
type PostStatusResponse = SuccessResponse | ErrorResponse;

src/crash/crash-details/crash-details.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AdditionalInfo, ProcessingStatus } from '@crash';
1+
import { AdditionalInfo, CrashStatus, ProcessingStatus } from '@crash';
22
import { createFakeCrashApiResponse } from '@spec/fakes/crash/crash-api-response';
33
import ac from 'argument-contracts';
44
import { createEvents } from '../../events/events-api-client/event';
@@ -44,7 +44,8 @@ describe('createCrashDetails', () => {
4444
processor: 'OBAN-10.0.7.144',
4545
comments: null,
4646
processed: ProcessingStatus.Complete,
47-
thread: (<any>{ stackFrames: [], stackKeyId: 0 })
47+
thread: (<any>{ stackFrames: [], stackKeyId: 0 }),
48+
status: CrashStatus.Open,
4849
};
4950

5051
const result = createCrashDetails(<any>options);

src/crash/crash-details/crash-details.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ export enum DefectTrackerType {
2424
Favro = 'Favro',
2525
}
2626

27+
export enum CrashStatus {
28+
Open = 0,
29+
Closed = 1,
30+
Regression = 2,
31+
}
32+
2733
export interface CrashDetails {
2834
processed: ProcessingStatus;
2935

@@ -50,6 +56,7 @@ export interface CrashDetails {
5056
platform: string;
5157
previousCrashId: number;
5258
processor: string;
59+
status: CrashStatus;
5360
stackKey: string;
5461
stackKeyComment: string;
5562
stackKeyId: number;
@@ -93,6 +100,7 @@ export function createCrashDetails(options: CrashDetailsRawResponse): CrashDetai
93100
ac.assertType(options.thread, ThreadCollection, 'options.thread');
94101
ac.assertType(options.events, Array, 'options.events');
95102

103+
const status = (options.status || 0) as CrashStatus;
96104
const events = createEvents(options.events as EventResponseObject[]);
97105
const thread = new GroupableThreadCollection({
98106
...<ThreadCollection>options.thread,
@@ -120,6 +128,7 @@ export function createCrashDetails(options: CrashDetailsRawResponse): CrashDetai
120128
ipAddress,
121129
platform,
122130
processor,
131+
status,
123132
stackKey,
124133
stackKeyComment,
125134
stackKeyDefectLabel,

src/crash/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export { AdditionalInfo } from './additional-info/additional-info';
22
export { CrashApiClient } from './crash-api-client/crash-api-client';
3-
export { CrashDetails, DefectTrackerType, ProcessingStatus } from './crash-details/crash-details';
3+
export { CrashDetails, DefectTrackerType, ProcessingStatus, CrashStatus } from './crash-details/crash-details';
44
export { Module } from './module/module';
55
export { Register } from './register/register';
66
export { StackFrame, VariableValuePair } from './stack-frame/stack-frame';

src/crashes/crashes-api-row/crashes-api-row.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CrashStatus } from '@crash';
12
import { safeParseJson } from '../../common/parse';
23

34
interface CrashData {
@@ -14,6 +15,7 @@ interface CrashData {
1415
defectId: string;
1516
defectUrl: string;
1617
defectLabel: string;
18+
status: CrashStatus;
1719
skDefectId: string;
1820
skDefectUrl: string;
1921
skDefectLabel: string;
@@ -70,6 +72,7 @@ export enum CrashTypeId {
7072
export class CrashesApiRow implements CrashDataWithMappedProperties {
7173
id: number;
7274
groupByCount: number;
75+
status: CrashStatus;
7376
stackKey: string;
7477
stackId: number;
7578
stackKeyId: number;
@@ -97,6 +100,7 @@ export class CrashesApiRow implements CrashDataWithMappedProperties {
97100
constructor(rawApiRow: CrashesApiResponseRow) {
98101
this.id = Number(rawApiRow.id);
99102
this.groupByCount = Number(rawApiRow.groupByCount) || 0;
103+
this.status = Number(rawApiRow.status) as CrashStatus;
100104
this.stackKey = rawApiRow.stackKey;
101105
this.stackKeyId = Number(rawApiRow.stackKeyId);
102106
this.stackId = Number(rawApiRow.stackId);

src/summary/summary-api-client/summary-api-client.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export class SummaryApiClient {
3333
row.stackKeyDefectLabel,
3434
row.comments,
3535
Number(row.subKeyDepth),
36-
Number(row.userSum)
36+
Number(row.userSum),
37+
Number(row.status)
3738
)
3839
);
3940

src/summary/summary-api-row/summary-api-row.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { CrashStatus } from '@crash';
2+
13
interface SummaryData {
4+
status: CrashStatus,
25
stackKey: string,
36
firstReport: string,
47
lastReport: string,
@@ -36,6 +39,7 @@ export class SummaryApiRow implements SummaryDataWithMappedProperties {
3639
public stackKeyDefectLabel: string,
3740
public comments: string,
3841
public subKeyDepth: number,
39-
public userSum: number
42+
public userSum: number,
43+
public status: CrashStatus
4044
) { }
4145
}

0 commit comments

Comments
 (0)