Skip to content

Commit 93c52bf

Browse files
committed
Working docker testing set-up with pureftpd
1 parent 8dd2a00 commit 93c52bf

21 files changed

+792
-236
lines changed

.npmignore

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,13 @@ coverage.html
33
lib-cov
44
reports
55
.c9revisions
6-
test
6+
/test/
7+
/.vscode
8+
.nyc_output
9+
.editorconfig
10+
.eslintrc
11+
.travis.yml
12+
Dockerfile
13+
jsconfig.json
14+
README.md
715
node_modules

.vscode/launch.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Launch",
6+
"type": "node",
7+
"request": "launch",
8+
"program": "${workspaceRoot}/lib/jsftp.js",
9+
"stopOnEntry": false,
10+
"args": [],
11+
"cwd": "${workspaceRoot}",
12+
"preLaunchTask": null,
13+
"runtimeExecutable": null,
14+
"runtimeArgs": [
15+
"--nolazy"
16+
],
17+
"env": {
18+
"NODE_ENV": "development"
19+
},
20+
"console": "internalConsole",
21+
"sourceMaps": false
22+
},
23+
{
24+
"name": "Run mocha",
25+
"type": "node",
26+
"request": "launch",
27+
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
28+
"stopOnEntry": false,
29+
"args": [
30+
"-R",
31+
"spec",
32+
"-t",
33+
"5000"
34+
],
35+
"cwd": "${workspaceRoot}",
36+
"runtimeExecutable": null,
37+
"env": {
38+
"NODE_ENV": "development"
39+
}
40+
},
41+
{
42+
"name": "Attach",
43+
"type": "node",
44+
"request": "attach",
45+
"port": 5858,
46+
"address": "localhost",
47+
"restart": false,
48+
"sourceMaps": false,
49+
"outDir": null,
50+
"localRoot": "${workspaceRoot}",
51+
"remoteRoot": null
52+
}
53+
]
54+
}

Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM node:alpine AS build-env-node
2+
ENV DEBUG=jsftp
3+
WORKDIR /jsftp
4+
COPY package.json .
5+
RUN npm install
6+
COPY ./lib/jsftp.js ./index.js
7+
COPY ./test/ ./test/

Makefile

Lines changed: 0 additions & 25 deletions
This file was deleted.

README.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ conciseness. It doesn't get in the way and plays nice with streaming APIs.
1717
## Starting it up
1818

1919
```javascript
20-
var JSFtp = require("jsftp");
20+
const jsftp = require("jsftp");
2121

22-
var Ftp = new JSFtp({
22+
const Ftp = new jsftp({
2323
host: "myserver.com",
2424
port: 3331, // defaults to 21
2525
user: "user", // defaults to "anonymous"
@@ -37,8 +37,7 @@ callback, in the form of an object that contains two properties: `code`, which
3737
is the response code of the FTP operation, and `text`, which is the complete
3838
text of the response.
3939

40-
Raw (or native) commands are accessible in the form `Ftp.raw(command, params,
41-
callback)`
40+
Raw (or native) commands are accessible in the form `Ftp.raw(command, params, callback)`
4241

4342
Thus, a command like `QUIT` will be called like this:
4443

@@ -104,7 +103,7 @@ const ftp = new Ffp({
104103

105104
destination: {
106105
host,
107-
port
106+
port
108107
}
109108
})
110109
}
@@ -161,9 +160,7 @@ file properties.
161160

162161
```javascript
163162
ftp.ls(".", (err, res) => {
164-
res.forEach(file => {
165-
console.log(file.name);
166-
});
163+
res.forEach(file => console.log(file.name));
167164
});
168165
```
169166

@@ -200,7 +197,9 @@ ftp.get("remote/path/file.txt", (err, socket) => {
200197
});
201198

202199
socket.on("close", err => {
203-
if (hadErr) console.error("There was an error retrieving the file.");
200+
if (hadErr) {
201+
console.error("There was an error retrieving the file.");
202+
}
204203
});
205204

206205
socket.resume();
@@ -306,19 +305,24 @@ Ftp.on("jsftp_debug", function(eventType, data) {
306305

307306
## Tests and Coverage
308307

308+
JSFtp tests against ProFTPD by default. To accomplish that, it uses a Docker set-up, so you'll need Docker installed in your machine in order to run tests.
309+
309310
To run tests and coverage reports:
310311

311312
npm test
312313

313314
...
314-
41 tests passing (6s)
315-
316-
|----------|----------|----------|----------|----------|----------------|
317-
|File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
318-
|----------|----------|----------|----------|----------|----------------|
319-
|All files | 88 | 74.87 | 95.45 | 88 | |
320-
| jsftp.js | 88 | 74.87 | 95.45 | 88 |... 693,695,704 |
321-
|----------|----------|----------|----------|----------|----------------|
315+
43 passing (10s)
316+
317+
|-----------|----------|----------|----------|----------|----------------|
318+
|File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
319+
|-----------|----------|----------|----------|----------|----------------|
320+
|All files | 86.47 | 73.17 | 95.45 | 86.47 | |
321+
|jsftp | 100 | 100 | 100 | 100 | |
322+
| index.js | 100 | 100 | 100 | 100 | |
323+
|jsftp/lib | 86.43 | 73.17 | 95.45 | 86.43 | |
324+
| jsftp.js | 86.43 | 73.17 | 95.45 | 86.43 |... 722,724,733 |
325+
|-----------|----------|----------|----------|----------|----------------|
322326

323327
## License
324328

lib/jsftp.js

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
"use strict";
1111

12-
const createConnection = require("net").createConnection;
12+
const createConnection = require("net").createConnection;
1313
const EventEmitter = require("events").EventEmitter;
1414
const inherits = require("util").inherits;
1515
const stream = require("stream");
@@ -39,18 +39,6 @@ const expectedMarks = {
3939
const RE_PASV = /([-\d]+,[-\d]+,[-\d]+,[-\d]+),([-\d]+),([-\d]+)/;
4040
const FTP_NEWLINE = /\r\n|\n/;
4141

42-
function getPasvPort(text) {
43-
const match = RE_PASV.exec(text);
44-
if (!match) {
45-
return null;
46-
}
47-
48-
return {
49-
host: match[1].replace(/,/g, "."),
50-
port: (parseInt(match[2], 10) & 255) * 256 + (parseInt(match[3], 10) & 255)
51-
};
52-
}
53-
5442
function runCmd(name, ...params) {
5543
let callback = NOOP;
5644
let completeCmd = name + " ";
@@ -110,7 +98,9 @@ Ftp.prototype._createSocket = function(port, host, firstAction = NOOP) {
11098
this.resParser = new ResponseParser();
11199

112100
this.authenticated = false;
113-
this.socket = this.createSocket ? this.createSocket({port, host}, firstAction) : createConnection(port, host, firstAction);
101+
this.socket = this.createSocket
102+
? this.createSocket({ port, host }, firstAction)
103+
: createConnection(port, host, firstAction);
114104
this.socket.on("connect", this.reemit("connect"));
115105
this.socket.on("timeout", this.reemit("timeout"));
116106

@@ -234,11 +224,28 @@ Ftp.prototype.parse = function(response, command) {
234224
err.code = response.code;
235225
}
236226

237-
command.callback(err, response);
238227
this.inProgress = false;
228+
command.callback(err, response);
239229
this.nextCmd();
240230
};
241231

232+
Ftp.prototype.getPasvPort = function(text) {
233+
const match = RE_PASV.exec(text);
234+
if (!match) {
235+
return null;
236+
}
237+
238+
let host = match[1].replace(/,/g, ".");
239+
if (host === "127.0.0.1") {
240+
host = this.host;
241+
}
242+
243+
return {
244+
host,
245+
port: (parseInt(match[2], 10) & 255) * 256 + (parseInt(match[3], 10) & 255)
246+
};
247+
};
248+
242249
/**
243250
* Returns true if the current server has the requested feature.
244251
*
@@ -607,7 +614,6 @@ Ftp.prototype.getPutSocket = function(from, path, next) {
607614
}
608615
return next(new Error("Unexpected command " + res.text));
609616
}
610-
611617
});
612618

613619
callback.expectsMark = expectedMarks;
@@ -633,12 +639,14 @@ Ftp.prototype.getPasvSocket = function(callback = NOOP) {
633639
return callback(err);
634640
}
635641

636-
const options = getPasvPort(res.text);
642+
const options = this.getPasvPort(res.text);
637643
if (!options) {
638644
return callback(new Error("Bad passive host/port combination"));
639645
}
640646

641-
const socket = (this._pasvSocket = this.createSocket ? this.createSocket(options) : createConnection(options));
647+
const socket = (this._pasvSocket = this.createSocket
648+
? this.createSocket(options)
649+
: createConnection(options));
642650
socket.setTimeout(this.timeout || TIMEOUT);
643651
socket.once("close", () => {
644652
this._pasvSocket = undefined;

package.json

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
{
22
"name": "jsftp",
33
"id": "jsftp",
4-
"version": "2.1.2",
4+
"version": "2.1.3",
55
"description": "A sane FTP client implementation for NodeJS",
6-
"keywords": [
7-
"ftp",
8-
"protocol",
9-
"files",
10-
"server",
11-
"client",
12-
"async"
13-
],
14-
"author": "Sergi Mansilla <[email protected]> (http://sergimansilla.com)",
6+
"keywords": ["ftp", "protocol", "files", "server", "client", "async"],
7+
"author":
8+
"Sergi Mansilla <[email protected]> (https://sergimansilla.com)",
159
"homepage": "https://github.com/sergi/jsftp",
1610
"repository": {
1711
"type": "git",
@@ -30,22 +24,20 @@
3024
},
3125
"devDependencies": {
3226
"concat-stream": "^1.6.0",
33-
"eslint": "^4.12.1",
34-
"eslint-plugin-security": "^1.4.0",
35-
"ftp-test-server": "0.0.2",
36-
"ftpd": "github:sstur/nodeftpd#0d299f7",
3727
"mocha": "^4.0.1",
3828
"nyc": "^11.4.0",
3929
"rimraf": "^2.6.1",
4030
"sinon": "^4.1.2"
4131
},
42-
"main": "lib/jsftp.js",
32+
"main": "index.js",
4333
"engines": {
4434
"node": ">=6"
4535
},
4636
"scripts": {
47-
"test": "nyc mocha -R spec -t 5000",
48-
"clean": "rm -rf reports"
37+
"test": "make -f test/Makefile test-pureftpd",
38+
"run-mocha": "nyc mocha -R spec -t 5000",
39+
"clean": "rm -rf reports",
40+
"check-format": "prettier --list-different ./lib/**"
4941
},
5042
"license": "MIT"
5143
}

test/Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Foolproof way to always have ROOT_DIR refer to this very folder
2+
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
3+
4+
build-pureftpd:
5+
docker build --rm -t pure-ftp-demo $(ROOT_DIR)/pureftpd
6+
7+
test-pureftpd: kill-pureftpd
8+
docker run -d --name pureftpd_server -p 21:21 -p 30000-30009:30000-30009 -e "PUBLICHOST=localhost" -e "ADDED_FLAGS=-d -d" pure-ftp-demo
9+
docker exec -it pureftpd_server sh -c "(echo test; echo test) | pure-pw useradd bob -f /etc/pure-ftpd/passwd/pureftpd.passwd -m -u ftpuser -d /home/ftpusers/bob"
10+
npm run run-mocha
11+
12+
kill-pureftpd:
13+
-docker kill pureftpd_server
14+
-docker rm pureftpd_server
15+
16+
.PHONY: build-pureftpd test-pureftpd kill-pureftpd

test/docker-compose.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
version: '3'
2+
3+
services:
4+
pureftpd:
5+
container_name: ftpd_server
6+
environment:
7+
- PUBLICHOST=localhost
8+
- ADDED_FLAGS=-d -d
9+
build: ./pureftpd
10+
ports:
11+
- "21:21"
12+
- "30000-30009:30000-30009"
13+
# expose:
14+
# - "21"
15+
# - "30000-30009"
16+
vsftpd:
17+
container_name: vsftpd_server
18+
environment:
19+
- FTP_USER=bob
20+
- FTP_PASS=test
21+
- PASV_MIN_PORT=21100
22+
- PASV_MAX_PORT=21110
23+
build: ./vsftpd
24+
ports:
25+
- "7001:21"
26+
- "21100-21110:21100-21110"
27+
# integration-test:
28+
# build: ..
29+
# environment:
30+
# - DEBUG=jsftp
31+
# command: npm run test
32+
# links:
33+
# - pureftpd

0 commit comments

Comments
 (0)