@forge/events 2.0.1-next.0 → 2.0.1-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/out/__test__/appEvents.test.d.ts +0 -2
- package/out/__test__/appEvents.test.d.ts.map +0 -1
- package/out/__test__/appEvents.test.js +0 -137
- package/out/__test__/invocationError.test.d.ts +0 -2
- package/out/__test__/invocationError.test.d.ts.map +0 -1
- package/out/__test__/invocationError.test.js +0 -36
- package/out/__test__/jobProgress.test.d.ts +0 -2
- package/out/__test__/jobProgress.test.d.ts.map +0 -1
- package/out/__test__/jobProgress.test.js +0 -118
- package/out/__test__/queue.test.d.ts +0 -2
- package/out/__test__/queue.test.d.ts.map +0 -1
- package/out/__test__/queue.test.js +0 -237
- package/out/__test__/queueResponse.test.d.ts +0 -2
- package/out/__test__/queueResponse.test.d.ts.map +0 -1
- package/out/__test__/queueResponse.test.js +0 -14
- package/out/__test__/utils.d.ts +0 -8
- package/out/__test__/utils.d.ts.map +0 -1
- package/out/__test__/utils.js +0 -41
- package/src/__test__/appEvents.test.ts +0 -201
- package/src/__test__/invocationError.test.ts +0 -40
- package/src/__test__/jobProgress.test.ts +0 -184
- package/src/__test__/queue.test.ts +0 -306
- package/src/__test__/queueResponse.test.ts +0 -14
- package/src/__test__/utils.ts +0 -47
- package/src/appEvents.ts +0 -107
- package/src/errors.ts +0 -46
- package/src/index.ts +0 -28
- package/src/invocationError.ts +0 -22
- package/src/invocationErrorCode.ts +0 -8
- package/src/jobProgress.ts +0 -51
- package/src/queries.ts +0 -17
- package/src/queue.ts +0 -39
- package/src/queueResponse.ts +0 -13
- package/src/retryOptions.ts +0 -14
- package/src/text.ts +0 -17
- package/src/types.ts +0 -62
- package/src/validators.ts +0 -160
- package/tsconfig.json +0 -14
- package/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"appEvents.test.d.ts","sourceRoot":"","sources":["../../src/__test__/appEvents.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const appEvents_1 = require("../appEvents");
|
|
4
|
-
const queries_1 = require("../queries");
|
|
5
|
-
const api_1 = require("@forge/api");
|
|
6
|
-
jest.mock('../queries', () => ({
|
|
7
|
-
post: jest.fn()
|
|
8
|
-
}));
|
|
9
|
-
jest.mock('@forge/api', () => ({
|
|
10
|
-
__requestAtlassianAsApp: jest.fn()
|
|
11
|
-
}));
|
|
12
|
-
describe('appEvents', () => {
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
jest.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
describe('publishEvent', () => {
|
|
17
|
-
it('should call post with the correct parameters', async () => {
|
|
18
|
-
const event = { key: 'test-event' };
|
|
19
|
-
const mockResponse = {
|
|
20
|
-
ok: true,
|
|
21
|
-
json: jest.fn().mockResolvedValue({
|
|
22
|
-
failedEvents: []
|
|
23
|
-
})
|
|
24
|
-
};
|
|
25
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
26
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
27
|
-
expect(queries_1.post).toHaveBeenCalledTimes(1);
|
|
28
|
-
expect(queries_1.post).toHaveBeenCalledWith('/forge/events/v1/app-events', {
|
|
29
|
-
events: [
|
|
30
|
-
{
|
|
31
|
-
key: event.key
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}, api_1.__requestAtlassianAsApp);
|
|
35
|
-
expect(result).toEqual({ type: 'success', failedEvents: [] });
|
|
36
|
-
});
|
|
37
|
-
it('should return a success result for successful requests', async () => {
|
|
38
|
-
const event = { key: 'test-event' };
|
|
39
|
-
const mockResponse = {
|
|
40
|
-
ok: true,
|
|
41
|
-
json: jest.fn().mockResolvedValue({
|
|
42
|
-
failedEvents: []
|
|
43
|
-
})
|
|
44
|
-
};
|
|
45
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
46
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
47
|
-
expect(result).toEqual({ type: 'success', failedEvents: [] });
|
|
48
|
-
});
|
|
49
|
-
it('should return an error result for failed requests', async () => {
|
|
50
|
-
const event = { key: 'test-event' };
|
|
51
|
-
const mockResponse = {
|
|
52
|
-
ok: false,
|
|
53
|
-
status: 500,
|
|
54
|
-
json: jest.fn().mockResolvedValue({
|
|
55
|
-
errorMessages: ['Internal server error']
|
|
56
|
-
})
|
|
57
|
-
};
|
|
58
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
59
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
60
|
-
expect(result).toEqual({
|
|
61
|
-
type: 'error',
|
|
62
|
-
errorType: 'SERVICE_ERROR',
|
|
63
|
-
errorMessage: 'Internal server error'
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
it('should handle validation errors', async () => {
|
|
67
|
-
const event = { key: 'test-event' };
|
|
68
|
-
const mockResponse = {
|
|
69
|
-
ok: false,
|
|
70
|
-
status: 400,
|
|
71
|
-
json: jest.fn().mockResolvedValue({
|
|
72
|
-
errorMessages: ['Invalid event type']
|
|
73
|
-
})
|
|
74
|
-
};
|
|
75
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
76
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
77
|
-
expect(result).toEqual({
|
|
78
|
-
type: 'error',
|
|
79
|
-
errorType: 'VALIDATION_ERROR',
|
|
80
|
-
errorMessage: 'Invalid event type'
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
it('should handle errors object in the error response', async () => {
|
|
84
|
-
const event = { key: 'test-event' };
|
|
85
|
-
const errorResponse = {
|
|
86
|
-
errorMessages: [],
|
|
87
|
-
errors: { key: 'Event key is required' }
|
|
88
|
-
};
|
|
89
|
-
const mockResponse = {
|
|
90
|
-
ok: false,
|
|
91
|
-
status: 400,
|
|
92
|
-
json: jest.fn().mockResolvedValue(errorResponse)
|
|
93
|
-
};
|
|
94
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
95
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
96
|
-
expect(result).toEqual({
|
|
97
|
-
type: 'error',
|
|
98
|
-
errorType: 'VALIDATION_ERROR',
|
|
99
|
-
errorMessage: 'key: Event key is required'
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
it('should use OTHER as errorType for unknown status codes', async () => {
|
|
103
|
-
const event = { key: 'test-event' };
|
|
104
|
-
const mockResponse = {
|
|
105
|
-
ok: false,
|
|
106
|
-
status: 418,
|
|
107
|
-
json: jest.fn().mockResolvedValue({
|
|
108
|
-
errorMessages: ['I refuse to brew coffee']
|
|
109
|
-
})
|
|
110
|
-
};
|
|
111
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
112
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
113
|
-
expect(result).toEqual({
|
|
114
|
-
type: 'error',
|
|
115
|
-
errorType: 'OTHER',
|
|
116
|
-
errorMessage: 'I refuse to brew coffee'
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
it('should handle empty error messages', async () => {
|
|
120
|
-
const event = { key: 'test-event' };
|
|
121
|
-
const mockResponse = {
|
|
122
|
-
ok: false,
|
|
123
|
-
status: 500,
|
|
124
|
-
json: jest.fn().mockResolvedValue({
|
|
125
|
-
errorMessages: []
|
|
126
|
-
})
|
|
127
|
-
};
|
|
128
|
-
queries_1.post.mockResolvedValue(mockResponse);
|
|
129
|
-
const result = await appEvents_1.appEvents.publish(event);
|
|
130
|
-
expect(result).toEqual({
|
|
131
|
-
type: 'error',
|
|
132
|
-
errorType: 'SERVICE_ERROR',
|
|
133
|
-
errorMessage: '{"errorMessages":[]}'
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invocationError.test.d.ts","sourceRoot":"","sources":["../../src/__test__/invocationError.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const invocationError_1 = require("../invocationError");
|
|
4
|
-
const invocationErrorCode_1 = require("../invocationErrorCode");
|
|
5
|
-
const retryOptions_1 = require("../retryOptions");
|
|
6
|
-
describe('InvocationError tests', () => {
|
|
7
|
-
let target = new invocationError_1.InvocationError();
|
|
8
|
-
it('Populate invocationError with default retryOptions and expect default retry option', async () => {
|
|
9
|
-
expect(target.retryOptions.retryAfter).toEqual(retryOptions_1.DEFAULT_RETRY_OPTIONS.retryAfter);
|
|
10
|
-
expect(target.retryOptions.retryReason).toEqual(invocationErrorCode_1.InvocationErrorCode.FUNCTION_RETRY_REQUEST);
|
|
11
|
-
expect(target.hasOwnProperty('_retry')).toBe(true);
|
|
12
|
-
});
|
|
13
|
-
it('Populate InvocationError with custom RetryOptions and expect the custom value to set.', () => {
|
|
14
|
-
const retryOptions = {
|
|
15
|
-
retryAfter: 10,
|
|
16
|
-
retryReason: invocationErrorCode_1.InvocationErrorCode.FUNCTION_OUT_OF_MEMORY,
|
|
17
|
-
retryData: {
|
|
18
|
-
eventsToSplit: 5
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
target = new invocationError_1.InvocationError(retryOptions);
|
|
22
|
-
expect(target.retryOptions).toEqual(retryOptions);
|
|
23
|
-
expect(target.hasOwnProperty('_retry')).toBe(true);
|
|
24
|
-
});
|
|
25
|
-
it('Use MIN_RETRY_AFTER when retryAfter <= 0', () => {
|
|
26
|
-
const retryOptions = {
|
|
27
|
-
retryAfter: 0,
|
|
28
|
-
retryReason: invocationErrorCode_1.InvocationErrorCode.FUNCTION_OUT_OF_MEMORY,
|
|
29
|
-
retryData: 'some string data'
|
|
30
|
-
};
|
|
31
|
-
target = new invocationError_1.InvocationError(retryOptions);
|
|
32
|
-
expect(target.retryOptions.retryAfter).toEqual(retryOptions_1.MIN_RETRY_AFTER);
|
|
33
|
-
expect(target.retryOptions.retryData).toEqual('some string data');
|
|
34
|
-
expect(target.hasOwnProperty('_retry')).toBe(true);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jobProgress.test.d.ts","sourceRoot":"","sources":["../../src/__test__/jobProgress.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const utils_1 = require("./utils");
|
|
4
|
-
const errors_1 = require("../errors");
|
|
5
|
-
const jobProgress_1 = require("../jobProgress");
|
|
6
|
-
const api_1 = require("@forge/api");
|
|
7
|
-
jest.mock('@forge/api', () => ({
|
|
8
|
-
__requestAtlassianAsApp: (0, utils_1.getMockFetchMethod)({ done: true }, 200)
|
|
9
|
-
}));
|
|
10
|
-
const queueParams = { key: 'test-queue-name' };
|
|
11
|
-
const getJobProgress = (jobId, apiClientMock) => new jobProgress_1.JobProgress(queueParams, jobId, apiClientMock);
|
|
12
|
-
describe('JobProgress methods', () => {
|
|
13
|
-
describe('getStats', () => {
|
|
14
|
-
it('should call the queue/stats endpoint', async () => {
|
|
15
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
16
|
-
success: 100,
|
|
17
|
-
inProgress: 50,
|
|
18
|
-
failed: 1
|
|
19
|
-
}, 200);
|
|
20
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
21
|
-
const { success, inProgress, failed } = await jobProgress.getStats();
|
|
22
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/stats/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
23
|
-
queueName: 'test-queue-name',
|
|
24
|
-
jobId: 'test-job-id'
|
|
25
|
-
});
|
|
26
|
-
expect(success).toEqual(100);
|
|
27
|
-
expect(inProgress).toEqual(50);
|
|
28
|
-
expect(failed).toEqual(1);
|
|
29
|
-
});
|
|
30
|
-
it('should throw JobDoesNotExistError', async () => {
|
|
31
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
32
|
-
message: 'Job Not Found',
|
|
33
|
-
code: 404
|
|
34
|
-
}, 404);
|
|
35
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
36
|
-
await expect(jobProgress.getStats()).rejects.toThrow(new errors_1.JobDoesNotExistError(`The job test-job-id was not found for the queue test-queue-name.`));
|
|
37
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/stats/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
38
|
-
queueName: 'test-queue-name',
|
|
39
|
-
jobId: 'test-job-id'
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
it('should throw RateLimitError', async () => {
|
|
43
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({}, 429);
|
|
44
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
45
|
-
await expect(jobProgress.getStats()).rejects.toThrow(new errors_1.RateLimitError(`Too many requests.`));
|
|
46
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/stats/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
47
|
-
queueName: 'test-queue-name',
|
|
48
|
-
jobId: 'test-job-id'
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
it('should throw InternalServerError', async () => {
|
|
52
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
53
|
-
message: 'Service is not available',
|
|
54
|
-
code: 513,
|
|
55
|
-
details: 'The request processing has failed because of an unknown error, exception or failure'
|
|
56
|
-
}, 513);
|
|
57
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
58
|
-
await expect(jobProgress.getStats()).rejects.toThrow(new errors_1.InternalServerError(`513 Status Text: Service is not available`, 513));
|
|
59
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/stats/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
60
|
-
queueName: 'test-queue-name',
|
|
61
|
-
jobId: 'test-job-id'
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('cancel', () => {
|
|
66
|
-
it('should call the queue/cancel endpoint', async () => {
|
|
67
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({}, 204);
|
|
68
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
69
|
-
await jobProgress.cancel();
|
|
70
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/cancel/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
71
|
-
queueName: 'test-queue-name',
|
|
72
|
-
jobId: 'test-job-id'
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
it('should throw JobDoesNotExistError', async () => {
|
|
76
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
77
|
-
message: 'Job Not Found',
|
|
78
|
-
code: 404
|
|
79
|
-
}, 404);
|
|
80
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
81
|
-
await expect(jobProgress.cancel()).rejects.toThrow(new errors_1.JobDoesNotExistError(`The job test-job-id was not found for the queue test-queue-name.`));
|
|
82
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/cancel/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
83
|
-
queueName: 'test-queue-name',
|
|
84
|
-
jobId: 'test-job-id'
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
it('should throw InternalServerError when WHP returns 422 response', async () => {
|
|
89
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
90
|
-
errors: ['jobId must not be null', 'queueName must not be null']
|
|
91
|
-
}, 422);
|
|
92
|
-
const jobProgress = getJobProgress('test-job-id', apiClientMock);
|
|
93
|
-
await expect(jobProgress.getStats()).rejects.toThrow(new errors_1.InternalServerError(`422 Status Text: jobId must not be null, queueName must not be null`));
|
|
94
|
-
(0, utils_1.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/stats/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
95
|
-
queueName: 'test-queue-name',
|
|
96
|
-
jobId: 'test-job-id'
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
it('should throw errors when queueName or jobId is empty', async () => {
|
|
100
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
101
|
-
success: 100,
|
|
102
|
-
inProgress: 50,
|
|
103
|
-
failed: 1
|
|
104
|
-
}, 200);
|
|
105
|
-
const jobProgress1 = getJobProgress('', apiClientMock);
|
|
106
|
-
await expect(jobProgress1.getStats()).rejects.toThrow(new errors_1.JobDoesNotExistError(`jobId cannot be empty.`));
|
|
107
|
-
const jobProgress2 = new jobProgress_1.JobProgress({ key: '!' }, 'test-job-id', apiClientMock);
|
|
108
|
-
await expect(jobProgress2.getStats()).rejects.toThrow(new errors_1.InvalidQueueNameError('Queue names can only contain alphanumeric characters, dashes and underscores.'));
|
|
109
|
-
const jobProgress3 = getJobProgress('', apiClientMock);
|
|
110
|
-
await expect(jobProgress3.getStats()).rejects.toThrow(new errors_1.JobDoesNotExistError(`jobId cannot be empty.`));
|
|
111
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
112
|
-
});
|
|
113
|
-
it('requests stargate if no api client is provided', async () => {
|
|
114
|
-
const jobProgress = getJobProgress('job-id');
|
|
115
|
-
await jobProgress.getStats();
|
|
116
|
-
expect(api_1.__requestAtlassianAsApp).toHaveBeenCalledTimes(1);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queue.test.d.ts","sourceRoot":"","sources":["../../src/__test__/queue.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const errors_1 = require("../errors");
|
|
4
|
-
const utils_1 = require("./utils");
|
|
5
|
-
const queue_1 = require("../queue");
|
|
6
|
-
const jobProgress_1 = require("../jobProgress");
|
|
7
|
-
const api_1 = require("@forge/api");
|
|
8
|
-
jest.mock('@forge/api', () => ({
|
|
9
|
-
__requestAtlassianAsApp: (0, utils_1.getMockFetchMethod)('done', 201)
|
|
10
|
-
}));
|
|
11
|
-
const getQueue = (queueName, apiClientMock) => new queue_1.Queue({ key: queueName }, apiClientMock);
|
|
12
|
-
describe('Queue methods', () => {
|
|
13
|
-
describe('constructor', () => {
|
|
14
|
-
it('should throw InvalidQueueNameError', async () => {
|
|
15
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
16
|
-
expect(() => getQueue('invalid name', apiClientMock)).toThrowError(new errors_1.InvalidQueueNameError('Queue names can only contain alphanumeric characters, dashes and underscores.'));
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
const PAYLOAD = { body: { page: 1 } };
|
|
20
|
-
describe('push', () => {
|
|
21
|
-
it.each([
|
|
22
|
-
['single payload', PAYLOAD, [PAYLOAD]],
|
|
23
|
-
['payload array', [PAYLOAD, PAYLOAD], [PAYLOAD, PAYLOAD]]
|
|
24
|
-
])('should call the queue/publish endpoint when given %s', async (_, payload, expectedPayload) => {
|
|
25
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
26
|
-
const queue = getQueue('name', apiClientMock);
|
|
27
|
-
await queue.push(payload);
|
|
28
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, expectedPayload, 'name');
|
|
29
|
-
});
|
|
30
|
-
it.each([
|
|
31
|
-
['number', 1],
|
|
32
|
-
['string', 'test'],
|
|
33
|
-
['boolean', true],
|
|
34
|
-
['array', [1, 2, 3]],
|
|
35
|
-
['null', null],
|
|
36
|
-
['undefined', undefined],
|
|
37
|
-
['array with non-object', [1]],
|
|
38
|
-
['array with an array', [[2, 3]]]
|
|
39
|
-
])('rejects non-object (%s) event', async (_, payload) => {
|
|
40
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
41
|
-
const queue = getQueue('name', apiClientMock);
|
|
42
|
-
await expect(queue.push(payload)).rejects.toThrow(new errors_1.InvalidPayloadError(`Event must be an object.`));
|
|
43
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
44
|
-
});
|
|
45
|
-
it.each([
|
|
46
|
-
['number', 1],
|
|
47
|
-
['string', 'test'],
|
|
48
|
-
['boolean', true],
|
|
49
|
-
['array', [1, 2, 3]],
|
|
50
|
-
['null', null],
|
|
51
|
-
['undefined', undefined],
|
|
52
|
-
['array with non-object', [1]],
|
|
53
|
-
['array with an array', [[2, 3]]]
|
|
54
|
-
])('rejects non-object (%s) event body', async (_, body) => {
|
|
55
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
56
|
-
const queue = getQueue('name', apiClientMock);
|
|
57
|
-
await expect(queue.push({ body })).rejects.toThrow(new errors_1.InvalidPayloadError(`Event body must be an object.`));
|
|
58
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
59
|
-
});
|
|
60
|
-
it('should throw InvalidPushSettingsError for delay', async () => {
|
|
61
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
62
|
-
const queue = getQueue('name', apiClientMock);
|
|
63
|
-
await expect(queue.push({ ...PAYLOAD, delayInSeconds: 901 })).rejects.toThrow(new errors_1.InvalidPushSettingsError(`The delayInSeconds setting must be between 0 and 900.`));
|
|
64
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
65
|
-
});
|
|
66
|
-
it('should throw NoEventsToPushError', async () => {
|
|
67
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
68
|
-
const queue = getQueue('name', apiClientMock);
|
|
69
|
-
await expect(queue.push([])).rejects.toThrow(new errors_1.NoEventsToPushError(`No events pushed.`));
|
|
70
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
71
|
-
});
|
|
72
|
-
it('should throw TooManyEventsError', async () => {
|
|
73
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
74
|
-
const queue = getQueue('name', apiClientMock);
|
|
75
|
-
await expect(queue.push(Array(51).fill(PAYLOAD))).rejects.toThrow(new errors_1.TooManyEventsError(`This push contains more than the 50 events allowed.`));
|
|
76
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
77
|
-
});
|
|
78
|
-
it('should throw PayloadTooBigError', async () => {
|
|
79
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
80
|
-
const queue = getQueue('name', apiClientMock);
|
|
81
|
-
await expect(queue.push({ body: { content: 'x'.repeat(201 * 1024) } })).rejects.toThrow(new errors_1.PayloadTooBigError(`The maximum payload size is 200KB.`));
|
|
82
|
-
expect(apiClientMock).toHaveBeenCalledTimes(0);
|
|
83
|
-
});
|
|
84
|
-
it('should throw RateLimitError', async () => {
|
|
85
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({}, 429);
|
|
86
|
-
const queue = getQueue('name', apiClientMock);
|
|
87
|
-
await expect(queue.push(PAYLOAD)).rejects.toThrow(new errors_1.RateLimitError(`Too many requests.`));
|
|
88
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, [PAYLOAD], 'name');
|
|
89
|
-
});
|
|
90
|
-
it('should throw InvocationLimitReachedError', async () => {
|
|
91
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({}, 405);
|
|
92
|
-
const queue = getQueue('name', apiClientMock);
|
|
93
|
-
await expect(queue.push(PAYLOAD)).rejects.toThrow(new errors_1.InvocationLimitReachedError(`The limit on cyclic invocation has been reached.`));
|
|
94
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, [PAYLOAD], 'name');
|
|
95
|
-
});
|
|
96
|
-
it('should throw PartialSuccessError when there are failed events', async () => {
|
|
97
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
98
|
-
failedEvents: [
|
|
99
|
-
{
|
|
100
|
-
index: '0',
|
|
101
|
-
errorMessage: 'failed-1'
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
index: 2,
|
|
105
|
-
errorMessage: 'failed-3'
|
|
106
|
-
}
|
|
107
|
-
]
|
|
108
|
-
}, 202);
|
|
109
|
-
const queue = getQueue('name', apiClientMock);
|
|
110
|
-
const payload = [
|
|
111
|
-
{
|
|
112
|
-
body: {
|
|
113
|
-
content: 'payload-1'
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
body: {
|
|
118
|
-
content: 'payload-2'
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
body: {
|
|
123
|
-
content: 'payload-3'
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
];
|
|
127
|
-
await expect(queue.push(payload)).rejects.toThrow(new errors_1.PartialSuccessError(`Failed to process 2 event(s).`, { jobId: 'some-job-id' }, [
|
|
128
|
-
{
|
|
129
|
-
errorMessage: 'failed-1',
|
|
130
|
-
event: {
|
|
131
|
-
body: {
|
|
132
|
-
content: 'payload-1'
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
errorMessage: 'failed-3',
|
|
138
|
-
event: {
|
|
139
|
-
body: {
|
|
140
|
-
content: 'payload-3'
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
]));
|
|
145
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, payload, 'name');
|
|
146
|
-
});
|
|
147
|
-
it('should throw PartialSuccessError when backend failed to create job stats', async () => {
|
|
148
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
149
|
-
errorMessage: 'Failed to create stats for job name#12345'
|
|
150
|
-
}, 202);
|
|
151
|
-
const queue = getQueue('name', apiClientMock);
|
|
152
|
-
const payload = [
|
|
153
|
-
{
|
|
154
|
-
body: {
|
|
155
|
-
content: 'payload-1'
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
body: {
|
|
160
|
-
content: 'payload-2'
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
body: {
|
|
165
|
-
content: 'payload-3'
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
];
|
|
169
|
-
await expect(queue.push(payload)).rejects.toThrow(new errors_1.PartialSuccessError(`Failed to create stats for job name#12345`, { jobId: 'some-job-id' }, []));
|
|
170
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, payload, 'name');
|
|
171
|
-
});
|
|
172
|
-
it('should throw PartialSuccessError when there are failed events and backend failed to create job stats', async () => {
|
|
173
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
174
|
-
errorMessage: 'Failed to create stats for job name#12345',
|
|
175
|
-
failedEvents: [
|
|
176
|
-
{
|
|
177
|
-
index: '0',
|
|
178
|
-
errorMessage: 'failed-1'
|
|
179
|
-
}
|
|
180
|
-
]
|
|
181
|
-
}, 202);
|
|
182
|
-
const queue = getQueue('name', apiClientMock);
|
|
183
|
-
const payload = [
|
|
184
|
-
{
|
|
185
|
-
body: {
|
|
186
|
-
content: 'payload-1'
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
body: {
|
|
191
|
-
content: 'payload-2'
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
];
|
|
195
|
-
await expect(queue.push(payload)).rejects.toThrow(new errors_1.PartialSuccessError(`Failed to process 1 event(s). Failed to create stats for job name#12345`, { jobId: 'some-job-id' }, [
|
|
196
|
-
{
|
|
197
|
-
errorMessage: 'failed-1',
|
|
198
|
-
event: {
|
|
199
|
-
body: {
|
|
200
|
-
content: 'payload-1'
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
]));
|
|
205
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, payload, 'name');
|
|
206
|
-
});
|
|
207
|
-
it('should throw InternalServerError', async () => {
|
|
208
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)({
|
|
209
|
-
message: 'AWS SQS timed out',
|
|
210
|
-
code: 500,
|
|
211
|
-
details: 'The request processing has failed because of an unknown error, exception or failure'
|
|
212
|
-
}, 500);
|
|
213
|
-
const queue = getQueue('name', apiClientMock);
|
|
214
|
-
await expect(queue.push(PAYLOAD)).rejects.toThrow(new errors_1.InternalServerError(`500 Status Text: AWS SQS timed out`, 500, 'The request processing has failed because of an unknown error, exception or failure'));
|
|
215
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, [PAYLOAD], 'name');
|
|
216
|
-
});
|
|
217
|
-
it('should throw InternalServerError for error response without response body', async () => {
|
|
218
|
-
const apiClientMock = (0, utils_1.getApiClientMockWithoutResponseBody)(504, 'Gateway Timeout');
|
|
219
|
-
const queue = getQueue('name', apiClientMock);
|
|
220
|
-
await expect(queue.push(PAYLOAD)).rejects.toThrow(new errors_1.InternalServerError(`504 Gateway Timeout`, 504));
|
|
221
|
-
(0, utils_1.verifyApiClientCalledPushPathWith)(apiClientMock, [PAYLOAD], 'name');
|
|
222
|
-
});
|
|
223
|
-
it('requests stargate if no api client is provided', async () => {
|
|
224
|
-
const queue = getQueue('queue');
|
|
225
|
-
await queue.push({ body: { test: 'stargate' } });
|
|
226
|
-
expect(api_1.__requestAtlassianAsApp).toHaveBeenCalledTimes(1);
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
describe('getJob', () => {
|
|
230
|
-
it('should create a JobProgress by jobId', async () => {
|
|
231
|
-
const apiClientMock = (0, utils_1.getMockFetchMethod)();
|
|
232
|
-
const queue = getQueue('name', apiClientMock);
|
|
233
|
-
const jobProgress = queue.getJob('test-job-id');
|
|
234
|
-
expect(jobProgress).toEqual(new jobProgress_1.JobProgress({ key: 'name' }, 'test-job-id', apiClientMock));
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queueResponse.test.d.ts","sourceRoot":"","sources":["../../src/__test__/queueResponse.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const queueResponse_1 = require("../queueResponse");
|
|
4
|
-
describe('QueueResponse', () => {
|
|
5
|
-
it('should contain property retry=false by default', async () => {
|
|
6
|
-
const res = new queueResponse_1.QueueResponse();
|
|
7
|
-
expect(JSON.stringify(res)).toEqual('{"_retry":false}');
|
|
8
|
-
});
|
|
9
|
-
it('doRetry() should change property retry=true', async () => {
|
|
10
|
-
const res = new queueResponse_1.QueueResponse();
|
|
11
|
-
res.retry();
|
|
12
|
-
expect(JSON.stringify(res)).toEqual('{"_retry":true}');
|
|
13
|
-
});
|
|
14
|
-
});
|
package/out/__test__/utils.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/// <reference types="jest" />
|
|
2
|
-
/// <reference types="jest-matcher-specific-error" />
|
|
3
|
-
import { Payload } from '../types';
|
|
4
|
-
export declare const getMockFetchMethod: (response?: any, statusCode?: number) => jest.Mock<any, any, any>;
|
|
5
|
-
export declare const getApiClientMockWithoutResponseBody: (statusCode: number, statusText: string) => jest.Mock<any, any, any>;
|
|
6
|
-
export declare const verifyApiClientCalledWith: (apiClientMock: jest.Mock, path: string, expectedBody: any) => void;
|
|
7
|
-
export declare const verifyApiClientCalledPushPathWith: (apiClientMock: jest.Mock, payloads: Payload | Payload[], name: string) => void;
|
|
8
|
-
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/__test__/utils.ts"],"names":[],"mappings":";;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,eAAO,MAAM,kBAAkB,cAAe,GAAG,kDAOhD,CAAC;AAEF,eAAO,MAAM,mCAAmC,eAAgB,MAAM,cAAc,MAAM,6BAMzF,CAAC;AAEF,eAAO,MAAM,yBAAyB,kBAAmB,KAAK,IAAI,QAAQ,MAAM,gBAAgB,GAAG,SAclG,CAAC;AAEF,eAAO,MAAM,iCAAiC,kBAC7B,KAAK,IAAI,YACd,OAAO,GAAG,OAAO,EAAE,QACvB,MAAM,SAQb,CAAC"}
|
package/out/__test__/utils.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.verifyApiClientCalledPushPathWith = exports.verifyApiClientCalledWith = exports.getApiClientMockWithoutResponseBody = exports.getMockFetchMethod = void 0;
|
|
4
|
-
const getMockFetchMethod = (response, statusCode = 201) => {
|
|
5
|
-
return jest.fn().mockReturnValue({
|
|
6
|
-
created: statusCode === 201,
|
|
7
|
-
status: statusCode,
|
|
8
|
-
statusText: 'Status Text',
|
|
9
|
-
json: jest.fn().mockResolvedValue(response)
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
|
-
exports.getMockFetchMethod = getMockFetchMethod;
|
|
13
|
-
const getApiClientMockWithoutResponseBody = (statusCode, statusText) => {
|
|
14
|
-
return jest.fn().mockReturnValue({
|
|
15
|
-
ok: statusCode === 200,
|
|
16
|
-
status: statusCode,
|
|
17
|
-
statusText: statusText
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
exports.getApiClientMockWithoutResponseBody = getApiClientMockWithoutResponseBody;
|
|
21
|
-
const verifyApiClientCalledWith = (apiClientMock, path, expectedBody) => {
|
|
22
|
-
expect(apiClientMock).toHaveBeenCalledWith(path, expect.objectContaining({
|
|
23
|
-
method: 'POST',
|
|
24
|
-
body: expect.any(String),
|
|
25
|
-
headers: {
|
|
26
|
-
'content-type': 'application/json'
|
|
27
|
-
}
|
|
28
|
-
}));
|
|
29
|
-
const [, { body }] = apiClientMock.mock.calls[0];
|
|
30
|
-
expect(JSON.parse(body)).toEqual(expect.objectContaining(expectedBody));
|
|
31
|
-
};
|
|
32
|
-
exports.verifyApiClientCalledWith = verifyApiClientCalledWith;
|
|
33
|
-
const verifyApiClientCalledPushPathWith = (apiClientMock, payloads, name) => {
|
|
34
|
-
(0, exports.verifyApiClientCalledWith)(apiClientMock, '/webhook/queue/publish/{contextAri}/{environmentId}/{appId}/{appVersion}', {
|
|
35
|
-
queueName: name,
|
|
36
|
-
schema: 'ari:cloud:ecosystem::forge/app-event-2',
|
|
37
|
-
type: 'avi:forge:app:event',
|
|
38
|
-
payload: payloads
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
exports.verifyApiClientCalledPushPathWith = verifyApiClientCalledPushPathWith;
|