egg/test/lib/cluster/app_worker.test.js
Yiyu He 04adb930de fix: onClientError remove content-length header (#3544)
<!--
Thank you for your pull request. Please review below requirements.
Bug fixes and new features should include tests and possibly benchmarks.
Contributors guide: https://github.com/eggjs/egg/blob/master/CONTRIBUTING.md

感谢您贡献代码。请确认下列 checklist 的完成情况。
Bug 修复和新功能必须包含测试,必要时请附上性能测试。
Contributors guide: https://github.com/eggjs/egg/blob/master/CONTRIBUTING.md
-->

##### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [ ] `npm test` passes
- [ ] tests and/or benchmarks are included
- [ ] documentation is changed or added
- [ ] commit message follows commit guidelines

##### Affected core subsystem(s)
<!-- Provide affected core subsystem(s). -->


##### Description of change
<!-- Provide a description of the change below this comment. -->

提升测试覆盖率到 100%
2019-03-17 01:48:16 +08:00

171 lines
4.8 KiB
JavaScript

'use strict';
const net = require('net');
const request = require('supertest');
const address = require('address');
const assert = require('assert-extends');
const sleep = require('mz-modules/sleep');
const utils = require('../../utils');
const DEFAULT_BAD_REQUEST_HTML = `<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>❤</center>
</body>
</html>`;
describe('test/lib/cluster/app_worker.test.js', () => {
let app;
before(() => {
app = utils.cluster('apps/app-server');
return app.ready();
});
after(() => app.close());
it('should start cluster success and app worker emit `server` event', () => {
return app.httpRequest()
.get('/')
.expect('true');
});
it('should response 400 bad request when HTTP request packet broken', async () => {
const test1 = app.httpRequest()
// Node.js (http-parser) will occur an error while the raw URI in HTTP
// request packet containing space.
//
// Refs: https://zhuanlan.zhihu.com/p/31966196
.get('/foo bar');
const test2 = app.httpRequest().get('/foo baz');
// app.httpRequest().expect() will encode the uri so that we cannot
// request the server with raw `/foo bar` to emit 400 status code.
//
// So we generate `test.req` via `test.request()` first and override the
// encoded uri.
//
// `test.req` will only generated once:
//
// ```
// function Request::request() {
// if (this.req) return this.req;
//
// // code to generate this.req
//
// return this.req;
// }
// ```
test1.request().path = '/foo bar';
test2.request().path = '/foo baz';
await Promise.all([
test1.expect(DEFAULT_BAD_REQUEST_HTML).expect(400),
test2.expect(DEFAULT_BAD_REQUEST_HTML).expect(400),
]);
});
describe('server timeout', () => {
let app;
beforeEach(() => {
app = utils.cluster('apps/app-server-timeout');
// app.debug();
return app.ready();
});
afterEach(() => app.close());
it('should not timeout', () => {
return app.httpRequest()
.get('/')
.expect(200);
});
it('should timeout', async () => {
await assert.asyncThrows(() => {
return app.httpRequest().get('/timeout');
}, /socket hang up/);
app.expect('stdout', /\[http_server] A request `GET \/timeout` timeout with client/);
});
});
describe('customized client error', () => {
let app;
beforeEach(() => {
app = utils.cluster('apps/app-server-customized-client-error');
app.debug();
return app.ready();
});
afterEach(() => app.close());
it('should do customized request when HTTP request packet broken', async () => {
const version = process.version.split('.').map(a => parseInt(a.replace('v', '')));
let html = '';
if ((version[0] === 8 && version[1] >= 10) ||
(version[0] === 9 && version[1] >= 4) ||
version[0] > 9) {
html = new RegExp(
'GET /foo bar HTTP/1.1\r\nHost: 127.0.0.1:\\d+\r\nAccept-Encoding: gzip, ' +
'deflate\r\nUser-Agent: node-superagent/\\d+\\.\\d+\\.\\d+\r\nConnection: close\r\n\r\n');
}
// customized client error response
const test1 = app.httpRequest().get('/foo bar');
test1.request().path = '/foo bar';
await test1.expect(html)
.expect('foo', 'bar')
.expect('content-length', '134')
.expect(418);
// customized client error handle function throws
const test2 = app.httpRequest().get('/foo bar');
test2.request().path = '/foo bar';
await test2.expect(DEFAULT_BAD_REQUEST_HTML).expect(400);
});
it('should not log when there is no rawPacket', async () => {
await connect(app.port);
await sleep(1000);
app.expect('stderr', /HPE_INVALID_EOF_STATE/);
app.notExpect('stderr', /A client/);
});
});
describe('listen hostname', () => {
let app;
before(() => {
app = utils.cluster('apps/app-server-with-hostname');
return app.ready();
});
after(() => app.close());
it('should refuse other ip', async () => {
const url = address.ip() + ':' + app.port;
await request(url)
.get('/')
.expect('done')
.expect(200);
try {
await request('http://127.0.0.1:17010')
.get('/')
.expect('done')
.expect(200);
throw new Error('should not run');
} catch (err) {
assert(err.message === 'ECONNREFUSED: Connection refused');
}
});
});
});
function connect(port) {
return new Promise(resolve => {
const socket = net.createConnection(port, '127.0.0.1', () => {
socket.write('GET http://127.0.0.1:8080/ HTTP', () => {
socket.destroy();
resolve();
});
});
});
}