From 996ef463b4b500125f095579f03f52d1a8154c6c Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Mon, 26 Nov 2018 19:04:41 +0100 Subject: [PATCH 01/21] Upgrade domapic-base version --- package-lock.json | 430 +++++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 370 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd20e00..7a25ceb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@pm2/agent": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-0.5.17.tgz", - "integrity": "sha512-F+Dki1W4QKRQUlp2pQzrs9vSlQ8S/ItbiDH4LrKZRGXxSfK6s90iv6kJ/UycmaDXpfK12POi0dCui6ptB967Sg==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-0.5.20.tgz", + "integrity": "sha512-WKZZ1fVlLjwWmN0qBpmR4Q3N8uV7KX5lq4D97ac1vEGHeO58I4GayabqYw7nxg2G/XFPdNIhLX6OrALEGFvv6Q==", "requires": { "async": "^2.6.0", "eventemitter2": "^5.0.1", @@ -31,12 +31,13 @@ } }, "@pm2/agent-node": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@pm2/agent-node/-/agent-node-1.0.7.tgz", - "integrity": "sha512-09m5zCJM9lpdA4MjHS+nahEVf+bjdvj5OepqiQiLxh+Jz1L5VSFmXyT9tUszanhJg3AajRfNKup1ASNtzVnPMg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@pm2/agent-node/-/agent-node-1.0.10.tgz", + "integrity": "sha512-GRJUmDVmhx/gJwKvgmdY6EbZDPtr0UIyTchf3uAoV8lFAboxWWshfv0V0s91A75BxKOE4AzIy886TA8Dnv54BA==", "requires": { "debug": "^3.1.0", "eventemitter2": "^5.0.1", + "proxy-agent": "^3.0.3", "ws": "^6.0.0" }, "dependencies": { @@ -54,9 +55,9 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "ws": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.0.tgz", - "integrity": "sha512-H3dGVdGvW2H8bnYpIDc3u3LH8Wue3Qh+Zto6aXXFzvESkTVT6rAfKR6tR/+coaUvxs8yHtmNV0uioBF62ZGSTg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", + "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", "requires": { "async-limiter": "~1.0.0" } @@ -64,11 +65,11 @@ } }, "@pm2/io": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@pm2/io/-/io-2.4.5.tgz", - "integrity": "sha512-+JPRL7T/5uoLzUnYV5SlrU1jWNOVfSRBeX386cx68EpotWRH0qS9HjGwh+DjBTeMRdvI9aVyhiBYqqRq8Lb6eg==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-2.4.7.tgz", + "integrity": "sha512-01IQBBeIFUO6Gs3mVDfoDYcZ3cbaN66gPo6guVQTfhiTv1+ftQlSuZH64dO+41wKbUYgDrXnIvFHR99bnpqj8Q==", "requires": { - "@pm2/agent-node": "^1.0.6", + "@pm2/agent-node": "^1.0.9", "async": "^2.6.1", "debug": "3.1.0", "deep-metrics": "0.0.2", @@ -100,9 +101,9 @@ } }, "@pm2/js-api": { - "version": "0.5.30", - "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.5.30.tgz", - "integrity": "sha512-kx0Fd3CBmq89OcX9eigcIc86nMuydn2MxZurPRhR5JhQcH7WINf8mrtqAntJtVo8Hv6IlQJslzaJ5UMKsxLKvw==", + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.5.34.tgz", + "integrity": "sha512-jHB4PD0J4KsvFoiqn5/8uZoBaQWojREItMgqCwktG7o0Kl2OlYSfBuhMjNqUJoi4b3o9dVREJXmZQGuUFp8Psw==", "requires": { "async": "^2.4.1", "axios": "^0.16.2", @@ -198,10 +199,19 @@ } } }, + "agent-base": { + "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==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", @@ -372,6 +382,11 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "ast-types": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.7.tgz", + "integrity": "sha512-2mP3TwtkY/aTv5X3ZsMpNAbOnyoC/aMJwJSoaELPkHId0nSQgFcnU4dRW3isxiz7+zBexk0ym3WNVjMiQBnJSw==" + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -1139,6 +1154,11 @@ "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" }, + "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==" + }, "date-fns": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", @@ -1191,8 +1211,7 @@ "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 + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "deep-metrics": { "version": "0.0.2", @@ -1267,6 +1286,23 @@ } } }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + } + } + }, "deglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", @@ -1347,9 +1383,9 @@ } }, "domapic-base": { - "version": "1.0.0-beta.14", - "resolved": "https://registry.npmjs.org/domapic-base/-/domapic-base-1.0.0-beta.14.tgz", - "integrity": "sha512-UHuf6SGfEIx9A19/w1ioVtN5CdgOXs6s2YOCwL6wqDomlsxlBjH0UZpoI7iMYHnBHTX8OTZ/2m7nJnK3vBWGsw==", + "version": "1.0.0-beta.16", + "resolved": "https://registry.npmjs.org/domapic-base/-/domapic-base-1.0.0-beta.16.tgz", + "integrity": "sha512-i7v2KDQ75Vs1iQ5QptzgSm1pvA28dZiQgq35tPfw5cnXTgpRKQ3ChnF+aAdWo8Fl758X/qvBH97TVCHx5YVvAw==", "requires": { "bluebird": "3.5.2", "body-parser": "1.18.3", @@ -1361,7 +1397,6 @@ "fs-extra": "7.0.0", "hbs": "4.0.1", "helmet": "3.14.0", - "ip": "1.1.5", "ip-range-check": "0.0.2", "is-promise": "2.1.0", "jsonschema": "1.2.4", @@ -1377,6 +1412,17 @@ "yargs": "12.0.2" }, "dependencies": { + "ajv": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", + "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "aws4": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", @@ -1392,15 +1438,25 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "ajv": "^5.3.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -1545,6 +1601,19 @@ "is-symbol": "^1.0.1" } }, + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1560,6 +1629,31 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "escodegen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, "eslint": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", @@ -1788,14 +1882,12 @@ "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "etag": { "version": "1.8.1", @@ -2048,7 +2140,8 @@ "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", @@ -2058,8 +2151,7 @@ "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 + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fclone": { "version": "1.0.11", @@ -2090,6 +2182,11 @@ "object-assign": "^4.0.1" } }, + "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==" + }, "fileset": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", @@ -2182,9 +2279,9 @@ } }, "follow-redirects": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.9.tgz", - "integrity": "sha512-Bh65EZI/RU8nx0wbYF9shkFZlqLP+6WT/5FnA3cE/djNSuKNHJEinGGZgu/cQEkeeb2GdFOgenAmn8qaqYke2w==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "requires": { "debug": "=3.1.0" }, @@ -2724,6 +2821,38 @@ } } }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "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=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "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=" + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -2758,6 +2887,19 @@ "resolved": "http://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==", + "requires": { + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "3", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -3015,6 +3157,25 @@ "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==", + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3025,6 +3186,30 @@ "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==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -3600,7 +3785,8 @@ "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -3731,7 +3917,6 @@ "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" @@ -3872,16 +4057,15 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, "map-age-cleaner": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz", - "integrity": "sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "requires": { "p-defer": "^1.0.0" } @@ -3901,7 +4085,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -4276,6 +4460,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4478,7 +4667,6 @@ "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", @@ -4491,8 +4679,7 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" } } }, @@ -4551,6 +4738,48 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "pac-proxy-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.0.tgz", + "integrity": "sha512-AOUX9jES/EkQX2zRz0AW7lSx9jD//hQS8wFXBvcnd/J2Py9KaMJMqV/LPqJssj1tgGufotb2mmopGPR15ODv1Q==", + "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": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "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==", + "requires": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, "pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", @@ -4899,8 +5128,7 @@ "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 + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "process-nextick-args": { "version": "2.0.0", @@ -4940,11 +5168,45 @@ "ipaddr.js": "1.8.0" } }, + "proxy-agent": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.3.tgz", + "integrity": "sha512-PXVVVuH9tiQuxQltFJVSnXWuDtNr+8aNBP6XVDDCDiUuDN8eRCm+ii4/mFWmXWEA0w8jjJSlePa4LXlM4jIzNA==", + "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": "^3.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "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=" + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "psl": { "version": "1.1.29", @@ -5268,7 +5530,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -5378,9 +5640,9 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "shelljs": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", - "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -5429,6 +5691,11 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "smart-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.1.tgz", + "integrity": "sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg==" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -5526,6 +5793,24 @@ "kind-of": "^3.2.0" } }, + "socks": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.2.tgz", + "integrity": "sha512-g6wjBnnMOZpE0ym6e0uHSddz9p3a+WsBaaYQaBaSCJYvrC4IXykQR9MNGjLQf38e9iIIhp3b1/Zk8YZI3KGJ0Q==", + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.0.1" + } + }, + "socks-proxy-agent": { + "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==", + "requires": { + "agent-base": "~4.2.0", + "socks": "~2.2.0" + } + }, "source-map": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", @@ -5746,7 +6031,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-json-comments": { @@ -5800,6 +6085,11 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=" + }, "tinytim": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/tinytim/-/tinytim-0.1.1.tgz", @@ -5925,7 +6215,6 @@ "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" } @@ -6082,6 +6371,21 @@ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==" }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -6290,9 +6594,9 @@ "integrity": "sha512-rx3GzJlgEeZ08MIcDsU2vY2B1QEriUKJTSiNHHUIem6eg9pzVOr2TL3Y4Pd6TMAM5D5azGjcxqI62piITBDHVg==" }, "xregexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", - "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" }, "xtend": { "version": "4.0.1", @@ -6308,8 +6612,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yaml-include": { "version": "1.2.0", @@ -6419,6 +6722,11 @@ "requires": { "ansi-regex": "^3.0.0" } + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" } } }, diff --git a/package.json b/package.json index 50881ea..ca53f5d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ }, "dependencies": { "bluebird": "3.5.1", - "domapic-base": "1.0.0-beta.14", + "domapic-base": "1.0.0-beta.16", "is-promise": "2.1.0", "lodash": "4.17.10", "rand-token": "0.4.0", From 30faa4776ce1deb301d799137dda1ade2a7a8dff Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Mon, 26 Nov 2018 19:21:12 +0100 Subject: [PATCH 02/21] Adapt functional tets to new domapic-base version --- test/functional/plugin-specs/config-api.specs.js | 3 ++- test/functional/specs/config-api.specs.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/functional/plugin-specs/config-api.specs.js b/test/functional/plugin-specs/config-api.specs.js index fc579d6..6e18a18 100644 --- a/test/functional/plugin-specs/config-api.specs.js +++ b/test/functional/plugin-specs/config-api.specs.js @@ -28,7 +28,8 @@ test.describe('config api', function () { exampleOption: false, authDisabled: [], hostName: utils.SERVICE_HOST, - path: path.resolve(__dirname, '..', '..', '..', utils.DOMAPIC_PATH) + path: path.resolve(__dirname, '..', '..', '..', utils.DOMAPIC_PATH), + rejectUntrusted: false }) ]) }) diff --git a/test/functional/specs/config-api.specs.js b/test/functional/specs/config-api.specs.js index f28bcc0..54f9ade 100644 --- a/test/functional/specs/config-api.specs.js +++ b/test/functional/specs/config-api.specs.js @@ -28,7 +28,8 @@ test.describe('config api', function () { initialStatus: true, authDisabled: [], hostName: utils.SERVICE_HOST, - path: path.resolve(__dirname, '..', '..', '..', utils.DOMAPIC_PATH) + path: path.resolve(__dirname, '..', '..', '..', utils.DOMAPIC_PATH), + rejectUntrusted: false }) ]) }) From bf13fe8e096eb2abd6e8d3366e4515f8e8b0df87 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Mon, 26 Nov 2018 20:07:31 +0100 Subject: [PATCH 03/21] Upgrade domapic-controller version in end-to-end tests --- test/end-to-end/fixtures/controller/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/end-to-end/fixtures/controller/package.json b/test/end-to-end/fixtures/controller/package.json index 62bf6b2..74cba0b 100644 --- a/test/end-to-end/fixtures/controller/package.json +++ b/test/end-to-end/fixtures/controller/package.json @@ -6,6 +6,6 @@ "domapic-controller": "node_modules/.bin/domapic-controller" }, "dependencies": { - "domapic-controller": "1.0.0-alpha.9" + "domapic-controller": "1.0.0-alpha.10" } } From d97738aecb70f639ecdcddfabf2457ebd20878e5 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Tue, 27 Nov 2018 20:23:44 +0100 Subject: [PATCH 04/21] Do not demand data in abilities. Only mandatory for abilities with state --- .narval.yml | 22 +++ lib/Abilities.js | 88 ++++++---- lib/abilitySchema.json | 4 +- lib/templates.js | 7 +- .../abilities-wrong-responses/package.json | 8 + .../abilities-wrong-responses/server.js | 152 ++++++++++++++++++ .../fixtures/multiple-abilities/server.js | 13 ++ .../functional/specs/ability-no-data.specs.js | 50 ++++++ .../specs/ability-wrong-responses.specs.js | 65 ++++++++ 9 files changed, 376 insertions(+), 33 deletions(-) create mode 100644 test/functional/fixtures/abilities-wrong-responses/package.json create mode 100644 test/functional/fixtures/abilities-wrong-responses/server.js create mode 100644 test/functional/specs/ability-no-data.specs.js create mode 100644 test/functional/specs/ability-wrong-responses.specs.js diff --git a/.narval.yml b/.narval.yml index f0d0d2f..091da26 100644 --- a/.narval.yml +++ b/.narval.yml @@ -295,6 +295,28 @@ suites: - test/functional/specs/ability-string-enum.specs.js - test/functional/specs/ability-number.specs.js - test/functional/specs/ability-number-enum.specs.js + - test/functional/specs/ability-no-data.specs.js + coverage: *disable-coverage + - name: ability-wrong-responses + describe: should validate handler responses for each type of ability data + before: *clean + services: + - name: domapic-service + abort-on-error: true + local: + <<: *local-service-auth + env: + <<: *local-service-auth-env + fixture: abilities-wrong-responses + docker: + <<: *docker-service-auth + env: + <<: *docker-service-auth-env + fixture: abilities-wrong-responses + test: + <<: *functional-test + specs: + - test/functional/specs/ability-wrong-responses.specs.js coverage: *disable-coverage - name: documentation-example describe: documentation example should work as expected diff --git a/lib/Abilities.js b/lib/Abilities.js index f25cce9..2c179cc 100644 --- a/lib/Abilities.js +++ b/lib/Abilities.js @@ -56,12 +56,21 @@ const Abilities = function (service, connection) { } validationError = jsonSchemaValidator.validate(ability, abilitySchema).errors.join('. ') if (validationError.length) { - return Promise.reject(new service.errors.BadImplementation(validationError)) + return Promise.reject(new service.errors.BadData(validationError)) } registered[name] = ability return Promise.resolve() } + const toEmptyDataSchema = function () { + return { + type: 'object', + properties: { + }, + additionalProperties: false + } + } + const toDataSchema = function (schema) { return { type: 'object', @@ -73,21 +82,29 @@ const Abilities = function (service, connection) { } } - const DataValidator = function (schema, name, type) { - const dataSchema = toDataSchema(schema) - return function (data) { - const validationError = jsonSchemaValidator.validate(data, dataSchema).errors.join('. ') - - if (!validationError.length) { - return Promise.resolve(data) + const DataValidator = function (name, type, ability) { + const dataSchema = ability.data ? toDataSchema(ability.data) : toEmptyDataSchema() + return function (data, isResponse) { + const validationType = isResponse ? 'response' : 'request' + let validationError + if (ability.data && (_.isUndefined(data) || _.isUndefined(data.data))) { + validationError = templates.compiled.dataIsMandatory() + } else if (!ability.data && !_.isUndefined(data) && !_.isUndefined(data.data)) { + validationError = templates.compiled.dataIsNotAllowed() + } else { + validationError = jsonSchemaValidator.validate(data, dataSchema).errors.join('. ') + if (!validationError.length) { + return Promise.resolve(data) + } } return service.tracer.error(templates.compiled.invalidAbilityData({ message: validationError, name: name, + validationType, type: type })).then(() => { - return Promise.reject(new service.errors.BadImplementation(validationError)) + return Promise.reject(new service.errors.BadData(`${validationType} ${validationError}`)) }) } } @@ -95,11 +112,13 @@ const Abilities = function (service, connection) { const registerSchema = function (ability, name) { const schema = {} if (!ability.data) { - return Promise.reject(new service.errors.BadData(templates.compiled.abilityHasNoData({ - name: name - }))) + if (ability.state) { + return Promise.reject(new service.errors.BadData(templates.compiled.abilityHasNoData({ + name: name + }))) + } } - schema[nameToSchema(name)] = toDataSchema(ability.data) + schema[nameToSchema(name)] = ability.data ? toDataSchema(ability.data) : toEmptyDataSchema() return service.server.extendOpenApi({ tags: [{ @@ -112,12 +131,12 @@ const Abilities = function (service, connection) { }) } - const EventHandler = function (name, dataSchema) { - const validateData = new DataValidator(dataSchema, name, 'event') + const EventHandler = function (name, ability) { + const validateData = new DataValidator(name, 'event', ability) const normalizedAbilityName = service.utils.services.normalizeName(name) return function (result) { - const data = { data: result } - return validateData(data) + const data = !_.isUndefined(result) ? { data: result } : result + return validateData(data, true) .then(() => { return connection.sendAbilityEvent(normalizedAbilityName, data) }) @@ -130,15 +149,18 @@ const Abilities = function (service, connection) { } } - const AbilityHandler = function (name, type, dataSchema, handler, auth) { - const validateData = new DataValidator(dataSchema, name, type) + const AbilityHandler = function (name, type, ability) { + const validateData = new DataValidator(name, type, ability) const abilityHandler = (params, requestBody, response, user) => { - const result = handler(requestBody && requestBody.data) - const resultPromise = isPromise(result) ? result : Promise.resolve(result) - return resultPromise.then(result => { - const data = { data: result } - return validateData(data) - .then(() => Promise.resolve(data)) + const bodyValidation = type === 'action' ? validateData(requestBody) : Promise.resolve() + return bodyValidation.then(() => { + const result = ability[type].handler(requestBody && requestBody.data) + const resultPromise = isPromise(result) ? result : Promise.resolve(result) + return resultPromise.then(result => { + const data = !_.isUndefined(result) ? { data: result } : result + return validateData(data, true) + .then(() => Promise.resolve(data)) + }) }) } return { @@ -150,7 +172,7 @@ const Abilities = function (service, connection) { if (!ability.event) { return Promise.resolve() } - events.on(name, new EventHandler(name, ability.data)) + events.on(name, new EventHandler(name, ability)) return Promise.resolve() } @@ -175,7 +197,7 @@ const Abilities = function (service, connection) { return Promise.resolve() } - operations[operationId] = new AbilityHandler(name, 'state', ability.data, ability.state.handler, ability.state.auth) + operations[operationId] = new AbilityHandler(name, 'state', ability) const get = { tags: ['state', name], @@ -211,7 +233,7 @@ const Abilities = function (service, connection) { return Promise.resolve() } - operations[operationId] = new AbilityHandler(name, 'action', ability.data, ability.action.handler, ability.action.auth) + operations[operationId] = new AbilityHandler(name, 'action', ability) const post = { tags: ['action', name], @@ -222,7 +244,7 @@ const Abilities = function (service, connection) { description: templates.compiled.actionRequestBodyDescription({ name: name }), - required: true, + required: !!ability.data, content: nameToJsonSchemaContent(name) } } @@ -282,6 +304,14 @@ const Abilities = function (service, connection) { .then(() => { return Promise.resolve(service) }) + .catch(err => { + const errorMessage = templates.compiled.errorRegisteringAbility({ + message: err.message + }) + return service.tracer.error(errorMessage).then(() => { + return Promise.reject(new service.errors.BadImplementation(errorMessage)) + }) + }) } const registerAbilities = function (abilities) { diff --git a/lib/abilitySchema.json b/lib/abilitySchema.json index 80e11c4..40a98f8 100644 --- a/lib/abilitySchema.json +++ b/lib/abilitySchema.json @@ -113,9 +113,9 @@ } }, "anyOf": [{ - "required": ["description", "data", "event"] + "required": ["description", "event"] }, { - "required": ["description", "data", "action"] + "required": ["description", "action"] }, { "required": ["description", "data", "state"] }], diff --git a/lib/templates.js b/lib/templates.js index ed74f9c..eb0d7f6 100644 --- a/lib/templates.js +++ b/lib/templates.js @@ -21,7 +21,9 @@ const templates = { stateResponseDescription: 'Current state of ability "{{name}}"', actionTagDescription: 'Service action', stateTagDescription: 'Service state', - invalidAbilityData: 'Invalid data in {{type}} "{{name}}": {{{message}}}', + dataIsMandatory: 'No data was defined', + dataIsNotAllowed: 'Data was provided to an ability without data defined', + invalidAbilityData: 'Invalid data in {{type}} {{validationType}} "{{name}}": {{{message}}}', abilityHasNothingToRegister: 'Must have at least an state, action or event to be registered', sendEventError: 'Error sending "{{name}}" event: {{message}}', @@ -55,7 +57,8 @@ const templates = { gettingUserApiKey: 'Getting service user api key from Controller', addingUserApiKey: 'Adding api key for service user into Controller', loggingIntoController: 'Loggin into controller with user id "{{_id}}" and apiKey "{{apiKey}}"', - storingControllerData: 'Storing controller data for next connections' + storingControllerData: 'Storing controller data for next connections', + errorRegisteringAbility: 'Error registering abilities: {{{message}}}' } module.exports = { diff --git a/test/functional/fixtures/abilities-wrong-responses/package.json b/test/functional/fixtures/abilities-wrong-responses/package.json new file mode 100644 index 0000000..5b9a688 --- /dev/null +++ b/test/functional/fixtures/abilities-wrong-responses/package.json @@ -0,0 +1,8 @@ +{ + "name": "console-domapic", + "version": "1.0.0", + "description": "Example of Node.js Domapic service with many abilities", + "dependencies": { + "domapic-service": "file:../../../../" + } +} diff --git a/test/functional/fixtures/abilities-wrong-responses/server.js b/test/functional/fixtures/abilities-wrong-responses/server.js new file mode 100644 index 0000000..b03e1c4 --- /dev/null +++ b/test/functional/fixtures/abilities-wrong-responses/server.js @@ -0,0 +1,152 @@ +'use strict' + +const path = require('path') + +const domapic = require('../../../../index') + +domapic.createModule({ + packagePath: path.resolve(__dirname) +}).then((service) => { + const consoleLog = function (data, ability) { + service.tracer.info('Console Called:', data) + } + + return service.register({ + booleanConsole: { + description: 'Handle boolean console logs', + data: { + type: 'boolean' + }, + event: { + description: 'Console has just printed a boolean' + }, + state: { + description: 'Last boolean printed in console', + handler: () => { + return Promise.resolve(null) + } + }, + action: { + description: 'Print the received boolean into console', + handler: (data) => { + consoleLog(data, 'booleanConsole') + return Promise.resolve(3) + } + } + }, + emailConsole: { + description: 'Handle email console logs', + data: { + type: 'string', + format: 'email', + maxLength: 15, + minLength: 11, + pattern: '^foo' + }, + event: { + description: 'Console has just printed an email' + }, + state: { + description: 'Last email printed in console', + handler: () => { + return Promise.resolve('foo') + } + }, + action: { + description: 'Print the received email into console', + handler: (data) => { + consoleLog(data, 'emailConsole') + return Promise.resolve(true) + } + } + }, + enumConsole: { + description: 'Handle string enum console logs', + data: { + type: 'string', + enum: ['foo1', 'foo2'] + }, + event: { + description: 'Console has just printed an string from enum' + }, + state: { + description: 'Last string from enum printed in console', + handler: () => { + return Promise.resolve(false) + } + }, + action: { + description: 'Print the received string from enum into console', + handler: (data) => { + consoleLog(data, 'enumConsole') + return Promise.resolve('foo3') + } + } + }, + numericConsole: { + description: 'Handle numeric console logs', + data: { + type: 'number', + multipleOf: 10, + minimum: 60, + maximum: 120 + }, + event: { + description: 'Console has just printed a number' + }, + state: { + description: 'Last number printed in console', + handler: () => { + return Promise.resolve('foo') + } + }, + action: { + description: 'Print the received number into console', + handler: (data) => { + consoleLog(data, 'numericConsole') + return Promise.resolve(150) + } + } + }, + numericEnumConsole: { + description: 'Handle numeric enum console logs', + data: { + type: 'number', + enum: [10, 20, 30, 40], + minimum: 10, + maximum: 40, + exclusiveMaximum: true, + exclusiveMinimum: true + }, + event: { + description: 'Console has just printed a number from enum' + }, + state: { + description: 'Last number printed in console', + handler: () => { + return Promise.resolve(4) + } + }, + action: { + description: 'Print the received number from enum into console', + handler: (data) => { + consoleLog(data, 'numericEnumConsole') + return Promise.resolve(false) + } + } + }, + noDataConsole: { + description: 'Prints hello into console', + event: { + description: 'Console has just printed hello' + }, + action: { + description: 'Print hello into console', + handler: () => { + consoleLog('hello', 'noDataConsole') + return Promise.resolve(5) + } + } + } + }).then(service.start) +}) diff --git a/test/functional/fixtures/multiple-abilities/server.js b/test/functional/fixtures/multiple-abilities/server.js index 3fd43bd..d25a94f 100644 --- a/test/functional/fixtures/multiple-abilities/server.js +++ b/test/functional/fixtures/multiple-abilities/server.js @@ -140,6 +140,19 @@ domapic.createModule({ return Promise.resolve(data) } } + }, + noDataConsole: { + description: 'Prints hello into console', + event: { + description: 'Console has just printed hello' + }, + action: { + description: 'Print hello into console', + handler: () => { + consoleLog('hello', 'noDataConsole') + return Promise.resolve() + } + } } }).then(service.start) }) diff --git a/test/functional/specs/ability-no-data.specs.js b/test/functional/specs/ability-no-data.specs.js new file mode 100644 index 0000000..f78b74a --- /dev/null +++ b/test/functional/specs/ability-no-data.specs.js @@ -0,0 +1,50 @@ + +const test = require('narval') +const testUtils = require('narval/utils') + +const utils = require('./utils') + +test.describe('when using an ability without data', function () { + this.timeout(10000) + let connection + + test.before(() => { + return utils.waitOnestimatedStartTime(2000) + .then(() => { + connection = new utils.Connection() + return Promise.resolve() + }) + }) + + test.it('should dispatch ability action', () => { + return connection.request('/abilities/no-data-console/action', { + method: 'POST' + }).then((response) => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('domapic-service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(200), + test.expect(log).to.contain(`Console Called: hello`), + test.expect(log).to.contain(`Error sending "noDataConsole" event: The service is not connected to Controller`) + ]) + }) + }) + }) + }) + + test.it('should return a bad data error when data is provided', () => { + return connection.request('/abilities/no-data-console/action', { + method: 'POST', + body: { + data: 'foo2323' + } + }).then((response) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422), + test.expect(response.body.message).to.contain('additionalProperty "data" exists in instance when not allowed') + ]) + }) + }) +}) diff --git a/test/functional/specs/ability-wrong-responses.specs.js b/test/functional/specs/ability-wrong-responses.specs.js new file mode 100644 index 0000000..1202d43 --- /dev/null +++ b/test/functional/specs/ability-wrong-responses.specs.js @@ -0,0 +1,65 @@ + +const test = require('narval') + +const utils = require('./utils') + +test.describe('when validating ability handlers responses', function () { + this.timeout(10000) + let connection + + test.before(() => { + return utils.waitOnestimatedStartTime(2000) + .then(() => { + connection = new utils.Connection() + return Promise.resolve() + }) + }) + + const testState = function (url, dataType, errorMessage) { + test.it(`state should return a bad data error when ${dataType} data is required, but not returned`, () => { + return connection.request(`/abilities/${url}/state`, { + method: 'GET' + }).then((response) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422), + test.expect(response.body.message).to.contain('response'), + test.expect(response.body.message).to.contain(`instance.data ${errorMessage}`) + ]) + }) + }) + } + + const testAction = function (url, dataType, errorMessage, data) { + test.it(`action should return a bad data error when ${dataType} data is required and response does not meet the expectative`, () => { + return connection.request(`/abilities/${url}/action`, { + method: 'POST', + body: { + data + } + }).then((response) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422), + test.expect(response.body.message).to.contain('response'), + test.expect(response.body.message).to.contain(`${errorMessage}`) + ]) + }) + }) + } + + testState('boolean-console', 'boolean', 'is not of a type(s) boolean') + testAction('boolean-console', 'boolean', 'is not of a type(s) boolean', false) + + testState('email-console', 'email', 'does not conform to the "email" format') + testAction('email-console', 'email', 'is not of a type(s) string', 'foo@foo.com') + + testState('enum-console', 'enum', 'is not one of enum values') + testAction('enum-console', 'enum', 'is not one of enum values', 'foo1') + + testState('numeric-console', 'number', 'is not of a type(s) number') + testAction('numeric-console', 'number', 'must have a maximum value of 120', 70) + + testState('numeric-enum-console', 'number enum', 'is not one of enum values') + testAction('numeric-enum-console', 'number enum', 'is not one of enum values', 30) + + testAction('no-data-console', 'no', 'Data was provided to an ability without data defined') +}) From 9aea351f1e28546a9f867ba84e18e333d419c4de Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Tue, 27 Nov 2018 20:43:41 +0100 Subject: [PATCH 05/21] Add functional tests --- .narval.yml | 21 +++++++++++++ lib/templates.js | 2 +- .../fixtures/multiple-abilities/server.js | 15 +++++++++- .../wrong-ability-no-data/package.json | 8 +++++ .../fixtures/wrong-ability-no-data/server.js | 30 +++++++++++++++++++ .../functional/specs/ability-no-data.specs.js | 20 ++++++++++++- .../specs/wrong-ability-no-data.specs.js | 20 +++++++++++++ 7 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 test/functional/fixtures/wrong-ability-no-data/package.json create mode 100644 test/functional/fixtures/wrong-ability-no-data/server.js create mode 100644 test/functional/specs/wrong-ability-no-data.specs.js diff --git a/.narval.yml b/.narval.yml index 091da26..1df3a4f 100644 --- a/.narval.yml +++ b/.narval.yml @@ -271,6 +271,27 @@ suites: specs: - test/functional/specs/wrong-ability.specs.js coverage: *disable-coverage + - name: wrong-ability-no-data + describe: should throw an error when trying to register an ability with state and no data + before: *clean + services: + - name: domapic-service + abort-on-error: true + local: + <<: *local-service-auth + env: + <<: *local-service-auth-env + fixture: wrong-ability-no-data + docker: + <<: *docker-service-auth + env: + <<: *docker-service-auth-env + fixture: wrong-ability-no-data + test: + <<: *functional-test + specs: + - test/functional/specs/wrong-ability-no-data.specs.js + coverage: *disable-coverage - name: ability-data-types describe: should work as expected and validate data for each type of ability data before: *clean diff --git a/lib/templates.js b/lib/templates.js index eb0d7f6..31a529c 100644 --- a/lib/templates.js +++ b/lib/templates.js @@ -16,7 +16,7 @@ const templates = { addingSecurityApi: 'Adding security api', registerAbilitiesServerStarted: 'Registering abilities once the server is started is not allowed', abilityValidationError: 'Ability "{{name}}" has an invalid format: {{{message}}}', - abilityHasNoData: 'Ability "{{name}}" has not mandatory "data" property defined', + abilityHasNoData: 'Ability "{{name}}" needs a "data" property when has an state defined', actionRequestBodyDescription: 'Data for the action "{{name}}"', stateResponseDescription: 'Current state of ability "{{name}}"', actionTagDescription: 'Service action', diff --git a/test/functional/fixtures/multiple-abilities/server.js b/test/functional/fixtures/multiple-abilities/server.js index d25a94f..8bba89c 100644 --- a/test/functional/fixtures/multiple-abilities/server.js +++ b/test/functional/fixtures/multiple-abilities/server.js @@ -149,7 +149,20 @@ domapic.createModule({ action: { description: 'Print hello into console', handler: () => { - consoleLog('hello', 'noDataConsole') + consoleLog(undefined, 'noDataConsole') + return Promise.resolve() + } + } + }, + noDataWrongConsole: { + description: 'Prints hello into console', + event: { + description: 'Console has just printed hello' + }, + action: { + description: 'Print hello into console', + handler: () => { + consoleLog('hello', 'noDataWrongConsole') return Promise.resolve() } } diff --git a/test/functional/fixtures/wrong-ability-no-data/package.json b/test/functional/fixtures/wrong-ability-no-data/package.json new file mode 100644 index 0000000..4d55830 --- /dev/null +++ b/test/functional/fixtures/wrong-ability-no-data/package.json @@ -0,0 +1,8 @@ +{ + "name": "console-domapic", + "version": "1.0.0", + "description": "Example of Node.js Domapic service", + "dependencies": { + "domapic-service": "file:../../../../" + } +} diff --git a/test/functional/fixtures/wrong-ability-no-data/server.js b/test/functional/fixtures/wrong-ability-no-data/server.js new file mode 100644 index 0000000..65bd19d --- /dev/null +++ b/test/functional/fixtures/wrong-ability-no-data/server.js @@ -0,0 +1,30 @@ +'use strict' + +const path = require('path') + +const domapic = require('../../../../index') + +domapic.createModule({ + packagePath: path.resolve(__dirname) +}).then((service) => { + return service.register({ + noDataConsole: { + description: 'Prints hello into console', + event: { + description: 'Console has just printed hello' + }, + state: { + description: 'Console state', + handler: () => { + return Promise.resolve(true) + } + }, + action: { + description: 'Print hello into console', + handler: () => { + return Promise.resolve() + } + } + } + }).catch(service.start) +}) diff --git a/test/functional/specs/ability-no-data.specs.js b/test/functional/specs/ability-no-data.specs.js index f78b74a..d214774 100644 --- a/test/functional/specs/ability-no-data.specs.js +++ b/test/functional/specs/ability-no-data.specs.js @@ -26,7 +26,7 @@ test.describe('when using an ability without data', function () { .then((log) => { return Promise.all([ test.expect(response.statusCode).to.equal(200), - test.expect(log).to.contain(`Console Called: hello`), + test.expect(log).to.contain(`Console Called: undefined`), test.expect(log).to.contain(`Error sending "noDataConsole" event: The service is not connected to Controller`) ]) }) @@ -47,4 +47,22 @@ test.describe('when using an ability without data', function () { ]) }) }) + + test.it('should not send event when trying to send data', () => { + return connection.request('/abilities/no-data-wrong-console/action', { + method: 'POST' + }).then((response) => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('domapic-service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(200), + test.expect(log).to.contain(`Console Called: hello`), + test.expect(log).to.contain(`Invalid data in event response "noDataWrongConsole": Data was provided to an ability without data defined`) + ]) + }) + }) + }) + }) }) diff --git a/test/functional/specs/wrong-ability-no-data.specs.js b/test/functional/specs/wrong-ability-no-data.specs.js new file mode 100644 index 0000000..710ecc9 --- /dev/null +++ b/test/functional/specs/wrong-ability-no-data.specs.js @@ -0,0 +1,20 @@ + +const test = require('narval') +const testUtils = require('narval/utils') + +const utils = require('./utils') + +test.describe('registering a wrong ability that has no data defined', function () { + this.timeout(10000) + + test.before(() => { + return utils.waitOnestimatedStartTime(2000) + }) + + test.it('should throw an error', () => { + return testUtils.logs.combined('domapic-service') + .then((log) => { + return test.expect(log).to.contain(`Ability "noDataConsole" needs a "data" property when has an state defined`) + }) + }) +}) From be2f63b2eb58a75323e2f6aeb249fb089ea27ced Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Tue, 27 Nov 2018 20:44:51 +0100 Subject: [PATCH 06/21] Add change to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f00623..838bffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] ### Added ### Changed +- Do not demand data in abilities. Still mandatory in abilities with state defined. ### Fixed ### Removed From 2aa7a45678d88a35308b41203df8ef9a8781c097 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Thu, 29 Nov 2018 20:53:51 +0100 Subject: [PATCH 07/21] Add end-to-end tests for abilities with no data --- lib/Abilities.js | 3 +- lib/serviceHandlers.js | 21 ++- .../console-ability-changed/server.js | 39 ++++- .../fixtures/console-changed/server.js | 39 ++++- test/end-to-end/fixtures/console/server.js | 39 ++++- .../specs/console-ability-changed.specs.js | 150 ++++++++++++++++- .../end-to-end/specs/console-changed.specs.js | 4 +- .../specs/console-registered.specs.js | 2 +- ...controller-action-changed-handler.specs.js | 3 +- .../specs/controller-action-handler.specs.js | 156 +++++++++++++++++- 10 files changed, 431 insertions(+), 25 deletions(-) diff --git a/lib/Abilities.js b/lib/Abilities.js index 2c179cc..7ca97bb 100644 --- a/lib/Abilities.js +++ b/lib/Abilities.js @@ -133,12 +133,11 @@ const Abilities = function (service, connection) { const EventHandler = function (name, ability) { const validateData = new DataValidator(name, 'event', ability) - const normalizedAbilityName = service.utils.services.normalizeName(name) return function (result) { const data = !_.isUndefined(result) ? { data: result } : result return validateData(data, true) .then(() => { - return connection.sendAbilityEvent(normalizedAbilityName, data) + return connection.sendAbilityEvent(name, data) }) .catch((error) => { return service.tracer.error(templates.compiled.sendEventError({ diff --git a/lib/serviceHandlers.js b/lib/serviceHandlers.js index 3a18b5d..7387121 100644 --- a/lib/serviceHandlers.js +++ b/lib/serviceHandlers.js @@ -53,15 +53,22 @@ class ServiceHandler { return this.getControllerStorageData() .then(storageControllerData => this.connection.connect(storageControllerData) .catch(() => this.getControllerConfigData() - .then(controllerData => this.connection.connect({ - ...controllerData, - userId: storageControllerData.userId - })) + .then(controllerData => { + // TODO, add trace + console.log('------------------------ Trying to connect with stored user and configuration data.') + return this.connection.connect({ + ...controllerData, + userId: storageControllerData.userId + }) + }) ) ) - .catch(() => this.getControllerConfigData() - .then(controllerData => this.connection.connect(controllerData)) - ) + .catch(() => { + // TODO, add trace + console.log('------------------------ Trying to connect only with configuration. Ignoring storage') + return this.getControllerConfigData() + .then(controllerData => this.connection.connect(controllerData)) + }) .catch(() => Promise.resolve()) } diff --git a/test/end-to-end/fixtures/console-ability-changed/server.js b/test/end-to-end/fixtures/console-ability-changed/server.js index 4205ecc..d184306 100644 --- a/test/end-to-end/fixtures/console-ability-changed/server.js +++ b/test/end-to-end/fixtures/console-ability-changed/server.js @@ -7,11 +7,12 @@ const domapic = require('../../../../index') domapic.createModule({ packagePath: path.resolve(__dirname) }).then((service) => { - let lastCharacter + let lastCharacter = '' - const consoleLog = function (data) { + const consoleLog = function (data, eventName) { lastCharacter = data console.log(`Printing into console: ${data}`) + service.events.emit(eventName, data) } return service.register({ @@ -33,10 +34,42 @@ domapic.createModule({ description: 'Print the received character into stdout', auth: false, handler: (data) => { - consoleLog(data) + consoleLog(data, 'stdout') return Promise.resolve(data) } } + }, + consoleNoData: { + description: 'Handle console log with no data before, now has data', + data: { + type: 'number', + maximum: 10, + minimum: 1 + }, + event: { + description: 'Console with data received' + }, + action: { + description: 'Print the received character into console', + handler: (data) => { + consoleLog(data, 'consoleNoData') + return Promise.resolve(data) + } + } + }, + consoleNumeric: { + description: 'Handle console log with numeric data before, now has no data', + event: { + description: 'Console with numeric data received' + }, + action: { + description: 'Print the received number into console', + handler: () => { + console.log('Printing consoleNumeric with no data') + service.events.emit('consoleNumeric') + return Promise.resolve() + } + } } }).then(service.start) }) diff --git a/test/end-to-end/fixtures/console-changed/server.js b/test/end-to-end/fixtures/console-changed/server.js index 9dd83c3..db5a19c 100644 --- a/test/end-to-end/fixtures/console-changed/server.js +++ b/test/end-to-end/fixtures/console-changed/server.js @@ -9,10 +9,10 @@ domapic.createModule({ }).then((service) => { let lastCharacter - const consoleLog = function (data) { + const consoleLog = function (data, eventName) { lastCharacter = data console.log(`Printing into console: ${data}`) - service.events.emit('console', data) + service.events.emit(eventName, data) } return service.register({ @@ -36,7 +36,40 @@ domapic.createModule({ description: 'Print the received character into console version 2', auth: false, handler: (data) => { - consoleLog(data) + consoleLog(data, 'console') + return Promise.resolve(data) + } + } + }, + consoleNoData: { + description: 'Handle console log with no data', + event: { + description: 'Console with no data received' + }, + action: { + description: 'Print the received character into console', + handler: () => { + console.log('Received action with no data') + service.events.emit('consoleNoData') + return Promise.resolve() + } + } + }, + consoleNumeric: { + description: 'Handle console log with numeric data', + data: { + type: 'number', + minimum: 1, + maximum: 10 + // TODO, add an enum + }, + event: { + description: 'Console with numeric data received' + }, + action: { + description: 'Print the received number into console', + handler: (data) => { + consoleLog(data, 'consoleNumeric') return Promise.resolve(data) } } diff --git a/test/end-to-end/fixtures/console/server.js b/test/end-to-end/fixtures/console/server.js index a402031..6c5b5d2 100644 --- a/test/end-to-end/fixtures/console/server.js +++ b/test/end-to-end/fixtures/console/server.js @@ -9,10 +9,10 @@ domapic.createModule({ }).then((service) => { let lastCharacter = '' - const consoleLog = function (data) { + const consoleLog = function (data, eventName) { lastCharacter = data console.log(`Printing into console: ${data}`) - service.events.emit('console', data) + service.events.emit(eventName, data) } return service.register({ @@ -35,7 +35,40 @@ domapic.createModule({ action: { description: 'Print the received character into console', handler: (data) => { - consoleLog(data) + consoleLog(data, 'console') + return Promise.resolve(data) + } + } + }, + consoleNoData: { + description: 'Handle console log with no data', + event: { + description: 'Console with no data received' + }, + action: { + description: 'Print the received character into console', + handler: () => { + console.log('Received action with no data') + service.events.emit('consoleNoData') + return Promise.resolve() + } + } + }, + consoleNumeric: { + description: 'Handle console log with numeric data', + data: { + type: 'number', + minimum: 1, + maximum: 10 + // TODO, add an enum + }, + event: { + description: 'Console with numeric data received' + }, + action: { + description: 'Print the received number into console', + handler: (data) => { + consoleLog(data, 'consoleNumeric') return Promise.resolve(data) } } diff --git a/test/end-to-end/specs/console-ability-changed.specs.js b/test/end-to-end/specs/console-ability-changed.specs.js index f5bca75..4d328c2 100644 --- a/test/end-to-end/specs/console-ability-changed.specs.js +++ b/test/end-to-end/specs/console-ability-changed.specs.js @@ -1,5 +1,6 @@ const test = require('narval') +const testUtils = require('narval/utils') const utils = require('./utils') @@ -38,7 +39,7 @@ test.describe('when connection with controller was successful', function () { .then(response => { const ability = response.body.find(ability => ability.name === 'stdout') return Promise.all([ - test.expect(response.body.length).to.equal(1), + test.expect(response.body.length).to.equal(3), test.expect(ability._service).to.equal(serviceId), test.expect(ability._user).to.equal(serviceUserId), test.expect(ability.event).to.equal(false), @@ -55,3 +56,150 @@ test.describe('when connection with controller was successful', function () { }) }) }) + +test.describe('when using controller action api to dispatch ability that previously has no data', function () { + let consoleAbilityId + this.timeout(10000) + const controllerConnection = new utils.ControllerConnection() + + test.before(() => { + return controllerConnection.request('/abilities') + .then(response => { + const ability = response.body.find(ability => ability.name === 'consoleNoData') + consoleAbilityId = ability._id + return Promise.resolve() + }) + }) + + test.it('should reject the request if no data is received', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST' + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422) + ]) + }) + }) + }) + }) + + test.it('should print into console a log when right data is received', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: { + data: 5 + } + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(201), + test.expect(log).to.contain(`Printing into console: 5`) + ]) + }) + }) + }) + }) + + test.it('should trigger related event, and it should be saved into controller database', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: { + data: 6 + } + }).then(response => { + return utils.waitOnestimatedStartTime(200) + .then(() => { + return controllerConnection.request(`/logs`, { + method: 'GET' + }).then(logsResponse => { + const actionLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.data === 6 && log.type === 'action') + const eventLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.data === 6 && log.type === 'event') + return Promise.all([ + test.expect(logsResponse.statusCode).to.equal(200), + test.expect(actionLog).to.not.be.undefined(), + test.expect(eventLog).to.not.be.undefined() + ]) + }) + }) + }) + }) +}) + +test.describe('when using controller action api to dispatch ability action with numeric data before, but now has not data', function () { + let consoleAbilityId + this.timeout(10000) + const controllerConnection = new utils.ControllerConnection() + + test.before(() => { + return controllerConnection.request('/abilities') + .then(response => { + const ability = response.body.find(ability => ability.name === 'consoleNumeric') + consoleAbilityId = ability._id + return Promise.resolve() + }) + }) + + test.it('should reject the request if data is invalid', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: { + data: 'foo' + } + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422) + ]) + }) + }) + }) + }) + + test.it('should print into console a log when no data is received', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST' + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(201), + test.expect(log).to.contain(`Printing consoleNumeric with no data`) + ]) + }) + }) + }) + }) + + test.it('should trigger related event, and it should be saved into controller database', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST' + }).then(response => { + return utils.waitOnestimatedStartTime(200) + .then(() => { + return controllerConnection.request(`/logs`, { + method: 'GET' + }).then(logsResponse => { + const actionLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.type === 'action') + const eventLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.type === 'event') + return Promise.all([ + test.expect(logsResponse.statusCode).to.equal(200), + test.expect(actionLog).to.not.be.undefined(), + test.expect(eventLog).to.not.be.undefined() + ]) + }) + }) + }) + }) +}) diff --git a/test/end-to-end/specs/console-changed.specs.js b/test/end-to-end/specs/console-changed.specs.js index 622721d..6594410 100644 --- a/test/end-to-end/specs/console-changed.specs.js +++ b/test/end-to-end/specs/console-changed.specs.js @@ -33,12 +33,12 @@ test.describe('when connection with controller is successful', function () { }) }) - test.it('console ability should be registered in controller', () => { + test.it('console abilities should be registered in controller', () => { return controllerConnection.request('/abilities') .then(response => { const ability = response.body.find(ability => ability.name === 'console') return Promise.all([ - test.expect(response.body.length).to.equal(1), + test.expect(response.body.length).to.equal(3), test.expect(ability._service).to.equal(serviceId), test.expect(ability._user).to.equal(serviceUserId), test.expect(ability.event).to.equal(true), diff --git a/test/end-to-end/specs/console-registered.specs.js b/test/end-to-end/specs/console-registered.specs.js index a25205b..a85f191 100644 --- a/test/end-to-end/specs/console-registered.specs.js +++ b/test/end-to-end/specs/console-registered.specs.js @@ -38,7 +38,7 @@ test.describe('when connection with controller is successful', function () { .then(response => { const ability = response.body.find(ability => ability.name === 'console') return Promise.all([ - test.expect(response.body.length).to.equal(1), + test.expect(response.body.length).to.equal(3), test.expect(ability._service).to.equal(serviceId), test.expect(ability._user).to.equal(serviceUserId), test.expect(ability.event).to.equal(true), diff --git a/test/end-to-end/specs/controller-action-changed-handler.specs.js b/test/end-to-end/specs/controller-action-changed-handler.specs.js index dc65115..cc57257 100644 --- a/test/end-to-end/specs/controller-action-changed-handler.specs.js +++ b/test/end-to-end/specs/controller-action-changed-handler.specs.js @@ -32,8 +32,7 @@ test.describe('when using controller action api to dispatch module action', func return testUtils.logs.combined('service') .then((log) => { return Promise.all([ - test.expect(response.statusCode).to.equal(422), - test.expect(log).to.not.contain('Printing into console:') + test.expect(response.statusCode).to.equal(422) ]) }) }) diff --git a/test/end-to-end/specs/controller-action-handler.specs.js b/test/end-to-end/specs/controller-action-handler.specs.js index e29b48d..af59097 100644 --- a/test/end-to-end/specs/controller-action-handler.specs.js +++ b/test/end-to-end/specs/controller-action-handler.specs.js @@ -11,7 +11,7 @@ const randomChar = () => { return chars.substring(pos, pos + 1) } -test.describe('when using controller action api to dispatch module action', function () { +test.describe('when using controller action api to dispatch ability action', function () { let consoleAbilityId this.timeout(10000) const controllerConnection = new utils.ControllerConnection() @@ -92,3 +92,157 @@ test.describe('when using controller action api to dispatch module action', func }) }) }) + +test.describe('when using controller action api to dispatch ability action with no data', function () { + let consoleAbilityId + this.timeout(10000) + const controllerConnection = new utils.ControllerConnection() + + test.before(() => { + return controllerConnection.request('/abilities') + .then(response => { + const ability = response.body.find(ability => ability.name === 'consoleNoData') + consoleAbilityId = ability._id + return Promise.resolve() + }) + }) + + test.it('should reject the request if data is invalid', () => { + const fooConsoleData = { + data: 53 + } + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: fooConsoleData + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422) + ]) + }) + }) + }) + }) + + test.it('should print into console a log when no data is received', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST' + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(201), + test.expect(log).to.contain(`Received action with no data`) + ]) + }) + }) + }) + }) + + test.it('should trigger related event, and it should be saved into controller database', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST' + }).then(response => { + return utils.waitOnestimatedStartTime(200) + .then(() => { + return controllerConnection.request(`/logs`, { + method: 'GET' + }).then(logsResponse => { + const actionLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.type === 'action') + const eventLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.type === 'event') + return Promise.all([ + test.expect(logsResponse.statusCode).to.equal(200), + test.expect(actionLog).to.not.be.undefined(), + test.expect(eventLog).to.not.be.undefined(), + test.expect(actionLog.data).to.be.undefined(), + test.expect(eventLog.data).to.be.undefined() + ]) + }) + }) + }) + }) +}) + +test.describe('when using controller action api to dispatch ability action with numeric data', function () { + let consoleAbilityId + this.timeout(10000) + const controllerConnection = new utils.ControllerConnection() + + test.before(() => { + return controllerConnection.request('/abilities') + .then(response => { + const ability = response.body.find(ability => ability.name === 'consoleNumeric') + consoleAbilityId = ability._id + return Promise.resolve() + }) + }) + + test.it('should reject the request if data is invalid', () => { + const fooConsoleData = { + data: 15 + } + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: fooConsoleData + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(422) + ]) + }) + }) + }) + }) + + test.it('should print into console a log when data is numeric', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: { + data: 3 + } + }).then(response => { + return utils.waitOnestimatedStartTime(100) + .then(() => { + return testUtils.logs.combined('service') + .then((log) => { + return Promise.all([ + test.expect(response.statusCode).to.equal(201), + test.expect(log).to.contain(`Printing into console: 3`) + ]) + }) + }) + }) + }) + + test.it('should trigger related event, and it should be saved into controller database', () => { + return controllerConnection.request(`/abilities/${consoleAbilityId}/action`, { + method: 'POST', + body: { + data: 2 + } + }).then(response => { + return utils.waitOnestimatedStartTime(200) + .then(() => { + return controllerConnection.request(`/logs`, { + method: 'GET' + }).then(logsResponse => { + const actionLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.data === 2 && log.type === 'action') + const eventLog = logsResponse.body.find(log => log._ability === consoleAbilityId && log.data === 2 && log.type === 'event') + return Promise.all([ + test.expect(logsResponse.statusCode).to.equal(200), + test.expect(actionLog).to.not.be.undefined(), + test.expect(eventLog).to.not.be.undefined() + ]) + }) + }) + }) + }) +}) From 507fd92f946092091470b331dbc04e11fbf4701a Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 08:09:52 +0100 Subject: [PATCH 08/21] Add end-to-end test for abilities with no data interacting with plugin --- .../plugin-specs/plugin-events.specs.js | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/test/end-to-end/plugin-specs/plugin-events.specs.js b/test/end-to-end/plugin-specs/plugin-events.specs.js index 9ac4a8b..cc40d6b 100644 --- a/test/end-to-end/plugin-specs/plugin-events.specs.js +++ b/test/end-to-end/plugin-specs/plugin-events.specs.js @@ -9,6 +9,7 @@ test.describe('plugin controller interface and events', function () { let userId let consoleServiceId let consoleAbilityId + let consoleNoDataAbilityId const requestController = (entity, operation, options = {}) => { const body = { @@ -122,12 +123,15 @@ test.describe('plugin controller interface and events', function () { test.describe('controller interface for getting abilities', () => { test.it('should return all abilities', () => { return requestController('abilities', 'get').then(response => { - const console = response.body.find(ability => ability._service === consoleServiceId) + const console = response.body.find(ability => ability._service === consoleServiceId && ability.name === 'console') + const consoleNoData = response.body.find(ability => ability._service === consoleServiceId && ability.name === 'consoleNoData') consoleAbilityId = console._id + consoleNoDataAbilityId = consoleNoData._id return Promise.all([ test.expect(response.statusCode).to.equal(200), - test.expect(response.body.length).to.equal(1), - test.expect(console).to.not.be.undefined() + test.expect(response.body.length).to.equal(3), + test.expect(console).to.not.be.undefined(), + test.expect(consoleNoDataAbilityId).to.not.be.undefined() ]) }) }) @@ -190,18 +194,50 @@ test.describe('plugin controller interface and events', function () { }) }) + test.describe('when using controller interface for dispatching ability action with no data', () => { + test.it('should return ability action response', () => { + return requestController('abilities', 'action', { + id: consoleNoDataAbilityId + }).then(response => { + return Promise.all([ + test.expect(response.statusCode).to.equal(200) + ]) + }) + }) + + test.it('should have received an event from controller about dispatched action', () => { + return utils.serviceLogs(500) + .then(logs => { + return Promise.all([ + test.expect(logs).to.contain(`Received ability:action event. Data: {"_id":"${consoleNoDataAbilityId}"}`) + ]) + }) + }) + + test.it('should have received an event from controller about triggered event', () => { + return utils.serviceLogs() + .then(logs => { + return Promise.all([ + test.expect(logs).to.contain(`Received ability:event event. Data: {"_id":"${consoleNoDataAbilityId}"}`) + ]) + }) + }) + }) + test.describe('controller interface for getting logs', () => { test.it('should return logs', () => { return requestController('logs', 'get').then(response => { - const action = response.body.find(log => log.type === 'action') - const event = response.body.find(log => log.type === 'event') + const action = response.body.find(log => log.type === 'action' && log._ability === consoleAbilityId) + const event = response.body.find(log => log.type === 'event' && log._ability === consoleAbilityId) + const actionNoData = response.body.find(log => log.type === 'action' && log._ability === consoleNoDataAbilityId) + const eventNoData = response.body.find(log => log.type === 'event' && log._ability === consoleNoDataAbilityId) return Promise.all([ test.expect(response.statusCode).to.equal(200), - test.expect(response.body.length).to.equal(2), + test.expect(response.body.length).to.equal(4), test.expect(action.data).to.equal('a'), test.expect(event.data).to.equal('a'), - test.expect(event._ability).to.equal(consoleAbilityId), - test.expect(action._ability).to.equal(consoleAbilityId) + test.expect(actionNoData.data).to.be.undefined(), + test.expect(eventNoData.data).to.be.undefined() ]) }) }) From f81eb20e1599dd20afee4139fffcc6961834d0c6 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 09:25:28 +0100 Subject: [PATCH 09/21] Upgrade domapic-base version, which fixes a problem in Client concurrent requests --- CHANGELOG.md | 1 + package-lock.json | 28 +++++++++---------- package.json | 2 +- .../fixtures/controller/package.json | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 838bffc..b426fc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] ### Added ### Changed +- Upgrade domapic-base version, which fixes a problem in Client concurrent requests. - Do not demand data in abilities. Still mandatory in abilities with state defined. ### Fixed ### Removed diff --git a/package-lock.json b/package-lock.json index 7a25ceb..6d15293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,9 +31,9 @@ } }, "@pm2/agent-node": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@pm2/agent-node/-/agent-node-1.0.10.tgz", - "integrity": "sha512-GRJUmDVmhx/gJwKvgmdY6EbZDPtr0UIyTchf3uAoV8lFAboxWWshfv0V0s91A75BxKOE4AzIy886TA8Dnv54BA==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@pm2/agent-node/-/agent-node-1.0.11.tgz", + "integrity": "sha512-6I63aohLevRSBWEnG1E+2PJ6GtUiF4iXlEcxoKpFc+3stZGTgMj5e79dOpRvzSETbsYJVihIkzihaJeyk8Wkrg==", "requires": { "debug": "^3.1.0", "eventemitter2": "^5.0.1", @@ -101,9 +101,9 @@ } }, "@pm2/js-api": { - "version": "0.5.34", - "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.5.34.tgz", - "integrity": "sha512-jHB4PD0J4KsvFoiqn5/8uZoBaQWojREItMgqCwktG7o0Kl2OlYSfBuhMjNqUJoi4b3o9dVREJXmZQGuUFp8Psw==", + "version": "0.5.36", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.5.36.tgz", + "integrity": "sha512-I2wX/Yl+fOtDfFeXCZb6FNNJOR72ufoe0wzJSnKOP20ywdBRsjYAAK2/sPLTkyLFJza1fp/l9pRvqExQv9IXlg==", "requires": { "async": "^2.4.1", "axios": "^0.16.2", @@ -1383,9 +1383,9 @@ } }, "domapic-base": { - "version": "1.0.0-beta.16", - "resolved": "https://registry.npmjs.org/domapic-base/-/domapic-base-1.0.0-beta.16.tgz", - "integrity": "sha512-i7v2KDQ75Vs1iQ5QptzgSm1pvA28dZiQgq35tPfw5cnXTgpRKQ3ChnF+aAdWo8Fl758X/qvBH97TVCHx5YVvAw==", + "version": "1.0.0-beta.17", + "resolved": "https://registry.npmjs.org/domapic-base/-/domapic-base-1.0.0-beta.17.tgz", + "integrity": "sha512-d3wFDdOc3bhI8iFeBTSGeNS62DbVFkQ6xgfaqYtUdHW0Qw2Yw2ENcVuokj5QKGBP9S0duu7tDHQpwCTfw+BowA==", "requires": { "bluebird": "3.5.2", "body-parser": "1.18.3", @@ -1413,9 +1413,9 @@ }, "dependencies": { "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz", + "integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==", "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -2848,7 +2848,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } @@ -4782,7 +4782,7 @@ }, "pako": { "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "resolved": "http://registry.npmjs.org/pako/-/pako-0.2.9.tgz", "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" }, "parse-json": { diff --git a/package.json b/package.json index ca53f5d..f6db34b 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ }, "dependencies": { "bluebird": "3.5.1", - "domapic-base": "1.0.0-beta.16", + "domapic-base": "1.0.0-beta.17", "is-promise": "2.1.0", "lodash": "4.17.10", "rand-token": "0.4.0", diff --git a/test/end-to-end/fixtures/controller/package.json b/test/end-to-end/fixtures/controller/package.json index 74cba0b..36896df 100644 --- a/test/end-to-end/fixtures/controller/package.json +++ b/test/end-to-end/fixtures/controller/package.json @@ -6,6 +6,6 @@ "domapic-controller": "node_modules/.bin/domapic-controller" }, "dependencies": { - "domapic-controller": "1.0.0-alpha.10" + "domapic-controller": "1.0.0-alpha.11" } } From f9ee470f1b7f0b62d089140e46f59bcbb33f2ba2 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 10:04:15 +0100 Subject: [PATCH 10/21] Expose storage to services --- .narval.yml | 1 + README.md | 5 +++++ lib/serviceHandlers.js | 1 + test/functional/fixtures/console/server.js | 10 +++++++--- test/functional/specs/storage.specs.js | 12 ++++++++++++ 5 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 test/functional/specs/storage.specs.js diff --git a/.narval.yml b/.narval.yml index 1df3a4f..eecb5d8 100644 --- a/.narval.yml +++ b/.narval.yml @@ -183,6 +183,7 @@ suites: specs: - test/functional/specs/no-controller-api-key.specs.js - test/functional/specs/not-connected.specs.js + - test/functional/specs/storage.specs.js coverage: *disable-coverage - name: auth-api describe: should add or remove api keys diff --git a/README.md b/README.md index 6c561a0..d8b68e5 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ This package provides you all the API infrastructure, authentication, data valid If you are going to __publish your module, add the `domapic-module` suffix to the name__, in order to allow npm users finding it easily searching in the website that keyword. +__NOTE: The next schema includes some Domapic pieces that are still not released. The web ui for the Controller, Domapic Cloud, mobile apps, as well as Homekit and Alexa plugins will be available soon.__ + ![Domapic system example][domapic-example-image] > Above, an example of two modules in a [Domapic System][website-url]. Now, the relay can be controlled using the web or mobile applications, or interacting with ["Alexa"][alexa-url] or ["HomeKit"][homekit-url]. Automatisms can be configured in the [Domapic Controller Web UI][domapic-controller-url] to make the [_Phillips Hue_][hue-url] bulb be switched off automatically when the relay bulb is switched on, for example. @@ -116,6 +118,9 @@ Returns a module instance, containing: * `config` `` containing methods for getting and setting configuration. * `get([key])` - Returns a promise resolved with the module configuration. Resolved with specific property value if argument `key` is provided. * `set(key [, value])` - Sets `value` for provided `key` into module configuration. Returns a promise. +* `storage` `` containing methods for getting and setting data in the built-in file system storage. + * `get([key])` - Returns a promise resolved with the module storage. Resolved with specific property value if argument `key` is provided. + * `set(key [, value])` - Sets `value` for provided `key` into module storage. Returns a promise. * `api` - Object containing methods for [extending the built-in api](#extending-api). * `register(abilitiesData)` - Register provided abilities into the module. Read the [abilities](#abilities) chapter for further info. * `start` - Starts the server. diff --git a/lib/serviceHandlers.js b/lib/serviceHandlers.js index 7387121..d7b81e1 100644 --- a/lib/serviceHandlers.js +++ b/lib/serviceHandlers.js @@ -82,6 +82,7 @@ class ServiceHandler { return { tracer: this.service.tracer, config: this.service.config, + storage: this.service.storage, api: { extendOpenApi: this.service.server.extendOpenApi, addOperations: this.service.server.addOperations diff --git a/test/functional/fixtures/console/server.js b/test/functional/fixtures/console/server.js index 5be43dd..3a1a147 100644 --- a/test/functional/fixtures/console/server.js +++ b/test/functional/fixtures/console/server.js @@ -6,7 +6,7 @@ const domapic = require('../../../../index') domapic.createModule({ packagePath: path.resolve(__dirname) -}).then((service) => { +}).then(async service => { let lastCharacter const consoleLog = function (data) { @@ -17,7 +17,9 @@ domapic.createModule({ }) } - return service.register({ + await service.storage.set('storageTest', 'foo-storage-value') + + await service.register({ console: { description: 'Handle custom console logs', data: { @@ -40,5 +42,7 @@ domapic.createModule({ } } } - }).then(service.start) + }) + + return service.start() }) diff --git a/test/functional/specs/storage.specs.js b/test/functional/specs/storage.specs.js new file mode 100644 index 0000000..2fc10f0 --- /dev/null +++ b/test/functional/specs/storage.specs.js @@ -0,0 +1,12 @@ +const test = require('narval') + +const utils = require('./utils') + +test.describe('service storage', function () { + test.it('should have saved test value to storage', () => { + return utils.readStorage() + .then(storedData => { + return test.expect(storedData.storageTest).to.equal('foo-storage-value') + }) + }) +}) From b70e6de46cd0a5cd34c74299bf42afe88716cbb3 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 10:26:59 +0100 Subject: [PATCH 11/21] Add more detailed Controller connection traces --- lib/serviceHandlers.js | 31 +++++++++++++++++++------------ lib/templates.js | 6 +++++- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/serviceHandlers.js b/lib/serviceHandlers.js index d7b81e1..eed9319 100644 --- a/lib/serviceHandlers.js +++ b/lib/serviceHandlers.js @@ -51,23 +51,30 @@ class ServiceHandler { connect () { return this.getControllerStorageData() - .then(storageControllerData => this.connection.connect(storageControllerData) - .catch(() => this.getControllerConfigData() + .then(storageControllerData => { + return Promise.all([ + this.service.tracer.info(templates.compiled.connectingUsingStorage()), + this.connection.connect(storageControllerData) + ]).catch(() => this.getControllerConfigData() .then(controllerData => { - // TODO, add trace - console.log('------------------------ Trying to connect with stored user and configuration data.') - return this.connection.connect({ - ...controllerData, - userId: storageControllerData.userId - }) + return Promise.all([ + this.service.tracer.info(templates.compiled.connectingUsingUserAndConfig()), + this.connection.connect({ + ...controllerData, + userId: storageControllerData.userId + }) + ]) }) ) - ) + }) .catch(() => { - // TODO, add trace - console.log('------------------------ Trying to connect only with configuration. Ignoring storage') return this.getControllerConfigData() - .then(controllerData => this.connection.connect(controllerData)) + .then(controllerData => { + return Promise.all([ + this.service.tracer.info(templates.compiled.connectingIgnoringStorage()), + this.connection.connect(controllerData) + ]) + }) }) .catch(() => Promise.resolve()) } diff --git a/lib/templates.js b/lib/templates.js index 31a529c..7a5b6b2 100644 --- a/lib/templates.js +++ b/lib/templates.js @@ -58,7 +58,11 @@ const templates = { addingUserApiKey: 'Adding api key for service user into Controller', loggingIntoController: 'Loggin into controller with user id "{{_id}}" and apiKey "{{apiKey}}"', storingControllerData: 'Storing controller data for next connections', - errorRegisteringAbility: 'Error registering abilities: {{{message}}}' + errorRegisteringAbility: 'Error registering abilities: {{{message}}}', + + connectingUsingStorage: 'Trying to connect with Controller using last connection data', + connectingUsingUserAndConfig: 'Trying to connect with Controller using user data from storage and configuration data', + connectingIgnoringStorage: 'Trying to connect with Controller only with configuration. Ignoring storage' } module.exports = { From b1203b5e78608757356e8c9695d618c2e29ef75c Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 10:41:43 +0100 Subject: [PATCH 12/21] Improve documentation --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d8b68e5..fcc8f40 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Each Module can has many abilities, each one with its own action, state and even Each ability must be an object, which key will be the name of the ability (will be converted to snake case when referenced in api uris). Properties of each ability must be: * `description` `` Description of the ability. -* `data` `` Defines the type of data that the ability will handle, and will be used to execute data validation for the action, state and event related api resources. +* `data` `` Defines the type of data that the ability will handle, and will be used to execute data validation for the action, state and event related api resources. If the ability don't needs any type of data, this property should be omitted (in that case, the ability can't have an state, because it has no sense). * `type` `` Type of data. Can be one of `string`, `boolean`, `number`, `integer` or `float` * `enum` `` Used to restrict data to a fixed set of values. It must be an array with at least one element, where each element is unique. * `minLength` `` Minimum length of the data string. @@ -162,7 +162,7 @@ Each ability must be an object, which key will be the name of the ability (will #### Action -When an [ability](#abilities) has an `action` property defined, an api resource will be created with the uri `/api/[ability_key]/action`. It has to be requested using `POST` method, and data has to be provided in the request body, contained in the "data" property: +When an [ability](#abilities) has an `action` property defined, an api resource will be created with the uri `/api/[ability_key]/action`. It has to be requested using `POST` method, and data (if needed) has to be provided in the request body, contained in the "data" property: > Example: http://localhost:3000/api/switch/action ```json @@ -423,6 +423,7 @@ npm start -- --help * `logLevel` - Tracing level. Choices are 'log', 'trace', 'debug', 'info', 'warn' and 'error'. Default is `info`. * `path` - Path to be used as home path for the process, instead of user´s default (a `.domapic` folder will be created inside). * `saveConfig` - Save current options for next execution (except `name` and `path`). Default is false. +* `rejectUntrusted` - Reject untrusted ssl certificates when making requests to modules or plugins. Use it if you are using a self-signed certificate in your Controller. Default is false. > Example of defining options from command line: @@ -528,9 +529,9 @@ npm run relay logs -- --lines=300 This command will display last logs of server, and will continue displaying logs until CTRL-C is pressed. -Server logs are managed by [PM2][pm2-url] when using CLI, so, it is recommended to install [_PM2 log rotate_][pm2-log-rotate-url] to avoid pm2 logs file growing too much. +Service process and logs are managed by [PM2][pm2-url] when using CLI, so, it is recommended to install [_PM2 log rotate_][pm2-log-rotate-url] to avoid pm2 logs file growing too much. -Server logs are saved too into a daily file. These files are rotated automatically and only last ten days files are kept. You´ll find these files in the `~/.domapic/[module-name]/logs` folder. +Service logs are saved too into a daily file. These files are rotated automatically and only last ten days files are kept. You´ll find these files in the `~/.domapic/[module-name]/logs` folder. [domapic-logo-image]: http://domapic.com/assets/domapic-logo.png From ffb151e1aaa15eca781840a549a3c3c898f57346 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:17:04 +0100 Subject: [PATCH 13/21] Extend exposed cli options with service options --- .narval.yml | 4 ++-- cli/index.js | 11 ----------- index.js | 4 +++- lib/options.js | 4 ++-- test/functional/specs/config-api.specs.js | 3 ++- 5 files changed, 9 insertions(+), 17 deletions(-) delete mode 100644 cli/index.js diff --git a/.narval.yml b/.narval.yml index eecb5d8..d4daedc 100644 --- a/.narval.yml +++ b/.narval.yml @@ -352,14 +352,14 @@ suites: env: &documentation-example-local-env <<: *local-service-auth-env fixture: example - service_extra_options: --authDisabled --initialStatus=true + service_extra_options: --authDisabled --initialStatus=true --controllerApiKey=foo docker: <<: *docker-service-auth command: test/functional/commands/start-service-no-name.sh env: &documentation-example-docker-env <<: *docker-service-auth-env fixture: example - service_extra_options: --authDisabled --initialStatus=true + service_extra_options: --authDisabled --initialStatus=true --controllerApiKey=foo test: &documentation-example-test <<: *functional-test local: diff --git a/cli/index.js b/cli/index.js deleted file mode 100644 index 245e5da..0000000 --- a/cli/index.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict' - -const domapic = require('domapic-base') - -const options = require('./lib/options') - -const cli = function (cliOptions) { - domapic.cli(options.extend(cliOptions)) -} - -module.exports = cli diff --git a/index.js b/index.js index 8b9d902..d2b860b 100644 --- a/index.js +++ b/index.js @@ -19,8 +19,10 @@ const ServiceCreator = function (Builder, type) { const createModule = new ServiceCreator(serviceHandlers.Module, SERVICE_TYPES.MODULE) const createPlugin = new ServiceCreator(serviceHandlers.Plugin, SERVICE_TYPES.PLUGIN) +const cli = cliOptions => domapic.cli(options.extendWith(cliOptions)) + module.exports = { createModule, createPlugin, - cli: domapic.cli + cli } diff --git a/lib/options.js b/lib/options.js index d9742dd..bd56105 100644 --- a/lib/options.js +++ b/lib/options.js @@ -16,7 +16,7 @@ const customConfig = { } } -const extendWith = function (options = {}, type) { +const extendWith = function (options = {}, type = '') { _.each(options.customConfig, (config, key) => { if (customConfig[key]) { throw new Error(templates.core.compiled.cli.overwriteOptionError({ @@ -34,5 +34,5 @@ const extendWith = function (options = {}, type) { } module.exports = { - extendWith: extendWith + extendWith } diff --git a/test/functional/specs/config-api.specs.js b/test/functional/specs/config-api.specs.js index 54f9ade..246e6b6 100644 --- a/test/functional/specs/config-api.specs.js +++ b/test/functional/specs/config-api.specs.js @@ -29,7 +29,8 @@ test.describe('config api', function () { authDisabled: [], hostName: utils.SERVICE_HOST, path: path.resolve(__dirname, '..', '..', '..', utils.DOMAPIC_PATH), - rejectUntrusted: false + rejectUntrusted: false, + controllerApiKey: 'foo' }) ]) }) From 901235efd7175b8da5b469ae5ce9f636d4ea323f Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:18:24 +0100 Subject: [PATCH 14/21] Add changes to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b426fc8..8fa9a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] ### Added +- Expose storage method to services ### Changed - Upgrade domapic-base version, which fixes a problem in Client concurrent requests. - Do not demand data in abilities. Still mandatory in abilities with state defined. ### Fixed +- Extend exposed cli options with service options ### Removed ## [1.0.0-alpha.2] - 2018-11-20 From a1f73bddbeaaf5e7eff04887ae4b5920dd9c8eed Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:23:28 +0100 Subject: [PATCH 15/21] Change reserved word module by dpmcModule in examples --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fcc8f40..32762f3 100644 --- a/README.md +++ b/README.md @@ -72,10 +72,10 @@ const path = require('path') const domapic = require('domapic-service') domapic.createModule({ packagePath: path.resolve(__dirname) }) - .then(async module => { + .then(async dmpcModule => { let status = false - await module.register({ + await dmpcModule.register({ switch: { description: 'Handle the relay status', data: { @@ -92,14 +92,14 @@ domapic.createModule({ packagePath: path.resolve(__dirname) }) description: 'Switch on/off the relay', handler: newStatus => { status = newStatus - module.events.emit('switch', status) + dmpcModule.events.emit('switch', status) return Promise.resolve(status) } } } }) - return module.start() + return dmpcModule.start() }) ``` > When started, a REST api will be available to connect with controller, authenticate using api key, dispatch the switch action, consulting the switch state, the module configuration, etc. @@ -324,7 +324,7 @@ Consult the Controller Swagger interface to get more info about supported filter First of all, remember to start the server programatically after adding the abilities in your code: ```js -module.start() +dmpcModule.start() ``` Once the module code is ready, the server can be started calling directly to the `npm start` command @@ -461,8 +461,8 @@ const options = require('./options') domapic.createModule({ packagePath: path.resolve(__dirname), customConfig: options -}).then(async module => { - let status = await module.config.get('initialStatus') +}).then(async dmpcModule => { + let status = await dmpcModule.config.get('initialStatus') //... }) ``` From d63489844d2d1078f11a194649f0c11366bf262f Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:27:35 +0100 Subject: [PATCH 16/21] Add trace for debugging docker tests in CI --- .travis.yml | 2 +- test/functional/specs/storage.specs.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cb640a8..36282d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,6 @@ addons: name: "$TRAVIS_CURRENT_BRANCH" script: - - npm test + - npm test -- --logLevel=trace - npm run coveralls - sonar-scanner diff --git a/test/functional/specs/storage.specs.js b/test/functional/specs/storage.specs.js index 2fc10f0..4e6d0c7 100644 --- a/test/functional/specs/storage.specs.js +++ b/test/functional/specs/storage.specs.js @@ -6,6 +6,7 @@ test.describe('service storage', function () { test.it('should have saved test value to storage', () => { return utils.readStorage() .then(storedData => { + console.log(storedData) return test.expect(storedData.storageTest).to.equal('foo-storage-value') }) }) From 5074f982c8b96c68ec4aa4089bbb4b03ac5652e5 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:36:12 +0100 Subject: [PATCH 17/21] Increase narval log level for debugging docker tests in CI --- .narval.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.narval.yml b/.narval.yml index d4daedc..db74164 100644 --- a/.narval.yml +++ b/.narval.yml @@ -183,7 +183,7 @@ suites: specs: - test/functional/specs/no-controller-api-key.specs.js - test/functional/specs/not-connected.specs.js - - test/functional/specs/storage.specs.js + #- test/functional/specs/storage.specs.js coverage: *disable-coverage - name: auth-api describe: should add or remove api keys diff --git a/.travis.yml b/.travis.yml index 36282d0..a785f60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,6 @@ addons: name: "$TRAVIS_CURRENT_BRANCH" script: - - npm test -- --logLevel=trace + - npm test -- --logLevel=log - npm run coveralls - sonar-scanner From 0ad4852bc680338a56619cf2dc85e1b7e4a0afc7 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:40:30 +0100 Subject: [PATCH 18/21] Fix docker build. Do not bind removed folder cli --- .narval.yml | 3 +-- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.narval.yml b/.narval.yml index db74164..9c0d72c 100644 --- a/.narval.yml +++ b/.narval.yml @@ -2,7 +2,6 @@ schemas: bind: &bind - lib - test - - cli - index.js coverage: &disable-coverage enabled: false @@ -183,7 +182,7 @@ suites: specs: - test/functional/specs/no-controller-api-key.specs.js - test/functional/specs/not-connected.specs.js - #- test/functional/specs/storage.specs.js + - test/functional/specs/storage.specs.js coverage: *disable-coverage - name: auth-api describe: should add or remove api keys diff --git a/.travis.yml b/.travis.yml index a785f60..cb640a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,6 @@ addons: name: "$TRAVIS_CURRENT_BRANCH" script: - - npm test -- --logLevel=log + - npm test - npm run coveralls - sonar-scanner From ee54fed6da6ba9679c2fac5c426723959febf181 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:41:15 +0100 Subject: [PATCH 19/21] Remove tests traces --- test/functional/specs/storage.specs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/functional/specs/storage.specs.js b/test/functional/specs/storage.specs.js index 4e6d0c7..2fc10f0 100644 --- a/test/functional/specs/storage.specs.js +++ b/test/functional/specs/storage.specs.js @@ -6,7 +6,6 @@ test.describe('service storage', function () { test.it('should have saved test value to storage', () => { return utils.readStorage() .then(storedData => { - console.log(storedData) return test.expect(storedData.storageTest).to.equal('foo-storage-value') }) }) From b80f410a29231473d76938fd39a00ab0d4a1137d Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:47:11 +0100 Subject: [PATCH 20/21] Upgrade version --- CHANGELOG.md | 9 ++++++++- README.md | 4 ++-- package-lock.json | 2 +- package.json | 2 +- sonar-project.properties | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fa9a60..634cf1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] ### Added +### Changed +### Fixed +### Removed + +## [1.0.0-alpha.3] - 2018-12-01 +### Added - Expose storage method to services + ### Changed - Upgrade domapic-base version, which fixes a problem in Client concurrent requests. - Do not demand data in abilities. Still mandatory in abilities with state defined. + ### Fixed - Extend exposed cli options with service options -### Removed ## [1.0.0-alpha.2] - 2018-11-20 ### BREAKING CHANGES diff --git a/README.md b/README.md index 32762f3..967bb54 100644 --- a/README.md +++ b/README.md @@ -57,11 +57,11 @@ Modules can be created with few lines of code. Here is an example of a module co ```json { - "name": "relay-domapic-module", + "name": "example-domapic-module", "version": "1.0.0", "description": "Domapic module controlling a relay", "dependencies": { - "domapic-service": "1.0.0-alpha.2" + "domapic-service": "1.0.0-alpha.3" } } ``` diff --git a/package-lock.json b/package-lock.json index 6d15293..90367fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "domapic-service", - "version": "1.0.0-alpha.2", + "version": "1.0.0-alpha.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f6db34b..d8761f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "domapic-service", - "version": "1.0.0-alpha.2", + "version": "1.0.0-alpha.3", "description": "Base for Domapic Node.js services", "main": "index.js", "keywords": [ diff --git a/sonar-project.properties b/sonar-project.properties index f504dae..4e48860 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,6 +1,6 @@ sonar.organization=domapic sonar.projectKey=domapic-service -sonar.projectVersion=1.0.0-alpha.2 +sonar.projectVersion=1.0.0-alpha.3 sonar.sources=. sonar.exclusions=node_modules/**,test/end-to-end/fixtures/** From d3bddab2eb5129003752b1a3726d56a620ad0c21 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Sat, 1 Dec 2018 11:52:21 +0100 Subject: [PATCH 21/21] Remove unnecesary if statement --- lib/Abilities.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/Abilities.js b/lib/Abilities.js index 7ca97bb..1a447b9 100644 --- a/lib/Abilities.js +++ b/lib/Abilities.js @@ -111,12 +111,10 @@ const Abilities = function (service, connection) { const registerSchema = function (ability, name) { const schema = {} - if (!ability.data) { - if (ability.state) { - return Promise.reject(new service.errors.BadData(templates.compiled.abilityHasNoData({ - name: name - }))) - } + if (!ability.data && ability.state) { + return Promise.reject(new service.errors.BadData(templates.compiled.abilityHasNoData({ + name: name + }))) } schema[nameToSchema(name)] = ability.data ? toDataSchema(ability.data) : toEmptyDataSchema()