ssh-client-wrapper 2.13.2 → 2.15.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.
- package/README.md +34 -0
- package/lib/index.d.ts +61 -0
- package/lib/index.js +36 -0
- package/lib/rsyncExec.js +67 -0
- package/lib/util.js +6 -0
- package/package.json +4 -2
- package/.dockerignore +0 -2
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/coverage_report.yml +0 -24
- package/.github/workflows/release.yml +0 -29
- package/.github/workflows/run_test.yml +0 -40
- package/.husky/_pre-commit +0 -1
- package/.husky/pre-commit +0 -1
- package/.releaserc.json +0 -16
- package/CHANGELOG.md +0 -27
- package/Dockerfile +0 -7
- package/Dockerfile-bullseye +0 -7
- package/Dockerfile-buster +0 -7
- package/compose.yml +0 -36
- package/eslint.config.mjs +0 -181
- package/run_test_all.sh +0 -18
- package/run_test_local.sh +0 -13
- package/test/getSshOption.js +0 -49
- package/test/interface.js +0 -182
- package/test/rsyncExec.js +0 -406
- package/test/sanityCheck.js +0 -106
- package/test/sshExec.js +0 -145
- package/test/testUtil/hostInfo.js +0 -9
- package/test/testUtil/testFiles.js +0 -101
- package/test/testUtil/testrc +0 -1
package/run_test_all.sh
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
function cleanup(){
|
|
3
|
-
docker compose down
|
|
4
|
-
}
|
|
5
|
-
trap cleanup EXIT
|
|
6
|
-
set -e -o pipefail
|
|
7
|
-
|
|
8
|
-
./run_test_local.sh keep
|
|
9
|
-
|
|
10
|
-
docker compose run --build --rm tester
|
|
11
|
-
echo test on latest ubuntu success
|
|
12
|
-
|
|
13
|
-
docker compose run --build --rm tester-bullseye
|
|
14
|
-
echo test on bullseye success
|
|
15
|
-
|
|
16
|
-
docker compose run --build --rm tester-buster
|
|
17
|
-
echo test on buster success
|
|
18
|
-
docker compose down
|
package/run_test_local.sh
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
docker compose up testbed -d
|
|
3
|
-
export TEST_HOST=localhost
|
|
4
|
-
export TEST_USER=testuser
|
|
5
|
-
export TEST_PW=passw0rd
|
|
6
|
-
export TEST_PORT=4100
|
|
7
|
-
ssh-keygen -R '[localhost]:4100'
|
|
8
|
-
|
|
9
|
-
npm run test
|
|
10
|
-
echo local test success
|
|
11
|
-
if [ x${1} != xkeep ];then
|
|
12
|
-
docker compose down
|
|
13
|
-
fi
|
package/test/getSshOption.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
process.on("unhandledRejection", console.dir);
|
|
2
|
-
|
|
3
|
-
//setup test framework
|
|
4
|
-
import * as chai from "chai";
|
|
5
|
-
import { expect } from "chai";
|
|
6
|
-
import chaiAsPromised from "chai-as-promised";
|
|
7
|
-
chai.use(chaiAsPromised);
|
|
8
|
-
|
|
9
|
-
//testee
|
|
10
|
-
import { getSshOption } from "../lib/util.js";
|
|
11
|
-
|
|
12
|
-
describe("test for getSshOption", ()=>{
|
|
13
|
-
const defaultValues = {
|
|
14
|
-
host: "testHostName",
|
|
15
|
-
ControlPersist: 180,
|
|
16
|
-
maxRetry: 3,
|
|
17
|
-
retryDuration: 1000
|
|
18
|
-
};
|
|
19
|
-
it("should return minimum ssh option array", ()=>{
|
|
20
|
-
const sshOpts = getSshOption(defaultValues);
|
|
21
|
-
expect(sshOpts).to.be.an("array");
|
|
22
|
-
expect(sshOpts).to.have.lengthOf(4);
|
|
23
|
-
expect(sshOpts[0]).to.equal(defaultValues.host);
|
|
24
|
-
expect(sshOpts[1]).to.equal("-oControlMaster=auto");
|
|
25
|
-
expect(sshOpts[2]).to.equal("-oControlPath=~/.ssh/ssh-client-wrapper-%r@%h:%p");
|
|
26
|
-
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
27
|
-
});
|
|
28
|
-
it("should change ControlPath by ControlPersistDir", ()=>{
|
|
29
|
-
const hostInfo = { ...defaultValues };
|
|
30
|
-
hostInfo.ControlPersistDir = "/tmp";
|
|
31
|
-
const sshOpts = getSshOption(hostInfo);
|
|
32
|
-
expect(sshOpts).to.be.an("array");
|
|
33
|
-
expect(sshOpts).to.have.lengthOf(4);
|
|
34
|
-
expect(sshOpts[0]).to.equal(defaultValues.host);
|
|
35
|
-
expect(sshOpts[1]).to.equal("-oControlMaster=auto");
|
|
36
|
-
expect(sshOpts[2]).to.equal("-oControlPath=/tmp/ssh-client-wrapper-%r@%h:%p");
|
|
37
|
-
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
38
|
-
});
|
|
39
|
-
it("should change ControlPath by Environment variable", ()=>{
|
|
40
|
-
process.env.SSH_CONTROL_PERSIST_DIR = "/tmp";
|
|
41
|
-
const sshOpts = getSshOption(defaultValues);
|
|
42
|
-
expect(sshOpts).to.be.an("array");
|
|
43
|
-
expect(sshOpts).to.have.lengthOf(4);
|
|
44
|
-
expect(sshOpts[0]).to.equal(defaultValues.host);
|
|
45
|
-
expect(sshOpts[1]).to.equal("-oControlMaster=auto");
|
|
46
|
-
expect(sshOpts[2]).to.equal("-oControlPath=/tmp/ssh-client-wrapper-%r@%h:%p");
|
|
47
|
-
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
48
|
-
});
|
|
49
|
-
});
|
package/test/interface.js
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
process.on("unhandledRejection", console.dir);
|
|
2
|
-
Error.traceLimit = 100000;
|
|
3
|
-
|
|
4
|
-
//setup test framework
|
|
5
|
-
import * as chai from "chai";
|
|
6
|
-
import { expect } from "chai";
|
|
7
|
-
import sinon from "sinon";
|
|
8
|
-
import sinonChai from "sinon-chai";
|
|
9
|
-
import chaiAsPromised from "chai-as-promised";
|
|
10
|
-
chai.use(sinonChai);
|
|
11
|
-
chai.use(chaiAsPromised);
|
|
12
|
-
|
|
13
|
-
//testee
|
|
14
|
-
import SshClientWrapper from "../lib/index.js";
|
|
15
|
-
|
|
16
|
-
const sshExec = sinon.stub();
|
|
17
|
-
const canConnect = sinon.stub();
|
|
18
|
-
const disconnect = sinon.stub();
|
|
19
|
-
const expectStub = sinon.stub();
|
|
20
|
-
const send = sinon.stub();
|
|
21
|
-
const recv = sinon.stub();
|
|
22
|
-
|
|
23
|
-
const deps = {
|
|
24
|
-
sshExec,
|
|
25
|
-
canConnect,
|
|
26
|
-
disconnect,
|
|
27
|
-
expect: expectStub,
|
|
28
|
-
send,
|
|
29
|
-
recv
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
describe("test for interface", ()=>{
|
|
33
|
-
describe("test for constructor", ()=>{
|
|
34
|
-
it("should throw error when instanciate with non-empty string host", ()=>{
|
|
35
|
-
expect(()=>{
|
|
36
|
-
new SshClientWrapper({}, deps);
|
|
37
|
-
}).to.throw("host is required");
|
|
38
|
-
expect(()=>{
|
|
39
|
-
new SshClientWrapper({ host: "" }, deps);
|
|
40
|
-
}).to.throw("empty host is not allowed");
|
|
41
|
-
});
|
|
42
|
-
it("should successfully instanciate only with host prop", ()=>{
|
|
43
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("exec");
|
|
44
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("execAndGetOutput");
|
|
45
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("ls");
|
|
46
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("expect");
|
|
47
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("send");
|
|
48
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("recv");
|
|
49
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("canConnect");
|
|
50
|
-
expect(new SshClientWrapper({ host: "hoge" }, deps)).to.have.property("disconnect");
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
describe("test for public method", ()=>{
|
|
54
|
-
let ssh;
|
|
55
|
-
const hostInfoOrg = {
|
|
56
|
-
host: "hoge",
|
|
57
|
-
ControlPersist: 180,
|
|
58
|
-
maxRetry: 3,
|
|
59
|
-
retryDuration: 1000
|
|
60
|
-
};
|
|
61
|
-
const hostInfo = { ...hostInfoOrg, masterPty: null, rsyncVersion: null };
|
|
62
|
-
beforeEach(()=>{
|
|
63
|
-
ssh = new SshClientWrapper(hostInfoOrg, deps);
|
|
64
|
-
sshExec.reset();
|
|
65
|
-
canConnect.reset();
|
|
66
|
-
disconnect.reset();
|
|
67
|
-
send.reset();
|
|
68
|
-
recv.reset();
|
|
69
|
-
expectStub.reset();
|
|
70
|
-
});
|
|
71
|
-
describe("test for exec", ()=>{
|
|
72
|
-
it("should call sshExec with cmd", ()=>{
|
|
73
|
-
ssh.exec("ls");
|
|
74
|
-
expect(sshExec).to.be.calledWith(hostInfo, "ls", 0, null);
|
|
75
|
-
});
|
|
76
|
-
it("should call sshExec with cmd and timeout", ()=>{
|
|
77
|
-
ssh.exec("ls", 10);
|
|
78
|
-
expect(sshExec).to.be.calledWith(hostInfo, "ls", 10, null);
|
|
79
|
-
});
|
|
80
|
-
it("should call sshExec with cmd, timeout and call back function", ()=>{
|
|
81
|
-
const cb = ()=>{};
|
|
82
|
-
ssh.exec("ls", 10, cb);
|
|
83
|
-
expect(sshExec).to.be.calledWith(hostInfo, "ls", 10, cb);
|
|
84
|
-
});
|
|
85
|
-
it("should reject if cmd is not string (number)", ()=>{
|
|
86
|
-
return expect(ssh.exec(0)).to.be.rejectedWith("cmd must be string");
|
|
87
|
-
});
|
|
88
|
-
it("should reject if cmd is not string (null)", ()=>{
|
|
89
|
-
return expect(ssh.exec(null)).to.be.rejectedWith("cmd must be string");
|
|
90
|
-
});
|
|
91
|
-
it("should reject if cmd is empty string", ()=>{
|
|
92
|
-
return expect(ssh.exec("")).to.be.rejectedWith("cmd must be string");
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
describe("test for ls", ()=>{
|
|
96
|
-
it("should call ls without timeout", ()=>{
|
|
97
|
-
ssh.ls("hoge");
|
|
98
|
-
expect(sshExec).to.be.calledWith(hostInfo, "ls hoge", 0);
|
|
99
|
-
});
|
|
100
|
-
it("should call ls with option", ()=>{
|
|
101
|
-
ssh.ls("hoge", ["-l", "-r", "-t"]);
|
|
102
|
-
expect(sshExec).to.be.calledWith(hostInfo, "ls -l -r -t hoge", 0);
|
|
103
|
-
});
|
|
104
|
-
it("should call ls with option and timeout", ()=>{
|
|
105
|
-
ssh.ls("hoge", ["-l", "-r", "-t"], 10);
|
|
106
|
-
expect(sshExec).to.be.calledWith(hostInfo, "ls -l -r -t hoge", 10);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
describe("test for send", ()=>{
|
|
110
|
-
it("should call send with src and dst", ()=>{
|
|
111
|
-
ssh.send(["src"], "dst");
|
|
112
|
-
expect(send).to.be.calledWith(hostInfo, ["src"], "dst", [], 0);
|
|
113
|
-
});
|
|
114
|
-
it("should call send with src, dst, and opt", ()=>{
|
|
115
|
-
ssh.send(["src"], "dst", ["--dry-run", "--delete"]);
|
|
116
|
-
expect(send).to.be.calledWith(hostInfo, ["src"], "dst", ["--dry-run", "--delete"], 0);
|
|
117
|
-
});
|
|
118
|
-
it("should call send with src, dst, opt, and timeout", ()=>{
|
|
119
|
-
ssh.send(["src"], "dst", ["--dry-run", "--delete"], 10);
|
|
120
|
-
expect(send).to.be.calledWith(hostInfo, ["src"], "dst", ["--dry-run", "--delete"], 10);
|
|
121
|
-
});
|
|
122
|
-
it("should be rejected if src is not array of string", ()=>{
|
|
123
|
-
return expect(ssh.send(1)).to.be.rejectedWith("src must be array of string");
|
|
124
|
-
});
|
|
125
|
-
it("should be rejected if src has only empty string element", ()=>{
|
|
126
|
-
return expect(ssh.send(["", ""])).to.be.rejectedWith("src must contain non-empty string");
|
|
127
|
-
});
|
|
128
|
-
it("should be rejected if src has only empty string element", ()=>{
|
|
129
|
-
return expect(ssh.send([""])).to.be.rejectedWith("src must contain non-empty string");
|
|
130
|
-
});
|
|
131
|
-
it("should be called if src includes empty string ", ()=>{
|
|
132
|
-
ssh.send(["src", ""], "dst");
|
|
133
|
-
expect(send).to.be.calledWith(hostInfo, ["src", ""], "dst", [], 0);
|
|
134
|
-
});
|
|
135
|
-
it("should be rejected if dst is not string", ()=>{
|
|
136
|
-
return expect(ssh.send(["src"], 0)).to.be.rejectedWith("dst must be string");
|
|
137
|
-
});
|
|
138
|
-
it("should be rejected if dst is empty string", ()=>{
|
|
139
|
-
return expect(ssh.send(["src"], "")).to.be.rejectedWith("dst must be non-empty string");
|
|
140
|
-
});
|
|
141
|
-
it("should be rejected if opt is not array of string", ()=>{
|
|
142
|
-
return expect(ssh.send(["src"], "dst", [null])).to.be.rejectedWith("opt must be array of string");
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
describe("test for recv", ()=>{
|
|
146
|
-
it("should call recv with src and dst", ()=>{
|
|
147
|
-
ssh.recv(["src"], "dst");
|
|
148
|
-
expect(recv).to.be.calledWith(hostInfo, ["src"], "dst", [], 0);
|
|
149
|
-
});
|
|
150
|
-
it("should call recv with src, dst, and opt", ()=>{
|
|
151
|
-
ssh.recv(["src"], "dst", ["--dry-run", "--delete"]);
|
|
152
|
-
expect(recv).to.be.calledWith(hostInfo, ["src"], "dst", ["--dry-run", "--delete"], 0);
|
|
153
|
-
});
|
|
154
|
-
it("should call recv with src, dst, opt, and timeout", ()=>{
|
|
155
|
-
ssh.recv(["src"], "dst", ["--dry-run", "--delete"], 10);
|
|
156
|
-
expect(recv).to.be.calledWith(hostInfo, ["src"], "dst", ["--dry-run", "--delete"], 10);
|
|
157
|
-
});
|
|
158
|
-
it("should be rejected if src is not array of string", ()=>{
|
|
159
|
-
return expect(ssh.recv(1)).to.be.rejectedWith("src must be array of string");
|
|
160
|
-
});
|
|
161
|
-
it("should be rejected if src has only empty string element", ()=>{
|
|
162
|
-
return expect(ssh.recv(["", ""])).to.be.rejectedWith("src must contain non-empty string");
|
|
163
|
-
});
|
|
164
|
-
it("should be rejected if src has only empty string element", ()=>{
|
|
165
|
-
return expect(ssh.recv([""])).to.be.rejectedWith("src must contain non-empty string");
|
|
166
|
-
});
|
|
167
|
-
it("should be called if src includes empty string ", ()=>{
|
|
168
|
-
ssh.recv(["src", ""], "dst");
|
|
169
|
-
expect(recv).to.be.calledWith(hostInfo, ["src", ""], "dst", [], 0);
|
|
170
|
-
});
|
|
171
|
-
it("should be rejected if dst is not string", ()=>{
|
|
172
|
-
return expect(ssh.recv(["src"], 0)).to.be.rejectedWith("dst must be string");
|
|
173
|
-
});
|
|
174
|
-
it("should be rejected if dst is empty string", ()=>{
|
|
175
|
-
return expect(ssh.recv(["src"], "")).to.be.rejectedWith("dst must be non-empty string");
|
|
176
|
-
});
|
|
177
|
-
it("should be rejected if opt is not array of string", ()=>{
|
|
178
|
-
return expect(ssh.recv(["src"], "dst", [null])).to.be.rejectedWith("opt must be array of string");
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
});
|
package/test/rsyncExec.js
DELETED
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
import fs from "fs-extra";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import util from "util";
|
|
4
|
-
import { exec as exec_ } from "node:child_process";
|
|
5
|
-
const exec = util.promisify(exec_);
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* to enable debug log dynamically
|
|
9
|
-
* (1) enable folloing line
|
|
10
|
-
* const debug = require("debug");
|
|
11
|
-
* (2) insert this line into the beginning of it()
|
|
12
|
-
* debug.enable("ssh*");
|
|
13
|
-
* (3) insert this line into the end of it()
|
|
14
|
-
* debug.disable();
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
process.on("unhandledRejection", console.dir);
|
|
18
|
-
Error.traceLimit = 100000;
|
|
19
|
-
|
|
20
|
-
//setup test framework
|
|
21
|
-
import * as chai from "chai";
|
|
22
|
-
import { expect } from "chai";
|
|
23
|
-
import chaiAsPromised from "chai-as-promised";
|
|
24
|
-
chai.use(chaiAsPromised);
|
|
25
|
-
|
|
26
|
-
//testee
|
|
27
|
-
import { checkRsyncVersion, send, recv } from "../lib/rsyncExec.js";
|
|
28
|
-
|
|
29
|
-
//test helpers
|
|
30
|
-
import { sshExec, disconnect } from "../lib/sshExec.js";
|
|
31
|
-
import hostInfo from "./testUtil/hostInfo.js";
|
|
32
|
-
import {
|
|
33
|
-
clearLocalTestFiles,
|
|
34
|
-
clearRemoteTestFiles,
|
|
35
|
-
createLocalFiles,
|
|
36
|
-
localRoot,
|
|
37
|
-
localEmptyDir,
|
|
38
|
-
localFiles,
|
|
39
|
-
createRemoteFiles,
|
|
40
|
-
remoteRoot,
|
|
41
|
-
remoteEmptyDir,
|
|
42
|
-
remoteFiles
|
|
43
|
-
} from "./testUtil/testFiles.js";
|
|
44
|
-
|
|
45
|
-
const formatLsOutput = (array)=>{
|
|
46
|
-
const rt = [];
|
|
47
|
-
for (const e of array) {
|
|
48
|
-
rt.push(...e.split("\n"));
|
|
49
|
-
}
|
|
50
|
-
return rt.filter((e)=>{
|
|
51
|
-
return e !== "";
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
//actual test start from here
|
|
56
|
-
describe("test checkRsyncVersion", async ()=>{
|
|
57
|
-
const { major, minor, patch } = await checkRsyncVersion(1);
|
|
58
|
-
const versionString = `${major}.${minor}.${patch}`;
|
|
59
|
-
console.log(`==== test with rsync version ${versionString} ====`);
|
|
60
|
-
const { stdout } = await exec("rsync --version |grep 'version'");
|
|
61
|
-
expect(stdout).to.match(new RegExp(versionString));
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe("test rsync exec", function () {
|
|
65
|
-
this.timeout(10000);
|
|
66
|
-
const rt = [];
|
|
67
|
-
const output = (data)=>{
|
|
68
|
-
rt.push(data);
|
|
69
|
-
};
|
|
70
|
-
let remoteHome;
|
|
71
|
-
before(async ()=>{
|
|
72
|
-
await sshExec(hostInfo, "pwd", 0, (data)=>{
|
|
73
|
-
remoteHome = data.trim();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
beforeEach(async ()=>{
|
|
77
|
-
await clearRemoteTestFiles(hostInfo);
|
|
78
|
-
await createRemoteFiles(hostInfo);
|
|
79
|
-
await clearLocalTestFiles();
|
|
80
|
-
await createLocalFiles();
|
|
81
|
-
rt.splice(0, rt.length);
|
|
82
|
-
});
|
|
83
|
-
after(async ()=>{
|
|
84
|
-
if (!process.env.TEST_KEEP_FILES) {
|
|
85
|
-
await clearRemoteTestFiles(hostInfo);
|
|
86
|
-
await clearLocalTestFiles();
|
|
87
|
-
}
|
|
88
|
-
await disconnect(hostInfo);
|
|
89
|
-
});
|
|
90
|
-
describe("#send", async ()=>{
|
|
91
|
-
describe("send single file", ()=>{
|
|
92
|
-
it("should accept relative src file and relative dst dir name", async ()=>{
|
|
93
|
-
await send(hostInfo, [localFiles[0]], remoteEmptyDir, [], 0);
|
|
94
|
-
|
|
95
|
-
await sshExec(hostInfo, `ls ${remoteEmptyDir}`, 0, output);
|
|
96
|
-
expect(formatLsOutput(rt)).to.have.members(["foo"]);
|
|
97
|
-
});
|
|
98
|
-
it("should accept absolute src file and relative dst dir name", async ()=>{
|
|
99
|
-
await send(hostInfo, [path.resolve(localFiles[3])], remoteEmptyDir, [], 0);
|
|
100
|
-
|
|
101
|
-
await sshExec(hostInfo, `ls ${remoteEmptyDir}`, 0, output);
|
|
102
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo"]);
|
|
103
|
-
});
|
|
104
|
-
it("should accept relative src file and absolute dst dir name", async ()=>{
|
|
105
|
-
await send(hostInfo, [localFiles[0]], `${path.posix.join(remoteHome, remoteEmptyDir)}/`, [], 0);
|
|
106
|
-
|
|
107
|
-
await sshExec(hostInfo, `ls ${remoteEmptyDir}`, 0, output);
|
|
108
|
-
expect(formatLsOutput(rt)).to.have.members(["foo"]);
|
|
109
|
-
});
|
|
110
|
-
it("should accept absolute src file and absolute dst dir name", async ()=>{
|
|
111
|
-
await send(hostInfo, [path.resolve(localFiles[0])], path.posix.join(remoteHome, remoteEmptyDir), [], 0);
|
|
112
|
-
|
|
113
|
-
await sshExec(hostInfo, `ls ${remoteEmptyDir}`, 0, output);
|
|
114
|
-
expect(formatLsOutput(rt)).to.have.members(["foo"]);
|
|
115
|
-
});
|
|
116
|
-
it("should accept relative src file and relative dst file name", async ()=>{
|
|
117
|
-
await send(hostInfo, [localFiles[0]], path.posix.join(remoteEmptyDir, "hoge"), [], 0);
|
|
118
|
-
|
|
119
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, "hoge")}`, 0, output);
|
|
120
|
-
expect(formatLsOutput(rt.map((e)=>{
|
|
121
|
-
return path.posix.basename(e);
|
|
122
|
-
}))).to.have.members(["hoge"]);
|
|
123
|
-
});
|
|
124
|
-
it("should accept absolute src file and relative dst file name", async ()=>{
|
|
125
|
-
await send(hostInfo, [path.resolve(localFiles[0])], path.posix.join(remoteEmptyDir, "hoge"), [], 0);
|
|
126
|
-
|
|
127
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, "hoge")}`, 0, output);
|
|
128
|
-
expect(formatLsOutput(rt.map((e)=>{
|
|
129
|
-
return path.posix.basename(e);
|
|
130
|
-
}))).to.have.members(["hoge"]);
|
|
131
|
-
});
|
|
132
|
-
it("should accept relative src file and absolute dst file name", async ()=>{
|
|
133
|
-
await send(hostInfo, [localFiles[0]], path.posix.join(remoteHome, remoteEmptyDir, "hoge"), [], 0);
|
|
134
|
-
|
|
135
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, "hoge")}`, 0, output);
|
|
136
|
-
expect(formatLsOutput(rt.map((e)=>{
|
|
137
|
-
return path.posix.basename(e);
|
|
138
|
-
}))).to.have.members(["hoge"]);
|
|
139
|
-
});
|
|
140
|
-
it("should accept absolute src file and absolute dst file name", async ()=>{
|
|
141
|
-
await send(hostInfo, [path.resolve(localFiles[0])], path.posix.join(remoteHome, remoteEmptyDir, "hoge"), [], 0);
|
|
142
|
-
|
|
143
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, "hoge")}`, 0, output);
|
|
144
|
-
expect(formatLsOutput(rt.map((e)=>{
|
|
145
|
-
return path.posix.basename(e);
|
|
146
|
-
}))).to.have.members(["hoge"]);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("should overwrite existing file", async ()=>{
|
|
150
|
-
const target = path.posix.join(remoteEmptyDir, "hoge");
|
|
151
|
-
await send(hostInfo, [localFiles[0]], target, [], 0);
|
|
152
|
-
await sshExec(hostInfo, `ls ${target}`, 0, output);
|
|
153
|
-
expect(formatLsOutput(rt.map((e)=>{
|
|
154
|
-
return path.posix.basename(e);
|
|
155
|
-
}))).to.have.members(["hoge"]);
|
|
156
|
-
rt.splice(0, rt.length);
|
|
157
|
-
|
|
158
|
-
const time = new Date();
|
|
159
|
-
time.setMinutes(time.getMinutes() + 3);
|
|
160
|
-
await fs.utimes(localFiles[1], time, time);
|
|
161
|
-
await send(hostInfo, [localFiles[1]], target, [], 0);
|
|
162
|
-
await sshExec(hostInfo, `ls ${target}`, 0, output);
|
|
163
|
-
expect(formatLsOutput(rt.map((e)=>{
|
|
164
|
-
return path.posix.basename(e);
|
|
165
|
-
}))).to.have.members(["hoge"]);
|
|
166
|
-
|
|
167
|
-
rt.splice(0, rt.length);
|
|
168
|
-
await sshExec(hostInfo, `cat ${target}`, 0, output);
|
|
169
|
-
expect(formatLsOutput(rt)).to.have.members(["ARssh_testLocalDir/bar"]);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
describe("send directory tree", ()=>{
|
|
173
|
-
it("should accept relative src dirname and relative dst dirname", async ()=>{
|
|
174
|
-
await send(hostInfo, [localRoot], remoteEmptyDir, [], 0);
|
|
175
|
-
|
|
176
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
177
|
-
expect(formatLsOutput(rt)).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
178
|
-
|
|
179
|
-
rt.splice(0, rt.length);
|
|
180
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot, "hoge")}`, 0, output);
|
|
181
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo", "puyo", "poyo"]);
|
|
182
|
-
});
|
|
183
|
-
it("should accept absolute src dirname and relative dst dirname", async ()=>{
|
|
184
|
-
await send(hostInfo, [path.resolve(localRoot)], remoteEmptyDir, [], 0);
|
|
185
|
-
|
|
186
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
187
|
-
expect(formatLsOutput(rt)).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
188
|
-
|
|
189
|
-
rt.splice(0, rt.length);
|
|
190
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot, "hoge")}`, 0, output);
|
|
191
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo", "puyo", "poyo"]);
|
|
192
|
-
});
|
|
193
|
-
it("should accept relative src dirname and absolute dst dirname", async ()=>{
|
|
194
|
-
await send(hostInfo, [localRoot], path.posix.join(remoteHome, remoteEmptyDir), [], 0);
|
|
195
|
-
|
|
196
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
197
|
-
expect(formatLsOutput(rt)).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
198
|
-
|
|
199
|
-
rt.splice(0, rt.length);
|
|
200
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot, "hoge")}`, 0, output);
|
|
201
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo", "puyo", "poyo"]);
|
|
202
|
-
});
|
|
203
|
-
it("should accept absolute src dirname and absolute dst dirname", async ()=>{
|
|
204
|
-
await send(hostInfo, [path.resolve(localRoot)], path.posix.join(remoteHome, remoteEmptyDir), [], 0);
|
|
205
|
-
|
|
206
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
207
|
-
expect(formatLsOutput(rt)).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
208
|
-
|
|
209
|
-
rt.splice(0, rt.length);
|
|
210
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot, "hoge")}`, 0, output);
|
|
211
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo", "puyo", "poyo"]);
|
|
212
|
-
});
|
|
213
|
-
//only option need special treatment in rsyncExec. it's hard to set in WHEEL
|
|
214
|
-
it.skip("[not implemented] should send directory tree if only filter matched", async ()=>{
|
|
215
|
-
await send(hostInfo, [localRoot], remoteEmptyDir, [`--include=${localRoot}`, `--include=${localRoot}/ba*`, `--include=${localRoot}/hoge/*`, "--exclude=*"], [], 0);
|
|
216
|
-
|
|
217
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
218
|
-
expect(formatLsOutput(rt)).to.have.members(["hoge", "bar", "baz"]);
|
|
219
|
-
|
|
220
|
-
rt.splice(0, rt.length);
|
|
221
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot, "hoge")}`, 0, output);
|
|
222
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo", "puyo", "poyo"]);
|
|
223
|
-
});
|
|
224
|
-
it("should send directory tree if exclude filter not matched", async ()=>{
|
|
225
|
-
await send(hostInfo, [localRoot], remoteEmptyDir, ["--exclude=ba*", "--exclude=hoge*}"], [], 0);
|
|
226
|
-
|
|
227
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
228
|
-
expect(formatLsOutput(rt)).to.have.members(["foo", "hoge", "huga"]);
|
|
229
|
-
});
|
|
230
|
-
it.skip("[not implemented] should send directory tree if only filter matched but exclude filter not matched", async ()=>{
|
|
231
|
-
await send(hostInfo, [localRoot], remoteEmptyDir, "*/{ba*,hoge/*}", "**/poyo", [], 0);
|
|
232
|
-
|
|
233
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot)}`, 0, output);
|
|
234
|
-
expect(formatLsOutput(rt)).to.have.members(["hoge", "bar", "baz"]);
|
|
235
|
-
|
|
236
|
-
rt.splice(0, rt.length);
|
|
237
|
-
await sshExec(hostInfo, `ls ${path.posix.join(remoteEmptyDir, localRoot, "hoge")}`, 0, output);
|
|
238
|
-
expect(formatLsOutput(rt)).to.have.members(["piyo", "puyo"]);
|
|
239
|
-
});
|
|
240
|
-
it("shoud not send empty directory with -m option", async ()=>{
|
|
241
|
-
await send(hostInfo, [localEmptyDir], remoteEmptyDir, ["-m"], [], 0);
|
|
242
|
-
|
|
243
|
-
await sshExec(hostInfo, `ls ${remoteEmptyDir}`, 0, output);
|
|
244
|
-
expect(rt).to.have.lengthOf(0);
|
|
245
|
-
});
|
|
246
|
-
it("should send files which match glob pattern", async ()=>{
|
|
247
|
-
await send(hostInfo, [path.join(localRoot, "b*")], remoteEmptyDir, [], 0);
|
|
248
|
-
|
|
249
|
-
await sshExec(hostInfo, `ls ${remoteEmptyDir}`, 0, output);
|
|
250
|
-
expect(formatLsOutput(rt)).to.have.members(["bar", "baz"]);
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
describe("error case", ()=>{
|
|
254
|
-
it("should not send directory to existing file path", ()=>{
|
|
255
|
-
return expect(send(hostInfo, [localRoot], path.posix.join(remoteRoot, "foo"), [], 0)).to.be.rejected;
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
describe("#recv", async ()=>{
|
|
260
|
-
describe("recieve single file", ()=>{
|
|
261
|
-
it("should accept relative src file and relative dst dir name", async ()=>{
|
|
262
|
-
await recv(hostInfo, [remoteFiles[3]], localEmptyDir, [], 0);
|
|
263
|
-
|
|
264
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
265
|
-
expect(rt2).to.have.members(["piyo"]);
|
|
266
|
-
});
|
|
267
|
-
it("should accept absolute src file and relative dst dir name", async ()=>{
|
|
268
|
-
await recv(hostInfo, [path.posix.join(remoteHome, remoteFiles[3])], localEmptyDir, [], 0);
|
|
269
|
-
|
|
270
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
271
|
-
expect(rt2).to.have.members(["piyo"]);
|
|
272
|
-
});
|
|
273
|
-
it("should accept relative src file and absolute dst dir name", async ()=>{
|
|
274
|
-
await recv(hostInfo, [remoteFiles[3]], path.resolve(localEmptyDir), [], 0);
|
|
275
|
-
|
|
276
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
277
|
-
expect(rt2).to.have.members(["piyo"]);
|
|
278
|
-
});
|
|
279
|
-
it("should accept absolute src file and absolute dst dir name", async ()=>{
|
|
280
|
-
await recv(hostInfo, [path.posix.join(remoteHome, remoteFiles[3])], path.resolve(localEmptyDir), [], 0);
|
|
281
|
-
|
|
282
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
283
|
-
expect(rt2).to.have.members(["piyo"]);
|
|
284
|
-
});
|
|
285
|
-
it("should accept relative src file and relative dst file name", async ()=>{
|
|
286
|
-
await recv(hostInfo, [remoteFiles[0]], path.join(localEmptyDir, "hoge"), [], 0);
|
|
287
|
-
|
|
288
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
289
|
-
expect(rt2).to.have.members(["hoge"]);
|
|
290
|
-
});
|
|
291
|
-
it("should accept absolute src file and relative dst file name", async ()=>{
|
|
292
|
-
await recv(hostInfo, [path.posix.join(remoteHome, remoteFiles[0])], path.join(localEmptyDir, "hoge"), [], 0);
|
|
293
|
-
|
|
294
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
295
|
-
expect(rt2).to.have.members(["hoge"]);
|
|
296
|
-
});
|
|
297
|
-
it("should accept relative src file and absolute dst file name", async ()=>{
|
|
298
|
-
await recv(hostInfo, [remoteFiles[0]], path.resolve(localEmptyDir, "hoge"), [], 0);
|
|
299
|
-
|
|
300
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
301
|
-
expect(rt2).to.have.members(["hoge"]);
|
|
302
|
-
});
|
|
303
|
-
it("should accept absolute src file and absolute dst file name", async ()=>{
|
|
304
|
-
await recv(hostInfo, [path.posix.join(remoteHome, remoteFiles[0])], path.resolve(localEmptyDir, "hoge"), [], 0);
|
|
305
|
-
|
|
306
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
307
|
-
expect(rt2).to.have.members(["hoge"]);
|
|
308
|
-
});
|
|
309
|
-
it("should accept glob pattern as src", async ()=>{
|
|
310
|
-
await recv(hostInfo, [path.posix.join(remoteRoot, "b*")], path.resolve(localEmptyDir), [], 0);
|
|
311
|
-
|
|
312
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
313
|
-
expect(rt2).to.have.members(["bar", "baz"]);
|
|
314
|
-
});
|
|
315
|
-
it("should accept glob pattern as src", async ()=>{
|
|
316
|
-
await recv(hostInfo, [path.posix.join(remoteRoot, "*/p[iu]yo")], path.resolve(localEmptyDir), [], 0);
|
|
317
|
-
|
|
318
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
319
|
-
expect(rt2).to.have.members(["piyo", "puyo"]);
|
|
320
|
-
});
|
|
321
|
-
it.skip("[temporarily disabled number 23 was thrown] should accept glob pattern as src", async ()=>{
|
|
322
|
-
await recv(hostInfo, [path.posix.join(remoteRoot, "hoge/p[iu]yo"), path.posix.join(remoteRoot, "foo")], path.resolve(localEmptyDir), [], 0);
|
|
323
|
-
|
|
324
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
325
|
-
expect(rt2).to.have.members(["piyo", "puyo", "foo"]);
|
|
326
|
-
});
|
|
327
|
-
});
|
|
328
|
-
describe("recieve directory tree", ()=>{
|
|
329
|
-
it("should get directory tree which match specified glob", async ()=>{
|
|
330
|
-
await recv(hostInfo, [path.posix.join(remoteRoot, "?o*")], localEmptyDir, [], 0);
|
|
331
|
-
|
|
332
|
-
let rt2 = await fs.readdir(localEmptyDir);
|
|
333
|
-
expect(rt2).to.have.members(["foo", "hoge"]);
|
|
334
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, "hoge"));
|
|
335
|
-
expect(rt2).to.have.members(["piyo", "puyo", "poyo"]);
|
|
336
|
-
});
|
|
337
|
-
it("should accept relative src dirname and relative dst dirname", async ()=>{
|
|
338
|
-
await recv(hostInfo, [remoteRoot], localEmptyDir, [], 0);
|
|
339
|
-
|
|
340
|
-
let rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
341
|
-
expect(rt2).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
342
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, remoteRoot, "hoge"));
|
|
343
|
-
expect(rt2).to.have.members(["piyo", "puyo", "poyo"]);
|
|
344
|
-
});
|
|
345
|
-
it("should accept absolute src dirname and relative dst dirname", async ()=>{
|
|
346
|
-
await recv(hostInfo, [path.posix.join(remoteHome, remoteRoot)], localEmptyDir, [], 0);
|
|
347
|
-
|
|
348
|
-
let rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
349
|
-
expect(rt2).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
350
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, remoteRoot, "hoge"));
|
|
351
|
-
expect(rt2).to.have.members(["piyo", "puyo", "poyo"]);
|
|
352
|
-
});
|
|
353
|
-
it("should accept relative src dirname and absolute dst dirname", async ()=>{
|
|
354
|
-
await recv(hostInfo, [remoteRoot], path.resolve(localEmptyDir), [], 0);
|
|
355
|
-
|
|
356
|
-
let rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
357
|
-
expect(rt2).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
358
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, remoteRoot, "hoge"));
|
|
359
|
-
expect(rt2).to.have.members(["piyo", "puyo", "poyo"]);
|
|
360
|
-
});
|
|
361
|
-
it("should accept absolute src dirname and absolute dst dirname", async ()=>{
|
|
362
|
-
await recv(hostInfo, [path.posix.join(remoteHome, remoteRoot)], path.resolve(localEmptyDir), [], 0);
|
|
363
|
-
|
|
364
|
-
let rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
365
|
-
expect(rt2).to.have.members(["foo", "bar", "baz", "hoge", "huga"]);
|
|
366
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, remoteRoot, "hoge"));
|
|
367
|
-
expect(rt2).to.have.members(["piyo", "puyo", "poyo"]);
|
|
368
|
-
});
|
|
369
|
-
it.skip("[not implemented] should recv files which matches only filter", async ()=>{
|
|
370
|
-
await recv(hostInfo, [remoteRoot], localEmptyDir, "*/{ba*,hoge/*}", [], 0);
|
|
371
|
-
|
|
372
|
-
let rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
373
|
-
expect(rt2).to.have.members(["bar", "baz", "hoge"]);
|
|
374
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, remoteRoot, "hoge"));
|
|
375
|
-
expect(rt2).to.have.members(["piyo", "puyo", "poyo"]);
|
|
376
|
-
});
|
|
377
|
-
it("should not recv files which matches exclude filter", async ()=>{
|
|
378
|
-
await recv(hostInfo, [remoteRoot], localEmptyDir, ["--exclude=*/ba*", "--exclude=hoge"], [], 0);
|
|
379
|
-
|
|
380
|
-
const rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
381
|
-
expect(rt2).to.have.members(["foo", "huga"]);
|
|
382
|
-
});
|
|
383
|
-
it.skip("[not implemented] should recv files which matches only filter but should not recv which matches exclude filter", async ()=>{
|
|
384
|
-
await recv(hostInfo, [remoteRoot], localEmptyDir, "*/{ba*,hoge/*}", "**/piyo", [], 0);
|
|
385
|
-
|
|
386
|
-
let rt2 = await fs.readdir(path.posix.join(localEmptyDir, remoteRoot));
|
|
387
|
-
expect(rt2).to.have.members(["bar", "baz", "hoge"]);
|
|
388
|
-
rt2 = await fs.readdir(path.join(localEmptyDir, remoteRoot, "hoge"));
|
|
389
|
-
expect(rt2).to.have.members(["puyo", "poyo"]);
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
describe("degradation check", ()=>{
|
|
393
|
-
it("should recieve multiple files from remote machine", async ()=>{
|
|
394
|
-
await recv(hostInfo, [path.posix.join(remoteRoot, "foo"),
|
|
395
|
-
path.posix.join(remoteRoot, "bar"), path.posix.join(remoteRoot, "baz")], localEmptyDir, [], 0);
|
|
396
|
-
const rt2 = await fs.readdir(localEmptyDir);
|
|
397
|
-
expect(rt2).to.have.members(["foo", "bar", "baz"]);
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
describe("error case", ()=>{
|
|
401
|
-
it("should not send directory to existing file path", ()=>{
|
|
402
|
-
return expect(recv(hostInfo, [remoteRoot], localFiles[0], [], 0)).to.be.rejected;
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
});
|