Skip to content

Commit b6d5797

Browse files
Merge pull request #10 from volatilization/feature/add-tests
Feature/add tests
2 parents 2bf7ff6 + 89cb3ee commit b6d5797

29 files changed

+2579
-178
lines changed

.github/workflows/npm-publish.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@ on:
55
types: [published]
66

77
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: actions/setup-node@v3
13+
with:
14+
node-version: 21
15+
cache: 'npm'
16+
- run: npm test
17+
818
publish-npm:
19+
needs: [test]
920
runs-on: ubuntu-latest
1021
steps:
1122
- uses: actions/checkout@v3

.github/workflows/npm-test.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Test hook
2+
3+
on:
4+
push:
5+
branches: [ "master" ]
6+
pull_request:
7+
branches: [ "master" ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
- uses: actions/setup-node@v3
15+
with:
16+
node-version: 21
17+
- run: npm test

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"description": "Proxy classes for creating a http server",
66
"keywords": ["web", "web-server", "http", "http-server", "oop"],
77
"scripts": {
8-
"prepareToPublish": "node dist/prepareToPublish.js"
8+
"prepareToPublish": "node dist/prepareToPublish.js",
9+
"test": "node --test"
910
},
1011
"author": {
1112
"name": "volatilization",

src/js/server/ClusteredServer.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ module.exports = class ClusteredServer {
1616
}
1717

1818
} else {
19-
await this.#origin.start();
19+
return new ClusteredServer(await this.#origin.start(), this.#cluster, this.#options);
2020
}
21-
22-
return this;
2321
}
2422

2523
options() {

src/js/server/LoggedServer.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ module.exports = class LoggedServer {
88
}
99

1010
async start() {
11-
await this.#origin.start();
11+
const server = await this.#origin.start();
1212

1313
this.#logger.debug(`HttpServer is running at port: ${this.#origin.options().port}`);
1414

15-
return this;
15+
return new LoggedServer(server, this.#logger);
1616
}
1717

18+
async stop() {
19+
const server = await this.#origin.stop();
20+
21+
this.#logger.debug(`HttpServer at port: ${this.#origin.options().port} is stopped`);
22+
23+
return new LoggedServer(server, this.#logger);
24+
}
25+
26+
1827
options() {
1928
return this.#origin.options();
2029
}

src/js/server/Server.js

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,74 @@ module.exports = class HttpServer {
44
#response;
55
#endpoints;
66
#options;
7+
#server;
78

8-
constructor(http, request, response, endpoints, options) {
9+
constructor(http, request, response, endpoints, options, server) {
910
this.#http = http;
1011
this.#request = request;
1112
this.#response = response;
1213
this.#endpoints = endpoints;
1314
this.#options = options;
15+
this.#server = server;
1416
}
1517

1618
start() {
17-
return new Promise(resolve => {
18-
this.#http
19-
.createServer(async (requestStream, responseStream) => {
20-
try {
21-
return await (this.#response
22-
.copy(responseStream, await this.#endpoints
23-
.handle(await (this.#request
24-
.copy(requestStream))
25-
.flush())))
26-
.flush();
19+
const server = this.#http.createServer(async (requestStream, responseStream) => {
20+
try {
21+
return await (this.#response
22+
.copy(responseStream, await this.#endpoints
23+
.handle(await (this.#request
24+
.copy(requestStream))
25+
.flush())))
26+
.flush();
27+
28+
} catch (e) {
29+
if (e.cause === 'INVALID_REQUEST') {
30+
return await (this.#response
31+
.copy(responseStream, {
32+
statusCode: 400,
33+
body: e.message
34+
}))
35+
.flush();
36+
}
37+
38+
return await (this.#response
39+
.copy(responseStream, {
40+
statusCode: 500,
41+
body: 'Unexpected server error.'
42+
}))
43+
.flush();
44+
}
45+
});
2746

28-
} catch (e) {
29-
if (e.cause === 'INVALID_REQUEST') {
30-
return this.#response
31-
.copy(responseStream, {
32-
statusCode: 400,
33-
body: e.message
34-
})
35-
.flush();
36-
}
47+
return new Promise(resolve => {
48+
server.listen(
49+
this.#options,
50+
() => resolve(new HttpServer(
51+
this.#http,
52+
this.#request,
53+
this.#response,
54+
this.#endpoints,
55+
this.#options,
56+
server))
57+
);
58+
});
59+
}
3760

38-
return this.#response
39-
.copy(responseStream, {
40-
statusCode: 500,
41-
body: 'Unexpected server error.'
42-
})
43-
.flush();
44-
}
45-
})
46-
.listen(
47-
{port: this.#options.port},
48-
() => resolve(this)
49-
);
61+
stop() {
62+
return new Promise(resolve => {
63+
this.#server.close(
64+
() => resolve(new HttpServer(
65+
this.#http,
66+
this.#request,
67+
this.#response,
68+
this.#endpoints,
69+
this.#options))
70+
);
5071
});
5172
}
5273

5374
options() {
5475
return this.#options;
5576
}
56-
}
77+
};

src/js/server/request/InputRequest.js

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,24 @@ module.exports = class InputRequest {
1212
}
1313

1414
flush() {
15-
return new Promise((resolve, reject) => {
16-
try {
17-
this.#inputStream.on('error', (e) => reject(e));
15+
return new Promise((resolve) => {
16+
this.#inputStream.once('error', (e) => {
17+
throw new Error(e.message, {cause: 'INVALID_REQUEST'});
18+
});
1819

19-
if (!this.#isChunkedInputStream(this.#inputStream)) {
20-
resolve(new InputRequest(
21-
this.#inputStream,
22-
this.#extractOptionsFromInputStream(this.#inputStream)
23-
));
24-
}
25-
26-
let chunks = [];
27-
this.#inputStream.on('data', (chunk) => chunks.push(chunk));
28-
this.#inputStream.on('end', () => resolve(new InputRequest(
20+
if (!this.#isChunkedInputStream(this.#inputStream)) {
21+
return resolve(new InputRequest(
2922
this.#inputStream,
30-
{... this.#extractOptionsFromInputStream(this.#inputStream), body: Buffer.concat(chunks)}
31-
)));
32-
33-
} catch (e) {
34-
reject(e);
23+
this.#extractOptionsFromInputStream(this.#inputStream)
24+
));
3525
}
26+
27+
let chunks = [];
28+
this.#inputStream.on('data', (chunk) => chunks.push(chunk));
29+
this.#inputStream.on('end', () => resolve(new InputRequest(
30+
this.#inputStream,
31+
{... this.#extractOptionsFromInputStream(this.#inputStream), body: Buffer.concat(chunks)}
32+
)));
3633
});
3734
}
3835

@@ -51,6 +48,10 @@ module.exports = class InputRequest {
5148
return this.#options.body;
5249
}
5350

51+
headers() {
52+
return this.#options.headers;
53+
}
54+
5455
#isChunkedInputStream(inputStream) {
5556
return ['POST', 'PUT'].some(method => method === inputStream.method.toString().toUpperCase());
5657
}

src/js/server/request/JsonInputRequest.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ module.exports = class JsonInputRequest {
3232
return null;
3333
}
3434

35-
return JSON.parse(this.#origin.body().toString());
35+
try {
36+
return JSON.parse(this.#origin.body().toString());
37+
38+
} catch (e) {
39+
throw new Error('Wrong body format. Only JSON accepted.', {cause: 'INVALID_REQUEST'});
40+
}
41+
}
42+
43+
headers() {
44+
return this.#origin.headers();
3645
}
3746

3847
#useChunkMethod(requestMethod) {

src/js/server/request/LoggedInputRequest.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,8 @@ module.exports = class LoggedInputRequest {
3030
body() {
3131
return this.#origin.body();
3232
}
33+
34+
headers() {
35+
return this.#origin.headers();
36+
}
3337
}

src/js/server/response/OutputResponse.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ module.exports = class OutputResponse {
3131
}
3232

3333
#mergeOptions(existedOptions, newOptions) {
34+
if (newOptions == null) {
35+
return existedOptions;
36+
}
37+
3438
if (newOptions.statusCode != null) {
3539
existedOptions.statusCode = newOptions.statusCode;
3640
}

0 commit comments

Comments
 (0)