diff --git a/package-lock.json b/package-lock.json index 936fcc2..0f4fdfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,36 +1,32 @@ { "name": "lambda-framework", - "version": "1.0.16", + "version": "1.0.19", "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/aws-lambda": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-0.0.16.tgz", - "integrity": "sha512-sk0LAN9NJGdmlcvUvtzsm6azYLqZArMiRnjC4TaHghczJjEcryIaEeuG1C/OQDBMZDvSLn/TTHKhY+s7jJXwyg==" - }, "@types/chai": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.4.tgz", - "integrity": "sha512-cvU0HomQ7/aGDQJZsbtJXqBQ7w4J4TqLB0Z/h8mKrpRjfeZEvTbygkfJEb7fWdmwpIeDeFmIVwAEqS0OYuUv3Q==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.10.tgz", + "integrity": "sha512-Ejh1AXTY8lm+x91X/yar3G2z4x9RyKwdTVdyyu7Xj3dNB35fMNCnEWqTO9FgS3zjzlRNqk1MruYhgb8yhRN9rA==", "dev": true }, "@types/mocha": { - "version": "2.2.43", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.43.tgz", - "integrity": "sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==", + "version": "2.2.44", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz", + "integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==", "dev": true }, "@types/node": { - "version": "8.0.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.28.tgz", - "integrity": "sha512-HupkFXEv3O3KSzcr3Ylfajg0kaerBg1DyaZzRBBQfrU3NN1mTBRE7sCveqHwXLS5Yrjvww8qFzkzYQQakG9FuQ==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.2.tgz", + "integrity": "sha512-KA4GKOpgXnrqEH2eCVhiv2CsxgXGQJgV1X0vsGlh+WCnxbeAE1GT44ZsTU1IN5dEeV/gDupKa7gWo08V5IxWVQ==", "dev": true }, "@types/sinon": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-2.3.7.tgz", - "integrity": "sha512-w+LjztaZbgZWgt/y/VMP5BUAWLtSyoIJhXyW279hehLPyubDoBNwvhcj3WaSptcekuKYeTCVxrq60rdLc6ImJA==" + "integrity": "sha512-w+LjztaZbgZWgt/y/VMP5BUAWLtSyoIJhXyW279hehLPyubDoBNwvhcj3WaSptcekuKYeTCVxrq60rdLc6ImJA==", + "dev": true }, "accepts": { "version": "1.3.4", @@ -42,15 +38,15 @@ } }, "ajv": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", - "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "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", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "ansi-regex": { @@ -103,23 +99,6 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "aws-sdk": { - "version": "2.141.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.141.0.tgz", - "integrity": "sha1-PZallw/Z9UDOq8wdS66zO3FYOqc=", - "requires": { - "buffer": "4.9.1", - "crypto-browserify": "1.0.9", - "events": "1.1.1", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.1.0", - "xml2js": "0.4.17", - "xmlbuilder": "4.2.1" - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -141,6 +120,27 @@ "chalk": "1.1.3", "esutils": "2.0.2", "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } } }, "balanced-match": { @@ -149,11 +149,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "base64-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", - "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==" - }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", @@ -189,22 +184,11 @@ "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", "dev": true }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "1.2.1", - "ieee754": "1.1.8", - "isarray": "1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - } - } + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true }, "bytes": { "version": "3.0.0", @@ -228,27 +212,28 @@ "deep-eql": "3.0.1", "get-func-name": "2.0.0", "pathval": "1.1.0", - "type-detect": "4.0.3" + "type-detect": "4.0.5" } }, "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { - "ansi-styles": "2.2.1", + "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "supports-color": "4.5.0" }, "dependencies": { - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } } } }, @@ -269,10 +254,19 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "combined-stream": { @@ -353,11 +347,6 @@ } } }, - "crypto-browserify": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz", - "integrity": "sha1-zFRJaF37hesRyYKKzHy4erW7/MA=" - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -382,7 +371,7 @@ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "type-detect": "4.0.3" + "type-detect": "4.0.5" } }, "delayed-stream": { @@ -392,9 +381,9 @@ "dev": true }, "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=" + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", + "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==" }, "ecc-jsbn": { "version": "0.1.1", @@ -434,11 +423,6 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -457,6 +441,12 @@ "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", "dev": true }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -508,6 +498,20 @@ "assert-plus": "1.0.0" } }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, "graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", @@ -532,7 +536,7 @@ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "ajv": "5.2.3", + "ajv": "5.5.2", "har-schema": "2.0.0" } }, @@ -546,10 +550,9 @@ } }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" }, "hawk": { "version": "6.0.2", @@ -560,7 +563,7 @@ "boom": "4.3.1", "cryptiles": "3.1.2", "hoek": "4.2.0", - "sntp": "2.0.2" + "sntp": "2.1.0" } }, "he": { @@ -586,11 +589,6 @@ "sshpk": "1.13.1" } }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -624,11 +622,6 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -664,15 +657,6 @@ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "0.0.0" - } - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -685,12 +669,6 @@ "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", "dev": true }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -704,9 +682,9 @@ } }, "just-extend": { - "version": "1.1.26", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.26.tgz", - "integrity": "sha512-IIG0FXHB/XpUZ7vGbktoc2EGsF+fLHJ1tU+vaqoKkVRBwH2FDxLTmkGkSp0XHRp6Y3KGZPIldH1YW8lOluGYrA==" + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==" }, "lcov-parse": { "version": "0.0.10", @@ -804,9 +782,9 @@ "integrity": "sha1-ywgXH4pvb2dLhJna31C+1L77csQ=" }, "lolex": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.1.3.tgz", - "integrity": "sha512-BdHq78SeI+6PAUtl4atDuCt7L6E4fab3mSRtqxm4ywaXe4uP7jZ0TTcFNuU20syUjxZc2l7jFqKVMJ+AX0LnpQ==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", + "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==" }, "mime-db": { "version": "1.30.0", @@ -873,19 +851,17 @@ "supports-color": "3.1.2" }, "dependencies": { - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true }, "supports-color": { "version": "3.1.2", @@ -921,7 +897,7 @@ "integrity": "sha512-q9jXh3UNsMV28KeqI43ILz5+c3l+RiNW8mhurEwCKckuHQbL+hTJIKKTiUlCPKlgQ/OukFvSnKB/Jk3+sFbkGA==", "requires": { "formatio": "1.2.0", - "just-extend": "1.1.26", + "just-extend": "1.1.27", "lolex": "1.6.0", "path-to-regexp": "1.7.0", "text-encoding": "0.6.4" @@ -960,15 +936,15 @@ } }, "nyc": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.3.0.tgz", - "integrity": "sha512-oUu0WHt1k/JMIODvAYXX6C50Mupw2GO34P/Jdg2ty9xrLufBthHiKR2gf08aF+9S0abW1fl24R7iKRBXzibZmg==", + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.4.1.tgz", + "integrity": "sha512-5eCZpvaksFVjP2rt1r60cfXmt3MUtsQDw8bAzNqNEr4WLvUMLgiVENMf/B9bE9YAX0mGVvaGA3v9IS9ekNqB1Q==", "dev": true, "requires": { "archy": "1.0.0", "arrify": "1.0.1", "caching-transform": "1.0.1", - "convert-source-map": "1.5.0", + "convert-source-map": "1.5.1", "debug-log": "1.0.1", "default-require-extensions": "1.0.0", "find-cache-dir": "0.1.1", @@ -988,7 +964,7 @@ "resolve-from": "2.0.0", "rimraf": "2.6.2", "signal-exit": "3.0.2", - "spawn-wrap": "1.3.8", + "spawn-wrap": "1.4.2", "test-exclude": "4.1.1", "yargs": "10.0.3", "yargs-parser": "8.0.0" @@ -1098,8 +1074,8 @@ "bundled": true, "dev": true, "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" } }, "babel-template": { @@ -1248,12 +1224,12 @@ "dev": true }, "convert-source-map": { - "version": "1.5.0", + "version": "1.5.1", "bundled": true, "dev": true }, "core-js": { - "version": "2.5.1", + "version": "2.5.3", "bundled": true, "dev": true }, @@ -1557,7 +1533,7 @@ "dev": true }, "is-buffer": { - "version": "1.1.5", + "version": "1.1.6", "bundled": true, "dev": true }, @@ -1755,7 +1731,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "1.1.6" } }, "lazy-cache": { @@ -2124,7 +2100,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "1.1.6" } } } @@ -2134,7 +2110,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.5" + "is-buffer": "1.1.6" } } } @@ -2170,7 +2146,7 @@ } }, "regenerator-runtime": { - "version": "0.11.0", + "version": "0.11.1", "bundled": true, "dev": true }, @@ -2276,7 +2252,7 @@ "dev": true }, "spawn-wrap": { - "version": "1.3.8", + "version": "1.4.2", "bundled": true, "dev": true, "requires": { @@ -2581,9 +2557,9 @@ "dev": true }, "path-to-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.0.0.tgz", - "integrity": "sha512-DPZblKdQsbV6B3fHknj89h6Nw/Z5zFK0nFX+DVN7y8a+IUHf9taJWvMK+ue0+AEjXrke0KVRCcfm2pOYGSRk8g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.1.0.tgz", + "integrity": "sha512-dZY7QPCPp5r9cnNuQ955mOv4ZFVDXY/yvqeV7Y1W2PJA3PEFcuow9xKFfJxbBj1pIjOAP+M2B4/7xubmykLrXw==" }, "pathval": { "version": "1.1.0", @@ -2651,6 +2627,15 @@ "uuid": "3.1.0" } }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -2662,49 +2647,29 @@ "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, "sinon": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.0.2.tgz", - "integrity": "sha512-4mUsjHfjrHyPFGDTtNJl0q8cv4VOJGvQykI1r3fnn05ys0sQL9M1Y+DyyGNWLD2PMcoyqjJ/nFDm4K54V1eQOg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.3.tgz", + "integrity": "sha512-c7u0ZuvBRX1eXuB4jN3BRCAOGiUTlM8SE3TxbJHrNiHUKL7wonujMOB6Fi1gQc00U91IscFORQHDga/eccqpbw==", "requires": { - "diff": "3.2.0", + "diff": "3.4.0", "formatio": "1.2.0", "lodash.get": "4.4.2", - "lolex": "2.1.3", + "lolex": "2.3.1", "nise": "1.2.0", "supports-color": "4.5.0", - "type-detect": "4.0.3" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "requires": { - "has-flag": "2.0.0" - } - } + "type-detect": "4.0.5" } }, "sntp": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", - "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "dev": true, "requires": { "hoek": "4.2.0" @@ -2733,9 +2698,9 @@ } }, "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" }, "stringstream": { "version": "0.0.5", @@ -2752,6 +2717,14 @@ "ansi-regex": "2.1.1" } }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "requires": { + "has-flag": "2.0.0" + } + }, "text-encoding": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", @@ -2767,52 +2740,28 @@ } }, "tslib": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz", - "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.1.tgz", + "integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=", "dev": true }, "tslint": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", - "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz", + "integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=", "dev": true, "requires": { "babel-code-frame": "6.26.0", - "colors": "1.1.2", + "builtin-modules": "1.1.1", + "chalk": "2.3.0", "commander": "2.9.0", - "diff": "3.2.0", - "glob": "7.1.2", + "diff": "3.4.0", + "glob": "7.1.1", "minimatch": "3.0.4", - "resolve": "1.4.0", + "resolve": "1.5.0", "semver": "5.4.1", - "tslib": "1.8.0", - "tsutils": "2.12.1" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "resolve": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } - } + "tslib": "1.8.1", + "tsutils": "2.13.1" } }, "tslint-microsoft-contrib": { @@ -2833,12 +2782,12 @@ } }, "tsutils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.1.tgz", - "integrity": "sha1-9Nlc4zkciXHkblTEzw7bCiHdWyQ=", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.13.1.tgz", + "integrity": "sha512-XMOEvc2TiYesVSOJMI7OYPnBMSgcvERuGW5Li/J+2A0TuH607BPQnOLQ82oSPZCssB8c9+QGi6qhTBa/f1xQRA==", "dev": true, "requires": { - "tslib": "1.8.0" + "tslib": "1.8.1" } }, "tunnel-agent": { @@ -2858,37 +2807,21 @@ "optional": true }, "type-detect": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", - "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=" + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz", + "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==" }, "typeis": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/typeis/-/typeis-1.1.1.tgz", - "integrity": "sha1-NCZiUSpa29eKqJbVkUtzjn7dtUE=" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/typeis/-/typeis-1.1.2.tgz", + "integrity": "sha512-6BZAhYe0D904bKoUgJpy3A7jEWyb5C5m2mYUM2+jccjSUVUmruINMqBtGmeiEjchY+gtHuTHf9dW8/p34IOVZw==" }, "typescript": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", - "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", "dev": true }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2897,7 +2830,8 @@ "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true }, "verror": { "version": "1.10.0", @@ -2915,23 +2849,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true - }, - "xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", - "requires": { - "sax": "1.2.1", - "xmlbuilder": "4.2.1" - } - }, - "xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "requires": { - "lodash": "4.17.4" - } } } } diff --git a/package.json b/package.json index 81a16de..e851e15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lambda-framework", - "version": "1.0.16", + "version": "1.0.19", "description": "Framework to create web apps in AWS Lambda", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -30,6 +30,7 @@ "@types/chai": "^4.0.4", "@types/mocha": "^2.2.43", "@types/node": "^8.0.28", + "@types/sinon": "^2.3.7", "chai": "^4.1.2", "coveralls": "^3.0.0", "mocha": "^3.5.3", @@ -40,10 +41,7 @@ "typescript": "^2.5.2" }, "dependencies": { - "@types/aws-lambda": "0.0.16", - "@types/sinon": "^2.3.7", "accepts": "^1.3.4", - "aws-sdk": "^2.141.0", "bytes": "^3.0.0", "content-type": "^1.0.4", "cookie": "^0.3.1", diff --git a/src/index.ts b/src/index.ts index f4b06c0..c887d6f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,5 @@ export { default as ITemplate } from "./lib/types/http/renderEngine/ITemplate"; export { default as ITemplateEngine } from "./lib/types/http/renderEngine/ITemplateEngine"; export { default as ITemplateLoader } from "./lib/types/http/renderEngine/ITemplateLoader"; export { default as ITemplateRenderer } from "./lib/types/http/renderEngine/ITemplateRenderer"; -export { default as DefaultTemplateLoader } from "./lib/http/renderEngine/DefaultTemplateLoader"; export { default as DevTemplateLoader } from "./lib/http/renderEngine/DevTemplateLoader"; export { default as Template } from "./lib/http/renderEngine/Template"; diff --git a/src/lib/App.ts b/src/lib/App.ts index c0442d4..12efa0a 100644 --- a/src/lib/App.ts +++ b/src/lib/App.ts @@ -1,4 +1,3 @@ -import { Callback, Context } from "aws-lambda"; import configuration from "./configuration/configuration"; import defaultConfiguration from "./configuration/defaultConfiguration"; import eventFinalHandler from "./event/eventFinalHandler"; @@ -18,8 +17,9 @@ import IHttpResponse from "./types/http/IHttpResponse"; import IHttpRoute from "./types/http/IHttpRoute"; import ITemplateRenderer from "./types/http/renderEngine/ITemplateRenderer"; import IApp from "./types/IApp"; +import IRawCallback from "./types/IRawCallback"; +import IRawEvent from "./types/IRawEvent"; import IRouter from "./types/IRouter"; -import { getEventType } from "./utils/utils"; /** * The main object that describes and configures the lambda application. @@ -54,9 +54,8 @@ export default class App implements IApp { return this._settings[key]; } - public handle(event: any, context: Context, callback?: Callback): void { - const eventType = getEventType(event); - if (eventType === "APIGatewayEvent") { + public handle(event: IRawEvent, callback: IRawCallback): void { + if (event.isHttp) { const req: IHttpRequest = new HttpRequest(event); const res: IHttpResponse = new HttpResponse(this, req, callback); const done = httpFinalHandler(req, res, { diff --git a/src/lib/RawEvent.ts b/src/lib/RawEvent.ts new file mode 100644 index 0000000..24bbe0a --- /dev/null +++ b/src/lib/RawEvent.ts @@ -0,0 +1,28 @@ +import IRawEvent from "./types/IRawEvent"; + +/** + * The raw incoming event of the lambda function. + */ +export default class RawEvent implements IRawEvent { + + public type: string; + + public original: any; + + public isHttp: boolean; + + public body: string; + + public headers: {[name: string]: string}; + + public queryParams: {[name: string]: string}; + + public stageVariables: {[name: string]: string}; + + public ip: string; + + public path: string; + + public httpMethod: string; + +} diff --git a/src/lib/Router.ts b/src/lib/Router.ts index 44624a8..899cef9 100644 --- a/src/lib/Router.ts +++ b/src/lib/Router.ts @@ -174,9 +174,6 @@ export default class Router implements IRouter { public event(event: string|IEventRoutePredicate, handler: IEventHandler): IRouter { const layer = new EventLayer( event, - { - end: true - }, handler ); diff --git a/src/lib/event/EventLayer.ts b/src/lib/event/EventLayer.ts index fabc91d..5e7fe11 100644 --- a/src/lib/event/EventLayer.ts +++ b/src/lib/event/EventLayer.ts @@ -10,12 +10,10 @@ import INext from "./../types/INext"; export default class EventLayer implements IEventLayer { private _event: string|IEventRoutePredicate; - private _options: {}; private _handler: IEventHandler; - constructor(event: string|IEventRoutePredicate, options: {}, handler: IEventHandler) { + constructor(event: string|IEventRoutePredicate, handler: IEventHandler) { this._event = event; - this._options = options; this._handler = handler; } diff --git a/src/lib/event/EventRequest.ts b/src/lib/event/EventRequest.ts index 98dcb54..bd6edde 100644 --- a/src/lib/event/EventRequest.ts +++ b/src/lib/event/EventRequest.ts @@ -1,6 +1,6 @@ import IEventRequest from "./../types/event/IEventRequest"; import INext from "./../types/INext"; -import { getEventType } from "./../utils/utils"; +import IRawEvent from "./../types/IRawEvent"; /** * It represents an incoming event. @@ -9,10 +9,10 @@ export default class EventRequest implements IEventRequest { public next: INext; - private _event: any; + private _event: IRawEvent; private _context: { [name: string]: any }; - constructor(event: any) { + constructor(event: IRawEvent) { this._event = event; this._context = {}; } @@ -22,7 +22,7 @@ export default class EventRequest implements IEventRequest { } get eventType(): string { - return getEventType(this._event); + return this._event.type; } get context(): { [name: string]: any } { diff --git a/src/lib/http/HttpLayer.ts b/src/lib/http/HttpLayer.ts index eab9a30..8f56500 100644 --- a/src/lib/http/HttpLayer.ts +++ b/src/lib/http/HttpLayer.ts @@ -31,7 +31,6 @@ export default class HttpLayer implements IHttpLayer { private _router: IRouter; private _path: string; - private _options: {}; private _handler: IHttpHandler; private _regexp: RegExp; @@ -43,7 +42,6 @@ export default class HttpLayer implements IHttpLayer { constructor(router: IRouter, path: string, options: {[name: string]: any}, handler?: IHttpHandler, regexOptions?: RegExpOptions) { this._router = router; this._path = path; - this._options = options; this._handler = handler; const regexOpts = regexOptions || {}; diff --git a/src/lib/http/HttpRequest.ts b/src/lib/http/HttpRequest.ts index 97211f4..f285733 100644 --- a/src/lib/http/HttpRequest.ts +++ b/src/lib/http/HttpRequest.ts @@ -1,11 +1,11 @@ import * as accepts from "accepts"; -import { APIGatewayEvent } from "aws-lambda"; import * as fresh from "fresh"; import IHttpRequest from "./../types/http/IHttpRequest"; import IHttpResponse from "./../types/http/IHttpResponse"; import IHttpRoute from "./../types/http/IHttpRoute"; import IHttpUploadedFile from "./../types/http/IHttpUploadedFile"; import INext from "./../types/INext"; +import IRawEvent from "./../types/IRawEvent"; import { mergeParams, normalizeType } from "./../utils/utils"; /** @@ -21,11 +21,11 @@ export default class HttpRequest implements IHttpRequest { public params: { [name: string]: string }; public route: IHttpRoute; - private _event: APIGatewayEvent; + private _event: IRawEvent; private _headers: { [name: string]: string }; private _context: { [name: string]: any }; - constructor(event: APIGatewayEvent) { + constructor(event: IRawEvent) { this.body = event.body; // Default body this._event = event; this._context = {}; @@ -56,7 +56,7 @@ export default class HttpRequest implements IHttpRequest { return ips[ips.length - 1]; } else { - return this._event.requestContext.identity.sourceIp.replace("\:d+$", ""); + return this._event.ip; } } @@ -77,8 +77,8 @@ export default class HttpRequest implements IHttpRequest { return val.toLowerCase() === "xmlhttprequest"; } - get event(): APIGatewayEvent { - return this._event; + get event(): any { + return this._event.original; } get context(): { [name: string]: any } { diff --git a/src/lib/http/HttpResponse.ts b/src/lib/http/HttpResponse.ts index 4a43c6b..3b37e38 100644 --- a/src/lib/http/HttpResponse.ts +++ b/src/lib/http/HttpResponse.ts @@ -1,4 +1,3 @@ -import { Callback } from "aws-lambda"; import { parse, serialize } from "cookie"; import { sign } from "cookie-signature"; import * as encodeUrl from "encodeurl"; @@ -13,6 +12,7 @@ import IHttpResponse from "./../types/http/IHttpResponse"; import ITemplateEngine from "./../types/http/renderEngine/ITemplateEngine"; import IApp from "./../types/IApp"; import INext from "./../types/INext"; +import IRawCallback from "./../types/IRawCallback"; import IRouter from "./../types/IRouter"; import { merge, normalizeType, setCharset, stringify } from "./../utils/utils"; @@ -26,12 +26,12 @@ export default class HttpResponse implements IHttpResponse { private _statusCode: number; private _app: IApp; private _request: IHttpRequest; - private _callback: Callback; + private _callback: IRawCallback; private _headers: { [name: string]: string|string[] }; private _error: IHttpError; private _isSent: boolean; - constructor(app: IApp, request: IHttpRequest, callback: Callback) { + constructor(app: IApp, request: IHttpRequest, callback: IRawCallback) { this._app = app; this._request = request; this._callback = callback; @@ -389,7 +389,11 @@ export default class HttpResponse implements IHttpResponse { const error: Error = this._error && this._error.cause ? this._error.cause : this._error; this._isSent = true; - this._callback(error, {statusCode, headers, body: resultBody}); + if (error) { + this._callback.sendError(error); + } else { + this._callback.send(statusCode, headers, resultBody); + } } } diff --git a/src/lib/http/bodyParsers/UrlEncodedParser.ts b/src/lib/http/bodyParsers/UrlEncodedParser.ts index ba12b5c..67c2a82 100644 --- a/src/lib/http/bodyParsers/UrlEncodedParser.ts +++ b/src/lib/http/bodyParsers/UrlEncodedParser.ts @@ -24,7 +24,9 @@ const parameterCount = (body: string, limit: number): number => { return count; }; -const extendedParser = (body: string, parameterLimit: number, arrayLimit: number): {[name: string]: string} => { +type IParser = (body: string, parameterLimit: number, arrayLimit: number) => {[name: string]: string|string[]}; + +const extendedParser: IParser = (body: string, parameterLimit: number, arrayLimit: number): {[name: string]: string|string[]} => { return qs.parse(body, { allowPrototypes: true, arrayLimit, @@ -33,11 +35,11 @@ const extendedParser = (body: string, parameterLimit: number, arrayLimit: number }); }; -const simpleParser = (body: string, parameterLimit: number, arrayLimit: number): {[name: string]: string} => { +const simpleParser: IParser = (body: string, parameterLimit: number, arrayLimit: number): {[name: string]: string|string[]} => { return querystring.parse(body, undefined, undefined, {maxKeys: parameterLimit}); }; -const abstractParser = (options: {[name: string]: any}, parser: (body: string, parameterLimit: number, arrayLimit: number) => {[name: string]: string}): (body: string) => {[name: string]: string} => { +const abstractParser = (options: {[name: string]: any}, parser: IParser): (body: string) => {[name: string]: string|string[]} => { let parameterLimit = options.parameterLimit !== undefined ? options.parameterLimit : 1000; @@ -50,7 +52,7 @@ const abstractParser = (options: {[name: string]: any}, parser: (body: string, p parameterLimit = Number.MAX_SAFE_INTEGER - 1; } - return (body: string): {[name: string]: string} => { + return (body: string): {[name: string]: string|string[]} => { const paramCount = parameterCount(body, parameterLimit + 1); if (paramCount === undefined) { @@ -76,10 +78,10 @@ export default class UrlEncodedParser implements IBodyParser { const contentType = opts.type || "application/x-www-form-urlencoded"; // create the appropriate query parser - const queryParser: (body: string, parameterLimit: number, arrayLimit: number) => {[name: string]: string} = extended + const queryParser: (body: string, parameterLimit: number, arrayLimit: number) => {[name: string]: string|string[]} = extended ? extendedParser : simpleParser; - const parser: (body: string) => {[name: string]: string} = abstractParser(options, queryParser); + const parser: (body: string) => {[name: string]: string|string[]} = abstractParser(options, queryParser); return parserHelper( (initialBody: string, req: IHttpRequest): void => { diff --git a/src/lib/http/bodyParsers/parserHelper.ts b/src/lib/http/bodyParsers/parserHelper.ts index 8b8d625..5605c15 100644 --- a/src/lib/http/bodyParsers/parserHelper.ts +++ b/src/lib/http/bodyParsers/parserHelper.ts @@ -20,7 +20,7 @@ const parserHelper = (func: (body: string, req: IHttpRequest) => void, allowCont if (!allowContentTypes || req.is(allowContentTypes)) { const contentType = req.header("content-type"); try { - func(req.event.body, req); + func(req.body as string, req); req.context._previouslyBodyParsed = true; } catch (e) { diff --git a/src/lib/http/renderEngine/DefaultTemplateLoader.ts b/src/lib/http/renderEngine/DefaultTemplateLoader.ts deleted file mode 100644 index 54b0410..0000000 --- a/src/lib/http/renderEngine/DefaultTemplateLoader.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as S3 from "aws-sdk/clients/s3"; -import * as NodeCache from "node-cache"; -import Template from "./../../http/renderEngine/Template"; -import ITemplate from "./../../types/http/renderEngine/ITemplate"; -import ITemplateLoader from "./../../types/http/renderEngine/ITemplateLoader"; - -/** - * Loads the template from AWS S3 bucket. - */ -export default class DefaultTemplateLoader implements ITemplateLoader { - - private _s3: S3; - private _bucket: string; - private _cache: NodeCache; - - constructor(bucket: string, ttl: number) { - this._s3 = new S3(); - this._bucket = bucket; - if (ttl) { - this._cache = new NodeCache({ stdTTL: ttl }); - } - } - - public load(fileName: string, callback: (err: Error, template: ITemplate) => void): void { - this.getFromCache(fileName, (cacheErr: Error, cacheValue: ITemplate) => { - if (cacheErr) { - callback(cacheErr, null); - } else { - if (cacheValue === undefined) { - this._s3.getObject( - { - Bucket: this._bucket, - Key: fileName - }, - (err: Error, data: S3.Types.GetObjectOutput) => { - if (err) { - callback(err, null); - } else { - const content: string = data.Body.toString(); - const template: ITemplate = new Template(fileName, content); - this.setToCache(template); - callback(null, template); - } - } - ); - } else { - callback(null, cacheValue); - } - } - }); - } - - private getFromCache(fileName: string, callback: (cacheErr: Error, cacheValue: ITemplate) => void): void { - if (this._cache) { - this._cache.get(fileName, callback); - } else { - callback(null, undefined); - } - } - - private setToCache(template: ITemplate): void { - if (this._cache) { - this._cache.set(template.fileName, template, (err: Error, success: boolean) => { - if (err || !success) { - console.error("Error saving template into cache: " + template.fileName, err); - } - }); - } - } - -} diff --git a/src/lib/types/IApp.ts b/src/lib/types/IApp.ts index 3719ab4..803a527 100644 --- a/src/lib/types/IApp.ts +++ b/src/lib/types/IApp.ts @@ -1,10 +1,11 @@ -import { Callback, Context } from "aws-lambda"; import IEventHandler from "./event/IEventHandler"; import IEventRoutePredicate from "./event/IEventRoutePredicate"; import IHttpHandler from "./http/IHttpHandler"; import IHttpPlaceholderHandler from "./http/IHttpPlaceholderHandler"; import IHttpRoute from "./http/IHttpRoute"; import ITemplateRenderer from "./http/renderEngine/ITemplateRenderer"; +import IRawCallback from "./IRawCallback"; +import IRawEvent from "./IRawEvent"; import IRouter from "./IRouter"; /** @@ -53,13 +54,12 @@ export default interface IApp { get(key: string): any; /** - * Handle an incoming lambda funciton. + * Handle an incoming lambda function. * * @param {any} event - * @param {Context} context * @param {Callback} callback */ - handle(event: any, context: Context, callback?: Callback): void; + handle(event: IRawEvent, callback: IRawCallback): void; /** * Use the given handler, with optional path, defaulting to "/". diff --git a/src/lib/types/IRawCallback.ts b/src/lib/types/IRawCallback.ts new file mode 100644 index 0000000..81abc06 --- /dev/null +++ b/src/lib/types/IRawCallback.ts @@ -0,0 +1,10 @@ +/** + * A provider callback mechanism has to implements this interface. + */ +export default interface IRawCallback { + + sendError(error: Error): void; + + send(statusCode: number, headers: {[name: string]: string|string[]}, body: object|Buffer): void; + +} diff --git a/src/lib/types/IRawEvent.ts b/src/lib/types/IRawEvent.ts new file mode 100644 index 0000000..868d3ab --- /dev/null +++ b/src/lib/types/IRawEvent.ts @@ -0,0 +1,26 @@ +/** + * The raw incoming event of the lambda function. + */ +export default interface IRawEvent { + + type: string; + + original: any; + + isHttp: boolean; + + body: string; + + headers: {[name: string]: string}; + + queryParams: {[name: string]: string}; + + stageVariables: {[name: string]: string}; + + ip: string; + + path: string; + + httpMethod: string; + +} diff --git a/src/lib/types/http/IHttpRequest.ts b/src/lib/types/http/IHttpRequest.ts index 46a0bc1..64e105d 100644 --- a/src/lib/types/http/IHttpRequest.ts +++ b/src/lib/types/http/IHttpRequest.ts @@ -1,4 +1,3 @@ -import { APIGatewayEvent } from "aws-lambda"; import INext from "./../INext"; import IHttpResponse from "./IHttpResponse"; import IHttpRoute from "./IHttpRoute"; @@ -22,17 +21,17 @@ export default interface IHttpRequest { /** * The protocol of the incomig request. Can be http or https. */ - protocol: string; + readonly protocol: string; /** * If the protocol of the incoming request is secure (https). */ - secure: boolean; + readonly secure: boolean; /** * The remote address from the trusted proxy. */ - ip: string; + readonly ip: string; /** * The request body. @@ -47,27 +46,27 @@ export default interface IHttpRequest { /** * The parsed path of the request. */ - path: string; + readonly path: string; /** * The incoming request HTTP method (GET, POST, PUT, DELETE,...) */ - method: string; + readonly method: string; /** * The "Host" header field. */ - hostname: string; + readonly hostname: string; /** * Check if the request was an _XMLHttpRequest_. */ - xhr: boolean; + readonly xhr: boolean; /** * The incoming request headers. */ - headers: { [name: string]: string }; + readonly headers: { [name: string]: string }; /** * All the params of the incoming request (query, path variables and body). @@ -87,7 +86,7 @@ export default interface IHttpRequest { /** * Original event. */ - event: APIGatewayEvent; + readonly event: any; /** * Context to save thins and use it diff --git a/src/lib/utils/utils.ts b/src/lib/utils/utils.ts index b5dff38..0d11f56 100644 --- a/src/lib/utils/utils.ts +++ b/src/lib/utils/utils.ts @@ -1,6 +1,6 @@ -import { APIGatewayEvent } from "aws-lambda"; import { format, parse } from "content-type"; import { lookup } from "mime-types"; +import IRawEvent from "./../types/IRawEvent"; /** * Utils functions shared between multiple classes. @@ -34,57 +34,8 @@ export function merge(...objs: object[]): any { return result; } -export function getEventType(obj: any): string { - if ("httpMethod" in obj) { - return "APIGatewayEvent"; - } else if ("authorizationToken" in obj) { - return "CustomAuthorizerEvent"; - } else if ("Records" in obj) { - const obj2 = obj.Records[0] || {}; - if ("Sns" in obj2) { - return "SNSEvent"; - } else if ("s3" in obj2) { - return "S3CreateEvent"; - } else if ("kinesis" in obj2) { - return "KinesisEvent"; - } else if ("dynamodb" in obj2) { - return "DynamoDbEvent"; - } else { - return null; - } - } else if ("triggerSource" in obj) { - return "CognitoUserPoolEvent"; - } else if ("RequestType" in obj) { - const obj2 = obj.RequestType; - switch (obj2) { - case "Create": - return "CloudFormationCustomResourceCreateEvent"; - case "Update": - return "CloudFormationCustomResourceUpdateEvent"; - case "Delete": - return "CloudFormationCustomResourceDeleteEvent"; - default: - return null; - } - } else if ("Status" in obj) { - const obj2 = obj.Status; - switch (obj2) { - case "SUCCESS": - return "CloudFormationCustomResourceSuccessResponse"; - case "FAILED": - return "CloudFormationCustomResourceFailedResponse"; - default: - return null; - } - } else if ("time" in obj) { - return "ScheduledEvent"; - } else { - return null; - } -} - -export function mergeParams(event: APIGatewayEvent): {[name: string]: string} { - const query = event.queryStringParameters || {}; +export function mergeParams(event: IRawEvent): {[name: string]: string} { + const query = event.queryParams || {}; const stageVariables = event.stageVariables || {}; return merge(query, stageVariables); diff --git a/test/app.spec.ts b/test/app.spec.ts index be39758..9172b3a 100644 --- a/test/app.spec.ts +++ b/test/app.spec.ts @@ -4,12 +4,15 @@ import App from '../src/index' import Router from "../src/lib/Router"; import { configuration } from '../src/index' import defaultConfiguration from '../src/lib/configuration/defaultConfiguration' +import DefaultCallback from './utils/DefaultCallback'; +import httpEvent from './utils/httpEvent'; +import otherEvent from './utils/otherEvent'; /** * Test for App. */ describe('App', () => { - let app; + let app: App; beforeEach(() => { app = new App() @@ -46,16 +49,16 @@ describe('App', () => { }); describe("#handle", () => { - it("should call the router httpHandle if the event type is APIGatewayEvent.", () => { + it("should call the router httpHandle if the event type is HTTP.", () => { const httpHandleStub = stub(Router.prototype, "httpHandle"); - app.handle({httpMethod: "GET", headers: []}); + app.handle(httpEvent, new DefaultCallback()); Chai.expect(httpHandleStub.calledOnce).to.be.true; httpHandleStub.restore(); }); - it("should call the router eventHandle if the event type is NOT APIGatewayEvent.", () => { + it("should call the router eventHandle if the event type is NOT HTTP.", () => { const eventHandleStub = stub(Router.prototype, "eventHandle"); - app.handle({eventParam: "1"}); + app.handle(otherEvent, new DefaultCallback()); Chai.expect(eventHandleStub.calledOnce).to.be.true; eventHandleStub.restore(); }); @@ -82,7 +85,7 @@ describe('App', () => { describe("#param", () => { it("should delegate the action to the default router.", () => { const paramStub = stub(Router.prototype, "param"); - app.param(null); + app.param(null, null); Chai.expect(paramStub.calledOnce).to.be.true; paramStub.restore(); }); @@ -100,7 +103,7 @@ describe('App', () => { describe("#event", () => { it("should delegate the action to the default router.", () => { const eventStub = stub(Router.prototype, "event"); - app.event(null); + app.event(null, null); Chai.expect(eventStub.calledOnce).to.be.true; eventStub.restore(); }); diff --git a/test/event/EventLayer.spec.ts b/test/event/EventLayer.spec.ts index ae10ec2..9df0093 100644 --- a/test/event/EventLayer.spec.ts +++ b/test/event/EventLayer.spec.ts @@ -1,82 +1,45 @@ import * as Chai from 'chai' import EventRequest from './../../src/lib/event/EventRequest' import EventLayer from './../../src/lib/event/EventLayer' +import otherEvent from './../utils/otherEvent'; /** * Test for EventLayer. */ describe('EventLayer', () => { - const event = { - "Records": [ - { - "eventVersion": "2.0", - "eventTime": "1970-01-01T00:00:00.000Z", - "requestParameters": { - "sourceIPAddress": "127.0.0.1" - }, - "s3": { - "configurationId": "testConfigRule", - "object": { - "eTag": "0123456789abcdef0123456789abcdef", - "sequencer": "0A1B2C3D4E5F678901", - "key": "test/key", - "size": 1024 - }, - "bucket": { - "arn": "arn:aws:s3:::example-bucket", - "name": "example-bucket", - "ownerIdentity": { - "principalId": "EXAMPLE" - } - }, - "s3SchemaVersion": "1.0" - }, - "responseElements": { - "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", - "x-amz-request-id": "EXAMPLE123456789" - }, - "awsRegion": "us-east-1", - "eventName": "ObjectCreated:Put", - "userIdentity": { - "principalId": "EXAMPLE" - }, - "eventSource": "aws:s3" - } - ] - } let req beforeEach(() => { - req = new EventRequest(event) + req = new EventRequest(Object.assign({}, otherEvent)) }) describe('#match', () => { it('should return true if the looking event is an event type (string) and the event type of the given #request is the same.', () => { - const layer = new EventLayer('S3CreateEvent', {}, () => {}) + const layer = new EventLayer('S3CreateEvent', () => {}) Chai.expect(layer.match(req)).to.be.true }); it('should return false if the looking event is an event type (string) and the event type of the given #request is NOT the same.', () => { - const layer = new EventLayer('SNSEvent', {}, () => {}) + const layer = new EventLayer('SNSEvent', () => {}) Chai.expect(layer.match(req)).to.be.false }); it('should return true if the looking event is a predicate (function) and the result of calling that function with the given #request is true.', () => { - const predicate = (req) => req.event.Records[0].s3.bucket.arn == 'arn:aws:s3:::example-bucket' - const layer = new EventLayer(predicate, {}, () => {}) + const predicate = (req) => req.event.original.Records[0].s3.bucket.arn == 'arn:aws:s3:::example-bucket' + const layer = new EventLayer(predicate, () => {}) Chai.expect(layer.match(req)).to.be.true }); it('should return false if the looking event is a predicate (function) and the result of calling that function with the given #request is false.', () => { - const predicate = (req) => req.event.Records[0].s3.bucket.arn == 'other-bucket' - const layer = new EventLayer(predicate, {}, () => {}) + const predicate = (req) => req.event.original.Records[0].s3.bucket.arn == 'other-bucket' + const layer = new EventLayer(predicate, () => {}) Chai.expect(layer.match(req)).to.be.false }); }); describe('#handle', () => { it('should call the handler if it exists.', (done) => { - const layer = new EventLayer('S3CreateEvent', {}, () => { + const layer = new EventLayer('S3CreateEvent', () => { done() }) @@ -84,7 +47,7 @@ describe('EventLayer', () => { }); it('should call #next if the handler does not exist.', (done) => { - const layer = new EventLayer('S3CreateEvent', {}, null) + const layer = new EventLayer('S3CreateEvent', null) layer.handle(req, () => { done() @@ -94,19 +57,19 @@ describe('EventLayer', () => { describe('#isErrorHandler', () => { it('should return true if the handler has 3 arguments as input.', () => { - const layer = new EventLayer('S3CreateEvent', {}, (arg1, arg2, arg3) => { + const layer = new EventLayer('S3CreateEvent', (arg1, arg2, arg3) => { }) Chai.expect(layer.isErrorHandler()).to.be.true }); it('should return false if the handler doesn\'t exist.', () => { - const layer = new EventLayer('S3CreateEvent', {}, null) + const layer = new EventLayer('S3CreateEvent', null) Chai.expect(layer.isErrorHandler()).to.be.false }); it('should return false if the handler has NOT 3 arguments as input.', () => { - const layer = new EventLayer('S3CreateEvent', {}, (arg1, arg2) => { + const layer = new EventLayer('S3CreateEvent', (arg1, arg2) => { }) Chai.expect(layer.isErrorHandler()).to.be.false diff --git a/test/event/EventRequest.spec.ts b/test/event/EventRequest.spec.ts index d2c646d..d95d0f9 100644 --- a/test/event/EventRequest.spec.ts +++ b/test/event/EventRequest.spec.ts @@ -1,313 +1,22 @@ -import * as Chai from 'chai' -import EventRequest from './../../src/lib/event/EventRequest' - -const apiGatewayEvent = { - "body": "{ \"test\": \"body\"}", - "resource": "/{proxy+}", - "requestContext": { - "resourceId": "123456", - "apiId": "1234567890", - "resourcePath": "/{proxy+}", - "httpMethod": "POST", - "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", - "accountId": "123456789012", - "identity": { - "apiKey": null, - "userArn": null, - "cognitoAuthenticationType": null, - "caller": null, - "userAgent": "Custom User Agent String", - "user": null, - "cognitoIdentityPoolId": null, - "cognitoIdentityId": null, - "cognitoAuthenticationProvider": null, - "sourceIp": "127.0.0.1", - "accountId": null - }, - "stage": "prod" - }, - "queryStringParameters": { - "foo": "bar" - }, - "headers": { - "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", - "Accept-Language": "en-US,en;q=0.8", - "CloudFront-Is-Desktop-Viewer": "true", - "CloudFront-Is-SmartTV-Viewer": "false", - "CloudFront-Is-Mobile-Viewer": "false", - "X-Forwarded-For": "127.0.0.1, 127.0.0.2", - "CloudFront-Viewer-Country": "US", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Upgrade-Insecure-Requests": "1", - "X-Forwarded-Port": "443", - "Host": "1234567890.execute-api.us-east-1.amazonaws.com", - "X-Forwarded-Proto": "https", - "X-Amz-Cf-Id": "aaaaaaaaaae3VYQb9jd-nvCd-de396Uhbp027Y2JvkCPNLmGJHqlaA==", - "CloudFront-Is-Tablet-Viewer": "false", - "Cache-Control": "max-age=0", - "User-Agent": "Custom User Agent String", - "CloudFront-Forwarded-Proto": "https", - "Accept-Encoding": "gzip, deflate, sdch" - }, - "pathParameters": { - "proxy": "/examplepath" - }, - "httpMethod": "POST", - "stageVariables": { - "baz": "qux" - }, - "path": "/examplepath" -} -const customAuthorizerEvent = { - "type" : "TOKEN", - "authorizationToken" : "Bearer ACCESS_TOKEN", - "methodArn":"arn:aws:execute-api:us-east-1:1234567890:apiId/stage/method/resourcePath" -} -const sNSEvent = { - "Records": [ - { - "EventVersion": "1.0", - "EventSubscriptionArn": "arn:aws:sns:EXAMPLE", - "EventSource": "aws:sns", - "Sns": { - "SignatureVersion": "1", - "Timestamp": "1970-01-01T00:00:00.000Z", - "Signature": "EXAMPLE", - "SigningCertUrl": "EXAMPLE", - "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e", - "Message": "example message", - "MessageAttributes": { - "Test": { - "Type": "String", - "Value": "TestString" - }, - "TestBinary": { - "Type": "Binary", - "Value": "TestBinary" - } - }, - "Type": "Notification", - "UnsubscribeUrl": "EXAMPLE", - "TopicArn": "arn:aws:sns:us-east-1:111122223333:ExampleTopic", - "Subject": "example subject" - } - } - ] -} -const s3CreateEvent = { - "Records": [ - { - "eventVersion": "2.0", - "eventTime": "1970-01-01T00:00:00.000Z", - "requestParameters": { - "sourceIPAddress": "127.0.0.1" - }, - "s3": { - "configurationId": "testConfigRule", - "object": { - "eTag": "0123456789abcdef0123456789abcdef", - "sequencer": "0A1B2C3D4E5F678901", - "key": "test/key", - "size": 1024 - }, - "bucket": { - "arn": "arn:aws:s3:::example-bucket", - "name": "example-bucket", - "ownerIdentity": { - "principalId": "EXAMPLE" - } - }, - "s3SchemaVersion": "1.0" - }, - "responseElements": { - "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", - "x-amz-request-id": "EXAMPLE123456789" - }, - "awsRegion": "us-east-1", - "eventName": "ObjectCreated:Put", - "userIdentity": { - "principalId": "EXAMPLE" - }, - "eventSource": "aws:s3" - } - ] -} -const kinesisEvent = { - "Records": [ - { - "eventID": "shardId-000000000000:49545115243490985018280067714973144582180062593244200961", - "eventVersion": "1.0", - "kinesis": { - "approximateArrivalTimestamp": 1428537600, - "partitionKey": "partitionKey-03", - "data": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0IDEyMy4=", - "kinesisSchemaVersion": "1.0", - "sequenceNumber": "49545115243490985018280067714973144582180062593244200961" - }, - "invokeIdentityArn": "arn:aws:iam::EXAMPLE", - "eventName": "aws:kinesis:record", - "eventSourceARN": "arn:aws:kinesis:EXAMPLE", - "eventSource": "aws:kinesis", - "awsRegion": "us-east-1" - } - ] -} -const cognitoUserPoolEvent = { - "version": 1, - "triggerSource": "string", - "region": "us-east-1", - "userPoolId": "string", - "callerContext": { - "awsSdkVersion": "string", - "clientId": "string" - }, - "request": { - "userAttributes": { - "string": "string" - } - }, - "response": {} -} -const dynamoDbEvent = { - "Records": [ - { - "eventID": "1", - "eventVersion": "1.0", - "dynamodb": { - "Keys": { - "Id": { - "N": "101" - } - }, - "NewImage": { - "Message": { - "S": "New item!" - }, - "Id": { - "N": "101" - } - }, - "StreamViewType": "NEW_AND_OLD_IMAGES", - "SequenceNumber": "111", - "SizeBytes": 26 - }, - "awsRegion": "us-east-1", - "eventName": "INSERT", - "eventSourceARN": "arn:aws:dynamodb:us-east-1:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", - "eventSource": "aws:dynamodb" - } - ] -} -const cloudFormationCustomResourceCreateEvent = { - "RequestType": "Create" -} -const cloudFormationCustomResourceUpdateEvent = { - "RequestType": "Update" -} -const cloudFormationCustomResourceDeleteEvent = { - "RequestType": "Delete" -} -const cloudFormationCustomResourceSuccessResponse = { - "Status": "SUCCESS" -} -const cloudFormationCustomResourceFailedResponse = { - "Status": "FAILED" -} -const scheduledEvent = { - "account": "123456789012", - "region": "us-east-1", - "detail": {}, - "detail-type": "Scheduled Event", - "source": "aws.events", - "time": "1970-01-01T00:00:00Z", - "id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c", - "resources": [ - "arn:aws:events:us-east-1:123456789012:rule/my-schedule" - ] -} -const unknownEvent = { - "a": "b" -} +import * as Chai from "chai" +import otherEvent from "./../utils/otherEvent"; +import RawEvent from "./../../src/lib/RawEvent"; +import EventRequest from "./../../src/lib/event/EventRequest" /** * Test for EventRequest. */ -describe('EventRequest', () => { - - describe('#eventType', () => { - it('should return "APIGatewayEvent" if the event is of this type.', () => { - const req = new EventRequest(apiGatewayEvent) - Chai.expect(req.eventType).to.be.equal('APIGatewayEvent') - }); - - it('should return "CustomAuthorizerEvent" if the event is of this type.', () => { - const req = new EventRequest(customAuthorizerEvent) - Chai.expect(req.eventType).to.be.equal('CustomAuthorizerEvent') - }); - - it('should return "SNSEvent" if the event is of this type.', () => { - const req = new EventRequest(sNSEvent) - Chai.expect(req.eventType).to.be.equal('SNSEvent') - }); - - it('should return "S3CreateEvent" if the event is of this type.', () => { - const req = new EventRequest(s3CreateEvent) - Chai.expect(req.eventType).to.be.equal('S3CreateEvent') - }); - - it('should return "KinesisEvent" if the event is of this type.', () => { - const req = new EventRequest(kinesisEvent) - Chai.expect(req.eventType).to.be.equal('KinesisEvent') - }); - - it('should return "DynamoDbEvent" if the event is of this type.', () => { - const req = new EventRequest(dynamoDbEvent) - Chai.expect(req.eventType).to.be.equal('DynamoDbEvent') - }); - - it('should return "CognitoUserPoolEvent" if the event is of this type.', () => { - const req = new EventRequest(cognitoUserPoolEvent) - Chai.expect(req.eventType).to.be.equal('CognitoUserPoolEvent') - }); - - it('should return "CloudFormationCustomResourceCreateEvent" if the event is of this type.', () => { - const req = new EventRequest(cloudFormationCustomResourceCreateEvent) - Chai.expect(req.eventType).to.be.equal('CloudFormationCustomResourceCreateEvent') - }); - - it('should return "CloudFormationCustomResourceUpdateEvent" if the event is of this type.', () => { - const req = new EventRequest(cloudFormationCustomResourceUpdateEvent) - Chai.expect(req.eventType).to.be.equal('CloudFormationCustomResourceUpdateEvent') - }); - - it('should return "CloudFormationCustomResourceDeleteEvent" if the event is of this type.', () => { - const req = new EventRequest(cloudFormationCustomResourceDeleteEvent) - Chai.expect(req.eventType).to.be.equal('CloudFormationCustomResourceDeleteEvent') - }); - - it('should return "CloudFormationCustomResourceSuccessResponse" if the event is of this type.', () => { - const req = new EventRequest(cloudFormationCustomResourceSuccessResponse) - Chai.expect(req.eventType).to.be.equal('CloudFormationCustomResourceSuccessResponse') - }); - - it('should return "CloudFormationCustomResourceFailedResponse" if the event is of this type.', () => { - const req = new EventRequest(cloudFormationCustomResourceFailedResponse) - Chai.expect(req.eventType).to.be.equal('CloudFormationCustomResourceFailedResponse') - }); - - it('should return "ScheduledEvent" if the event is of this type.', () => { - const req = new EventRequest(scheduledEvent) - Chai.expect(req.eventType).to.be.equal('ScheduledEvent') - }); +describe("EventRequest", () => { - it('should return null if the event is of unknown type.', () => { - const req = new EventRequest(unknownEvent) - Chai.expect(req.eventType).to.be.null + describe("#eventType", () => { + it("should return the type of the raw event.", () => { + const req = new EventRequest(otherEvent) + Chai.expect(req.eventType).to.be.equal("S3CreateEvent") }); describe("#context", () => { it("should return an empty initialized object where variables can be shared between layers.", () => { - const req = new EventRequest(customAuthorizerEvent); + const req = new EventRequest(new RawEvent()); Chai.expect(req.context).to.be.deep.equal({}); }); }); diff --git a/test/event/EventRouterExecutor.spec.ts b/test/event/EventRouterExecutor.spec.ts index ac31260..586a25d 100644 --- a/test/event/EventRouterExecutor.spec.ts +++ b/test/event/EventRouterExecutor.spec.ts @@ -2,45 +2,7 @@ import * as Chai from 'chai' import EventRouterExecutor from './../../src/lib/event/EventRouterExecutor' import EventRequest from './../../src/lib/event/EventRequest' import Router from './../../src/lib/Router' - -const event = { - "Records": [ - { - "eventVersion": "2.0", - "eventTime": "1970-01-01T00:00:00.000Z", - "requestParameters": { - "sourceIPAddress": "127.0.0.1" - }, - "s3": { - "configurationId": "testConfigRule", - "object": { - "eTag": "0123456789abcdef0123456789abcdef", - "sequencer": "0A1B2C3D4E5F678901", - "key": "test/key", - "size": 1024 - }, - "bucket": { - "arn": "arn:aws:s3:::example-bucket", - "name": "example-bucket", - "ownerIdentity": { - "principalId": "EXAMPLE" - } - }, - "s3SchemaVersion": "1.0" - }, - "responseElements": { - "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", - "x-amz-request-id": "EXAMPLE123456789" - }, - "awsRegion": "us-east-1", - "eventName": "ObjectCreated:Put", - "userIdentity": { - "principalId": "EXAMPLE" - }, - "eventSource": "aws:s3" - } - ] -} +import otherEvent from './../utils/otherEvent'; /** * Test for EventRouterExecutor. @@ -50,7 +12,7 @@ describe('EventRouterExecutor', () => { let router beforeEach(() => { - req = new EventRequest(event) + req = new EventRequest(otherEvent) router = new Router }) diff --git a/test/event/eventFinalHandler.spec.ts b/test/event/eventFinalHandler.spec.ts index 68e3f34..addfa38 100644 --- a/test/event/eventFinalHandler.spec.ts +++ b/test/event/eventFinalHandler.spec.ts @@ -1,53 +1,16 @@ import * as Chai from 'chai' import eventFinalHandler from './../../src/lib/event/eventFinalHandler' import EventRequest from './../../src/lib/event/EventRequest' +import otherEvent from './../utils/otherEvent'; /** * Test for eventFinalHandler. */ describe('eventFinalHandler', () => { - const event = { - "Records": [ - { - "eventVersion": "2.0", - "eventTime": "1970-01-01T00:00:00.000Z", - "requestParameters": { - "sourceIPAddress": "127.0.0.1" - }, - "s3": { - "configurationId": "testConfigRule", - "object": { - "eTag": "0123456789abcdef0123456789abcdef", - "sequencer": "0A1B2C3D4E5F678901", - "key": "test/key", - "size": 1024 - }, - "bucket": { - "arn": "arn:aws:s3:::example-bucket", - "name": "example-bucket", - "ownerIdentity": { - "principalId": "EXAMPLE" - } - }, - "s3SchemaVersion": "1.0" - }, - "responseElements": { - "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", - "x-amz-request-id": "EXAMPLE123456789" - }, - "awsRegion": "us-east-1", - "eventName": "ObjectCreated:Put", - "userIdentity": { - "principalId": "EXAMPLE" - }, - "eventSource": "aws:s3" - } - ] - } let req beforeEach(() => { - req = new EventRequest(event) + req = new EventRequest(otherEvent) }); it("should call #onerror handler if it is set in the #options when #error is undefined.", (done) => { diff --git a/test/http/HttpLayer.spec.ts b/test/http/HttpLayer.spec.ts index 88eac06..7fe1cc7 100644 --- a/test/http/HttpLayer.spec.ts +++ b/test/http/HttpLayer.spec.ts @@ -1,5 +1,6 @@ import * as Chai from 'chai' import { stub, SinonStub } from "sinon"; +import HttpError from './../../src/lib/exceptions/HttpError' import HttpLayer from './../../src/lib/http/HttpLayer' import IHttpLayer from './../../src/lib/types/http/IHttpLayer' import HttpRoute from './../../src/lib/http/HttpRoute' @@ -12,59 +13,8 @@ import HttpResponse from './../../src/lib/http/HttpResponse' import IHttpResponse from './../../src/lib/types/http/IHttpResponse' import IRouter from './../../src/lib/types/IRouter' import Router from './../../src/lib/Router' -import HttpError from './../../src/lib/exceptions/HttpError' - -const event = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Accept': 'application/json', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' -} +import DefaultCallback from "./../utils/DefaultCallback"; +import httpEvent from "./../utils/httpEvent"; /** * Test for HttpLayer. @@ -77,14 +27,12 @@ describe('HttpLayer', () => { router.mount(subrouter, '/blog'); let req: IHttpRequest let res: IHttpResponse - let callbackErrorResult, callBackSuccessResult + + const callback: DefaultCallback = new DefaultCallback(); beforeEach(() => { - req = new HttpRequest(Object.assign({}, event)) - res = new HttpResponse(app, req, (error, success) => { - callbackErrorResult = error - callBackSuccessResult = success - }) + req = new HttpRequest(Object.assign({}, httpEvent)) + res = new HttpResponse(app, req, callback) layer = new HttpLayer(router, '/blog/:id', {}) }); diff --git a/test/http/HttpRequest.spec.ts b/test/http/HttpRequest.spec.ts index df5dbee..03f7ec8 100644 --- a/test/http/HttpRequest.spec.ts +++ b/test/http/HttpRequest.spec.ts @@ -4,7 +4,9 @@ import IHttpRequest from './../../src/lib/types/http/IHttpRequest' import HttpResponse from './../../src/lib/http/HttpResponse' import HttpRoute from './../../src/lib/http/HttpRoute' import App from './../../src/lib/App' -import { APIGatewayEvent } from 'aws-lambda' +import IRawEvent from "./../../src/lib/types/IRawEvent"; +import DefaultCallback from "./../utils/DefaultCallback"; +import httpEvent from "./../utils/httpEvent"; /** * Test for HttpRequest. @@ -12,62 +14,11 @@ import { APIGatewayEvent } from 'aws-lambda' describe('HttpRequest', () => { let request: IHttpRequest let nextResult - let event: APIGatewayEvent + let event: IRawEvent; const app = new App() beforeEach(function(done) { nextResult = undefined - event = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Content-Type': 'application/json,text/html', - 'Accept': 'application/json,text/html', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' - } + event = Object.assign({}, httpEvent); request = new HttpRequest(event) done() @@ -210,7 +161,7 @@ describe('HttpRequest', () => { }); it('#fresh should return true if the request is "fresh"', () => { - const callback = function() {} + const callback: DefaultCallback = new DefaultCallback(); const response = new HttpResponse(app, request, callback) response.status(200) response.putHeader('ETag', 'etagValue') @@ -219,14 +170,14 @@ describe('HttpRequest', () => { }); it('#fresh should return false if the request is not "fresh"', () => { - const callback = function() {} + const callback: DefaultCallback = new DefaultCallback(); const response = new HttpResponse(app, request, callback) response.status(200) Chai.expect(request.fresh(response)).to.be.false }); it('#stale should return true if the request is "stale"', () => { - const callback = function() {} + const callback: DefaultCallback = new DefaultCallback(); const response = new HttpResponse(app, request, callback) response.status(200) response.putHeader('ETag', 'etagValue') @@ -235,7 +186,7 @@ describe('HttpRequest', () => { }); it('#stale should return false if the request is not "stale"', () => { - const callback = function() {} + const callback: DefaultCallback = new DefaultCallback(); const response = new HttpResponse(app, request, callback) response.status(200) Chai.expect(request.stale(response)).to.be.true diff --git a/test/http/HttpResponse.spec.ts b/test/http/HttpResponse.spec.ts index 2d9c207..637bc3d 100644 --- a/test/http/HttpResponse.spec.ts +++ b/test/http/HttpResponse.spec.ts @@ -13,8 +13,10 @@ import HttpRoute from './../../src/lib/http/HttpRoute' import TemplateEngine from './../../src/lib/http/renderEngine/TemplateEngine' import App from './../../src/lib/App' import IApp from './../../src/lib/types/IApp' -import { APIGatewayEvent } from 'aws-lambda' import { stringify } from './../../src/lib/utils/utils' +import IRawEvent from "./../../src/lib/types/IRawEvent"; +import DefaultCallback from "./../utils/DefaultCallback"; +import httpEvent from "./../utils/httpEvent"; /** * Test for HttpResponse. @@ -22,70 +24,16 @@ import { stringify } from './../../src/lib/utils/utils' describe('HttpResponse', () => { let request: IHttpRequest let response: IHttpResponse - let event: APIGatewayEvent - let errResult - let succResult - let app: IApp + let event: IRawEvent; + let app: IApp; + let callback: DefaultCallback; + beforeEach(function(done) { app = new App() - errResult = undefined - succResult = undefined - event = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Accept': 'application/json,text/html', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' - } + event = Object.assign({}, httpEvent); request = new HttpRequest(event) - response = new HttpResponse(app, request, (err, succ) => { - errResult = err; - succResult = succ - }); + callback = new DefaultCallback(); + response = new HttpResponse(app, request, callback); done() }); @@ -93,7 +41,7 @@ describe('HttpResponse', () => { it('#status should set the outcoming response status code', () => { response.status(302) response.send('') - Chai.expect(succResult.statusCode).to.be.equal(302) + Chai.expect(callback.successResult.statusCode).to.be.equal(302) }); it('#statusCode should returns the outcoming response status code previously set', () => { @@ -104,78 +52,78 @@ describe('HttpResponse', () => { describe("#send", () => { it('should set the outcoming response body to the given string with "html" content type header and the right content length header', () => { response.send('ABC') - Chai.expect(succResult.headers['Content-Type']).to.be.equal('text/html; charset=utf-8') - Chai.expect(succResult.headers['Content-Length']).to.be.equal('3') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('text/html; charset=utf-8') + Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('3') Chai.expect(response.isSent).to.be.true }); it('should set the outcoming response body to the given number with no content type header and the right content length header', () => { response.send(false) - Chai.expect(succResult.headers['Content-Type']).to.be.undefined - Chai.expect(succResult.headers['Content-Length']).to.be.equal('5') - Chai.expect(succResult.body).to.be.equal('false') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined + Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('5') + Chai.expect(callback.successResult.body).to.be.equal('false') Chai.expect(response.isSent).to.be.true }); it('should set the outcoming response body to the given boolean with no content type header and the right content length header', () => { response.send(1) - Chai.expect(succResult.headers['Content-Type']).to.be.undefined - Chai.expect(succResult.headers['Content-Length']).to.be.equal('1') - Chai.expect(succResult.body).to.be.equal('1') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined + Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('1') + Chai.expect(callback.successResult.body).to.be.equal('1') Chai.expect(response.isSent).to.be.true }); it('should set the outcoming response body to the given Buffer with "bin" content type header and the right content length header', () => { response.send(new Buffer('test')) - Chai.expect(succResult.headers['Content-Type']).to.be.equal('bin') - Chai.expect(succResult.headers['Content-Length']).to.be.equal('4') - Chai.expect(succResult.body).to.be.equal('test') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('bin') + Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal('4') + Chai.expect(callback.successResult.body).to.be.equal('test') Chai.expect(response.isSent).to.be.true }); it('should set the outcoming response header ETag to the generated with the function in #app.get(Configuration.ETAG_FN)', () => { app.set(configuration.ETAG_FN, (buff, encoding) => 'ETAG' + buff.toString(encoding)) response.send('test') - Chai.expect(succResult.headers['ETag']).to.be.equal('ETAGtest') + Chai.expect(callback.successResult.headers['ETag']).to.be.equal('ETAGtest') }); it('should set the outcoming response status code to 304 if the response is not fresh', () => { app.set(configuration.ETAG_FN, (buff, encoding) => 'etagValue') response.putHeader('Last-Modified', '2017-10-10T10:10:09') response.send('test') - Chai.expect(succResult.statusCode).to.be.equal(304) + Chai.expect(callback.successResult.statusCode).to.be.equal(304) }); it('should not set the outcoming response irrelevant headers (Content-Type, Content-Length and Transfer-Encoding) and the body if the response status code is 204', () => { response.status(204) response.send('') - Chai.expect(succResult.headers['Content-Type']).to.be.undefined - Chai.expect(succResult.headers['Content-Length']).to.be.undefined - Chai.expect(succResult.headers['Transfer-Encoding']).to.be.undefined + Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined + Chai.expect(callback.successResult.headers['Content-Length']).to.be.undefined + Chai.expect(callback.successResult.headers['Transfer-Encoding']).to.be.undefined }); it('should not set the outcoming response irrelevant headers (Content-Type, Content-Length and Transfer-Encoding) and the body if the response status code is 304', () => { response.status(304) response.send('') - Chai.expect(succResult.headers['Content-Type']).to.be.undefined - Chai.expect(succResult.headers['Content-Length']).to.be.undefined - Chai.expect(succResult.headers['Transfer-Encoding']).to.be.undefined + Chai.expect(callback.successResult.headers['Content-Type']).to.be.undefined + Chai.expect(callback.successResult.headers['Content-Length']).to.be.undefined + Chai.expect(callback.successResult.headers['Transfer-Encoding']).to.be.undefined }); it('should set the outcoming response body to null if the request method is HEAD', () => { event.httpMethod = 'HEAD' response.send('test') - Chai.expect(succResult.body).to.be.undefined + Chai.expect(callback.successResult.body).to.be.undefined }); it("should set content type to bin if the sent body is a buffer and there is no previous set content type into the response.", () => { response.send(new Buffer(1)); - Chai.expect(succResult.headers["Content-Type"]).to.be.equal("bin"); + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("bin"); }); it("should no set the conent-length header.", () => { response.send(undefined); - Chai.expect(succResult.headers["Content-Length"]).to.be.undefined; + Chai.expect(callback.successResult.headers["Content-Length"]).to.be.undefined; }); it("should generate a etag and put it into the response header if there is a generator function configurated in the app.", () => { @@ -184,14 +132,14 @@ describe('HttpResponse', () => { }); response.send("test"); - Chai.expect(succResult.headers["ETag"]).to.be.equal("test-undefined"); + Chai.expect(callback.successResult.headers["ETag"]).to.be.equal("test-undefined"); }); it("should pass the error param to the callback function if an error is set.", () => { const err = new HttpError("Test error.", 500); response.setError(err); response.send(""); - Chai.expect(errResult).to.be.equal(err); + Chai.expect(callback.errorResult).to.be.equal(err); }); it("should pass the error param with the cause to the callback function if an error is set and it has a cause.", () => { @@ -199,41 +147,41 @@ describe('HttpResponse', () => { const err = new HttpError("Test error.", 500, cause); response.setError(err); response.send(""); - Chai.expect(errResult).to.be.equal(cause); + Chai.expect(callback.errorResult).to.be.equal(cause); }); }); describe("#json", () => { it('should set the outcoming response header Content-Type to "application/json"', () => { response.json({}) - Chai.expect(succResult.headers['Content-Type']).to.be.equal('application/json; charset=utf-8') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('application/json; charset=utf-8') }); it("should keep the previous set content type if exists.", () => { response.contentType("text/plain"); response.json({}) - Chai.expect(succResult.headers["Content-Type"]).to.be.equal("text/plain; charset=utf-8") + Chai.expect(callback.successResult.headers["Content-Type"]).to.be.equal("text/plain; charset=utf-8") }); it('should set the outcoming response header Content-Length to the right length', () => { const body = {test: 'test1'} const parsedBody = stringify(body, undefined, undefined, undefined) response.json(body) - Chai.expect(succResult.headers['Content-Length']).to.be.equal(parsedBody.length.toString()) - Chai.expect(succResult.body).to.be.equal(parsedBody) + Chai.expect(callback.successResult.headers['Content-Length']).to.be.equal(parsedBody.length.toString()) + Chai.expect(callback.successResult.body).to.be.equal(parsedBody) }); }); describe("#sendStatus", () => { it('should set the outcoming response header Content-Length to "txt", the body to the status code body and the satus code to the given status code', () => { response.sendStatus(404) - Chai.expect(succResult.headers['Content-Type']).to.be.equal('text/plain; charset=utf-8') - Chai.expect(succResult.body).to.be.equal('Not Found') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('text/plain; charset=utf-8') + Chai.expect(callback.successResult.body).to.be.equal('Not Found') }); it("should set the status code as response body if there is no message for it.", () => { response.sendStatus(1) - Chai.expect(succResult.body).to.be.equal("1"); + Chai.expect(callback.successResult.body).to.be.equal("1"); }); }); @@ -241,14 +189,14 @@ describe('HttpResponse', () => { const contentType = 'application/xml' response.contentType(contentType) response.send('test') - Chai.expect(succResult.headers['Content-Type']).to.be.equal('application/xml; charset=utf-8') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('application/xml; charset=utf-8') }); it('#contentType should set content type to the given one and transform it to a full mime type if it does not have /', () => { const contentType = 'xml' response.contentType(contentType) response.send('test') - Chai.expect(succResult.headers['Content-Type']).to.be.equal('application/xml; charset=utf-8') + Chai.expect(callback.successResult.headers['Content-Type']).to.be.equal('application/xml; charset=utf-8') }); it('#format should execute the first function which key (mime type) is accepted by the incoming request', () => { @@ -316,7 +264,7 @@ describe('HttpResponse', () => { it('#putHeader should set the header `field` to `value`', () => { response.putHeader('field', 'value'); response.send('test'); - Chai.expect(succResult.headers['field']).to.be.equal('value') + Chai.expect(callback.successResult.headers['field']).to.be.equal('value') }); it('#putHeaders should set each header of `obj`', () => { @@ -325,8 +273,8 @@ describe('HttpResponse', () => { 'field2': 'value2' }); response.send('test'); - Chai.expect(succResult.headers['field1']).to.be.equal('value1') - Chai.expect(succResult.headers['field2']).to.be.equal('value2') + Chai.expect(callback.successResult.headers['field1']).to.be.equal('value1') + Chai.expect(callback.successResult.headers['field2']).to.be.equal('value2') }); it('#header should return a previously set header', () => { @@ -437,52 +385,52 @@ describe('HttpResponse', () => { it("should set the header Location to the Referrer URL if it exists and the given URL is \"back\".", () => { request.headers["referrer"] = "/previous-url"; response.redirect("back"); - Chai.expect(succResult.headers["Location"]).to.be.equal("/previous-url"); + Chai.expect(callback.successResult.headers["Location"]).to.be.equal("/previous-url"); }); it("should set the header Location to / if the Referrer URL does not exist and the given URL is \"back\".", () => { response.redirect("back"); - Chai.expect(succResult.headers["Location"]).to.be.equal("/"); + Chai.expect(callback.successResult.headers["Location"]).to.be.equal("/"); }); }); describe("#redirect", () => { it('should set the header Location to the given URL and the status code to 302', () => { response.redirect('/test'); - Chai.expect(succResult.headers['Location']).to.be.equal('/test') - Chai.expect(succResult.statusCode).to.be.equal(302) + Chai.expect(callback.successResult.headers['Location']).to.be.equal('/test') + Chai.expect(callback.successResult.statusCode).to.be.equal(302) }); it('should set the header Location to the given URL and the status code to the given one', () => { response.redirect('/test', 301); - Chai.expect(succResult.headers['Location']).to.be.equal('/test') - Chai.expect(succResult.statusCode).to.be.equal(301) + Chai.expect(callback.successResult.headers['Location']).to.be.equal('/test') + Chai.expect(callback.successResult.statusCode).to.be.equal(301) }); it("should set the body to HTML text if the request accepts text/html.", () => { request.headers["accept"] = "text/html"; response.redirect("/test"); - Chai.expect(succResult.body).to.be.equal("

Found. Redirecting to /test

"); + Chai.expect(callback.successResult.body).to.be.equal("

Found. Redirecting to /test

"); }); it("should set the body to plain text if the request accepts text/plain.", () => { request.headers["accept"] = "text/plain"; response.redirect("/test"); - Chai.expect(succResult.body).to.be.equal("Found. Redirecting to /test."); + Chai.expect(callback.successResult.body).to.be.equal("Found. Redirecting to /test."); }); it("should set the body to empty string if the request doesn't accepts neither text/html nor text/plain.", () => { request.headers["accept"] = "application/json"; response.redirect("/test"); - Chai.expect(succResult.body).to.be.equal(""); + Chai.expect(callback.successResult.body).to.be.equal(""); }); it("should set the body to empty string, 200 status code, and no Location header if the request HTTP method is HEAD.", () => { - request.event.httpMethod = "HEAD"; + event.httpMethod = "HEAD"; response.redirect("/test"); - Chai.expect(succResult.body).to.be.undefined; - Chai.expect(succResult.headers["Location"]).to.be.equal("/test"); - Chai.expect(succResult.statusCode).to.be.equal(302); + Chai.expect(callback.successResult.body).to.be.undefined; + Chai.expect(callback.successResult.headers["Location"]).to.be.equal("/test"); + Chai.expect(callback.successResult.statusCode).to.be.equal(302); }); }); @@ -546,8 +494,8 @@ describe('HttpResponse', () => { const expectedResult: string = "Result of render."; renderStub.callsFake((view, params, callback) => callback(null, expectedResult)); response.render("fileName"); - Chai.expect(succResult.headers["Content-Type"]).to.contain("text/html"); - Chai.expect(succResult.body).to.be.equal(expectedResult); + Chai.expect(callback.successResult.headers["Content-Type"]).to.contain("text/html"); + Chai.expect(callback.successResult.body).to.be.equal(expectedResult); }); }); diff --git a/test/http/HttpRoute.spec.ts b/test/http/HttpRoute.spec.ts index 2758271..43ea13f 100644 --- a/test/http/HttpRoute.spec.ts +++ b/test/http/HttpRoute.spec.ts @@ -9,60 +9,11 @@ import HttpRequest from './../../src/lib/http/HttpRequest' import IHttpRequest from './../../src/lib/types/http/IHttpRequest' import HttpResponse from './../../src/lib/http/HttpResponse' import IHttpResponse from './../../src/lib/types/http/IHttpResponse' +import IRawEvent from './../../src/lib/types/IRawEvent' import IRouter from './../../src/lib/types/IRouter' import Router from './../../src/lib/Router' - -const event = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Accept': 'application/json', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' -} +import DefaultCallback from "./../utils/DefaultCallback"; +import httpEvent from "./../utils/httpEvent"; /** * Test for HttpRoute. @@ -72,13 +23,17 @@ describe('HttpRoute', () => { const router: IRouter = new Router let layer: IHttpLayer, route: IHttpRoute let req: IHttpRequest, res: IHttpResponse + let event: IRawEvent; + let callback: DefaultCallback; beforeEach(() => { + event = Object.assign({}, httpEvent); + callback = new DefaultCallback(); layer = new HttpLayer(router, '/blog/:id', {}) route = new HttpRoute(layer) layer.route = route - req = new HttpRequest(Object.assign({}, event)) - res = new HttpResponse(app, req, (error, success) => {}) + req = new HttpRequest(event) + res = new HttpResponse(app, req, callback); }) @@ -142,7 +97,7 @@ describe('HttpRoute', () => { route.get((req, res, next) => { done(); }); - req.event.httpMethod = "GET"; + event.httpMethod = "GET"; route.dispatch(req, res, null); }); }); @@ -152,7 +107,7 @@ describe('HttpRoute', () => { route.post((req, res, next) => { done(); }); - req.event.httpMethod = "POST"; + event.httpMethod = "POST"; route.dispatch(req, res, null); }); }); @@ -162,7 +117,7 @@ describe('HttpRoute', () => { route.put((req, res, next) => { done(); }); - req.event.httpMethod = "PUT"; + event.httpMethod = "PUT"; route.dispatch(req, res, null); }); }); @@ -172,7 +127,7 @@ describe('HttpRoute', () => { route.delete((req, res, next) => { done(); }); - req.event.httpMethod = "DELETE"; + event.httpMethod = "DELETE"; route.dispatch(req, res, null); }); }); diff --git a/test/http/HttpRouterExecutor.spec.ts b/test/http/HttpRouterExecutor.spec.ts index ebf29a9..6a5fd46 100644 --- a/test/http/HttpRouterExecutor.spec.ts +++ b/test/http/HttpRouterExecutor.spec.ts @@ -9,73 +9,21 @@ import HttpResponse from './../../src/lib/http/HttpResponse' import IHttpResponse from './../../src/lib/types/http/IHttpResponse' import Router from './../../src/lib/Router' import IRouter from './../../src/lib/types/IRouter' - -const event = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Accept': 'application/json', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' -} +import DefaultCallback from "./../utils/DefaultCallback"; +import httpEvent from "./../utils/httpEvent"; /** * Test for HttpRouterExecutor. */ describe('HttpRouterExecutor', () => { const app: IApp = new App - let req: IHttpRequest, res: IHttpResponse, router: IRouter - let callbackErrorResult, callBackSuccessResult + let req: IHttpRequest, res: IHttpResponse, router: IRouter; + let callback: DefaultCallback; beforeEach(() => { - req = new HttpRequest(event) - res = new HttpResponse(app, req, (error, success) => { - callbackErrorResult = error - callBackSuccessResult = success - }) + callback = new DefaultCallback(); + req = new HttpRequest(Object.assign({}, httpEvent)); + res = new HttpResponse(app, req, callback); router = new Router }) diff --git a/test/http/bodyParsers/JsonParser.spec.ts b/test/http/bodyParsers/JsonParser.spec.ts index 415fc08..b2568ac 100644 --- a/test/http/bodyParsers/JsonParser.spec.ts +++ b/test/http/bodyParsers/JsonParser.spec.ts @@ -1,22 +1,12 @@ import * as Chai from "chai"; import { spy, SinonSpy } from "sinon"; +import httpEvent from "./../../utils/httpEvent"; import JsonParser from "./../../../src/lib/http/bodyParsers/JsonParser"; import HttpRequest from "./../../../src/lib/http/HttpRequest"; import IHttpHandler from "./../../../src/lib/types/http/IHttpHandler"; import IHttpRequest from "./../../../src/lib/types/http/IHttpRequest"; import IHttpResponse from "./../../../src/lib/types/http/IHttpResponse"; -const mainEvent: any = { - body: "{\"param1\": \"value1\"}", - headers: { - "Content-Type": "application/json" - }, - httpMethod: "POST", - isBase64Encoded: true, - path: "/blog", - resource: "API" -}; - /** * Test for JsonParser. */ @@ -27,8 +17,11 @@ describe("JsonParser", () => { const handler: IHttpHandler = (new JsonParser()).create(); beforeEach(() => { - event = Object.assign({}, mainEvent); - event.headers = Object.assign({}, mainEvent.headers); + event = Object.assign({}, httpEvent); + event.httpMethod = "POST"; + event.headers = Object.assign({}, httpEvent.headers); + event.headers["Content-Type"] = "application/json"; + event.body = "{\"param1\": \"value1\"}"; next = spy(); }); diff --git a/test/http/httpFinalHandler.spec.ts b/test/http/httpFinalHandler.spec.ts index aa0a466..ad688a6 100644 --- a/test/http/httpFinalHandler.spec.ts +++ b/test/http/httpFinalHandler.spec.ts @@ -7,58 +7,9 @@ import HttpResponse from './../../src/lib/http/HttpResponse' import IHttpResponse from './../../src/lib/types/http/IHttpResponse' import httpFinalHandler from './../../src/lib/http/httpFinalHandler' import HttpError from './../../src/lib/exceptions/HttpError' - -const event = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Accept': 'application/json', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' -} +import DefaultCallback from "./../utils/DefaultCallback"; +import httpEvent from "./../utils/httpEvent"; +import IRawEvent from "./../../src/lib/types/IRawEvent"; /** * Test for httpFinalHandler. @@ -67,33 +18,34 @@ describe('httpFinalHandler', () => { const app: IApp = new App let req: IHttpRequest let res: IHttpResponse - let callbackErrorResult, callBackSuccessResult + let callback: DefaultCallback; + let event: IRawEvent; beforeEach(() => { - req = new HttpRequest(Object.assign({}, event)) - res = new HttpResponse(app, req, (error, success) => { - callbackErrorResult = error - callBackSuccessResult = success - }) + callback = new DefaultCallback(); + event = Object.assign({}, httpEvent); + event.headers['Accept'] ='application/json'; + req = new HttpRequest(Object.assign({}, event)); + res = new HttpResponse(app, req, callback); }); it('should send a response with the headers: Content-Security-Policy, X-Content-Type-Options, Content-Type and Content-Length.', () => { const handler = httpFinalHandler(req, res, {}) handler() - Chai.expect(callBackSuccessResult.headers['Content-Security-Policy']).to.be.not.empty - Chai.expect(callBackSuccessResult.headers['X-Content-Type-Options']).to.be.not.empty - Chai.expect(callBackSuccessResult.headers['Content-Type']).to.be.not.empty - Chai.expect(callBackSuccessResult.headers['Content-Length']).to.be.not.empty + Chai.expect(callback.successResult.headers['Content-Security-Policy']).to.be.not.empty + Chai.expect(callback.successResult.headers['X-Content-Type-Options']).to.be.not.empty + Chai.expect(callback.successResult.headers['Content-Type']).to.be.not.empty + Chai.expect(callback.successResult.headers['Content-Length']).to.be.not.empty }); it('should not send a response if a response is prevously sent.', () => { res.send('') - Chai.expect(callBackSuccessResult).to.be.not.undefined - callBackSuccessResult = null + Chai.expect(callback.successResult).to.be.not.undefined + callback.successResult.body = null const handler = httpFinalHandler(req, res, {}) handler() - Chai.expect(callBackSuccessResult).to.be.null + Chai.expect(callback.successResult.body).to.be.null }); it('should call #onerror handler if it is set in the #options.', (done) => { @@ -108,9 +60,10 @@ describe('httpFinalHandler', () => { it('should set the response status code as 404 and acording message if #err is undefined.', () => { const handler = httpFinalHandler(req, res, {}) handler() - Chai.expect(callBackSuccessResult.statusCode).to.be.equals(404) - Chai.expect(JSON.parse(callBackSuccessResult.body).message).to.be.equals('Cannot GET /blog/1') - Chai.expect(JSON.parse(callBackSuccessResult.body).error).to.be.equals(404) + Chai.expect(callback.successResult.statusCode).to.be.equals(404) + console.log(callback.successResult.body) + Chai.expect(JSON.parse(callback.successResult.body).message).to.be.equals('Cannot GET /blog/1') + Chai.expect(JSON.parse(callback.successResult.body).error).to.be.equals(404) }); it('should set the response status code, headers and body from #err if it is not undefined.', () => { @@ -118,38 +71,36 @@ describe('httpFinalHandler', () => { const error = new HttpError('Test msg', 403) error.headers = {errorHeader: 'test'} handler(error) - Chai.expect(callBackSuccessResult.statusCode).to.be.equals(403) - Chai.expect(JSON.parse(callBackSuccessResult.body).message).to.be.equals('Test msg') - Chai.expect(JSON.parse(callBackSuccessResult.body).error).to.be.equals(403) - Chai.expect(callBackSuccessResult.headers.errorHeader).to.be.equals('test') + Chai.expect(callback.successResult.statusCode).to.be.equals(403) + Chai.expect(JSON.parse(callback.successResult.body).message).to.be.equals('Test msg') + Chai.expect(JSON.parse(callback.successResult.body).error).to.be.equals(403) + Chai.expect(callback.successResult.headers.errorHeader).to.be.equals('test') }); it('should send a HTML response and HTML as content type if the request accepts HTML.', () => { - const newEvent = Object.assign({}, event) - newEvent.headers = Object.assign({}, event.headers) - newEvent.headers['Accept'] = 'application/json,text/html' - const req = new HttpRequest(newEvent) + event.headers = Object.assign({}, event.headers) + event.headers['Accept'] ='application/json,text/html' + const req = new HttpRequest(event) const handler = httpFinalHandler(req, res, {}) handler() - Chai.expect(callBackSuccessResult.body).to.contain('') + Chai.expect(callback.successResult.body).to.contain('') }); it('should send a JSON response and JSON as content type if the request accepts JSON and it does not accept HTML.', () => { const handler = httpFinalHandler(req, res, {}) handler() - Chai.expect(JSON.parse(callBackSuccessResult.body)).to.be.a('object') + Chai.expect(JSON.parse(callback.successResult.body)).to.be.a('object') }); it('should send a PLAIN response and PLAIN as content type if the request does not accept JSON neither HTML.', () => { - const newEvent = Object.assign({}, event) - newEvent.headers = Object.assign({}, event.headers) - newEvent.headers['Accept'] = 'application/pdf' - const req = new HttpRequest(newEvent) + event.headers = Object.assign({}, event.headers) + event.headers['Accept'] = 'application/pdf' + const req = new HttpRequest(event) const handler = httpFinalHandler(req, res, {}) handler() - Chai.expect(callBackSuccessResult.body).to.be.equals('Cannot GET /blog/1') + Chai.expect(callback.successResult.body).to.be.equals('Cannot GET /blog/1') }); it("should set status code from res if it is higher than 400, lower than 600 and the error is not of type HttpError.", () => { @@ -157,7 +108,7 @@ describe('httpFinalHandler', () => { res.status(404); const error = new Error("No HTTP error."); handler(error) - Chai.expect(callBackSuccessResult.statusCode).to.be.equals(404); + Chai.expect(callback.successResult.statusCode).to.be.equals(404); }); it("should set status code 500 if the res status code is lower than 400 or higher than 600 and the error is not of type HttpError.", () => { @@ -165,14 +116,14 @@ describe('httpFinalHandler', () => { res.status(300); const error = new Error("No HTTP error."); handler(error) - Chai.expect(callBackSuccessResult.statusCode).to.be.equals(500); + Chai.expect(callback.successResult.statusCode).to.be.equals(500); }); it("should set status code 500 if the status code of HttpError is not set.", () => { const handler = httpFinalHandler(req, res, {}) const error = new HttpError("HTTP error.", null); handler(error) - Chai.expect(callBackSuccessResult.statusCode).to.be.equals(500); + Chai.expect(callback.successResult.statusCode).to.be.equals(500); }); }); diff --git a/test/http/renderEngine/DefaultTemplateLoader.spec.ts b/test/http/renderEngine/DefaultTemplateLoader.spec.ts deleted file mode 100644 index 97a228d..0000000 --- a/test/http/renderEngine/DefaultTemplateLoader.spec.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as S3 from "aws-sdk/clients/s3"; -import * as Chai from "chai"; -import * as NodeCache from "node-cache"; -import { stub, SinonStub } from "sinon"; -import DefaultTemplateLoader from "./../../../src/lib/http/renderEngine/DefaultTemplateLoader"; -import Template from "./../../../src/lib/http/renderEngine/Template"; -import ITemplate from "./../../../src/lib/types/http/renderEngine/ITemplate"; -import ITemplateLoader from "./../../../src/lib/types/http/renderEngine/ITemplateLoader"; - -/** - * Test for DefaultTemplateLoader. - */ -describe("DefaultTemplateLoader", () => { - const getCacheStub = stub(NodeCache.prototype, "get"); - const getObjectStub = stub(S3.prototype, "makeRequest").withArgs("getObject"); - const loader: ITemplateLoader = new DefaultTemplateLoader("bucket", 30000); - - afterEach(() => { - getObjectStub.reset(); - getCacheStub.reset(); - }); - - describe("load", () => { - it("should load from cache the template if has been previously loaded and run the callback with the cached content.", (done) => { - getCacheStub.callsFake((key: string, callback) => { - callback(null, new Template("prueba.pug", "Cached content.")); - }); - loader.load("prueba.pug", (err: Error, template: ITemplate) => { - Chai.expect(getCacheStub.calledOnce).to.be.true; - Chai.expect(getObjectStub.calledOnce).to.be.false; - Chai.expect(template.fileName).to.be.equal("prueba.pug"); - Chai.expect(template.content).to.be.equal("Cached content."); - done(); - }); - }); - - it("should call the `callback` with an error if an error happens getting the template from the cache.", (done) => { - const returnedError: Error = new Error("Test error."); - getCacheStub.callsFake((key: string, callback) => { - callback(returnedError, null); - }); - loader.load("prueba.pug", (err: Error, template: ITemplate) => { - Chai.expect(err).to.be.equal(returnedError); - done(); - }); - }); - - it("should load from S3 if the cache is not defined and run the callback with the content.", (done) => { - const loader: ITemplateLoader = new DefaultTemplateLoader("bucket", null); - getObjectStub.callsFake((operation: string, params?: {[key: string]: any}, callback?: (err: Error, data: any) => void) => { - callback(null, { - Body: "Test content." - }); - }); - loader.load("prueba.pug", (err: Error, template: ITemplate) => { - Chai.expect(getObjectStub.called).to.be.true; - Chai.expect(template.fileName).to.be.equal("prueba.pug"); - Chai.expect(template.content).to.be.equal("Test content."); - done(); - }); - }); - - it("should load from S3 if the template has not been previously loaded.", (done) => { - getObjectStub.callsFake((operation: string, params?: {[key: string]: any}, callback?: (err: Error, data: any) => void) => { - callback(null, { - Body: "Test content." - }); - }); - getCacheStub.callsFake((key: string, callback) => { - callback(null, undefined); - }); - loader.load("prueba.pug", (err: Error, template: ITemplate) => { - Chai.expect(getCacheStub.called).to.be.true; - Chai.expect(getObjectStub.called).to.be.true; - Chai.expect(template.fileName).to.be.equal("prueba.pug"); - Chai.expect(template.content).to.be.equal("Test content."); - done(); - }); - }); - - it("should call the `callback` with an error if an error happens getting the template from S3.", (done) => { - const returnedError: Error = new Error("Test error."); - getObjectStub.callsFake((operation: string, params?: {[key: string]: any}, callback?: (err: Error, data: any) => void) => { - callback(returnedError, null); - }); - getCacheStub.callsFake((key: string, callback) => { - callback(null, undefined); - }); - loader.load("prueba.pug", (err: Error, template: ITemplate) => { - Chai.expect(err).to.be.equal(returnedError); - done(); - }); - }); - }); - -}); diff --git a/test/http/renderEngine/TemplateEngine.spec.ts b/test/http/renderEngine/TemplateEngine.spec.ts index 2d0175e..8fdabcc 100644 --- a/test/http/renderEngine/TemplateEngine.spec.ts +++ b/test/http/renderEngine/TemplateEngine.spec.ts @@ -1,6 +1,5 @@ import * as Chai from "chai"; import { SinonStub, stub } from "sinon"; -import DefaultTemplateLoader from "./../../../src/lib/http/renderEngine/DefaultTemplateLoader"; import Template from "./../../../src/lib/http/renderEngine/Template"; import TemplateEngine from "./../../../src/lib/http/renderEngine/TemplateEngine"; import ITemplate from "./../../../src/lib/types/http/renderEngine/ITemplate"; diff --git a/test/router.spec.ts b/test/router.spec.ts index 72b1990..934c519 100644 --- a/test/router.spec.ts +++ b/test/router.spec.ts @@ -9,97 +9,9 @@ import HttpResponse from './../src/lib/http/HttpResponse' import IHttpResponse from './../src/lib/types/http/IHttpResponse' import App from './../src/lib/App' import IApp from './../src/lib/types/IApp' - -const httpEvent = { - body: 'BODY', - headers: { - header1: 'HEADER VALUE 1', - header2: 'HEADER VALU 2', - 'X-Forwarded-Proto': 'https', - 'Host': 'localhost', - 'Accept': 'application/json', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Charset': 'UTF-8, ISO-8859-1', - 'Accept-Language': 'es,en', - 'If-None-Match': 'etagValue', - 'If-Modified-Since': '2017-10-10T10:10:10' - }, - httpMethod: 'GET', - isBase64Encoded: true, - path: '/blog/1', - pathParameters: { - param1: 'Param 1' - }, - queryStringParameters: { - query1: 'Query 1' - }, - stageVariables: { - stage1: 'Stage 1' - }, - requestContext: { - accountId: 'A1', - apiId: 'API1', - httpMethod: 'GET', - identity: { - accessKey: 'ABCD', - accountId: 'AAA', - apiKey: 'BBB', - caller: 'caller', - cognitoAuthenticationProvider: 'facebook', - cognitoAuthenticationType: 'authtype', - cognitoIdentityId: 'IID', - cognitoIdentityPoolId: 'PID', - sourceIp: '197.0.0.0', - user: 'user', - userAgent: 'Chrome', - userArn: 'ARN' - }, - stage: 'test', - requestId: 'RQID', - resourceId: 'RSID', - resourcePath: '/blog/1' - }, - resource: 'API' -} - -const s3Event = { - "Records": [ - { - "eventVersion": "2.0", - "eventTime": "1970-01-01T00:00:00.000Z", - "requestParameters": { - "sourceIPAddress": "127.0.0.1" - }, - "s3": { - "configurationId": "testConfigRule", - "object": { - "eTag": "0123456789abcdef0123456789abcdef", - "sequencer": "0A1B2C3D4E5F678901", - "key": "test/key", - "size": 1024 - }, - "bucket": { - "arn": "arn:aws:s3:::example-bucket", - "name": "example-bucket", - "ownerIdentity": { - "principalId": "EXAMPLE" - } - }, - "s3SchemaVersion": "1.0" - }, - "responseElements": { - "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", - "x-amz-request-id": "EXAMPLE123456789" - }, - "awsRegion": "us-east-1", - "eventName": "ObjectCreated:Put", - "userIdentity": { - "principalId": "EXAMPLE" - }, - "eventSource": "aws:s3" - } - ] -} +import httpEvent from "./utils/httpEvent"; +import otherEvent from "./utils/otherEvent"; +import DefaultCallback from "./utils/DefaultCallback"; /** * Test for Router. @@ -108,20 +20,14 @@ describe('Router', () => { const app: IApp = new App let router: IRouter, eventReq: IEventRequest let httpReq: IHttpRequest, res: IHttpResponse - let callbackErrorResult, callBackSuccessResult, doCallback: Function + let callback: DefaultCallback; beforeEach(() => { - doCallback = undefined + callback = new DefaultCallback(); router = new Router - eventReq = new EventRequest(s3Event) + eventReq = new EventRequest(otherEvent) httpReq = new HttpRequest(httpEvent) - res = new HttpResponse(app, httpReq, (error, success) => { - callbackErrorResult = error - callBackSuccessResult = success - if(doCallback) { - doCallback() - } - }) + res = new HttpResponse(app, httpReq, callback) }) describe('#fullSubpath', () => { @@ -164,10 +70,10 @@ describe('Router', () => { router.route('/blog/:id').get((req, res) => {}) router.route('/blog/:id').post((req, res) => {}) - doCallback = () => { - Chai.expect(callBackSuccessResult.headers['Allow']).to.be.equals('GET,POST') + callback.setCallback(() => { + Chai.expect(callback.successResult.headers['Allow']).to.be.equals('GET,POST') done() - } + }); router.httpHandle(req, res, () => {}) }); diff --git a/test/utils/DefaultCallback.ts b/test/utils/DefaultCallback.ts new file mode 100644 index 0000000..5aa568e --- /dev/null +++ b/test/utils/DefaultCallback.ts @@ -0,0 +1,34 @@ +import IRawCallback from "./../../src/lib/types/IRawCallback"; + +export default class DefaultCallback implements IRawCallback { + + private _errorResult: Error; + + private _successResult: {[name: string]: any}; + + private _callback: () => void; + + get errorResult(): Error { + return this._errorResult; + } + + get successResult(): {[name: string]: any} { + return this._successResult; + } + + sendError(error: Error): void { + this._errorResult = error; + } + + send(statusCode: number, headers: {[name: string]: string|string[]}, body: object|Buffer): void { + this._successResult = {statusCode, headers, body}; + if(this._callback) { + this._callback() + } + } + + setCallback(callback: () => void) { + this._callback = callback; + } + +} diff --git a/test/utils/httpEvent.ts b/test/utils/httpEvent.ts new file mode 100644 index 0000000..1937915 --- /dev/null +++ b/test/utils/httpEvent.ts @@ -0,0 +1,31 @@ +import RawEvent from "./../../src/lib/RawEvent"; +import IRawEvent from "./../../src/lib/types/IRawEvent"; + +const httpEvent: IRawEvent = new RawEvent(); +httpEvent.type = "APIGatewayEvent"; +httpEvent.original = {}; +httpEvent.isHttp = true; +httpEvent.headers = { + header1: "HEADER VALUE 1", + header2: "HEADER VALU 2", + "X-Forwarded-Proto": "https", + "Host": "localhost", + "Content-Type": "application/json,text/html", + "Accept": "application/json,text/html", + "Accept-Encoding": "gzip, deflate", + "Accept-Charset": "UTF-8, ISO-8859-1", + "Accept-Language": "es,en", + "If-None-Match": "etagValue", + "If-Modified-Since": "2017-10-10T10:10:10" +}; +httpEvent.queryParams = { + query1: "Query 1" +}; +httpEvent.stageVariables = { + stage1: "Stage 1" +}; +httpEvent.ip = "197.0.0.0"; +httpEvent.path = "/blog/1"; +httpEvent.httpMethod = "GET"; + +export default httpEvent; diff --git a/test/utils/otherEvent.ts b/test/utils/otherEvent.ts new file mode 100644 index 0000000..e7d15b2 --- /dev/null +++ b/test/utils/otherEvent.ts @@ -0,0 +1,46 @@ +import RawEvent from "./../../src/lib/RawEvent"; +import IRawEvent from "./../../src/lib/types/IRawEvent"; + +const otherEvent: IRawEvent = new RawEvent(); +otherEvent.type = "S3CreateEvent"; +otherEvent.original = { + "Records": [ + { + "eventVersion": "2.0", + "eventTime": "1970-01-01T00:00:00.000Z", + "requestParameters": { + "sourceIPAddress": "127.0.0.1" + }, + "s3": { + "configurationId": "testConfigRule", + "object": { + "eTag": "0123456789abcdef0123456789abcdef", + "sequencer": "0A1B2C3D4E5F678901", + "key": "test/key", + "size": 1024 + }, + "bucket": { + "arn": "arn:aws:s3:::example-bucket", + "name": "example-bucket", + "ownerIdentity": { + "principalId": "EXAMPLE" + } + }, + "s3SchemaVersion": "1.0" + }, + "responseElements": { + "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", + "x-amz-request-id": "EXAMPLE123456789" + }, + "awsRegion": "us-east-1", + "eventName": "ObjectCreated:Put", + "userIdentity": { + "principalId": "EXAMPLE" + }, + "eventSource": "aws:s3" + } + ] +}; +otherEvent.isHttp = false; + +export default otherEvent;