From 1c296790241c95e26ecc39c6fcb9476bac18ab86 Mon Sep 17 00:00:00 2001 From: Zachary Boyd Date: Sun, 9 Sep 2018 02:59:38 -0400 Subject: [PATCH] Splits the mocha tests into individual files --- CHANGELOG.md | 1 + package-lock.json | 483 ++++++++++++++++- package.json | 8 +- src/ControlServer.js | 2 +- src/winston-silent-logger.js | 4 +- test/ControlServer.js | 64 +++ test/DNSServer.js | 53 ++ test/HTTPServer.js | 53 ++ test/RPCServer.js | 349 +++++++++++++ test/SOCKSServer.js | 42 ++ test/TorPool.js | 259 +++++++++ test/TorProcess.js | 80 +++ test/constants.js | 4 + test/index.js | 8 + test/test.js | 979 ----------------------------------- 15 files changed, 1391 insertions(+), 998 deletions(-) create mode 100644 test/ControlServer.js create mode 100644 test/DNSServer.js create mode 100644 test/HTTPServer.js create mode 100644 test/RPCServer.js create mode 100644 test/SOCKSServer.js create mode 100644 test/TorPool.js create mode 100644 test/TorProcess.js create mode 100644 test/constants.js create mode 100644 test/index.js delete mode 100644 test/test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d00ef5..e327189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Changes - All methods now return promises instead of accepting callbacks. Methods now take advantage of async/await to increase readability. - The `logger` argument to the constructor's of all classes is now optional +- The mocha test has been split into individual files ### Removes - The `new_ips` and `new_ip_at` TorPool and `new_ip` TorProcess have been removed. Use `new_identites`, `new_identity_at` and `new_identity` instead. diff --git a/package-lock.json b/package-lock.json index 7c16501..aa9344f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,9 +16,10 @@ "integrity": "sha512-2whhQUfDHRBiZ3L54Ulyl1X+fZWbWabxPYRDAsibgOAtE6adwusD15Xv0Bw/D7cPah35Z/wKTdW3iAKsevw1uw==" }, "agent-base": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", - "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, "requires": { "es6-promisify": "^5.0.0" } @@ -64,6 +65,18 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "ast-types": { + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz", + "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==", + "dev": true + }, "async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", @@ -147,6 +160,12 @@ "verror": "^1.4.0" } }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", @@ -158,6 +177,26 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "dev": true, + "requires": { + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "cheerio": { "version": "1.0.0-rc.2", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", @@ -369,6 +408,12 @@ "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", + "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -383,6 +428,32 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "dev": true, + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + } + }, "del": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", @@ -402,6 +473,12 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, "diagnostics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.0.tgz", @@ -487,12 +564,14 @@ "es6-promise": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true }, "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, "requires": { "es6-promise": "^4.0.3" } @@ -503,6 +582,37 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "escodegen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", @@ -550,11 +660,23 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fecha": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -603,11 +725,53 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, "get-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-port": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/get-port/-/get-port-2.1.0.tgz", @@ -621,6 +785,31 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, + "get-uri": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", + "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==", + "dev": true, + "requires": { + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "3", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -745,6 +934,28 @@ "readable-stream": "^2.0.2" } }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -756,6 +967,25 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -788,7 +1018,8 @@ "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true }, "ipaddr.js": { "version": "0.1.9", @@ -940,6 +1171,16 @@ "invert-kv": "^1.0.0" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -1187,6 +1428,12 @@ "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", "optional": true }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -1232,6 +1479,20 @@ "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, "os-locale": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", @@ -1278,6 +1539,47 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, + "pac-proxy-agent": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz", + "integrity": "sha512-cDNAN1Ehjbf5EHkNY5qnRhGPUCp6SnpyVof5fRzN800QV1Y2OkzbH9rmjZkbBRa8igof903yOnjIl6z0SlAhxA==", + "dev": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^3.0.0" + }, + "dependencies": { + "socks-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", + "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "socks": "^1.1.10" + } + } + } + }, + "pac-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "dev": true, + "requires": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, "parse5": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", @@ -1311,6 +1613,12 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -1340,11 +1648,39 @@ "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, + "proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.1.tgz", + "integrity": "sha512-mAZexaz9ZxQhYPWfAjzlrloEjW+JHiBFryE4AJXFDTnaXfmH/FKqC1swTRKuEPbHWz02flQNXFOyDUF7zfEG6A==", + "dev": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^2.0.1", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^4.0.1" + } + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -1353,8 +1689,7 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "qs": { "version": "6.5.2", @@ -1362,6 +1697,18 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -1414,6 +1761,25 @@ "uuid": "^3.1.0" } }, + "request-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", + "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "requires": { + "lodash": "^4.13.1" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1442,6 +1808,12 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, "secure-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", @@ -1457,6 +1829,12 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -1488,7 +1866,8 @@ "smart-buffer": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", - "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=" + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", + "dev": true }, "sntp": { "version": "2.1.0", @@ -1503,18 +1882,38 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", + "dev": true, "requires": { "ip": "^1.1.4", "smart-buffer": "^1.0.13" } }, "socks-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", - "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", + "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", + "dev": true, "requires": { - "agent-base": "^4.1.0", - "socks": "^1.1.10" + "agent-base": "~4.2.0", + "socks": "~2.2.0" + }, + "dependencies": { + "smart-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.1.tgz", + "integrity": "sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg==", + "dev": true + }, + "socks": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.1.tgz", + "integrity": "sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.0.1" + } + } } }, "socksv5": { @@ -1541,6 +1940,13 @@ } } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, "sshpk": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", @@ -1562,6 +1968,17 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -1621,11 +2038,16 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-0.0.0.tgz", "integrity": "sha1-V4+8haapJjbkLdF7QdAhjM6esrM=" }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "dev": true + }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "dev": true, "requires": { "punycode": "^1.4.1" } @@ -1651,6 +2073,27 @@ "dev": true, "optional": true }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1710,6 +2153,12 @@ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-3.2.1.tgz", "integrity": "sha512-WPqbdAmMK/kfWCWKM2bA1o997wWPZ0jg5NpO8JPqoaDZgCiZnFpIEddcf7Ur4UZV2sYRUdySVBWKx0+gQQ/jrg==" }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", @@ -1757,6 +2206,12 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index 6646dc3..8fefe89 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,15 @@ }, "scripts": { "start": "bin/tor-router -s -d -j 1", - "test": "mocha --exit test/test.js", + "test": "mocha --exit test/index.js", "debug": "node --inspect-brk bin/tor-router" }, "devDependencies": { + "chai": "^4.1.2", "mocha": "^5.2.0", - "request": "^2.79.0" + "proxy-agent": "^3.0.1", + "request": "^2.79.0", + "request-promise": "^4.2.2" }, "dependencies": { "async": "^2.1.4", @@ -32,7 +35,6 @@ "native-dns": "git+https://github.com/znetstar/node-dns.git", "nconf": "^0.10.0", "shelljs": "^0.8.2", - "socks-proxy-agent": "^3.0.1", "socksv5": "git+https://github.com/lee-elenbaas/socksv5.git", "temp": "^0.8.3", "winston": "^3.0.0-rc5", diff --git a/src/ControlServer.js b/src/ControlServer.js index 3cbd5c6..728e958 100644 --- a/src/ControlServer.js +++ b/src/ControlServer.js @@ -110,7 +110,7 @@ class ControlServer { server.expose('signalInstanceByName', this.torPool.signal_by_name.bind(this.torPool)); } - listen(port) { + async listen(port) { this.tcpTransport = new rpc.tcpTransport({ port }); this.tcpTransport.listen(this.server); } diff --git a/src/winston-silent-logger.js b/src/winston-silent-logger.js index 215d982..2da6934 100644 --- a/src/winston-silent-logger.js +++ b/src/winston-silent-logger.js @@ -1,4 +1,6 @@ -module.exports = require('winston').createLogger({ +const winston = require('winston'); + +module.exports = winston.createLogger({ level: 'info', format: winston.format.simple(), silent: true, diff --git a/test/ControlServer.js b/test/ControlServer.js new file mode 100644 index 0000000..10db111 --- /dev/null +++ b/test/ControlServer.js @@ -0,0 +1,64 @@ + +const _ = require('lodash'); +const assert = require('chai').assert; +const rpc = require('jrpc2'); +const Promise = require('bluebird'); +const nconf = require('nconf'); + +const logger = require('../src/winston-silent-logger'); + +require(`${__dirname}/../src/nconf_load_env.js`)(nconf); +nconf.defaults(require(`${__dirname}/../src/default_config.js`)); +const { ControlServer } = require('../'); + +let controlServer = new ControlServer(logger, nconf); +let controlPort; +describe('ControlServer', function () { + describe('#listen(port)', function () { + it('should bind to a given port', async function () { + controlPort = await getPort(); + await controlServer.listen(controlPort); + }); + }); + describe('#createTorPool(options)', function () { + it('should create a TorPool with a given configuration', function () { + let torPool = controlServer.createTorPool({ ProtocolWarnings: 1 }); + + assert.ok((controlServer.torPool instanceof (TorRouter.TorPool))); + assert.equal(1, torPool.default_tor_config.ProtocolWarnings); + }); + }); + describe('#createSOCKSServer(port)', function () { + it('should create a SOCKS Server', async function () { + let port = await getPort(); + controlServer.createSOCKSServer(port); + assert.instanceOf(controlServer.socksServer, SOCKSServer); + }); + }); + describe('#createDNSServer(port)', function () { + it('should create a DNS Server', async function () { + let port = await getPort(); + controlServer.createDNSServer(port); + assert.instanceOf(controlServer.dnsServer, DNSServer); + }); + }); + describe('#createHTTPServer(port)', function () { + it('should create a HTTP Server', async function () { + let port = await getPort(); + controlServer.createHTTPServer(port); + assert.instanceOf(controlServer.httpServer, HTTPServer); + }); + }); + + describe('#close()', function () { + it('should close the RPC Server', function () { + controlServer.close(); + }); + }); + + after('shutdown tor pool', async function () { + await controlServer.torPool.exit(); + }); +}); + +require('./RPCServer'); \ No newline at end of file diff --git a/test/DNSServer.js b/test/DNSServer.js new file mode 100644 index 0000000..8461708 --- /dev/null +++ b/test/DNSServer.js @@ -0,0 +1,53 @@ + +const nconf = require('nconf'); +const getPort = require('get-port'); +const dns = require('native-dns'); + +const logger = require('../src/winston-silent-logger'); +const { TorPool, DNSServer } = require('../'); +const { WAIT_FOR_CREATE } = require('./constants'); + +let dnsServerTorPool; +let dnsServer; +describe('DNSServer', function () { + dnsServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); + dnsServer = new DNSServer(dnsServerTorPool, {}, 10000, logger); + let dnsPort; + before('start up server', async function (){ + this.timeout(WAIT_FOR_CREATE); + + await dnsServerTorPool.create(1); + dnsPort = await getPort(); + + dnsServer.serve(dnsPort); + }); + + describe('#handle_dns_request(req, res)', function () { + it('should service a request for example.com', function (done) { + this.timeout(10000); + + let req = dns.Request({ + question: dns.Question({ + name: 'example.com', + type: 'A' + }), + server: { address: '127.0.0.1', port: dnsPort, type: 'udp' }, + timeout: 1000, + }); + + req.on('timeout', function () { + done(new Error('Connection timed out')); + }); + + req.on('message', function () { + done(); + }); + + req.send(); + }); + }); + + after('shutdown tor pool', async function () { + await dnsServerTorPool.exit(); + }); +}); \ No newline at end of file diff --git a/test/HTTPServer.js b/test/HTTPServer.js new file mode 100644 index 0000000..c022663 --- /dev/null +++ b/test/HTTPServer.js @@ -0,0 +1,53 @@ +const nconf = require('nconf'); +const request = require('request-promise'); +const getPort = require('get-port'); +const ProxyAgent = require('proxy-agent'); + +const logger = require('../src/winston-silent-logger'); +const { TorPool, HTTPServer } = require('../'); +const { WAIT_FOR_CREATE, PAGE_LOAD_TIME } = require('./constants'); + +require(`${__dirname}/../src/nconf_load_env.js`)(nconf); +nconf.defaults(require(`${__dirname}/../src/default_config.js`)); + +let httpServerTorPool; +let httpServer; +describe('HTTPServer', function () { + httpServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); + httpServer = new HTTPServer(httpServerTorPool, logger); + let httpPort; + before('start up server', async function (){ + this.timeout(WAIT_FOR_CREATE); + + await httpServerTorPool.create(1); + httpPort = await getPort(); + + httpServer.listen(httpPort); + }); + + describe('#handle_http_connections(req, res)', function () { + it('should service a request for example.com', async function () { + this.timeout(PAGE_LOAD_TIME); + + await request({ + url: 'http://example.com', + agent: new ProxyAgent(`http://localhost:${httpPort}`) + }); + }); + }); + + describe('#handle_connect_connections(req, inbound_socket, head)', function () { + it('should service a request for example.com', async function () { + this.timeout(PAGE_LOAD_TIME); + + await request({ + url: 'https://example.com', + agent: new ProxyAgent(`http://localhost:${httpPort}`) + }); + }); + }); + + after('shutdown tor pool', async function () { + await httpServerTorPool.exit(); + }); +}); diff --git a/test/RPCServer.js b/test/RPCServer.js new file mode 100644 index 0000000..96fde2c --- /dev/null +++ b/test/RPCServer.js @@ -0,0 +1,349 @@ + +const _ = require('lodash'); +const assert = require('chai').assert; +const rpc = require('jrpc2'); +const Promise = require('bluebird'); +const nconf = require('nconf'); +const rpc = require('jrpc2'); + +const logger = require('../src/winston-silent-logger'); + +require(`${__dirname}/../src/nconf_load_env.js`)(nconf); +nconf.defaults(require(`${__dirname}/../src/default_config.js`)); +const { ControlServer } = require('../'); + +let rpcControlServer = new ControlServer(logger, nconf); +let rpcControlPort; +let rpcClient; +describe('ControlServer - RPC', function () { + before('setup control server', async function () { + rpcControlPort = await getPort(); + await rpcControlServer.listen(rpcControlPort); + rpcClient = new rpc.Client(new rpc.tcpTransport({ port: rpcControlPort, hostname: 'localhost' })); + Promise.promisifyAll(rpcClient); + }); + + describe('#createInstances(number_of_instances)', function () { + this.timeout(WAIT_FOR_CREATE*2); + it('should create an instance', async function () { + await rpcClient.invokeAsync('createInstances', [2]); + }); + }); + + describe('#queryInstances()', function () { + this.timeout(3000); + it('should return a list of instances', async function () { + let raw = await rpcClient.invokeAsync('queryInstances', []); + + var instances = JSON.parse(raw).result; + + assert.isArray(instances, 'Did not return an array'); + assert.isNotEmpty(instances); + assert.isTrue(instances.every((instance) => ( typeof(instance.name) !== 'undefined' ) && ( instance.name !== null ))); + }); + }); + + describe('#addInstances(definitions)', function () { + this.timeout(WAIT_FOR_CREATE); + it("should add an instance based on a defintion", async function () { + var def = { + Name: 'instance-1' + }; + await rpcClient.invokeAsync('addInstances', [ [ def ] ]); + }); + + it("tor pool should now contain and instance that has the same name as the name specified in the defintion", function () { + assert.ok(rpcControlServer.torPool.instance_by_name('instance-1')); + }); + }); + + describe('#queryInstanceByName(instance_name)', function () { + this.timeout(3000); + it('should return a single instance by name', async function () { + let raw = await rpcClient.invokeAsync('queryInstanceByName', ['instance-1']); + + var instance = JSON.parse(raw).result; + + assert.isOk(instance); + }); + }); + + describe('#queryInstanceAt(index)', function () { + this.timeout(3000); + it('should return a single instance by index', async function () { + let raw = await rpcClient.invokeAsync('queryInstanceAt', [0]); + + var instance = JSON.parse(raw).result; + + assert.isOk(instance); + }); + }); + + describe('#newIdentites()', function () { + this.timeout(3000); + it('should request new identities for all instances', async function () { + await rpcClient.invokeAsync('newIdentites', []); + }); + }); + + describe('#newIdentityByName(instance_name)', function () { + this.timeout(3000); + it('should request new identities for all instances', async function () { + await rpcClient.invokeAsync('newIdentityByName', ['instance-1']); + }); + }); + + describe('#newIdentityAt(index)', function () { + this.timeout(3000); + it('should request new identities for all instances', async function () { + await rpcClient.invokeAsync('newIdentityAt', [0]); + }); + }); + + describe("#setTorConfig(config_object)", function () { + this.timeout(3000); + it('should set several config variables on all instances', async function () { + await rpcClient.invokeAsync('setTorConfig', [ { TestSocks: 1, ProtocolWarnings: 1 } ]); + }); + + it('all instances should have the modified variables', async function() { + await Promise.all(rpcControlServer.torPool.instances.map(async (instance) => { + let var1 = await instance.get_config('TestSocks'); + let var2 = await instance.get_config('ProtocolWarnings'); + + assert.equal(var1, 1); + assert.equal(var2, 1); + })); + }); + + after('unset config variables', async function () { + await rpcControlServer.torPool.set_config_all('TestSocks', 0); + await rpcControlServer.torPool.set_config_all('ProtocolWarnings', 0); + }); + }); + + describe('#setDefaultTorConfig(object)', function () { + it('should set the default config of new instances', async function () { + this.timeout(3000); + await rpcClient.invokeAsync('setDefaultTorConfig', [ { TestSocks: 1 } ]); + }); + + it('a new instance should be created with the modified property', async function () { + this.timeout(WAIT_FOR_CREATE); + + await rpcControlServer.torPool.create_instance({ Name: 'config-test' }); + let value = await rpcControlServer.torPool.instance_by_name('config-test').get_config('TestSocks'); + + assert.equal(value, 1); + }); + + after('remove instance', async function () { + this.timeout(10000); + nconf.set('torConfig', {}); + await rpcControlServer.torPool.remove_by_name('config-test'); + }); + }); + + describe('#getDefaultTorConfig()', function () { + before('set tor config', function () { + nconf.set('torConfig', { TestSocks: 1 }); + }); + + it('should return a tor config with a modified property', async function () { + this.timeout(3000); + let raw = await rpcClient.invokeAsync('getDefaultTorConfig', [ { } ]); + let config = JSON.parse(raw).result; + + assert.equal(config.TestSocks, 1); + }); + + after('unset property', function () { + nconf.set('torConfig', {}); + }); + }); + + describe('#getLoadBalanceMethod()', function () { + this.timeout(3000); + before(function () { + rpcControlServer.torPool.load_balance_method = 'round_robin'; + }); + + it('should return the current load balance method', async function () { + let raw = await rpcClient.invokeAsync('getLoadBalanceMethod', []); + let lb_method = JSON.parse(raw).result; + assert.equal(lb_method, 'round_robin'); + }); + }); + + describe('#setLoadBalanceMethod(load_balance_method)', function () { + this.timeout(3000); + + it('should set the load balance method', async function () { + await rpcClient.invokeAsync('setLoadBalanceMethod', ['weighted']); + }); + + it('the load balance method should be changed', function () { + assert.equal(rpcControlServer.torPool.load_balance_method, 'weighted'); + }); + + after(function () { + rpcControlServer.torPool.load_balance_method = 'round_robin'; + }); + }); + + describe("#getInstanceConfigByName(instance_name)", function () { + this.timeout(3000); + + before('set config property', async function () { + await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 1); + }); + + it('should retrieve the property from the tor instance', async function (done) { + let raw = await rpcClient.invokeAsync('getInstanceConfigByName', ['instance-1']); + let value = JSON.parse(raw).result; + + assert.equal(value, 1); + }); + + after('unset config property', async function () { + await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0); + }); + }); + + describe("#getInstanceConfigAt(index)", function () { + this.timeout(3000); + + before('set config property', async function () { + await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 1); + }); + + it('should retrieve the property from the tor instance', async function () { + let raw = await rpcClient.invokeAsync('getInstanceConfigByName', [0]); + let value = JSON.parse(raw).result; + + assert.equal(value, 1); + }); + + after('unset config property', async function () { + await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0); + }); + }); + + describe("#setInstanceConfigByName(instance_name)", function () { + this.timeout(3000); + + before('set config property', async function () { + await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0); + }); + + it('should set the property for the tor instance', async function () { + await rpcClient.invokeAsync('setInstanceConfigByName', ['instance-1', 'TestSocks', 1]); + }); + + it('tor instance should have the modified property', async function () { + let value = await rpcControlServer.torPool.instance_by_name('instance-1').get_config('TestSocks'); + assert.equal(value, 1); + }); + + after('unset config property', async function () { + await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0); + }); + }); + + describe("#setInstanceConfigAt(index)", function () { + this.timeout(3000); + + before('set config property', async function () { + await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0); + }); + + it('should set the property for the tor instance', async function () { + await rpcClient.invokeAsync('setInstanceConfigAt', [0, 'TestSocks', 1]); + }); + + it('tor instance should have the modified property', async function () { + let value = await rpcControlServer.torPool.instance_at(0).get_config('TestSocks'); + assert.equal(value, 1); + }); + + after('unset config property', async function () { + await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0); + }); + }); + + describe('#signalAllInstances(signal)', function () { + this.timeout(3000); + it('should signal to all interfaces', async function () { + await rpcClient.invokeAsync('signalAllInstances', [ 'DEBUG' ]); + }); + }); + + describe('#signalInstanceAt(signal)', function () { + this.timeout(3000); + it('should signal to all interfaces', async function () { + await rpcClient.invokeAsync('signalInstanceAt', [ 0, 'DEBUG' ]); + }); + }); + + describe('#signalAllInstances(signal)', function () { + this.timeout(3000); + it('should signal to all interfaces', async function () { + await rpcClient.invokeAsync('signalInstanceByName', [ 'instance-1', 'DEBUG' ]); + }); + }); + + describe("#nextInstance()", function () { + this.timeout(3000); + let instance_name; + it('should rotate the 0th item in the instances array', async function () { + instance_name = rpcControlServer.torPool.instances[0].instance_name; + await rpcClient.invokeAsync('nextInstance', []); + }); + + it('0th item in the instances array should be different after nextInstance is called', function () { + assert.notEqual(rpcControlServer.torPool.instances[0].instance_name, instance_name); + }); + }); + var instance_num1, instance_num2, i_num; + describe('#removeInstanceAt(index)', function () { + this.timeout(10000); + it("should remove an instance at the position specified", async function () { + instance_num1 = rpcControlServer.torPool.instances.length; + await rpcClient.invokeAsync('removeInstanceAt', [0]); + }); + + it('the tor pool should contain one instance fewer', function () { + assert.equal(rpcControlServer.torPool.instances.length, (instance_num1 - 1)); + }); + }); + + describe('#removeInstanceByName(instance_name)', function () { + this.timeout(10000); + it("should remove an instance at the position specified", async function () { + instance_num2 = rpcControlServer.torPool.instances.length; + await rpcClient.invokeAsync('removeInstanceByName', [ "instance-1" ]); + }); + + it('the tor pool should contain one instance fewer', function () { + assert.equal(rpcControlServer.torPool.instances.length, (instance_num2 - 1)); + }); + }); + + describe('#closeInstances()', function () { + this.timeout(10000); + it('should shutdown all instances', async function () { + instance_num = rpcControlServer.torPool.instances.length; + await rpcClient.invokeAsync('closeInstances', [ ]); + }); + + it('no instances should be present in the pool', function () { + assert.equal(rpcControlServer.torPool.instances.length, 0); + assert.notEqual(rpcControlServer.torPool.instances.length, instance_num); + }); + }); + + after('shutdown tor pool', async function () { + this.timeout(10000); + await rpcControlServer.torPool.exit(); + }); +}); \ No newline at end of file diff --git a/test/SOCKSServer.js b/test/SOCKSServer.js new file mode 100644 index 0000000..4ee48cf --- /dev/null +++ b/test/SOCKSServer.js @@ -0,0 +1,42 @@ +const nconf = require('nconf'); +const request = require('request-promise'); +const getPort = require('get-port'); +const ProxyAgent = require('proxy-agent'); + +const logger = require('../src/winston-silent-logger'); +const { TorPool, SOCKSServer } = require('../'); +const { WAIT_FOR_CREATE, PAGE_LOAD_TIME } = require('./constants'); + +require(`${__dirname}/../src/nconf_load_env.js`)(nconf); +nconf.defaults(require(`${__dirname}/../src/default_config.js`)); + +let socksServerTorPool; +let socksServer; +describe('SOCKSServer', function () { + socksServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); + socksServer = new SOCKSServer(socksServerTorPool, logger); + let socksPort; + before('start up server', async function (){ + this.timeout(WAIT_FOR_CREATE); + + await socksServerTorPool.create(1); + socksPort = await getPort(); + + socksServer.listen(socksPort); + }); + + describe('#handleConnection(socket)', function () { + it('should service a request for example.com', async function () { + this.timeout(PAGE_LOAD_TIME); + + await request({ + url: 'http://example.com', + agent: new ProxyAgent(`socks://localhost:${socksPort}`) + }); + }); + }); + + after('shutdown tor pool', async function () { + await socksServerTorPool.exit(); + }); +}); \ No newline at end of file diff --git a/test/TorPool.js b/test/TorPool.js new file mode 100644 index 0000000..a4a8565 --- /dev/null +++ b/test/TorPool.js @@ -0,0 +1,259 @@ +const nconf = require('nconf'); +const assert = require('chai').assert; +const Promise = require('bluebird'); +const _ = require('lodash'); + +const { TorPool } = require('../'); +const { WAIT_FOR_CREATE } = require('./constants'); +const logger = require('../src/winston-silent-logger'); + +require(`${__dirname}/../src/nconf_load_env.js`)(nconf); +nconf.defaults(require(`${__dirname}/../src/default_config.js`)); + +let torPool; +describe('TorPool', function () { + torPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); + + describe('#create_instance(instance_defintion)', function () { + let instance_defintion = { + Name: 'instance-1', + Config: { + ProtocolWarnings: 1 + } + }; + + it('should create one tor instance based on the provided definition', async function () { + this.timeout(WAIT_FOR_CREATE); + await torPool.create_instance(instance_defintion); + }); + + it('one instance should exist in the instances collection', function () { + assert.equal(1, torPool.instances.length); + }); + + it('the created instance should have the defintion properties as the input definition', function () { + assert.deepEqual(instance_defintion, torPool.instances[0].definition); + }); + + it('the created instance should have the same config properties specified in the definiton', async function () { + let value = await torPool.instances[0].get_config('ProtocolWarnings'); + assert.equal(value, instance_defintion.Config.ProtocolWarnings); + }); + + after('shutdown tor pool', async function () { + torPool.exit(); + }); + }); + + describe('#add(instance_defintions)', function () { + var instance_defintions = [ + { Name: 'instance-1', Config: { ProtocolWarnings: 1} }, + { Name: 'instance-2', Config: { ProtocolWarnings: 1 } } + ]; + + it('should create instances from several instance definitions', async function () { + this.timeout(WAIT_FOR_CREATE*2); + await torPool.add(instance_defintions) + }); + + it('2 instances should exist in the pool', function () { + assert.equal(2, torPool.instances.length); + }); + + it('the created instances should have the same defintion properties as the input definitions', function () { + assert.deepEqual(instance_defintions, torPool.instances.map((instance) => { + let def_clone = _.cloneDeep(instance.definition); + delete def_clone.Config.DataDirectory; + return def_clone; + }).sort(function(a,b) {return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0);})); + }); + + it('the created instances should have the same config properties specified in the definiton', async function (done) { + this.timeout(10000); + + let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('ProtocolWarnings'))); + + assert.isTrue( values.every((value) => value === 1) ); + }); + + after('shutdown tor pool', async function () { + await torPool.exit(); + }); + }); + + describe('#create(number_of_instances)', function () { + torPool.default_tor_config = { TestSocks: 1 }; + it('should create 2 instances with the default config', async function () { + this.timeout(WAIT_FOR_CREATE*2); + await torPool.create(2); + }); + + it('2 instances should exist in the pool', function () { + assert.equal(2, torPool.instances.length); + }); + + it('the created instances should have the same config properties specified in the default config', async function () { + this.timeout(10000); + + let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('ProtocolWarnings'))); + + assert.isTrue( values.every((value) => value === 1) ); + }); + + after('shutdown tor pool', async function () { + torPool.default_tor_config = {}; + await torPool.exit(done); + }); + }); + + + describe('#next()', function () { + before('create tor instances', async function () { + this.timeout(WAIT_FOR_CREATE * 3); + await torPool.add([ + { + Name: 'instance-1', + Weight: 50 + }, + { + Name: 'instance-2', + Weight: 25 + }, + { + Name: 'instance-3', + Weight: 2 + } + ]); + }); + + it('result of next should be different if run twice', function () { + var t1 = torPool.next().instance_name; + var t2 = torPool.next().instance_name; + assert.notEqual(t1, t2); + }); + }); + + describe('#instance_by_name(instance_name)', function () { + it('should retrieve instance by name', function () { + assert.ok(torPool.instance_by_name('instance-1')); + }); + }); + + describe('#remove_by_name(instance_name)', function () { + this.timeout(5000); + it('should remove instance by name', async function () { + await torPool.remove_by_name('instance-3'); + }); + }); + + describe('#instance_at(index)', function () { + this.timeout(5000); + it('should retrieve an instance by id', function () { + assert.ok(torPool.instance_at(0)); + }); + }); + + describe('#remove_at(index)', function () { + this.timeout(5000); + it('should remove an instance by id', async function () { + await torPool.remove_at(1); + }); + }); + + describe('#new_identites()', function () { + this.timeout(5000); + it('should signal to retrieve a new identity to all instances', async function () { + await torPool.new_identites(); + }); + }); + + describe('#new_identity_at(index)', function () { + this.timeout(5000); + it('should signal to retrieve a new identity identified by index', async function () { + await torPool.new_identity_at(0); + }); + }); + + describe('#new_identity_by_name(instance_name)', function () { + this.timeout(5000); + it('should signal to retrieve a new identity identified by name', async function () { + await torPool.new_identity_by_name('instance-1'); + }); + }); + + + describe('#set_config_all(keyword, value)', function () { + it('should set configuration on all active instances', async function () { + this.timeout(5000); + await torPool.set_config_all('TestSocks', 1); + }); + + it('all instances should contain the same changed configuration', async function () { + this.timeout(5000); + + let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('TestSocks'))); + + assert.isTrue( values.every((value) => value === 1) ); + }); + + after('unset config options', async function () { + await torPool.set_config_all('TestSocks', 0); + }); + }); + + describe('#set_config_by_name(name, keyword, value)', function () { + this.timeout(5000); + it('should set a configuration property of an instance identified by name', async function () { + await torPool.set_config_by_name('instance-1', 'ProtocolWarnings', 1); + }); + }); + + describe('#get_config_by_name(name, keyword)', function () { + this.timeout(5000); + it('should get retrieve the configuration of an instance identified by name', async function () { + let value = await torPool.get_config_by_name('instance-1', 'ProtocolWarnings'); + assert.equal(value, 1); + }); + }); + + describe('#set_config_at(index, keyword, value)', function () { + this.timeout(5000); + it('should set a configuration property of an instance identified by index', async function () { + await torPool.set_config_at(0, 'ProtocolWarnings', 0); + }); + }); + + describe('#get_config_at(index, keyword)', function () { + this.timeout(5000); + it('should get retrieve the configuration of an instance identified by name', async function () { + let value = await torPool.get_config_at(0, 'ProtocolWarnings'); + + assert.equal(value, 0); + }); + }); + + describe('#signal_all(signal)', function () { + this.timeout(5000); + it('should send a signal to all instances', async function () { + await torPool.signal_all('DEBUG'); + }); + }); + + describe('#signal_by_name(name, signal)', async function () { + this.timeout(5000); + it('should send a signal to an instance identified by name', async function () { + await torPool.signal_by_name('instance-1', 'DEBUG'); + }); + }); + + describe('#signal_at(index, signal)', function () { + this.timeout(5000); + it('should send a signal to an instance identified by index', async function () { + await torPool.signal_at(0, 'DEBUG'); + }); + }); + + after('shutdown tor pool', async function () { + await torPool.exit(); + }); +}); \ No newline at end of file diff --git a/test/TorProcess.js b/test/TorProcess.js new file mode 100644 index 0000000..a191848 --- /dev/null +++ b/test/TorProcess.js @@ -0,0 +1,80 @@ +const nconf = require('nconf'); +const assert = require('chai').assert; + +const { TorProcess } = require('../'); +const { WAIT_FOR_CREATE } = require('./constants'); +const logger = require('../src/winston-silent-logger'); + +require(`${__dirname}/../src/nconf_load_env.js`)(nconf); +nconf.defaults(require(`${__dirname}/../src/default_config.js`)); + +describe('TorProcess', function () { + let tor = new TorProcess(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null, logger); + describe('#create()', function () { + this.timeout(WAIT_FOR_CREATE); + + it('should create the child process', async function () { + await tor.create(); + }); + + it('should signal when it is listening on the control port', function (done) { + if (tor.control_port_listening) + return done(); + tor.once('control_listen', done); + }); + + it('should signal when connected to the control port', function (done) { + if (tor.control_port_connected) + return done(); + tor.once('controller_ready', done); + }); + + it('should signal when it is listening on the socks port', function (done) { + if (tor.socks_port_listening) + return done(); + tor.once('socks_listen', done); + }); + + it('should signal when it is listening on the dns port', function (done) { + if (tor.dns_port_listening) + return done(); + tor.once('dns_listen', done); + }); + + it('should signal when bootstrapped', function (done) { + tor.once('error', done); + if (tor.bootstrapped) + return done(); + tor.once('ready', done); + }); + }); + + describe('#set_config(keyword, value)', function () { + it('should set sample configuration option via the control protocol', async function () { + await tor.set_config('ProtocolWarnings', 1); + }); + }); + + describe('#get_config(keyword, value)', function () { + it('should retrieve sample configuration option via the control protocol', async function () { + let value = await tor.get_config('ProtocolWarnings'); + assert.equal(value, 1); + }); + }); + + describe('#new_identity()', function () { + it('should use a new identity', async function () { + await tor.new_identity(); + }); + }); + + describe('#signal()', function () { + it('should send a signal via the control protocol', async function () { + await tor.signal('DEBUG'); + }); + }); + + after('shutdown tor', async function () { + await tor.exit(); + }); +}); \ No newline at end of file diff --git a/test/constants.js b/test/constants.js new file mode 100644 index 0000000..a315659 --- /dev/null +++ b/test/constants.js @@ -0,0 +1,4 @@ +module.exports = { + WAIT_FOR_CREATE: 120000, + PAGE_LOAD_TIME: 60000 +}; \ No newline at end of file diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..fe25a5f --- /dev/null +++ b/test/index.js @@ -0,0 +1,8 @@ +describe("TorRouter", function () { + require('./TorProcess'); + require('./TorPool'); + require('./SOCKSServer'); + require('./HTTPServer'); + require('./DNSServer'); + require('./ControlServer'); +}); \ No newline at end of file diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 09e3c33..0000000 --- a/test/test.js +++ /dev/null @@ -1,979 +0,0 @@ -const SocksAgent = require('socks-proxy-agent'); -const request = require('request'); -const async = require('async'); -const TorRouter = require('../'); -const getPort = require('get-port'); -const dns = require('native-dns'); -const _ = require('lodash'); -const assert = require('assert'); -const winston = require('winston'); -const del = require('del'); -const rpc = require('jrpc2'); -const fs = require('fs'); - -const colors = require('mocha/lib/reporters/base').colors; -const nconf = require('nconf'); -nconf = require(`${__dirname}/../src/nconf_load_env.js`)(nconf); -nconf.defaults(require(`${__dirname}/../src/default_config.js`)); - -const logger = require('../src/winston-silent-logger'); - -const WAIT_FOR_CREATE = 120000; -const PAGE_LOAD_TIME = 60000; - -describe('TorProcess', function () { - var tor = new (TorRouter.TorProcess)(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null, logger); - describe('#create()', function () { - this.timeout(WAIT_FOR_CREATE); - - it('should create the child process', function (done) { - tor.create(done); - }); - - it('should signal when it is listening on the control port', function (done) { - if (tor.control_port_listening) - return done(); - tor.once('control_listen', done); - }); - - it('should signal when connected to the control port', function (done) { - if (tor.control_port_connected) - return done(); - tor.once('controller_ready', done); - }); - - it('should signal when it is listening on the socks port', function (done) { - if (tor.socks_port_listening) - return done(); - tor.once('socks_listen', done); - }); - - it('should signal when it is listening on the dns port', function (done) { - if (tor.dns_port_listening) - return done(); - tor.once('dns_listen', done); - }); - - it('should signal when bootstrapped', function (done) { - tor.once('error', done); - if (tor.bootstrapped) - return done(); - tor.once('ready', done); - }); - }); - - describe('#set_config(keyword, value)', function () { - it('should set sample configuration option via the control protocol', function (done) { - tor.set_config('ProtocolWarnings', 1, done); - }); - }); - - describe('#get_config(keyword, value)', function () { - it('should retrieve sample configuration option via the control protocol', function (done) { - tor.get_config('ProtocolWarnings', function (error, value) { - done(error, (value == 1)); - }); - }); - }); - - describe('#new_identity()', function () { - it('should use a new identity', function (done) { - tor.new_identity(done); - }); - }); - - describe('#signal()', function () { - it('should send a signal via the control protocol', function (done) { - tor.signal('DEBUG', done); - }); - }); - - after('shutdown tor', function (done) { - tor.exit(done); - }); -}); - -var torPool; - -describe('TorPool', function () { - torPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); - - describe('#create_instance(instance_defintion)', function () { - var instance_defintion = { - Name: 'instance-1', - Config: { - ProtocolWarnings: 1 - } - }; - - it('should create one tor instance based on the provided definition', function (done) { - this.timeout(WAIT_FOR_CREATE); - torPool.create_instance(instance_defintion, (err, _instance) => { - done(err); - }); - }); - - it('one instance should exist in the instances collection', function () { - assert.equal(1, torPool.instances.length); - }); - - it('the created instance should have the defintion properties as the input definition', function () { - assert.deepEqual(instance_defintion, torPool.instances[0].definition); - }); - - it('the created instance should have the same config properties specified in the definiton', function (done) { - torPool.instances[0].get_config('ProtocolWarnings', (err, v) => { - if (err) - return done(err); - done(null, (v === instance_defintion.Config.ProtocolWarnings)); - }); - }); - - after('shutdown tor pool', function (done) { - torPool.exit(done); - }); - }); - - describe('#add(instance_defintions)', function () { - var instance_defintions = [ - { Name: 'instance-1', Config: { ProtocolWarnings: 1} }, - { Name: 'instance-2', Config: { ProtocolWarnings: 1 } } - ]; - - it('should create instances from several instance definitions', function (done) { - this.timeout(WAIT_FOR_CREATE*2); - torPool.add(instance_defintions, function (error) { - done(error) - }); - }); - - it('2 instances should exist in the pool', function () { - assert.equal(2, torPool.instances.length); - }); - - it('the created instances should have the same defintion properties as the input definitions', function () { - assert.deepEqual(instance_defintions, torPool.instances.map((i) => { - let def_clone = _.extend({}, i.definition); - delete def_clone.Config.DataDirectory; - return def_clone; - }).sort(function(a,b) {return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0);})); - }); - - it('the created instances should have the same config properties specified in the definiton', function (done) { - this.timeout(10000); - async.map(torPool.instances, function grabConfig(instance, next) { - instance.get_config('ProtocolWarnings', next); - }, function (err, values) { - if (err) return done(err); - done(null, values.every((v) => v === 1)); - }); - }); - - after('shutdown tor pool', function (done) { - torPool.exit(done); - }); - }); - - describe('#create(number_of_instances)', function () { - torPool.default_tor_config = { TestSocks: 1 }; - it('should create 2 instances with the default config', function (done) { - this.timeout(WAIT_FOR_CREATE*2); - torPool.create(2, done); - }); - - it('2 instances should exist in the pool', function () { - assert.equal(2, torPool.instances.length); - }); - - it('the created instances should have the same config properties specified in the default config', function (done) { - this.timeout(10000); - async.map(torPool.instances, function grabConfig(instance, next) { - instance.get_config('ProtocolWarnings', next); - }, function (err, values) { - if (err) return done(err); - done(null, values.every((v) => v === 1)); - }); - }); - - after('shutdown tor pool', function (done) { - torPool.default_tor_config = {}; - torPool.exit(done); - }); - }); - - - describe('#next()', function () { - before('create tor instances', function (done) { - this.timeout(WAIT_FOR_CREATE * 3); - torPool.add([ - { - Name: 'instance-1', - Weight: 50 - }, - { - Name: 'instance-2', - Weight: 25 - }, - { - Name: 'instance-3', - Weight: 2 - } - ], done); - }); - - it('result of next should be different if run twice', function () { - var t1 = torPool.next().instance_name; - var t2 = torPool.next().instance_name; - assert.notEqual(t1, t2); - }); - }); - - describe('#instance_by_name(instance_name)', function () { - it('should retrieve instance by name', function () { - assert.ok(torPool.instance_by_name('instance-1')); - }); - }); - - describe('#remove_by_name(instance_name)', function () { - this.timeout(5000); - it('should remove instance by name', function (done) { - torPool.remove_by_name('instance-3', done); - }); - }); - - describe('#instance_at(index)', function () { - this.timeout(5000); - it('should retrieve an instance by id', function () { - assert.ok(torPool.instance_at(0)); - }); - }); - - describe('#remove_at(index)', function () { - this.timeout(5000); - it('should remove an instance by id', function (done) { - torPool.remove_at(1, done); - }); - }); - - describe('#new_identites()', function () { - this.timeout(5000); - it('should signal to retrieve a new identity to all instances', function (done) { - torPool.new_identites(done); - }); - }); - - describe('#new_identity_at(index)', function () { - this.timeout(5000); - it('should signal to retrieve a new identity identified by index', function (done) { - torPool.new_identity_at(0, done); - }); - }); - - describe('#new_identity_by_name(instance_name)', function () { - this.timeout(5000); - it('should signal to retrieve a new identity identified by name', function (done) { - torPool.new_identity_by_name('instance-1', done); - }); - }); - - - describe('#set_config_all(keyword, value)', function () { - it('should set configuration on all active instances', function (done) { - this.timeout(5000); - torPool.set_config_all('TestSocks', 1, done); - }); - - it('all instances should contain the same changed configuration', function (done) { - this.timeout(5000); - - async.map(torPool.instances, (instance, next) => { - instance.get_config('TestSocks', next); - }, function (error, results) { - if (error) return done(error); - done(null, results.every((r) => r === 1)); - }); - }); - - after('unset config options', function (done) { - torPool.set_config_all('TestSocks', 0, done); - }); - }); - - describe('#set_config_by_name(name, keyword, value)', function () { - this.timeout(5000); - it('should set a configuration property of an instance identified by name', function (done) { - torPool.set_config_by_name('instance-1', 'ProtocolWarnings', 1, done); - }); - }); - - describe('#get_config_by_name(name, keyword)', function () { - this.timeout(5000); - it('should get retrieve the configuration of an instance identified by name', function (done) { - torPool.get_config_by_name('instance-1', 'ProtocolWarnings', (error, value) => { - if (error) return done(error); - - done(null, (value === 1)); - }); - }); - }); - - describe('#set_config_at(index, keyword, value)', function () { - this.timeout(5000); - it('should set a configuration property of an instance identified by index', function (done) { - torPool.set_config_at(0, 'ProtocolWarnings', 0, done); - }); - }); - - describe('#get_config_at(index, keyword)', function () { - this.timeout(5000); - it('should get retrieve the configuration of an instance identified by name', function (done) { - torPool.get_config_at(0, 'ProtocolWarnings', (error, value) => { - if (error) return done(error); - - done(null, (value === 0)); - }); - }); - }); - - describe('#signal_all(signal)', function () { - this.timeout(5000); - it('should send a signal to all instances', function (done) { - torPool.signal_all('DEBUG', done); - }); - }); - - describe('#signal_by_name(name, signal)', function () { - this.timeout(5000); - it('should send a signal to an instance identified by name', function (done) { - torPool.signal_by_name('instance-1', 'DEBUG', done); - }); - }); - - describe('#signal_at(index, signal)', function () { - this.timeout(5000); - it('should send a signal to an instance identified by index', function (done) { - torPool.signal_at(0, 'DEBUG', done); - }); - }); - - after('shutdown tor pool', function (done) { - torPool.exit(done); - }); -}); - -var socksServerTorPool; -var socksServer; -describe('SOCKSServer', function () { - socksServerTorPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); - socksServer = new (TorRouter.SOCKSServer)(socksServerTorPool, logger); - var socksPort; - before('start up server', function (done){ - this.timeout(WAIT_FOR_CREATE); - async.waterfall([ - (callback) => { socksServerTorPool.create(1, callback); }, - (callback) => { getPort().then((port) => callback(null, port)); }, - (port, callback) => { - socksPort = port; - socksServer.listen(port); - callback(); - } - ], done); - }); - - describe('#handleConnection(socket)', function () { - it('should service a request for example.com', function (done) { - this.timeout(PAGE_LOAD_TIME); - - var req = request({ - url: 'http://example.com', - agent: new SocksAgent(`socks://localhost:${socksPort}`) - }); - - req.on('error', function (error) { - done(error); - }); - - req.on('response', function (res) { - done(); - }) - }); - }); - - after('shutdown tor pool', function (done) { - socksServerTorPool.exit(done); - }); -}); - - -var httpServerTorPool; -var httpServer; -describe('HTTPServer', function () { - httpServerTorPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); - httpServer = new (TorRouter.HTTPServer)(httpServerTorPool, logger); - var httpPort; - before('start up server', function (done){ - this.timeout(WAIT_FOR_CREATE); - async.waterfall([ - (callback) => { httpServerTorPool.create(1, callback); }, - (callback) => { getPort().then((port) => callback(null, port)); }, - (port, callback) => { - httpPort = port; - httpServer.listen(port); - callback(); - } - ], done); - }); - - describe('#handle_http_connections(req, res)', function () { - it('should service a request for example.com', function (done) { - this.timeout(PAGE_LOAD_TIME); - - var req = request({ - url: 'http://example.com', - proxy: `http://localhost:${httpPort}` - }); - - req.on('error', function (error) { - done(error); - }); - - req.on('response', function (res) { - done(); - }); - }); - }); - - describe('#handle_connect_connections(req, inbound_socket, head)', function () { - it('should service a request for example.com', function (done) { - this.timeout(PAGE_LOAD_TIME); - - var req = request({ - url: 'https://example.com', - proxy: `http://localhost:${httpPort}` - }); - - req.on('error', function (error) { - done(error); - }); - - req.on('response', function (res) { - done(); - }); - }); - }); - - after('shutdown tor pool', function (done) { - httpServerTorPool.exit(done); - }); -}); - -var dnsServerTorPool; -var dnsServer; -describe('DNSServer', function () { - dnsServerTorPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger); - dnsServer = new (TorRouter.DNSServer)(dnsServerTorPool, {}, 10000, logger); - var dnsPort; - before('start up server', function (done){ - this.timeout(WAIT_FOR_CREATE); - async.waterfall([ - (callback) => { dnsServerTorPool.create(1, callback); }, - (callback) => { getPort().then((port) => callback(null, port)); }, - (port, callback) => { - dnsPort = port; - dnsServer.serve(port); - callback(); - } - ], done); - }); - - describe('#handle_dns_request(req, res)', function () { - it('should service a request for example.com', function (done) { - this.timeout(10000); - - var req = dns.Request({ - question: dns.Question({ - name: 'example.com', - type: 'A' - }), - server: { address: '127.0.0.1', port: dnsPort, type: 'udp' }, - timeout: 1000, - }); - - req.on('timeout', function () { - done(new Error('Connection timed out')); - }); - - req.on('message', function () { - done(); - }); - - req.send(); - }); - }); - - after('shutdown tor pool', function (done) { - dnsServerTorPool.exit(done); - }); -}); - -var controlServer = new (TorRouter.ControlServer)(logger, nconf); -var controlPort; -describe('ControlServer', function () { - describe('#listen(port)', function () { - it('should bind to a given port', function (done) { - getPort().then((port) => { - controlPort = port; - controlServer.listen(port, done); - }); - }); - }); - describe('#createTorPool(options)', function () { - it('should create a TorPool with a given configuration', function () { - let torPool = controlServer.createTorPool({ ProtocolWarnings: 1 }); - - assert.ok((controlServer.torPool instanceof (TorRouter.TorPool))); - assert.equal(1, torPool.default_tor_config.ProtocolWarnings); - }); - }); - describe('#createSOCKSServer(port)', function () { - it('should create a SOCKS Server', function (done) { - getPort().then((port) => { - controlServer.createSOCKSServer(port); - done(null, ( - (controlServer.socksServer instanceof (TorRouter.SOCKSServer)) - )); - }); - }); - }); - describe('#createDNSServer(port)', function () { - it('should create a DNS Server', function (done) { - getPort().then((port) => { - controlServer.createDNSServer(port); - done(null, ( - (controlServer.dnsServer instanceof (TorRouter.DNSServer)) - )); - }); - }); - }); - describe('#createHTTPServer(port)', function () { - it('should create a HTTP Server', function (done) { - getPort().then((port) => { - controlServer.createHTTPServer(port); - done(null, ( - (controlServer.httpServer instanceof (TorRouter.HTTPServer)) - )); - }); - }); - }); - - describe('#close()', function () { - it('should close the RPC Server', function () { - controlServer.close(); - }); - }); - - after('shutdown tor pool', function (done) { - controlServer.torPool.exit(done); - }); -}); - -var rpcControlServer = new (TorRouter.ControlServer)(logger, nconf); -var rpcControlPort; -var rpcClient; -describe('ControlServer - RPC', function () { - before('setup control server', function (done) { - async.waterfall([ - (callback) => { getPort().then((port) => callback(null, port)); }, - (port, callback) => { rpcControlPort = port; rpcControlServer.listen(port, callback); }, - (callback) => { - rpcClient = new rpc.Client(new rpc.tcpTransport({ port: rpcControlPort, hostname: 'localhost' })); - return callback(); - } - ], done); - }); - - describe('#createInstances(number_of_instances)', function () { - this.timeout(WAIT_FOR_CREATE*2); - it('should create an instance', function (done) { - rpcClient.invoke('createInstances', [2], function (error) { - if (error) - return done(error); - done(); - }); - }); - }); - - describe('#queryInstances()', function () { - this.timeout(3000); - it('should return a list of instances', function (done) { - rpcClient.invoke('queryInstances', [], function (error, raw) { - if (error) - return done(error); - - var instances = JSON.parse(raw).result; - - if (!Array.isArray(instances)) - done(new Error('Did not return an array')); - - done(null, (instances.every((i) => (typeof(i.name) !== 'undefined') && (i.name !== null)) && instances.length)); - }); - }); - }); - - describe('#addInstances(definitions)', function () { - this.timeout(WAIT_FOR_CREATE); - it("should add an instance based on a defintion", function (done) { - var def = { - Name: 'instance-1' - }; - rpcClient.invoke('addInstances', [ [ def ] ], done); - }); - - it("tor pool should now contain and instance that has the same name as the name specified in the defintion", function () { - assert.ok(rpcControlServer.torPool.instance_by_name('instance-1')); - }); - }); - - describe('#queryInstanceByName(instance_name)', function () { - this.timeout(3000); - it('should return a single instance', function (done) { - rpcClient.invoke('queryInstanceByName', ['instance-1'], function (error, raw) { - if (error) - return done(error); - - var instance = JSON.parse(raw).result; - - done(null, (typeof(instance.name) !== undefined) && (instance.name !== null)); - }); - }); - }); - - describe('#queryInstanceAt(index)', function () { - this.timeout(3000); - it('should return a single instance', function (done) { - rpcClient.invoke('queryInstanceAt', [0], function (error, raw) { - if (error) - return done(error); - - var instance = JSON.parse(raw).result; - - done(null, (typeof(instance.name) !== undefined) && (instance.name !== null)); - }); - }); - }); - - describe('#newIdentites()', function () { - this.timeout(3000); - it('should request new identities for all instances', function (done) { - rpcClient.invoke('newIdentites', [], done); - }); - }); - - describe('#newIdentityByName(instance_name)', function () { - this.timeout(3000); - it('should request new identities for all instances', function (done) { - rpcClient.invoke('newIdentityByName', ['instance-1'], done); - }); - }); - - describe('#newIdentityAt(index)', function () { - this.timeout(3000); - it('should request new identities for all instances', function (done) { - rpcClient.invoke('newIdentityAt', [0], done); - }); - }); - - describe("#setTorConfig(config_object)", function () { - this.timeout(3000); - it('should set several config variables on all instances', function (done) { - rpcClient.invoke('setTorConfig', [ { TestSocks: 1, ProtocolWarnings: 1 } ], done); - }); - - it('all instances should have the modified variables', function(done) { - async.map(rpcControlServer.torPool.instances, (instance, next) => { - async.series([ - (cb) => { instance.get_config('TestSocks', next); }, - (cb) => { instance.get_config('ProtocolWarnings', next); } - ], next); - }, (error, results) => { - if (error) return done(error); - - done(null, results.every((i) => i[0] === 1 && i[1] === 1)); - }); - }); - - after('unset config variables', function (done) { - async.series([ - (cb) => { rpcControlServer.torPool.set_config_all('TestSocks', 0, cb); }, - (cb) => { rpcControlServer.torPool.set_config_all('ProtocolWarnings', 0, cb); } - ], done); - }); - }); - - describe('#setDefaultTorConfig(object)', function () { - it('should set the default config of new instances', function (done) { - this.timeout(3000); - rpcClient.invoke('setDefaultTorConfig', [ { TestSocks: 1 } ], done); - }); - - it('a new instance should be created with the modified property', function (done) { - this.timeout(WAIT_FOR_CREATE); - - rpcControlServer.torPool.create_instance({ Name: 'config-test' }, (err) => { - if (err) return done(err); - - rpcControlServer.torPool.instance_by_name('config-test').get_config('TestSocks', (err, val) => { - if (err) return done(err); - - done(null, val === 1); - }); - }); - }); - - after('remove instance', function (done) { - this.timeout(10000); - nconf.set('torConfig', {}); - rpcControlServer.torPool.remove_by_name('config-test', done); - }); - }); - - describe('#getDefaultTorConfig()', function () { - before('set tor config', function () { - nconf.set('torConfig', { TestSocks: 1 }); - }); - - it('should return a tor config with a modified property', function (done) { - this.timeout(3000); - rpcClient.invoke('getDefaultTorConfig', [ { } ], function (error, raw) { - if (error) return done(error); - - var config = JSON.parse(raw).result; - - done(null, (config.TestSocks === 1)) - }); - }); - - after('unset property', function () { - nconf.set('torConfig', {}); - }); - }); - - describe('#getLoadBalanceMethod()', function () { - this.timeout(3000); - before(function () { - rpcControlServer.torPool.load_balance_method = 'round_robin'; - }); - - it('should return the current load balance method', function (done) { - rpcClient.invoke('getLoadBalanceMethod', [], function (error, raw) { - if (error) return done(error); - var lb_method = JSON.parse(raw).result; - done(null, (lb_method === 'round_robin')); - }); - }); - }); - - describe('#setLoadBalanceMethod(load_balance_method)', function () { - this.timeout(3000); - - it('should set the load balance method', function (done) { - rpcClient.invoke('setLoadBalanceMethod', ['weighted'], function (error) { - return done(error); - }); - }); - - it('the load balance method should be changed', function () { - assert.equal(rpcControlServer.torPool.load_balance_method, 'weighted'); - }); - - after(function () { - rpcControlServer.torPool.load_balance_method = 'round_robin'; - }); - }); - - describe("#getInstanceConfigByName(instance_name)", function () { - this.timeout(3000); - - before('set config property', function (done) { - rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 1, done); - }); - - it('should retrieve the property from the tor instance', function (done) { - rpcClient.invoke('getInstanceConfigByName', ['instance-1'], function (error, raw) { - if (error) return done(error); - - var value = JSON.parse(raw).result; - - done(null, value === 1); - }); - }); - - after('unset config property', function (done) { - rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0, done); - }); - }); - - describe("#getInstanceConfigAt(index)", function () { - this.timeout(3000); - - before('set config property', function (done) { - rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 1, done); - }); - - it('should retrieve the property from the tor instance', function (done) { - rpcClient.invoke('getInstanceConfigByName', [0], function (error, raw) { - if (error) return done(error); - - var value = JSON.parse(raw).result; - - done(null, value === 1); - }); - }); - - after('unset config property', function (done) { - rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0, done); - }); - }); - - describe("#setInstanceConfigByName(instance_name)", function () { - this.timeout(3000); - - before('set config property', function (done) { - rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0, done); - }); - - it('should set the property for the tor instance', function (done) { - rpcClient.invoke('setInstanceConfigByName', ['instance-1', 'TestSocks', 1], function (error, value) { - done(error); - }); - }); - - it('tor instance should have the modified property', function (done) { - rpcControlServer.torPool.instance_by_name('instance-1').get_config('TestSocks', function (error, value) { - if (error) return done(error); - done(null, (value === 1)); - }); - }); - - after('unset config property', function (done) { - rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0, done); - }); - }); - - describe("#setInstanceConfigAt(index)", function () { - this.timeout(3000); - - before('set config property', function (done) { - rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0, done); - }); - - it('should set the property for the tor instance', function (done) { - rpcClient.invoke('setInstanceConfigAt', [0, 'TestSocks', 1], function (error, value) { - done(error); - }); - }); - - it('tor instance should have the modified property', function (done) { - rpcControlServer.torPool.instance_at(0).get_config('TestSocks', function (error, value) { - if (error) return done(error); - done(null, (value === 1)); - }); - }); - - after('unset config property', function (done) { - rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0, (err) => { - done(err); - }); - }); - }); - - describe('#signalAllInstances(signal)', function () { - this.timeout(3000); - it('should signal to all interfaces', function (done) { - rpcClient.invoke('signalAllInstances', [ 'DEBUG' ], function (error) { - done(error); - }); - }); - }); - - describe('#signalInstanceAt(signal)', function () { - this.timeout(3000); - it('should signal to all interfaces', function (done) { - rpcClient.invoke('signalInstanceAt', [ 0, 'DEBUG' ], function (error) { - done(error); - }); - }); - }); - - describe('#signalAllInstances(signal)', function () { - this.timeout(3000); - it('should signal to all interfaces', function (done) { - rpcClient.invoke('signalInstanceByName', [ 'instance-1', 'DEBUG' ], function (error) { - done(error); - }); - }); - }); - - describe("#nextInstance()", function () { - this.timeout(3000); - var i_name; - it('should rotate the 0th item in the instances array', function (done) { - i_name = rpcControlServer.torPool.instances[0].instance_name; - rpcClient.invoke('nextInstance', [], function (error) { - done(error); - }); - }); - - it('0th item in the instances array should be different after nextInstance is called', function () { - assert.notEqual(rpcControlServer.torPool.instances[0].instance_name, i_name); - }); - }); - var instance_num1, instance_num2, i_num; - describe('#removeInstanceAt(index)', function () { - this.timeout(10000); - it("should remove an instance at the position specified", function (done) { - instance_num1 = rpcControlServer.torPool.instances.length; - rpcClient.invoke('removeInstanceAt', [0], function (error) { - done(error); - }); - }); - - it('the tor pool should contain one instance fewer', function () { - assert.equal(rpcControlServer.torPool.instances.length, (instance_num1 - 1)); - }); - }); - - describe('#removeInstanceByName(instance_name)', function () { - this.timeout(10000); - it("should remove an instance at the position specified", function (done) { - instance_num2 = rpcControlServer.torPool.instances.length; - rpcClient.invoke('removeInstanceByName', [ "instance-1" ], function (error) { - done(error); - }); - }); - - it('the tor pool should contain one instance fewer', function () { - assert.equal(rpcControlServer.torPool.instances.length, (instance_num2 - 1)); - }); - }); - - describe('#closeInstances()', function () { - this.timeout(10000); - it('should shutdown all instances', function (done) { - i_num = rpcControlServer.torPool.instances.length; - rpcClient.invoke('closeInstances', [ ], function (error) { - done(error); - }); - }); - - it('no instances should be present in the pool', function () { - assert.equal(rpcControlServer.torPool.instances.length, 0); - assert.notEqual(rpcControlServer.torPool.instances.length, i_num); - }); - }); - - after('shutdown tor pool', function (done) { - this.timeout(10000); - rpcControlServer.torPool.exit(done); - }); -}); \ No newline at end of file