@dbos-inc/koa-serve 3.5.44-preview.gc094fdab44 → 3.6.5-preview
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/dist/src/dboshttp.d.ts +54 -0
- package/dist/src/dboshttp.d.ts.map +1 -1
- package/dist/src/dboshttp.js +418 -4
- package/dist/src/dboshttp.js.map +1 -1
- package/dist/src/dboskoa.js +1 -1
- package/dist/src/dboskoa.js.map +1 -1
- package/dist/src/index.d.ts +9 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +18 -3
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/dboshttp.ts +523 -4
- package/src/dboskoa.ts +1 -1
- package/src/index.ts +17 -0
- package/tests/argsource.test.ts +150 -0
- package/tests/auth.test.ts +26 -4
- package/tests/endpoints.test.ts +58 -34
- package/tests/steps.test.ts +5 -0
- package/tests/transactions.test.ts +5 -0
- package/tests/validation.test.ts +531 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import Koa from 'koa';
|
|
2
|
+
import Router from '@koa/router';
|
|
3
|
+
|
|
4
|
+
import { DBOS } from '@dbos-inc/dbos-sdk';
|
|
5
|
+
|
|
6
|
+
import { ArgSources, DBOSKoa } from '../src';
|
|
7
|
+
|
|
8
|
+
import request from 'supertest';
|
|
9
|
+
import bodyParser from '@koa/bodyparser';
|
|
10
|
+
|
|
11
|
+
const dhttp = new DBOSKoa();
|
|
12
|
+
|
|
13
|
+
describe('httpserver-argsource-tests', () => {
|
|
14
|
+
let app: Koa;
|
|
15
|
+
let appRouter: Router;
|
|
16
|
+
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
DBOS.setConfig({
|
|
19
|
+
name: 'dbos-koa-test',
|
|
20
|
+
});
|
|
21
|
+
return Promise.resolve();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
const _classes = [ArgTestEndpoints];
|
|
26
|
+
await DBOS.launch();
|
|
27
|
+
app = new Koa();
|
|
28
|
+
appRouter = new Router();
|
|
29
|
+
dhttp.registerWithApp(app, appRouter);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(async () => {
|
|
33
|
+
await DBOS.shutdown();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('get-query', async () => {
|
|
37
|
+
const response1 = await request(app.callback()).get('/getquery?name=alice');
|
|
38
|
+
expect(response1.statusCode).toBe(200);
|
|
39
|
+
expect(response1.text).toBe('hello alice');
|
|
40
|
+
const response2 = await request(app.callback()).get('/getquery').send({ name: 'alice' });
|
|
41
|
+
expect(response2.statusCode).toBe(400);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('get-body', async () => {
|
|
45
|
+
const response1 = await request(app.callback()).get('/getbody?name=alice');
|
|
46
|
+
expect(response1.statusCode).toBe(400);
|
|
47
|
+
const response2 = await request(app.callback()).get('/getbody').send({ name: 'alice' });
|
|
48
|
+
expect(response2.statusCode).toBe(200);
|
|
49
|
+
expect(response2.text).toBe('hello alice');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('get-default', async () => {
|
|
53
|
+
const response1 = await request(app.callback()).get('/getdefault?name=alice');
|
|
54
|
+
expect(response1.statusCode).toBe(200);
|
|
55
|
+
expect(response1.text).toBe('hello alice');
|
|
56
|
+
const response2 = await request(app.callback()).get('/getdefault').send({ name: 'alice' });
|
|
57
|
+
expect(response2.statusCode).toBe(400);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('get-auto', async () => {
|
|
61
|
+
const response1 = await request(app.callback()).get('/getauto?name=alice');
|
|
62
|
+
expect(response1.statusCode).toBe(200);
|
|
63
|
+
expect(response1.text).toBe('hello alice');
|
|
64
|
+
const response2 = await request(app.callback()).get('/getauto').send({ name: 'alice' });
|
|
65
|
+
expect(response2.statusCode).toBe(200);
|
|
66
|
+
expect(response2.text).toBe('hello alice');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('post-query', async () => {
|
|
70
|
+
const response1 = await request(app.callback()).post('/postquery?name=alice');
|
|
71
|
+
expect(response1.statusCode).toBe(200);
|
|
72
|
+
expect(response1.text).toBe('hello alice');
|
|
73
|
+
const response2 = await request(app.callback()).post('/postquery').send({ name: 'alice' });
|
|
74
|
+
expect(response2.statusCode).toBe(400);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('post-body', async () => {
|
|
78
|
+
const response1 = await request(app.callback()).post('/postbody?name=alice');
|
|
79
|
+
expect(response1.statusCode).toBe(400);
|
|
80
|
+
const response2 = await request(app.callback()).post('/postbody').send({ name: 'alice' });
|
|
81
|
+
expect(response2.statusCode).toBe(200);
|
|
82
|
+
expect(response2.text).toBe('hello alice');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('post-default', async () => {
|
|
86
|
+
const response1 = await request(app.callback()).post('/postdefault?name=alice');
|
|
87
|
+
expect(response1.statusCode).toBe(400);
|
|
88
|
+
const response2 = await request(app.callback()).post('/postdefault').send({ name: 'alice' });
|
|
89
|
+
expect(response2.statusCode).toBe(200);
|
|
90
|
+
expect(response2.text).toBe('hello alice');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('post-auto', async () => {
|
|
94
|
+
const response1 = await request(app.callback()).post('/postauto?name=alice');
|
|
95
|
+
expect(response1.statusCode).toBe(200);
|
|
96
|
+
expect(response1.text).toBe('hello alice');
|
|
97
|
+
const response2 = await request(app.callback()).post('/postauto').send({ name: 'alice' });
|
|
98
|
+
expect(response2.statusCode).toBe(200);
|
|
99
|
+
expect(response2.text).toBe('hello alice');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
@dhttp.koaBodyParser(
|
|
103
|
+
bodyParser({
|
|
104
|
+
enableTypes: ['json'],
|
|
105
|
+
parsedMethods: ['GET', 'POST'],
|
|
106
|
+
}),
|
|
107
|
+
)
|
|
108
|
+
@DBOSKoa.defaultArgRequired
|
|
109
|
+
class ArgTestEndpoints {
|
|
110
|
+
@dhttp.getApi('/getquery')
|
|
111
|
+
static async getQuery(@DBOSKoa.argSource(ArgSources.QUERY) name: string) {
|
|
112
|
+
return Promise.resolve(`hello ${name}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@dhttp.getApi('/getbody')
|
|
116
|
+
static async getBody(@DBOSKoa.argSource(ArgSources.BODY) name: string) {
|
|
117
|
+
return Promise.resolve(`hello ${name}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@dhttp.getApi('/getdefault')
|
|
121
|
+
static async getDefault(@DBOSKoa.argSource(ArgSources.DEFAULT) name: string) {
|
|
122
|
+
return Promise.resolve(`hello ${name}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@dhttp.getApi('/getauto')
|
|
126
|
+
static async getAuto(@DBOSKoa.argSource(ArgSources.AUTO) name: string) {
|
|
127
|
+
return Promise.resolve(`hello ${name}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@dhttp.postApi('/postquery')
|
|
131
|
+
static async postQuery(@DBOSKoa.argSource(ArgSources.QUERY) name: string) {
|
|
132
|
+
return Promise.resolve(`hello ${name}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@dhttp.postApi('/postbody')
|
|
136
|
+
static async postBody(@DBOSKoa.argSource(ArgSources.BODY) name: string) {
|
|
137
|
+
return Promise.resolve(`hello ${name}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@dhttp.postApi('/postdefault')
|
|
141
|
+
static async postDefault(@DBOSKoa.argSource(ArgSources.DEFAULT) name: string) {
|
|
142
|
+
return Promise.resolve(`hello ${name}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@dhttp.postApi('/postauto')
|
|
146
|
+
static async postAuto(@DBOSKoa.argSource(ArgSources.AUTO) name: string) {
|
|
147
|
+
return Promise.resolve(`hello ${name}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
package/tests/auth.test.ts
CHANGED
|
@@ -61,17 +61,17 @@ describe('httpserver-defsec-tests', () => {
|
|
|
61
61
|
|
|
62
62
|
test('not-authenticated', async () => {
|
|
63
63
|
const response = await request(app.callback()).get('/requireduser?name=alice');
|
|
64
|
-
expect(response.statusCode).toBe(
|
|
64
|
+
expect(response.statusCode).toBe(401);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
test('not-you', async () => {
|
|
68
68
|
const response = await request(app.callback()).get('/requireduser?name=alice&userid=go_away');
|
|
69
|
-
expect(response.statusCode).toBe(
|
|
69
|
+
expect(response.statusCode).toBe(401);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
test('not-authorized', async () => {
|
|
73
73
|
const response = await request(app.callback()).get('/requireduser?name=alice&userid=bob');
|
|
74
|
-
expect(response.statusCode).toBe(
|
|
74
|
+
expect(response.statusCode).toBe(403);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
test('authorized', async () => {
|
|
@@ -83,6 +83,22 @@ describe('httpserver-defsec-tests', () => {
|
|
|
83
83
|
test('cascade-authorized', async () => {
|
|
84
84
|
const response = await request(app.callback()).get('/workflow?name=alice&userid=a_real_user');
|
|
85
85
|
expect(response.statusCode).toBe(200);
|
|
86
|
+
|
|
87
|
+
const txnResponse = await request(app.callback()).get('/transaction?name=alice&userid=a_real_user');
|
|
88
|
+
expect(txnResponse.statusCode).toBe(200);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// We can directly test a transaction with passed in authorizedRoles.
|
|
92
|
+
test('direct-transaction-test', async () => {
|
|
93
|
+
await DBOS.withAuthedContext('user', ['user'], async () => {
|
|
94
|
+
const res = await TestEndpointDefSec.testStep('alice');
|
|
95
|
+
expect(res).toBe('hello 1');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Unauthorized.
|
|
99
|
+
await expect(TestEndpointDefSec.testStep('alice')).rejects.toThrow(
|
|
100
|
+
new DBOSError.DBOSNotAuthorizedError('User does not have a role with permission to call testStep', 403),
|
|
101
|
+
);
|
|
86
102
|
});
|
|
87
103
|
|
|
88
104
|
async function authTestMiddleware(ctx: DBOSKoaAuthContext) {
|
|
@@ -147,7 +163,8 @@ describe('httpserver-defsec-tests', () => {
|
|
|
147
163
|
|
|
148
164
|
@DBOS.step()
|
|
149
165
|
static async testStep(name: string) {
|
|
150
|
-
|
|
166
|
+
void name;
|
|
167
|
+
return Promise.resolve(`hello 1`);
|
|
151
168
|
}
|
|
152
169
|
|
|
153
170
|
@DBOS.workflow()
|
|
@@ -160,6 +177,11 @@ describe('httpserver-defsec-tests', () => {
|
|
|
160
177
|
static async testWfEndpoint(name: string) {
|
|
161
178
|
return await TestEndpointDefSec.testWorkflow(name);
|
|
162
179
|
}
|
|
180
|
+
|
|
181
|
+
@dhttp.getApi('/transaction')
|
|
182
|
+
static async testTxnEndpoint(name: string) {
|
|
183
|
+
return await TestEndpointDefSec.testStep(name);
|
|
184
|
+
}
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
class SecondClass {
|
package/tests/endpoints.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import Router from '@koa/router';
|
|
|
4
4
|
|
|
5
5
|
import { DBOS, Error as DBOSErrors, StatusString } from '@dbos-inc/dbos-sdk';
|
|
6
6
|
|
|
7
|
-
import { DBOSKoa, DBOSKoaAuthContext, RequestIDHeader, WorkflowIDHeader } from '../src';
|
|
7
|
+
import { DBOSKoa, DBOSKoaAuthContext, RequestIDHeader, WorkflowIDHeader, DBOSResponseError } from '../src';
|
|
8
8
|
|
|
9
9
|
import request from 'supertest';
|
|
10
10
|
|
|
@@ -97,12 +97,17 @@ describe('httpserver-tests', () => {
|
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
test('post-test-custom-body', async () => {
|
|
100
|
-
|
|
100
|
+
let response = await request(app.callback())
|
|
101
101
|
.post('/testpost')
|
|
102
102
|
.set('Content-Type', 'application/custom-content-type')
|
|
103
103
|
.send(JSON.stringify({ name: 'alice' }));
|
|
104
104
|
expect(response.statusCode).toBe(200);
|
|
105
105
|
expect(response.text).toBe('hello alice');
|
|
106
|
+
response = await request(app.callback())
|
|
107
|
+
.post('/testpost')
|
|
108
|
+
.set('Content-Type', 'application/rejected-custom-content-type')
|
|
109
|
+
.send(JSON.stringify({ name: 'alice' }));
|
|
110
|
+
expect(response.statusCode).toBe(400);
|
|
106
111
|
});
|
|
107
112
|
|
|
108
113
|
test('put-test', async () => {
|
|
@@ -112,12 +117,17 @@ describe('httpserver-tests', () => {
|
|
|
112
117
|
});
|
|
113
118
|
|
|
114
119
|
test('put-test-custom-body', async () => {
|
|
115
|
-
|
|
120
|
+
let response = await request(app.callback())
|
|
116
121
|
.put('/testput')
|
|
117
122
|
.set('Content-Type', 'application/custom-content-type')
|
|
118
123
|
.send(JSON.stringify({ name: 'alice' }));
|
|
119
124
|
expect(response.statusCode).toBe(200);
|
|
120
125
|
expect(response.text).toBe('hello alice');
|
|
126
|
+
response = await request(app.callback())
|
|
127
|
+
.put('/testput')
|
|
128
|
+
.set('Content-Type', 'application/rejected-custom-content-type')
|
|
129
|
+
.send(JSON.stringify({ name: 'alice' }));
|
|
130
|
+
expect(response.statusCode).toBe(400);
|
|
121
131
|
});
|
|
122
132
|
|
|
123
133
|
test('patch-test', async () => {
|
|
@@ -127,12 +137,17 @@ describe('httpserver-tests', () => {
|
|
|
127
137
|
});
|
|
128
138
|
|
|
129
139
|
test('patch-test-custom-body', async () => {
|
|
130
|
-
|
|
140
|
+
let response = await request(app.callback())
|
|
131
141
|
.patch('/testpatch')
|
|
132
142
|
.set('Content-Type', 'application/custom-content-type')
|
|
133
143
|
.send(JSON.stringify({ name: 'alice' }));
|
|
134
144
|
expect(response.statusCode).toBe(200);
|
|
135
145
|
expect(response.text).toBe('hello alice');
|
|
146
|
+
response = await request(app.callback())
|
|
147
|
+
.patch('/testpatch')
|
|
148
|
+
.set('Content-Type', 'application/rejected-custom-content-type')
|
|
149
|
+
.send(JSON.stringify({ name: 'alice' }));
|
|
150
|
+
expect(response.statusCode).toBe(400);
|
|
136
151
|
});
|
|
137
152
|
|
|
138
153
|
test('endpoint-step', async () => {
|
|
@@ -144,7 +159,7 @@ describe('httpserver-tests', () => {
|
|
|
144
159
|
test('endpoint-workflow', async () => {
|
|
145
160
|
const response = await request(app.callback()).post('/workflow?name=alice');
|
|
146
161
|
expect(response.statusCode).toBe(200);
|
|
147
|
-
expect(response.text).toBe('alice');
|
|
162
|
+
expect(response.text).toBe('hello alice');
|
|
148
163
|
});
|
|
149
164
|
|
|
150
165
|
test('endpoint-error', async () => {
|
|
@@ -155,19 +170,19 @@ describe('httpserver-tests', () => {
|
|
|
155
170
|
test('endpoint-handler', async () => {
|
|
156
171
|
const response = await request(app.callback()).get('/handler/alice');
|
|
157
172
|
expect(response.statusCode).toBe(200);
|
|
158
|
-
expect(response.text).toBe('alice');
|
|
173
|
+
expect(response.text).toBe('hello alice');
|
|
159
174
|
});
|
|
160
175
|
|
|
161
176
|
test('endpoint-testStartWorkflow', async () => {
|
|
162
177
|
const response = await request(app.callback()).get('/testStartWorkflow/alice');
|
|
163
178
|
expect(response.statusCode).toBe(200);
|
|
164
|
-
expect(response.text).toBe('alice');
|
|
179
|
+
expect(response.text).toBe('hello alice');
|
|
165
180
|
});
|
|
166
181
|
|
|
167
182
|
test('endpoint-testInvokeWorkflow', async () => {
|
|
168
183
|
const response = await request(app.callback()).get('/testInvokeWorkflow/alice');
|
|
169
184
|
expect(response.statusCode).toBe(200);
|
|
170
|
-
expect(response.text).toBe('alice');
|
|
185
|
+
expect(response.text).toBe('hello alice');
|
|
171
186
|
});
|
|
172
187
|
|
|
173
188
|
// This feels unclean, but supertest doesn't expose the error message the people we want. See:
|
|
@@ -178,11 +193,17 @@ describe('httpserver-tests', () => {
|
|
|
178
193
|
|
|
179
194
|
test('response-error', async () => {
|
|
180
195
|
const response = await request(app.callback()).get('/dbos-error');
|
|
181
|
-
expect(response.statusCode).toBe(
|
|
196
|
+
expect(response.statusCode).toBe(503);
|
|
182
197
|
expect((response as unknown as Res).res.statusMessage).toBe('customize error');
|
|
183
198
|
expect(response.body.message).toBe('customize error');
|
|
184
199
|
});
|
|
185
200
|
|
|
201
|
+
test('datavalidation-error', async () => {
|
|
202
|
+
const response = await request(app.callback()).get('/query');
|
|
203
|
+
expect(response.statusCode).toBe(400);
|
|
204
|
+
expect(response.body.details.dbosErrorCode).toBe(9);
|
|
205
|
+
});
|
|
206
|
+
|
|
186
207
|
test('dbos-redirect', async () => {
|
|
187
208
|
const response = await request(app.callback()).get('/redirect');
|
|
188
209
|
expect(response.statusCode).toBe(302);
|
|
@@ -210,17 +231,17 @@ describe('httpserver-tests', () => {
|
|
|
210
231
|
|
|
211
232
|
test('not-authenticated', async () => {
|
|
212
233
|
const response = await request(app.callback()).get('/requireduser?name=alice');
|
|
213
|
-
expect(response.statusCode).toBe(
|
|
234
|
+
expect(response.statusCode).toBe(401);
|
|
214
235
|
});
|
|
215
236
|
|
|
216
237
|
test('not-you', async () => {
|
|
217
238
|
const response = await request(app.callback()).get('/requireduser?name=alice&userid=go_away');
|
|
218
|
-
expect(response.statusCode).toBe(
|
|
239
|
+
expect(response.statusCode).toBe(401);
|
|
219
240
|
});
|
|
220
241
|
|
|
221
242
|
test('not-authorized', async () => {
|
|
222
243
|
const response = await request(app.callback()).get('/requireduser?name=alice&userid=bob');
|
|
223
|
-
expect(response.statusCode).toBe(
|
|
244
|
+
expect(response.statusCode).toBe(403);
|
|
224
245
|
});
|
|
225
246
|
|
|
226
247
|
test('authorized', async () => {
|
|
@@ -230,17 +251,17 @@ describe('httpserver-tests', () => {
|
|
|
230
251
|
|
|
231
252
|
test('not-authenticated2', async () => {
|
|
232
253
|
const response = await request(app.callback()).get('/requireduser2?name=alice');
|
|
233
|
-
expect(response.statusCode).toBe(
|
|
254
|
+
expect(response.statusCode).toBe(401);
|
|
234
255
|
});
|
|
235
256
|
|
|
236
257
|
test('not-you2', async () => {
|
|
237
258
|
const response = await request(app.callback()).get('/requireduser2?name=alice&userid=go_away');
|
|
238
|
-
expect(response.statusCode).toBe(
|
|
259
|
+
expect(response.statusCode).toBe(401);
|
|
239
260
|
});
|
|
240
261
|
|
|
241
262
|
test('not-authorized2', async () => {
|
|
242
263
|
const response = await request(app.callback()).get('/requireduser2?name=alice&userid=bob');
|
|
243
|
-
expect(response.statusCode).toBe(
|
|
264
|
+
expect(response.statusCode).toBe(403);
|
|
244
265
|
});
|
|
245
266
|
|
|
246
267
|
test('authorized2', async () => {
|
|
@@ -254,12 +275,12 @@ describe('httpserver-tests', () => {
|
|
|
254
275
|
.post('/workflow?name=bob')
|
|
255
276
|
.set({ 'dbos-idempotency-key': workflowID });
|
|
256
277
|
expect(response.statusCode).toBe(200);
|
|
257
|
-
expect(response.text).toBe('bob');
|
|
278
|
+
expect(response.text).toBe('hello bob');
|
|
258
279
|
|
|
259
280
|
// Retrieve the workflow with WFID.
|
|
260
281
|
const retrievedHandle = DBOS.retrieveWorkflow(workflowID);
|
|
261
282
|
expect(retrievedHandle).not.toBeNull();
|
|
262
|
-
await expect(retrievedHandle.getResult()).resolves.toBe('bob');
|
|
283
|
+
await expect(retrievedHandle.getResult()).resolves.toBe('hello bob');
|
|
263
284
|
await expect(retrievedHandle.getStatus()).resolves.toMatchObject({
|
|
264
285
|
status: StatusString.SUCCESS,
|
|
265
286
|
});
|
|
@@ -269,12 +290,12 @@ describe('httpserver-tests', () => {
|
|
|
269
290
|
const workflowID = randomUUID();
|
|
270
291
|
const response = await request(app.callback()).get('/handler/bob').set({ 'dbos-idempotency-key': workflowID });
|
|
271
292
|
expect(response.statusCode).toBe(200);
|
|
272
|
-
expect(response.text).toBe('bob');
|
|
293
|
+
expect(response.text).toBe('hello bob');
|
|
273
294
|
|
|
274
295
|
// Retrieve the workflow with WFID.
|
|
275
296
|
const retrievedHandle = DBOS.retrieveWorkflow(workflowID);
|
|
276
297
|
expect(retrievedHandle).not.toBeNull();
|
|
277
|
-
await expect(retrievedHandle.getResult()).resolves.toBe('bob');
|
|
298
|
+
await expect(retrievedHandle.getResult()).resolves.toBe('hello bob');
|
|
278
299
|
await expect(retrievedHandle.getStatus()).resolves.toMatchObject({
|
|
279
300
|
status: StatusString.SUCCESS,
|
|
280
301
|
});
|
|
@@ -311,6 +332,7 @@ describe('httpserver-tests', () => {
|
|
|
311
332
|
parsedMethods: ['POST', 'PUT', 'PATCH', 'GET', 'DELETE'],
|
|
312
333
|
}),
|
|
313
334
|
)
|
|
335
|
+
@DBOSKoa.defaultArgRequired
|
|
314
336
|
class TestEndpoints {
|
|
315
337
|
@dhttp.getApi('/hello')
|
|
316
338
|
static async hello() {
|
|
@@ -339,12 +361,6 @@ describe('httpserver-tests', () => {
|
|
|
339
361
|
return Promise.resolve(url);
|
|
340
362
|
}
|
|
341
363
|
|
|
342
|
-
@dhttp.getApi('/dbos-error')
|
|
343
|
-
@DBOS.workflow()
|
|
344
|
-
static async dbosErr() {
|
|
345
|
-
return Promise.reject(new Error('customize error'));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
364
|
@dhttp.getApi('/query')
|
|
349
365
|
static async helloQuery(name: string) {
|
|
350
366
|
DBOS.logger.info(`query with name ${name}`); // Test logging.
|
|
@@ -390,6 +406,12 @@ describe('httpserver-tests', () => {
|
|
|
390
406
|
return Promise.resolve(`hello ${name}`);
|
|
391
407
|
}
|
|
392
408
|
|
|
409
|
+
@dhttp.getApi('/dbos-error')
|
|
410
|
+
@DBOS.step()
|
|
411
|
+
static async dbosErr() {
|
|
412
|
+
return Promise.reject(new DBOSResponseError('customize error', 503));
|
|
413
|
+
}
|
|
414
|
+
|
|
393
415
|
@dhttp.getApi('/handler/:name')
|
|
394
416
|
static async testHandler(name: string) {
|
|
395
417
|
const workflowID: string = DBOSKoa.koaContext.get(WorkflowIDHeader);
|
|
@@ -420,27 +442,29 @@ describe('httpserver-tests', () => {
|
|
|
420
442
|
@dhttp.postApi('/workflow')
|
|
421
443
|
@DBOS.workflow()
|
|
422
444
|
static async testWorkflow(name: string) {
|
|
423
|
-
return TestEndpoints.testStep(name);
|
|
445
|
+
return TestEndpoints.testStep(`hello ${name}`);
|
|
424
446
|
}
|
|
425
447
|
|
|
426
448
|
@dhttp.postApi('/error')
|
|
427
449
|
@DBOS.workflow()
|
|
428
450
|
static async testWorkflowError(name: string) {
|
|
429
|
-
|
|
430
|
-
|
|
451
|
+
void name;
|
|
452
|
+
// This workflow should encounter duplicate primary key error.
|
|
453
|
+
throw new Error('fail');
|
|
454
|
+
return Promise.resolve('');
|
|
431
455
|
}
|
|
432
456
|
|
|
433
457
|
@dhttp.getApi('/requireduser')
|
|
434
458
|
@DBOS.requiredRole(['user'])
|
|
435
459
|
static async testAuth(name: string) {
|
|
436
460
|
if (DBOS.authenticatedUser !== 'a_real_user') {
|
|
437
|
-
throw new
|
|
461
|
+
throw new DBOSResponseError('uid not a real user!', 400);
|
|
438
462
|
}
|
|
439
463
|
if (!DBOS.authenticatedRoles.includes('user')) {
|
|
440
|
-
throw new
|
|
464
|
+
throw new DBOSResponseError("roles don't include user!", 400);
|
|
441
465
|
}
|
|
442
466
|
if (DBOS.assumedRole !== 'user') {
|
|
443
|
-
throw new
|
|
467
|
+
throw new DBOSResponseError('Should never happen! Not assumed to be user', 400);
|
|
444
468
|
}
|
|
445
469
|
return Promise.resolve(`Please say hello to ${name}`);
|
|
446
470
|
}
|
|
@@ -449,13 +473,13 @@ describe('httpserver-tests', () => {
|
|
|
449
473
|
@DBOS.requiredRole(['user'])
|
|
450
474
|
static async testAuth2(name: string) {
|
|
451
475
|
if (DBOS.authenticatedUser !== 'a_real_user') {
|
|
452
|
-
throw new
|
|
476
|
+
throw new DBOSResponseError('uid not a real user!', 400);
|
|
453
477
|
}
|
|
454
478
|
if (!DBOS.authenticatedRoles.includes('user')) {
|
|
455
|
-
throw new
|
|
479
|
+
throw new DBOSResponseError("roles don't include user!", 400);
|
|
456
480
|
}
|
|
457
481
|
if (DBOS.assumedRole !== 'user') {
|
|
458
|
-
throw new
|
|
482
|
+
throw new DBOSResponseError('Should never happen! Not assumed to be user', 400);
|
|
459
483
|
}
|
|
460
484
|
return Promise.resolve(`Please say hello to ${name}`);
|
|
461
485
|
}
|
package/tests/steps.test.ts
CHANGED
|
@@ -56,9 +56,14 @@ describe('registerstep', () => {
|
|
|
56
56
|
expect(response1.statusCode).toBe(200);
|
|
57
57
|
const response2 = await request(app.callback()).get('/api/i2?user=jeremy');
|
|
58
58
|
expect(response2.statusCode).toBe(200);
|
|
59
|
+
const response3 = await request(app.callback()).get('/api/i1');
|
|
60
|
+
expect(response3.statusCode).toBe(400);
|
|
61
|
+
const response4 = await request(app.callback()).get('/api/i2');
|
|
62
|
+
expect(response4.statusCode).toBe(400);
|
|
59
63
|
});
|
|
60
64
|
});
|
|
61
65
|
|
|
66
|
+
@DBOSKoa.defaultArgValidate
|
|
62
67
|
class KnexKoa {
|
|
63
68
|
@customstep()
|
|
64
69
|
@dhttp.getApi('/api/i2')
|
|
@@ -77,9 +77,14 @@ describe('KnexDataSource', () => {
|
|
|
77
77
|
expect(response1.statusCode).toBe(200);
|
|
78
78
|
const response2 = await request(app.callback()).get('/api/i2?user=jeremy');
|
|
79
79
|
expect(response2.statusCode).toBe(200);
|
|
80
|
+
const response3 = await request(app.callback()).get('/api/i1');
|
|
81
|
+
expect(response3.statusCode).toBe(400);
|
|
82
|
+
const response4 = await request(app.callback()).get('/api/i2');
|
|
83
|
+
expect(response4.statusCode).toBe(400);
|
|
80
84
|
});
|
|
81
85
|
});
|
|
82
86
|
|
|
87
|
+
@DBOSKoa.defaultArgValidate
|
|
83
88
|
class KnexKoa {
|
|
84
89
|
@knexds.transaction()
|
|
85
90
|
@dhttp.getApi('/api/i2')
|