web_plsql 0.3.2 → 0.5.0

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.
Files changed (44) hide show
  1. package/.editorconfig +8 -8
  2. package/.eslintignore +3 -3
  3. package/.eslintrc.js +347 -273
  4. package/CHANGELOG.md +127 -106
  5. package/LICENSE +21 -21
  6. package/README.md +165 -164
  7. package/examples/apex.js +70 -70
  8. package/examples/credentials.js +22 -22
  9. package/examples/oracledb_example.js +30 -30
  10. package/examples/sample.js +101 -84
  11. package/examples/sql/doc_table.sql +13 -13
  12. package/examples/sql/install.sql +31 -31
  13. package/examples/sql/sample.pkb +223 -223
  14. package/examples/sql/sample.pks +24 -24
  15. package/examples/sql/uninstall.sql +5 -5
  16. package/examples/static/sample.css +25 -25
  17. package/jest.config.js +204 -0
  18. package/package.json +85 -109
  19. package/src/cgi.ts +95 -95
  20. package/src/config.ts +97 -97
  21. package/src/errorPage.ts +286 -286
  22. package/src/fileUpload.ts +126 -132
  23. package/src/index.ts +65 -66
  24. package/src/page.ts +275 -277
  25. package/src/procedure.ts +360 -359
  26. package/src/procedureError.ts +27 -27
  27. package/src/request.ts +139 -139
  28. package/src/requestError.ts +19 -19
  29. package/src/stream.ts +26 -26
  30. package/src/trace.ts +194 -193
  31. package/test/.eslintrc.json +5 -5
  32. package/test/{cgi.ts → __tests__/cgi.ts} +96 -95
  33. package/test/{config.ts → __tests__/config.ts} +41 -41
  34. package/test/__tests__/errorPage.ts +101 -0
  35. package/test/{oracledb_mock.ts → __tests__/oracledb_mock.ts} +98 -98
  36. package/test/{server.ts → __tests__/server.ts} +495 -498
  37. package/test/{stream.ts → __tests__/stream.ts} +21 -21
  38. package/test/mock/oracledb.ts +85 -85
  39. package/test/static/static.html +1 -1
  40. package/tsconfig.json +24 -23
  41. package/tsconfig.src.json +23 -22
  42. package/test/errorPage.ts +0 -101
  43. package/test/mocha.opts +0 -7
  44. package/tsconfig.test.json +0 -19
@@ -1,498 +1,495 @@
1
- import {assert} from 'chai';
2
- import util from 'util';
3
- import express from 'express';
4
- import http from 'http';
5
- import oracledb from 'oracledb';
6
- import path from 'path';
7
- import bodyParser from 'body-parser';
8
- //@ts-ignore
9
- import multipart from 'connect-multiparty';
10
- import cookieParser from 'cookie-parser';
11
- import compression from 'compression';
12
- //@ts-ignore
13
- import request from 'supertest';
14
- import {setExecuteCallback, createPool} from './mock/oracledb';
15
-
16
- const webplsql = require('../src/index'); // eslint-disable-line @typescript-eslint/no-var-requires
17
-
18
- const PORT = 8765;
19
- const PATH = '/base';
20
- const DEFAULT_PAGE = 'sample.pageIndex';
21
- const DOC_TABLE = 'docTable';
22
-
23
- type serverConfigType = {
24
- app: express.Application;
25
- server: http.Server;
26
- connectionPool: oracledb.Pool;
27
- }
28
-
29
- describe('server utilities', () => {
30
- it('should start a server', async () => {
31
- const serverConfig = await serverStart();
32
-
33
- assert.strictEqual(Object.prototype.toString.call(serverConfig), '[object Object]');
34
- assert.strictEqual(Object.prototype.toString.call(serverConfig.app.listen), '[object Function]');
35
- assert.strictEqual(Object.prototype.toString.call(serverConfig.server), '[object Object]');
36
- //assert.isTrue(serverConfig.connectionPool instanceof oracledb.Pool);
37
-
38
- await serverStop(serverConfig);
39
- });
40
- });
41
-
42
- describe('server static', () => {
43
- let serverConfig: any;
44
-
45
- before('Start the server', async () => {
46
- serverConfig = await serverStart();
47
- });
48
-
49
- after('Stop the server', async () => {
50
- await serverStop(serverConfig);
51
- });
52
-
53
- beforeEach('Reset the execute callback', () => {
54
- setExecuteCallback();
55
- });
56
-
57
- it('get a static file', () =>
58
- request(serverConfig.app).get('/static/static.html')
59
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*')));
60
-
61
- it('report a 404 error on a missing static file', () =>
62
- request(serverConfig.app).get('/static/file_does_not_exist.html')
63
- .expect(404));
64
-
65
- it('get default page', () =>
66
- request(serverConfig.app).get(PATH)
67
- .expect(302, `Found. Redirecting to ${PATH}/${DEFAULT_PAGE}`));
68
-
69
- it('get page', () => {
70
- sqlExecuteProxy({
71
- proc: 'sample.pageIndex();',
72
- lines: [
73
- 'Content-type: text/html; charset=UTF-8\n',
74
- 'X-ORACLE-IGNORE: IGNORE\n',
75
- 'Custom-header: important\n',
76
- '\n',
77
- '<html><body><p>static</p></body></html>\n'
78
- ]
79
- });
80
-
81
- return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
82
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
83
- });
84
-
85
- it('get page with query string', () => {
86
- sqlExecuteProxy({
87
- proc: 'sample.pageIndex(a=>:p_a,b=>:p_b);',
88
- para: [
89
- {name: 'a', value: '1'},
90
- {name: 'b', value: '2'}
91
- ],
92
- lines: [
93
- 'Content-type: text/html; charset=UTF-8\n',
94
- '\n',
95
- '<html><body><p>static</p></body></html>\n'
96
- ]
97
- });
98
-
99
- return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}?a=1&b=2`)
100
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
101
- });
102
-
103
- it('get page with query string containing duplicate names', () => {
104
- sqlExecuteProxy({
105
- proc: 'sample.pageIndex(a=>:p_a);',
106
- para: [
107
- {name: 'a', value: ['1', '2']}
108
- ],
109
- lines: [
110
- 'Content-type: text/html; charset=UTF-8\n',
111
- '\n',
112
- '<html><body><p>static</p></body></html>\n'
113
- ]
114
- });
115
-
116
- return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}?a=1&a=2`)
117
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
118
- });
119
-
120
- it('get page with flexible parameters', () => {
121
- sqlExecuteProxy({
122
- proc: 'sample.pageIndex(:argnames, :argvalues);',
123
- para: [
124
- {name: 'argnames', value: ['a', 'b']},
125
- {name: 'argvalues', value: ['1', '2']}
126
- ],
127
- lines: [
128
- 'Content-type: text/html; charset=UTF-8\n',
129
- '\n',
130
- '<html><body><p>static</p></body></html>\n'
131
- ]
132
- });
133
-
134
- return request(serverConfig.app).get(`${PATH}/!${DEFAULT_PAGE}?a=1&b=2`)
135
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
136
- });
137
-
138
- it('get page with cookies', () => {
139
- sqlExecuteProxy({
140
- proc: 'sample.pageIndex();',
141
- lines: [
142
- 'Content-type: text/html; charset=UTF-8\n',
143
- 'Set-Cookie: C1=V1; path=/apex; Domain=mozilla.org; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly\n',
144
- '\n',
145
- '<html><body><p>static</p></body></html>\n'
146
- ]
147
- });
148
-
149
- return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
150
- .expect(200)
151
- .expect('set-cookie', 'C1=V1; Domain=mozilla.org; Path=/apex; Expires=Wed, 21 Oct 2015 07:28:00 GMT; HttpOnly')
152
- .expect(new RegExp('.*<html><body><p>static</p></body></html>.*'));
153
- });
154
-
155
- it('redirect to a new url', () => {
156
- sqlExecuteProxy({
157
- proc: 'sample.pageIndex();',
158
- lines: ['Location: www.google.com\n']
159
- });
160
-
161
- return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
162
- .expect(302);
163
- });
164
-
165
- it('get json', () => {
166
- sqlExecuteProxy({
167
- proc: 'sample.pageJson();',
168
- lines: [
169
- 'Content-type: application/json\n',
170
- '\n',
171
- '{"name":"johndoe"}'
172
- ]
173
- });
174
-
175
- return request(serverConfig.app).get(`${PATH}/sample.pageJson`)
176
- .expect(200, '{"name":"johndoe"}');
177
- });
178
-
179
- it('get application/x-www-form-urlencoded', () => {
180
- sqlExecuteProxy({
181
- proc: 'sample.pageForm(name=>:p_name);',
182
- para: [
183
- {name: 'name', value: 'johndoe'}
184
- ],
185
- lines: [
186
- 'Content-Type: text/html\n',
187
- '\n',
188
- '<html><body><p>static</p></body></html>\n'
189
- ]
190
- });
191
-
192
- return request(serverConfig.app)
193
- .get(`${PATH}/sample.pageForm`)
194
- .set('Content-Type', 'application/x-www-form-urlencoded')
195
- .send('name=johndoe')
196
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
197
- });
198
-
199
- it('get application/x-www-form-urlencoded with file', () => {
200
- sqlExecuteProxy({
201
- proc: 'sample.pageForm(',
202
- para: [
203
- {name: 'user_name', value: 'Tobi'}
204
- ],
205
- lines: [
206
- 'Content-Type: text/html\n',
207
- '\n',
208
- '<html><body><p>static</p></body></html>\n'
209
- ]
210
- });
211
-
212
- const test = request(serverConfig.app).post(`${PATH}/sample.pageForm`);
213
- test.set('Content-Type', 'multipart/form-data; boundary=foo');
214
- test.write('--foo\r\n');
215
- test.write('Content-Disposition: form-data; name="user_name"\r\n');
216
- test.write('\r\n');
217
- test.write('Tobi');
218
- test.write('\r\n--foo\r\n');
219
- test.write('Content-Disposition: form-data; name="text"; filename="test/server.js"\r\n');
220
- test.write('\r\n');
221
- test.write('some text here');
222
- test.write('\r\n--foo--');
223
-
224
- return test.expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
225
- });
226
-
227
- it('set status', () => {
228
- sqlExecuteProxy({
229
- proc: 'sample.pageIndex();',
230
- lines: [
231
- 'Status: 302 status\n'
232
- ]
233
- });
234
-
235
- return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
236
- .expect(302);
237
- });
238
-
239
- it('set x-db-content-length header', () => {
240
- sqlExecuteProxy({
241
- proc: 'sample.pageJson();',
242
- lines: [
243
- 'x-db-content-length: 0\n',
244
- ]
245
- });
246
-
247
- return request(serverConfig.app).get(`${PATH}/sample.pageJson`)
248
- .expect(200);
249
- });
250
-
251
- it('use the pathAlias configuration setting', () => {
252
- sqlExecuteProxy({
253
- proc: 'pathAlias(p_path=>:p_path);',
254
- lines: [
255
- 'Content-type: text/html; charset=UTF-8\n',
256
- '\n',
257
- '<html><body><p>static</p></body></html>\n'
258
- ]
259
- });
260
-
261
- return request(serverConfig.app).get(`${PATH}/alias`)
262
- .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
263
- });
264
-
265
- /*
266
-
267
- it('GET /sampleRoute/cgi should validate the cgi', () => {
268
- request(application.expressApplication).get('/sampleRoute/cgi')
269
- .expect(200, 'cgi', done);
270
- });
271
-
272
- it('GET /basicRoute/basicPage should generate a 401 error', () => {
273
- request(application.expressApplication)
274
- .get('/basicRoute/basicPage')
275
- .expect(401, 'Access denied', done);
276
- });
277
-
278
- it('GET /basicRoute/basicPage should authorize', () => {
279
- request(application.expressApplication)
280
- .get('/basicRoute/basicPage')
281
- .auth('myusername', 'mypassword')
282
- .expect(200, done);
283
- });
284
-
285
- it('should upload files', () => {
286
- const FILENAME = 'temp/index.html';
287
- const CONTENT = 'content of index.html';
288
- let test;
289
-
290
- // create a static file
291
- mkdirp.sync('temp');
292
- fs.writeFileSync(FILENAME, CONTENT);
293
-
294
- // test the upload
295
- test = request(application.expressApplication).post('/sampleRoute/fileUpload');
296
- test.attach('file', FILENAME);
297
- test.expect(200, done);
298
- });
299
-
300
- it('should respond with 404', () => {
301
- let test = request(application.expressApplication).get('/invalidRoute');
302
-
303
- test.expect(404, new RegExp('.*404 Not Found.*'), done);
304
- });
305
-
306
- it('should respond with 404', () => {
307
- let test = request(application.expressApplication).get('/sampleRoute/errorInPLSQL');
308
-
309
- test.expect(404, new RegExp('.*Failed to parse target procedure.*'), done);
310
- });
311
-
312
- it('should respond with 500', () => {
313
- let test = request(application.expressApplication).get('/sampleRoute/internalError');
314
-
315
- test.expect(500, done);
316
- });
317
-
318
- it('does stop', () => {
319
- server.stop(application, () => {
320
- application = null;
321
- assert.ok(true);
322
- done();
323
- });
324
- });
325
-
326
-
327
- it('does not start', () => {
328
- server.start().then(() => {
329
- }, function (err) {
330
- assert.strictEqual(err, 'Configuration object must be an object');
331
- done();
332
- });
333
- });
334
-
335
- */
336
- });
337
-
338
- /*
339
- * Start server
340
- */
341
- async function serverStart(): Promise<serverConfigType> {
342
- // create connection pool
343
- const connectionPool = await createPool({
344
- user: 'sample',
345
- password: 'sample',
346
- connectString: 'localhost:1521/TEST'
347
- });
348
-
349
- // create express app
350
- const app = express();
351
-
352
- // add middleware
353
- //@ts-ignore
354
- app.use(multipart());
355
- app.use(bodyParser.json());
356
- app.use(bodyParser.urlencoded({extended: true}));
357
- app.use(cookieParser());
358
- app.use(compression());
359
-
360
- // add the oracle pl/sql express middleware
361
- app.use(PATH + '/:name?', webplsql(connectionPool, {
362
- trace: 'test',
363
- defaultPage: DEFAULT_PAGE,
364
- doctable: DOC_TABLE,
365
- pathAlias: {
366
- alias: 'alias',
367
- procedure: 'pathAlias'
368
- }
369
- }));
370
-
371
- // serving static files
372
- const staticResourcesPath = path.join(process.cwd(), 'test', 'static');
373
- app.use('/static', express.static(staticResourcesPath));
374
-
375
- // listen on port
376
- const server = app.listen(PORT);
377
-
378
- //@ts-ignore
379
- return {app, server, connectionPool};
380
- }
381
-
382
- /*
383
- * Stop server
384
- */
385
- async function serverStop(config: serverConfigType) {
386
- await config.server.close();
387
- await config.connectionPool.close();
388
- }
389
-
390
- /*
391
- * Set the proxy for the next sql procedure to be executed
392
- */
393
- function sqlExecuteProxy(config: {proc: string; para?: Array<{name: string; value: string | Array<string>}>; lines: Array<string>}) {
394
- setExecuteCallback((sql: string, bind: any) => {
395
- if (sql.indexOf('dbms_utility.name_resolve') !== -1) {
396
- const noPara: {outBinds: {names: Array<string>; types: Array<string>}} = {
397
- outBinds: {
398
- names: [],
399
- types: []
400
- }
401
- };
402
-
403
- return typeof config.para === 'undefined' ? noPara : config.para.reduce((accumulator, currentValue) => {
404
- accumulator.outBinds.names.push(currentValue.name);
405
- accumulator.outBinds.types.push('VARCHAR2');
406
- return accumulator;
407
- }, noPara);
408
- }
409
-
410
- if (sql.indexOf(config.proc) !== -1) {
411
- if (typeof config.para !== 'undefined') {
412
- if (!parameterEqual(sql, bind, config.para)) {
413
- console.error(`===> Parameter mismatch\n${'-'.repeat(30)}\n${util.inspect(bind)}\n${'-'.repeat(30)}`);
414
- return {};
415
- }
416
- }
417
-
418
- return {
419
- outBinds: {
420
- fileType: null,
421
- fileSize: null,
422
- fileBlob: null,
423
- lines: config.lines,
424
- irows: config.lines.length
425
- }
426
- };
427
- }
428
-
429
- if (sql.indexOf('INSERT INTO') === 0) {
430
- return {
431
- rowsAffected: 1
432
- };
433
- }
434
-
435
- console.error(`===> sql statement cannot be identified\n${'-'.repeat(30)}\n${sql}\n${'-'.repeat(30)}`);
436
-
437
- return {};
438
- });
439
- }
440
-
441
- function parameterEqual(sql: string, bind: any, parameters: Array<{name: string; value: string | Array<string>}>): boolean {
442
- return sql.indexOf('(:argnames, :argvalues)') === -1 ? parameterFixedEqual(bind, parameters) : parameterFlexibleEqual(bind, parameters);
443
- }
444
-
445
- function parameterFixedEqual(bind: any, parameters: Array<{name: string; value: string | Array<string>}>): boolean {
446
- return parameters.every(para => {
447
- if (!bind.hasOwnProperty('p_' + para.name)) {
448
- console.error(`===> The parameter "${para.name}" is missing`);
449
- return false;
450
- }
451
-
452
- if (Array.isArray(para.value)) {
453
- return para.value.every((v, i) => {
454
- const equal = v === bind['p_' + para.name].val[i];
455
- if (!equal) {
456
- console.error(`===> The value "${v}" of parameter "${para.name}" is different`);
457
- }
458
- return equal;
459
- });
460
- }
461
-
462
- return para.value === bind['p_' + para.name].val;
463
- });
464
- }
465
-
466
- function parameterFlexibleEqual(bind: any, parameters: Array<{name: string; value: string | Array<string>}>): boolean {
467
- if (parameters.length !== 2) {
468
- console.error('===> Invalid number of parameters');
469
- return false;
470
- }
471
-
472
- if (!parameters.every(para => ['argnames', 'argvalues'].indexOf(para.name) !== -1)) {
473
- console.error('===> Invalid parameter names');
474
- return false;
475
- }
476
-
477
- if (!bind.hasOwnProperty('argnames') || !bind.hasOwnProperty('argvalues')) {
478
- console.error('===> Missing bindings');
479
- return false;
480
- }
481
-
482
- return parameters.every(para => Array.isArray(para.value) && arrayEqual(para.value, bind[para.name].val));
483
- }
484
-
485
- /*
486
- * Compare two arrays
487
- */
488
- function arrayEqual(array1: Array<any>, array2: Array<any>): boolean {
489
- if (!array1 || !array2) {
490
- return false;
491
- }
492
-
493
- if (array1.length !== array2.length) {
494
- return false;
495
- }
496
-
497
- return array1.every((e, i) => e === array2[i]);
498
- }
1
+ import {describe, beforeAll, afterAll, beforeEach, it, expect} from '@jest/globals';
2
+ import util from 'util';
3
+ import express from 'express';
4
+ import http from 'http';
5
+ import oracledb from 'oracledb';
6
+ import path from 'path';
7
+ import bodyParser from 'body-parser';
8
+ // @ts-expect-error
9
+ import multipart from 'connect-multiparty';
10
+ import cookieParser from 'cookie-parser';
11
+ import compression from 'compression';
12
+ import request from 'supertest';
13
+ import {setExecuteCallback, createPool} from '../mock/oracledb';
14
+
15
+ const webplsql = require('../../src/index'); // eslint-disable-line @typescript-eslint/no-var-requires
16
+
17
+ const PORT = 8765;
18
+ const PATH = '/base';
19
+ const DEFAULT_PAGE = 'sample.pageIndex';
20
+ const DOC_TABLE = 'docTable';
21
+
22
+ type serverConfigType = {
23
+ app: express.Application;
24
+ server: http.Server;
25
+ connectionPool: oracledb.Pool;
26
+ }
27
+
28
+ describe('server utilities', () => {
29
+ it('should start a server', async () => {
30
+ const serverConfig = await serverStart();
31
+
32
+ expect(Object.prototype.toString.call(serverConfig)).toBe('[object Object]');
33
+ expect(Object.prototype.toString.call(serverConfig.app.listen)).toBe('[object Function]');
34
+ expect(Object.prototype.toString.call(serverConfig.server)).toBe('[object Object]');
35
+ //expect(serverConfig.connectionPool).toBeInstanceOf(oracledb.Pool);
36
+
37
+ await serverStop(serverConfig);
38
+ });
39
+ });
40
+
41
+ describe('server static', () => {
42
+ let serverConfig: any;
43
+
44
+ beforeAll(async () => {
45
+ serverConfig = await serverStart();
46
+ });
47
+
48
+ afterAll(async () => {
49
+ await serverStop(serverConfig);
50
+ });
51
+
52
+ beforeEach(() => {
53
+ setExecuteCallback();
54
+ });
55
+
56
+ it('get a static file', () =>
57
+ request(serverConfig.app).get('/static/static.html')
58
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*')));
59
+
60
+ it('report a 404 error on a missing static file', () =>
61
+ request(serverConfig.app).get('/static/file_does_not_exist.html')
62
+ .expect(404));
63
+
64
+ it('get default page', () =>
65
+ request(serverConfig.app).get(PATH)
66
+ .expect(302, `Found. Redirecting to ${PATH}/${DEFAULT_PAGE}`));
67
+
68
+ it('get page', () => {
69
+ sqlExecuteProxy({
70
+ proc: 'sample.pageIndex();',
71
+ lines: [
72
+ 'Content-type: text/html; charset=UTF-8\n',
73
+ 'X-ORACLE-IGNORE: IGNORE\n',
74
+ 'Custom-header: important\n',
75
+ '\n',
76
+ '<html><body><p>static</p></body></html>\n'
77
+ ]
78
+ });
79
+
80
+ return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
81
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
82
+ });
83
+
84
+ it('get page with query string', () => {
85
+ sqlExecuteProxy({
86
+ proc: 'sample.pageIndex(a=>:p_a,b=>:p_b);',
87
+ para: [
88
+ {name: 'a', value: '1'},
89
+ {name: 'b', value: '2'}
90
+ ],
91
+ lines: [
92
+ 'Content-type: text/html; charset=UTF-8\n',
93
+ '\n',
94
+ '<html><body><p>static</p></body></html>\n'
95
+ ]
96
+ });
97
+
98
+ return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}?a=1&b=2`)
99
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
100
+ });
101
+
102
+ it('get page with query string containing duplicate names', () => {
103
+ sqlExecuteProxy({
104
+ proc: 'sample.pageIndex(a=>:p_a);',
105
+ para: [
106
+ {name: 'a', value: ['1', '2']}
107
+ ],
108
+ lines: [
109
+ 'Content-type: text/html; charset=UTF-8\n',
110
+ '\n',
111
+ '<html><body><p>static</p></body></html>\n'
112
+ ]
113
+ });
114
+
115
+ return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}?a=1&a=2`)
116
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
117
+ });
118
+
119
+ it('get page with flexible parameters', () => {
120
+ sqlExecuteProxy({
121
+ proc: 'sample.pageIndex(:argnames, :argvalues);',
122
+ para: [
123
+ {name: 'argnames', value: ['a', 'b']},
124
+ {name: 'argvalues', value: ['1', '2']}
125
+ ],
126
+ lines: [
127
+ 'Content-type: text/html; charset=UTF-8\n',
128
+ '\n',
129
+ '<html><body><p>static</p></body></html>\n'
130
+ ]
131
+ });
132
+
133
+ return request(serverConfig.app).get(`${PATH}/!${DEFAULT_PAGE}?a=1&b=2`)
134
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
135
+ });
136
+
137
+ it('get page with cookies', () => {
138
+ sqlExecuteProxy({
139
+ proc: 'sample.pageIndex();',
140
+ lines: [
141
+ 'Content-type: text/html; charset=UTF-8\n',
142
+ 'Set-Cookie: C1=V1; path=/apex; Domain=mozilla.org; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly\n',
143
+ '\n',
144
+ '<html><body><p>static</p></body></html>\n'
145
+ ]
146
+ });
147
+
148
+ return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
149
+ .expect(200)
150
+ .expect('set-cookie', 'C1=V1; Domain=mozilla.org; Path=/apex; Expires=Wed, 21 Oct 2015 07:28:00 GMT; HttpOnly')
151
+ .expect(new RegExp('.*<html><body><p>static</p></body></html>.*'));
152
+ });
153
+
154
+ it('redirect to a new url', () => {
155
+ sqlExecuteProxy({
156
+ proc: 'sample.pageIndex();',
157
+ lines: ['Location: www.google.com\n']
158
+ });
159
+
160
+ return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
161
+ .expect(302);
162
+ });
163
+
164
+ it('get json', () => {
165
+ sqlExecuteProxy({
166
+ proc: 'sample.pageJson();',
167
+ lines: [
168
+ 'Content-type: application/json\n',
169
+ '\n',
170
+ '{"name":"johndoe"}'
171
+ ]
172
+ });
173
+
174
+ return request(serverConfig.app).get(`${PATH}/sample.pageJson`)
175
+ .expect(200, '{"name":"johndoe"}');
176
+ });
177
+
178
+ it('get application/x-www-form-urlencoded', () => {
179
+ sqlExecuteProxy({
180
+ proc: 'sample.pageForm(name=>:p_name);',
181
+ para: [
182
+ {name: 'name', value: 'johndoe'}
183
+ ],
184
+ lines: [
185
+ 'Content-Type: text/html\n',
186
+ '\n',
187
+ '<html><body><p>static</p></body></html>\n'
188
+ ]
189
+ });
190
+
191
+ return request(serverConfig.app)
192
+ .get(`${PATH}/sample.pageForm`)
193
+ .set('Content-Type', 'application/x-www-form-urlencoded')
194
+ .send('name=johndoe')
195
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
196
+ });
197
+
198
+ it('get application/x-www-form-urlencoded with file', () => {
199
+ sqlExecuteProxy({
200
+ proc: 'sample.pageForm(',
201
+ para: [
202
+ {name: 'user_name', value: 'Tobi'}
203
+ ],
204
+ lines: [
205
+ 'Content-Type: text/html\n',
206
+ '\n',
207
+ '<html><body><p>static</p></body></html>\n'
208
+ ]
209
+ });
210
+
211
+ const test = request(serverConfig.app).post(`${PATH}/sample.pageForm`);
212
+ test.set('Content-Type', 'multipart/form-data; boundary=foo');
213
+ test.write('--foo\r\n');
214
+ test.write('Content-Disposition: form-data; name="user_name"\r\n');
215
+ test.write('\r\n');
216
+ test.write('Tobi');
217
+ test.write('\r\n--foo\r\n');
218
+ test.write('Content-Disposition: form-data; name="text"; filename="test/server.js"\r\n');
219
+ test.write('\r\n');
220
+ test.write('some text here');
221
+ test.write('\r\n--foo--');
222
+
223
+ return test.expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
224
+ });
225
+
226
+ it('set status', () => {
227
+ sqlExecuteProxy({
228
+ proc: 'sample.pageIndex();',
229
+ lines: [
230
+ 'Status: 302 status\n'
231
+ ]
232
+ });
233
+
234
+ return request(serverConfig.app).get(`${PATH}/${DEFAULT_PAGE}`)
235
+ .expect(302);
236
+ });
237
+
238
+ it('set x-db-content-length header', () => {
239
+ sqlExecuteProxy({
240
+ proc: 'sample.pageJson();',
241
+ lines: [
242
+ 'x-db-content-length: 0\n',
243
+ ]
244
+ });
245
+
246
+ return request(serverConfig.app).get(`${PATH}/sample.pageJson`)
247
+ .expect(200);
248
+ });
249
+
250
+ it('use the pathAlias configuration setting', () => {
251
+ sqlExecuteProxy({
252
+ proc: 'pathAlias(p_path=>:p_path);',
253
+ lines: [
254
+ 'Content-type: text/html; charset=UTF-8\n',
255
+ '\n',
256
+ '<html><body><p>static</p></body></html>\n'
257
+ ]
258
+ });
259
+
260
+ return request(serverConfig.app).get(`${PATH}/alias`)
261
+ .expect(200, new RegExp('.*<html><body><p>static</p></body></html>.*'));
262
+ });
263
+
264
+ /*
265
+
266
+ it('GET /sampleRoute/cgi should validate the cgi', () => {
267
+ request(application.expressApplication).get('/sampleRoute/cgi')
268
+ .expect(200, 'cgi', done);
269
+ });
270
+
271
+ it('GET /basicRoute/basicPage should generate a 401 error', () => {
272
+ request(application.expressApplication)
273
+ .get('/basicRoute/basicPage')
274
+ .expect(401, 'Access denied', done);
275
+ });
276
+
277
+ it('GET /basicRoute/basicPage should authorize', () => {
278
+ request(application.expressApplication)
279
+ .get('/basicRoute/basicPage')
280
+ .auth('myusername', 'mypassword')
281
+ .expect(200, done);
282
+ });
283
+
284
+ it('should upload files', () => {
285
+ const FILENAME = 'temp/index.html';
286
+ const CONTENT = 'content of index.html';
287
+ let test;
288
+
289
+ // create a static file
290
+ mkdirp.sync('temp');
291
+ fs.writeFileSync(FILENAME, CONTENT);
292
+
293
+ // test the upload
294
+ test = request(application.expressApplication).post('/sampleRoute/fileUpload');
295
+ test.attach('file', FILENAME);
296
+ test.expect(200, done);
297
+ });
298
+
299
+ it('should respond with 404', () => {
300
+ let test = request(application.expressApplication).get('/invalidRoute');
301
+
302
+ test.expect(404, new RegExp('.*404 Not Found.*'), done);
303
+ });
304
+
305
+ it('should respond with 404', () => {
306
+ let test = request(application.expressApplication).get('/sampleRoute/errorInPLSQL');
307
+
308
+ test.expect(404, new RegExp('.*Failed to parse target procedure.*'), done);
309
+ });
310
+
311
+ it('should respond with 500', () => {
312
+ let test = request(application.expressApplication).get('/sampleRoute/internalError');
313
+
314
+ test.expect(500, done);
315
+ });
316
+
317
+ it('does stop', () => {
318
+ server.stop(application, () => {
319
+ application = null;
320
+ assert.ok(true);
321
+ done();
322
+ });
323
+ });
324
+
325
+
326
+ it('does not start', () => {
327
+ server.start().then(() => {
328
+ }, function (err) {
329
+ assert.strictEqual(err, 'Configuration object must be an object');
330
+ done();
331
+ });
332
+ });
333
+
334
+ */
335
+ });
336
+
337
+ /*
338
+ * Start server
339
+ */
340
+ async function serverStart(): Promise<serverConfigType> {
341
+ // create connection pool
342
+ const connectionPool = await createPool({
343
+ user: 'sample',
344
+ password: 'sample',
345
+ connectString: 'localhost:1521/TEST'
346
+ });
347
+
348
+ // create express app
349
+ const app = express();
350
+
351
+ // add middleware
352
+ app.use(multipart());
353
+ app.use(bodyParser.json());
354
+ app.use(bodyParser.urlencoded({extended: true}));
355
+ app.use(cookieParser());
356
+ app.use(compression());
357
+
358
+ // add the oracle pl/sql express middleware
359
+ app.use(PATH + '/:name?', webplsql(connectionPool, {
360
+ trace: 'test',
361
+ defaultPage: DEFAULT_PAGE,
362
+ doctable: DOC_TABLE,
363
+ pathAlias: {
364
+ alias: 'alias',
365
+ procedure: 'pathAlias'
366
+ }
367
+ }));
368
+
369
+ // serving static files
370
+ const staticResourcesPath = path.join(process.cwd(), 'test', 'static');
371
+ app.use('/static', express.static(staticResourcesPath));
372
+
373
+ // listen on port
374
+ const server = app.listen(PORT);
375
+
376
+ return {app, server, connectionPool: connectionPool as unknown as oracledb.Pool};
377
+ }
378
+
379
+ /*
380
+ * Stop server
381
+ */
382
+ async function serverStop(config: serverConfigType) {
383
+ await config.server.close();
384
+ await config.connectionPool.close();
385
+ }
386
+
387
+ /*
388
+ * Set the proxy for the next sql procedure to be executed
389
+ */
390
+ function sqlExecuteProxy(config: {proc: string; para?: Array<{name: string; value: string | Array<string>}>; lines: Array<string>}) {
391
+ setExecuteCallback((sql: string, bind: any) => {
392
+ if (sql.indexOf('dbms_utility.name_resolve') !== -1) {
393
+ const noPara: {outBinds: {names: Array<string>; types: Array<string>}} = {
394
+ outBinds: {
395
+ names: [],
396
+ types: []
397
+ }
398
+ };
399
+
400
+ return typeof config.para === 'undefined' ? noPara : config.para.reduce((accumulator, currentValue) => {
401
+ accumulator.outBinds.names.push(currentValue.name);
402
+ accumulator.outBinds.types.push('VARCHAR2');
403
+ return accumulator;
404
+ }, noPara);
405
+ }
406
+
407
+ if (sql.indexOf(config.proc) !== -1) {
408
+ if (typeof config.para !== 'undefined') {
409
+ if (!parameterEqual(sql, bind, config.para)) {
410
+ console.error(`===> Parameter mismatch\n${'-'.repeat(30)}\n${util.inspect(bind)}\n${'-'.repeat(30)}`);
411
+ return {};
412
+ }
413
+ }
414
+
415
+ return {
416
+ outBinds: {
417
+ fileType: null,
418
+ fileSize: null,
419
+ fileBlob: null,
420
+ lines: config.lines,
421
+ irows: config.lines.length
422
+ }
423
+ };
424
+ }
425
+
426
+ if (sql.indexOf('INSERT INTO') === 0) {
427
+ return {
428
+ rowsAffected: 1
429
+ };
430
+ }
431
+
432
+ console.error(`===> sql statement cannot be identified\n${'-'.repeat(30)}\n${sql}\n${'-'.repeat(30)}`);
433
+
434
+ return {};
435
+ });
436
+ }
437
+
438
+ function parameterEqual(sql: string, bind: any, parameters: Array<{name: string; value: string | Array<string>}>): boolean {
439
+ return sql.indexOf('(:argnames, :argvalues)') === -1 ? parameterFixedEqual(bind, parameters) : parameterFlexibleEqual(bind, parameters);
440
+ }
441
+
442
+ function parameterFixedEqual(bind: any, parameters: Array<{name: string; value: string | Array<string>}>): boolean {
443
+ return parameters.every(para => {
444
+ if (!bind.hasOwnProperty('p_' + para.name)) {
445
+ console.error(`===> The parameter "${para.name}" is missing`);
446
+ return false;
447
+ }
448
+
449
+ if (Array.isArray(para.value)) {
450
+ return para.value.every((v, i) => {
451
+ const equal = v === bind['p_' + para.name].val[i];
452
+ if (!equal) {
453
+ console.error(`===> The value "${v}" of parameter "${para.name}" is different`);
454
+ }
455
+ return equal;
456
+ });
457
+ }
458
+
459
+ return para.value === bind['p_' + para.name].val;
460
+ });
461
+ }
462
+
463
+ function parameterFlexibleEqual(bind: any, parameters: Array<{name: string; value: string | Array<string>}>): boolean {
464
+ if (parameters.length !== 2) {
465
+ console.error('===> Invalid number of parameters');
466
+ return false;
467
+ }
468
+
469
+ if (!parameters.every(para => ['argnames', 'argvalues'].indexOf(para.name) !== -1)) {
470
+ console.error('===> Invalid parameter names');
471
+ return false;
472
+ }
473
+
474
+ if (!bind.hasOwnProperty('argnames') || !bind.hasOwnProperty('argvalues')) {
475
+ console.error('===> Missing bindings');
476
+ return false;
477
+ }
478
+
479
+ return parameters.every(para => Array.isArray(para.value) && arrayEqual(para.value, bind[para.name].val));
480
+ }
481
+
482
+ /*
483
+ * Compare two arrays
484
+ */
485
+ function arrayEqual(array1: Array<any>, array2: Array<any>): boolean {
486
+ if (!array1 || !array2) {
487
+ return false;
488
+ }
489
+
490
+ if (array1.length !== array2.length) {
491
+ return false;
492
+ }
493
+
494
+ return array1.every((e, i) => e === array2[i]);
495
+ }