Skip to content

Commit 8ef15d9

Browse files
committed
test(server): added unix socket helper tests
1 parent 4bd6aad commit 8ef15d9

File tree

5 files changed

+200
-33
lines changed

5 files changed

+200
-33
lines changed

lib/Server.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -752,16 +752,20 @@ class Server {
752752
}
753753
};
754754

755-
const onListeningCallback = () => {
755+
const listenCallback = () => {
756756
if (typeof this.options.onListening === 'function') {
757757
this.options.onListening(this);
758758
}
759759
};
760760

761-
const fullCallback = (err) => {
761+
const setupAndListenCallback = () => {
762762
setupCallback();
763+
listenCallback();
764+
};
765+
766+
const fullCallback = (err) => {
767+
setupAndListenCallback();
763768
userCallback(err);
764-
onListeningCallback();
765769
};
766770

767771
// try to follow the Node standard in terms of deciding
@@ -773,7 +777,12 @@ class Server {
773777
// set this so that status helper can identify how the project is being run correctly
774778
this.options.socket = socket;
775779

776-
startUnixSocket(this.listeningApp, socket, fullCallback, userCallback);
780+
startUnixSocket(
781+
this.listeningApp,
782+
socket,
783+
setupAndListenCallback,
784+
userCallback
785+
);
777786
} else {
778787
this.listeningApp.listen(port, hostname, fullCallback);
779788
}

lib/utils/startUnixSocket.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33
const fs = require('fs');
44
const net = require('net');
55

6+
// userCallback should always be called to indicate that either the server has
7+
// started listening, or an error was thrown.
8+
// setupAndListenCallback should only be called if the server starts listening
69
function startUnixSocket(
710
listeningApp,
811
socket,
9-
onListeningCallback,
10-
errorCallback
12+
setupAndListenCallback,
13+
userCallback
1114
) {
15+
const fullCallback = (err) => {
16+
setupAndListenCallback();
17+
userCallback(err);
18+
};
19+
1220
const chmodSocket = (done) => {
1321
// chmod 666 (rw rw rw) - octal
1422
const READ_WRITE = 438;
@@ -17,22 +25,22 @@ function startUnixSocket(
1725

1826
const startSocket = () => {
1927
listeningApp.on('error', (err) => {
20-
errorCallback(err);
28+
userCallback(err);
2129
});
2230

2331
// 511 is the default value for the server.listen backlog parameter
2432
// https://nodejs.org/api/net.html#net_server_listen
2533
listeningApp.listen(socket, 511, (err) => {
2634
if (err) {
27-
onListeningCallback(err);
35+
fullCallback(err);
2836
} else {
29-
chmodSocket(onListeningCallback);
37+
chmodSocket(fullCallback);
3038
}
3139
});
3240
};
3341

34-
fs.access(socket, fs.constants.F_OK, (err) => {
35-
if (err) {
42+
fs.access(socket, fs.constants.F_OK, (e) => {
43+
if (e) {
3644
// file does not exist
3745
startSocket();
3846
} else {
@@ -56,7 +64,7 @@ function startUnixSocket(
5664
clientSocket.destroy();
5765
// do not call onListening or the setup method, since the server
5866
// cannot start listening on a used socket
59-
errorCallback(err);
67+
userCallback(err);
6068
});
6169
}
6270
});

test/helpers/test-unix-socket.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
const http = require('http');
4+
5+
const TestUnixSocket = class TestUnixSocket {
6+
constructor() {
7+
this.server = http.createServer();
8+
this.sockets = new Set();
9+
this.server.on('connection', (socket) => {
10+
this.sockets.add(socket);
11+
socket.on('close', () => {
12+
this.sockets.delete(socket);
13+
});
14+
});
15+
}
16+
17+
close(done) {
18+
// get rid of connected sockets
19+
for (const socket of this.sockets.values()) {
20+
socket.destroy();
21+
}
22+
this.server.close(done);
23+
}
24+
};
25+
26+
module.exports = TestUnixSocket;

test/server/socket-option.test.js

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
'use strict';
22

3-
const http = require('http');
43
const net = require('net');
54
const fs = require('fs');
65
const path = require('path');
76
const webpack = require('webpack');
87
const testServer = require('../helpers/test-server');
8+
const TestUnixSocket = require('../helpers/test-unix-socket');
9+
const { skipTestOnWindows } = require('../helpers/conditional-test');
910
const config = require('../fixtures/simple-config/webpack.config');
1011
const Server = require('../../lib/Server');
11-
const { skipTestOnWindows } = require('../helpers/conditional-test');
1212

1313
describe('socket', () => {
1414
const socketPath = path.join('.', 'socket-option.webpack.sock');
@@ -87,19 +87,12 @@ describe('socket', () => {
8787
return;
8888
}
8989

90-
let dummyServer;
91-
const sockets = new Set();
90+
let testUnixSocket;
9291
beforeAll((done) => {
93-
dummyServer = http.createServer();
94-
dummyServer.listen(socketPath, 511, () => {
92+
testUnixSocket = new TestUnixSocket();
93+
testUnixSocket.server.listen(socketPath, 511, () => {
9594
done();
9695
});
97-
dummyServer.on('connection', (socket) => {
98-
sockets.add(socket);
99-
socket.on('close', () => {
100-
sockets.delete(socket);
101-
});
102-
});
10396
});
10497

10598
it('should work as Unix socket', (done) => {
@@ -118,21 +111,13 @@ describe('socket', () => {
118111
});
119112

120113
afterAll((done) => {
121-
// get rid of connected sockets on the dummyServer
122-
for (const socket of sockets.values()) {
123-
socket.destroy();
124-
}
125-
dummyServer.close(() => {
114+
testUnixSocket.close(() => {
126115
fs.unlink(socketPath, done);
127116
});
128117
});
129118
});
130119

131120
describe('path to existent, unused file', () => {
132-
if (skipTestOnWindows('Unix sockets are not supported on Windows')) {
133-
return;
134-
}
135-
136121
let devServer;
137122
const options = {
138123
socket: socketPath,
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
'use strict';
2+
3+
const net = require('net');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const TestUnixSocket = require('../../helpers/test-unix-socket');
7+
const { skipTestOnWindows } = require('../../helpers/conditional-test');
8+
const startUnixSocket = require('../../../lib/utils/startUnixSocket');
9+
10+
describe('startUnixSocket', () => {
11+
const socketPath = path.join('.', 'startUnixSocket.webpack.sock');
12+
let testUnixSocket = null;
13+
14+
describe('path to a non-existent file', () => {
15+
let err;
16+
beforeAll((done) => {
17+
testUnixSocket = new TestUnixSocket();
18+
startUnixSocket(
19+
testUnixSocket.server,
20+
socketPath,
21+
() => {},
22+
(e) => {
23+
err = e;
24+
done();
25+
}
26+
);
27+
});
28+
29+
it('should work as Unix socket or error on windows', (done) => {
30+
if (process.platform === 'win32') {
31+
expect(err.code).toEqual('EACCES');
32+
done();
33+
} else {
34+
const clientSocket = new net.Socket();
35+
clientSocket.connect({ path: socketPath }, () => {
36+
// this means the connection was made successfully
37+
expect(true).toBeTruthy();
38+
done();
39+
});
40+
}
41+
});
42+
43+
afterAll((done) => {
44+
testUnixSocket.close(() => {
45+
fs.unlink(socketPath, done);
46+
});
47+
});
48+
});
49+
50+
describe('path to existent, unused file', () => {
51+
if (skipTestOnWindows('Unix sockets are not supported on Windows')) {
52+
return;
53+
}
54+
55+
beforeAll((done) => {
56+
fs.writeFileSync(socketPath, '');
57+
testUnixSocket = new TestUnixSocket();
58+
startUnixSocket(testUnixSocket.server, socketPath, () => {}, done);
59+
});
60+
61+
it('should work as Unix socket', (done) => {
62+
const clientSocket = new net.Socket();
63+
clientSocket.connect({ path: socketPath }, () => {
64+
// this means the connection was made successfully
65+
expect(true).toBeTruthy();
66+
done();
67+
});
68+
});
69+
70+
afterAll((done) => {
71+
testUnixSocket.close(() => {
72+
fs.unlink(socketPath, done);
73+
});
74+
});
75+
});
76+
77+
describe('path to existent file with listening server', () => {
78+
if (skipTestOnWindows('Unix sockets are not supported on Windows')) {
79+
return;
80+
}
81+
82+
let dummyUnixSocket;
83+
beforeAll((done) => {
84+
dummyUnixSocket = new TestUnixSocket();
85+
dummyUnixSocket.server.listen(socketPath, 511, () => {
86+
done();
87+
});
88+
});
89+
90+
it('should work as Unix socket', (done) => {
91+
testUnixSocket = new TestUnixSocket();
92+
startUnixSocket(
93+
testUnixSocket.server,
94+
socketPath,
95+
() => {},
96+
(err) => {
97+
expect(err).not.toBeNull();
98+
expect(err).not.toBeUndefined();
99+
expect(err.message).toEqual('This socket is already used');
100+
testUnixSocket.close(done);
101+
}
102+
);
103+
});
104+
105+
afterAll((done) => {
106+
dummyUnixSocket.close(() => {
107+
fs.unlink(socketPath, done);
108+
});
109+
});
110+
});
111+
112+
describe('path to existent, unused file', () => {
113+
beforeAll(() => {
114+
fs.writeFileSync(socketPath, '');
115+
testUnixSocket = new TestUnixSocket();
116+
});
117+
118+
// this test is significant because previously the callback was called
119+
// twice if a file at the given socket path already existed, but
120+
// could be removed
121+
it('should only call server.listen callback once', (done) => {
122+
const userCallback = jest.fn();
123+
startUnixSocket(
124+
testUnixSocket.server,
125+
socketPath,
126+
() => {},
127+
userCallback
128+
);
129+
setTimeout(() => {
130+
expect(userCallback).toBeCalledTimes(1);
131+
done();
132+
}, 10000);
133+
});
134+
135+
afterAll((done) => {
136+
testUnixSocket.close(done);
137+
});
138+
});
139+
});

0 commit comments

Comments
 (0)