diff --git a/.gitignore b/.gitignore index b846825..060419f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,20 @@ - +config/*.xml + !config/config.xml + *.iml + .idea + ui/ + automated-perf-test + uiServices/test/*.xml *.bak main .idea ui/ **/node_modules -/.editorconfig \ No newline at end of file +/.editorconfig +config/*.xml +!config/config.xml +*.iml +.idea +ui/ +automated-perf-test +uiServices/test/*.xml \ No newline at end of file diff --git a/automated-perf-test.iml b/automated-perf-test.iml deleted file mode 100644 index 21e3f24..0000000 --- a/automated-perf-test.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/main.go b/main.go index 9ee0a3a..b94a697 100644 --- a/main.go +++ b/main.go @@ -5,14 +5,15 @@ import ( "encoding/xml" "flag" "fmt" - log "github.com/Sirupsen/logrus" - "github.com/xtracdev/automated-perf-test/perfTestUtils" - "github.com/xtracdev/automated-perf-test/testStrategies" - "github.com/xtracdev/automated-perf-test/uiServices/src" "io/ioutil" "net/http" "os" "time" + + log "github.com/Sirupsen/logrus" + "github.com/xtracdev/automated-perf-test/perfTestUtils" + "github.com/xtracdev/automated-perf-test/testStrategies" + "github.com/xtracdev/automated-perf-test/uiServices/src" ) //----- Globals ------------------------------------------------------------------ @@ -147,7 +148,7 @@ func initConfig(args []string, fs perfTestUtils.FileSystem, exit func(code int)) // Start server for the User Interface Mode if uiMode { - services.StartUiMode() + services.StartUIMode() } setLogLevel(boolVerbose, boolDebug) diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 48e341a..0000000 --- a/package-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lockfileVersion": 1 -} diff --git a/testStrategies/commonToAllTestStrategies.go b/testStrategies/commonToAllTestStrategies.go index 6156e39..89392f5 100644 --- a/testStrategies/commonToAllTestStrategies.go +++ b/testStrategies/commonToAllTestStrategies.go @@ -50,23 +50,23 @@ type ResponseValue struct { // TestDefinition encapsulates the XML data. type TestDefinition struct { - XMLName xml.Name `xml:"testDefinition" json:"testDefinition"` - TestName string `xml:"testName" json:"testName"` - OverrideHost string `xml:"overrideHost" json:"overrideHost"` - OverridePort string `xml:"overridePort" json:"overridePort"` - HTTPMethod string `xml:"httpMethod" json:"httpMethod"` - Description string `xml:"description" json:"description"` - BaseURI string `xml:"baseUri" json:"baseUri"` - Multipart bool `xml:"multipart" json:"multipart"` - Payload string `xml:"payload" json:"payload"` - MultipartPayload []multipartFormField `xml:"multipartPayload>multipartFormField" json:"multipartPayload"` - ResponseStatusCode int `xml:"responseStatusCode" json:"responseStatusCode"` - ResponseContentType string `xml:"responseContentType" json:"responseContentType"` - Headers []Header `xml:"headers>header" json:"headers"` - ResponseValues []ResponseValue `xml:"responseProperties>value" json:"responseValues"` - PreThinkTime int64 - PostThinkTime int64 - ExecWeight string + XMLName xml.Name `xml:"testDefinition"` + TestName string `xml:"testName"` + OverrideHost string `xml:"overrideHost"` + OverridePort string `xml:"overridePort"` + HTTPMethod string `xml:"httpMethod"` + Description string `xml:"description"` + BaseURI string `xml:"baseUri"` + Multipart bool `xml:"multipart"` + Payload string `xml:"payload"` + MultipartPayload []multipartFormField `xml:"multipartPayload>multipartFormField"` + ResponseStatusCode int `xml:"responseStatusCode"` + ResponseContentType string `xml:"responseContentType"` + Headers []Header `xml:"headers>header"` + ResponseValues []ResponseValue `xml:"responseProperties>value"` + PreThinkTime int64 `xml:"preThinkTime"` + PostThinkTime int64 `xml:"postThinkTime"` + ExecWeight string `xml:"execWeight"` } // TestSuite fields get populated from the TestSuiteDefinition after the XML @@ -75,8 +75,8 @@ type TestSuite struct { XMLName xml.Name `xml:"testSuite"` Name string `xml:"name" json:"name"` Description string `xml:"description" json:"description"` - TestStrategy string `xml:"testStrategy" json:"testStrategy"` - TestCases []TestCase `xml:"testCases>testCase" json:"testCases"` + TestStrategy string `xml:"testStrategy"` + TestCases []TestCase `xml:"testCases>testCase"` TestDefinitions []*TestDefinition } @@ -84,8 +84,9 @@ type TestSuite struct { // XML file. This data will then be consolidated into // the TestSuite/TestDefinition data structure for usage. type TestCase struct { - XMLName xml.Name `xml:"testCase" json:"testCase"` + XMLName xml.Name `xml:"testCase"` Name string `xml:",chardata"` + Description string `xml:"description,attr" json:"description"` PreThinkTime int64 `xml:"preThinkTime,attr" json:"preThinkTime"` PostThinkTime int64 `xml:"postThinkTime,attr" json:"postThinkTime"` ExecWeight string `xml:"execWeight,attr" json:"execWeight"` diff --git a/ui-src/e2e/components/configurationComponent.e2e-spec.ts b/ui-src/e2e/components/configurationComponent.e2e-spec.ts index 3e970ca..4f93611 100644 --- a/ui-src/e2e/components/configurationComponent.e2e-spec.ts +++ b/ui-src/e2e/components/configurationComponent.e2e-spec.ts @@ -1,3 +1,4 @@ + import { browser, element, @@ -36,11 +37,6 @@ describe("configuration component", () => { ); }); - it("should show submit button is disabled when requiredFields data is blank", () => { - // used to clear default data in this test - configPO.checkRequiredFields(); - expect(configPO.submitBtn.isEnabled()).toBe(false); - }); it("should check that all text box names are correct", () => { configPO.setConfigData(); @@ -65,7 +61,7 @@ describe("configuration component", () => { it("should check values of existing file are as expected", () => { configPO.configFilePath.sendKeys(configPO.absolutePath); - configPO.xmlFileName.sendKeys("config.xml"); + configPO.xmlFileName.sendKeys("config"); configPO.cancelBtn.click(); expect(configPO.applicationName.getAttribute("value")).toEqual("config"); expect(configPO.targetHost.getAttribute("value")).toEqual("localhost"); @@ -85,9 +81,10 @@ describe("configuration component", () => { expect(configPO.requestDelay.getAttribute("value")).toEqual("5000"); expect(configPO.tpsFreq.getAttribute("value")).toEqual("30"); expect(configPO.rampDelay.getAttribute("value")).toEqual("15"); - expect(configPO.rampUsers.getAttribute("value")).toEqual("5"); + expect(configPO.rampUsers.getAttribute("value")).toEqual("15"); }); + it("should throw error when file path does not exist", () => { configPO.setConfigData(); configPO.configFilePath.sendKeys("/path/to/bad/location"); @@ -228,18 +225,16 @@ describe("configuration component", () => { it("should update existing file", () => { configPO.configFilePath.sendKeys(configPO.absolutePath); - configPO.xmlFileName.sendKeys("config.xml"); + configPO.xmlFileName.sendKeys("config"); configPO.cancelBtn.click(); configPO.numIterations.sendKeys(5); configPO.btnUpdate.click(); configPO.numIterations.sendKeys(Key.BACK_SPACE); configPO.cancelBtn.click(); - configPO.getConfigFileBtn.click(); - expect(configPO.numIterations.getAttribute("value")).toEqual("10005"); }); it("should show update button is disabled when Xml File Name is blank", () => { - expect(configPO.btnUpdate.isEnabled()).toBe(false); + expect(configPO.btnUpdate.isPresent()).toBe(false); }); }); diff --git a/ui-src/e2e/pages/configuration-PO.ts b/ui-src/e2e/pages/configuration-PO.ts index b6ba8d4..816c9ad 100644 --- a/ui-src/e2e/pages/configuration-PO.ts +++ b/ui-src/e2e/pages/configuration-PO.ts @@ -14,14 +14,14 @@ const configFileLocation = "../../../config/"; class ConfigurationPageObject { configFilePath = element(by.id("config-file-path")); - btnUpdate = element(by.id("update-config-file-btn")); + btnUpdate = element(by.id("btn-update")); xmlFileName = element(by.id("xml-file-name")); applicationName = element(by.name("apiName")); targetHost = element(by.name("targetHost")); targetPort = element(by.name("targetPort")); memoryEndpoint = element(by.name("memoryEndpoint")); - submitBtn = element(by.className("btn")); - cancelBtn = element(by.id("cancel-btn")); + submitBtn = element(by.id("btn-create")); + cancelBtn = element(by.id("btn-cancel")); numIterations = element(by.name("numIterations")); concurrentUsers = element(by.name("concurrentUsers")); diff --git a/ui-src/package-lock.json b/ui-src/package-lock.json index 86845b9..12477bc 100644 --- a/ui-src/package-lock.json +++ b/ui-src/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@angular-devkit/build-optimizer": { - "version": "0.0.42", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.42.tgz", - "integrity": "sha512-BAYCVZ10ro6mgZQDZiNiVbX8ppygw4q7z/stpwG8WjMswgMRIcxsxYoC1VFuWcUPAf4UyfTIav6e8UZWA5+xnQ==", + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.36.tgz", + "integrity": "sha512-EFFF7hBbVoTOzYfXuSlGhcDr8neafmwuBAIkzAekEjzik7OaTLq7LPG7As+ebed9ll+3DAGypnrpdIE1Tp/H/A==", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -25,9 +25,9 @@ } }, "@angular-devkit/core": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.4.0.tgz", - "integrity": "sha512-SM6iC7GyAmFrAwQzNTmZbZZNPSHgPgpPb7k1zXUfJABZ/LfYx5HHiUk+2sWTMGNIQ00+AcNa0vrx6qF900E3XA==", + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.0.29.tgz", + "integrity": "sha512-jtUBA0pIrkdXcVqDmDrGlniqwM7NFOKdo7vWFDmCVLBbC9rZHeYW5Xv/+4HyBhGLJ4wxsAkUjsHKWGJINPPpiw==", "requires": { "ajv": "5.5.2", "chokidar": "1.7.0", @@ -36,12 +36,14 @@ } }, "@angular-devkit/schematics": { - "version": "0.0.52", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.52.tgz", - "integrity": "sha512-NtG8VB5aWtg0cw1Y7EJinJMuAnXsNdkQkkVe/i7CO6TPLyFQSFQCN1YojCr43l8jTWTRebRslrBawPCMOxsOgw==", + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.42.tgz", + "integrity": "sha512-elTiNL0Nx9oin2pfZTvMBU/d9sgutXaZe8n3xm2p7jfqQZry5MYYFES4hq+WIJjtV/X9gAniafncEpxuF7ikYw==", "dev": true, "requires": { "@ngtools/json-schema": "1.1.0", + "@schematics/schematics": "0.0.11", + "minimist": "1.2.0", "rxjs": "5.5.6" } }, @@ -67,18 +69,18 @@ "integrity": "sha512-At0/Q8CsldsvekOmAnYF8g7BAf0aHJImPLstxzPeWdg7EZbQxwCH0I+ZSZFHL43f8md6n9JmSeUWrlwANs+bHw==", "dev": true, "requires": { - "@angular-devkit/build-optimizer": "0.0.42", - "@angular-devkit/schematics": "0.0.52", + "@angular-devkit/build-optimizer": "0.0.36", + "@angular-devkit/schematics": "0.0.42", "@ngtools/json-schema": "1.1.0", "@ngtools/webpack": "1.9.3", - "@schematics/angular": "0.1.17", + "@schematics/angular": "0.1.11", "autoprefixer": "6.7.7", "chalk": "2.2.2", - "circular-dependency-plugin": "4.4.0", - "common-tags": "1.7.2", - "copy-webpack-plugin": "4.4.1", + "circular-dependency-plugin": "4.3.0", + "common-tags": "1.6.0", + "copy-webpack-plugin": "4.3.1", "core-object": "3.1.5", - "css-loader": "0.28.9", + "css-loader": "0.28.7", "cssnano": "3.10.0", "denodeify": "1.2.1", "ember-cli-string-utils": "1.1.0", @@ -102,8 +104,8 @@ "nopt": "4.0.1", "opn": "5.1.0", "portfinder": "1.0.13", - "postcss-custom-properties": "6.3.1", - "postcss-loader": "2.1.0", + "postcss-custom-properties": "6.2.0", + "postcss-loader": "2.0.10", "postcss-url": "7.3.0", "raw-loader": "0.5.1", "resolve": "1.5.0", @@ -116,14 +118,14 @@ "style-loader": "0.13.2", "stylus": "0.54.5", "stylus-loader": "3.0.1", - "uglifyjs-webpack-plugin": "1.2.0", + "uglifyjs-webpack-plugin": "1.1.5", "url-loader": "0.6.2", "webpack": "3.10.0", "webpack-dev-middleware": "1.12.2", "webpack-dev-server": "2.9.7", "webpack-merge": "4.1.1", "webpack-sources": "1.1.0", - "webpack-subresource-integrity": "1.0.4", + "webpack-subresource-integrity": "1.0.3", "zone.js": "0.8.19" } }, @@ -248,21 +250,16 @@ } }, "@schematics/angular": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.17.tgz", - "integrity": "sha512-PHE5gk/ogPY/aN94dbbtauHMCq+/7w4Kdcl7tGmSS8mPKEI0wa6XJi//Wq/tHi55lb2fP58oEZU6n6w/wQascw==", - "dev": true, - "requires": { - "typescript": "2.6.2" - }, - "dependencies": { - "typescript": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", - "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", - "dev": true - } - } + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.11.tgz", + "integrity": "sha512-jYTantZjdYeDjxh9ZLYvGbDI0VeUxgSrcBjHvnHqMNe+YGJenY988ifWCwzjmOowj57maLrQQGrdoO7oUeNdyw==", + "dev": true + }, + "@schematics/schematics": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@schematics/schematics/-/schematics-0.0.11.tgz", + "integrity": "sha512-HAXgAIuuAGjiIKohGlRUkmUTWYtNmclR12KHlQQxT9pHFdEb2OrpHjUp2YoV32jiU6jIZm4pf3ODwlPA0VbwnA==", + "dev": true }, "@types/jasmine": { "version": "2.5.54", @@ -314,9 +311,9 @@ } }, "acorn": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz", - "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz", + "integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==", "dev": true }, "acorn-dynamic-import": { @@ -378,9 +375,9 @@ } }, "ajv-keywords": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", - "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", "dev": true }, "align-text": { @@ -572,9 +569,9 @@ "dev": true }, "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz", + "integrity": "sha512-b/OsSjvWEo8Pi8H0zsDd2P6Uqo2TK2pH8gNLSJtNLM2Db0v2QaAZ0pBQJXVjAn4gBuugeVDr7s63ZogpUIwWDg==", "dev": true, "requires": { "bn.js": "4.11.8", @@ -631,7 +628,7 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000809", + "caniuse-db": "1.0.30000787", "normalize-range": "0.1.2", "num2fraction": "1.2.2", "postcss": "5.2.18", @@ -797,9 +794,9 @@ "dev": true }, "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", "dev": true }, "base64id": { @@ -917,7 +914,7 @@ "deep-equal": "1.0.1", "dns-equal": "1.0.0", "dns-txt": "2.0.2", - "multicast-dns": "6.2.3", + "multicast-dns": "6.2.1", "multicast-dns-service-types": "1.1.0" } }, @@ -1009,7 +1006,7 @@ "dev": true, "requires": { "bn.js": "4.11.8", - "randombytes": "2.0.6" + "randombytes": "2.0.5" } }, "browserify-sign": { @@ -1042,8 +1039,8 @@ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "dev": true, "requires": { - "caniuse-db": "1.0.30000809", - "electron-to-chromium": "1.3.33" + "caniuse-db": "1.0.30000787", + "electron-to-chromium": "1.3.30" } }, "buffer": { @@ -1052,7 +1049,7 @@ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "base64-js": "1.2.3", + "base64-js": "1.2.1", "ieee754": "1.1.8", "isarray": "1.0.0" } @@ -1088,9 +1085,9 @@ "dev": true }, "cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.1.tgz", + "integrity": "sha512-dRHYcs9LvG9cHgdPzjiI+/eS7e1xRhULrcyOx04RZQsszNJXU2SL9CyG60yLnge282Qq5nwTv+ieK2fH+WPZmA==", "dev": true, "requires": { "bluebird": "3.5.1", @@ -1098,14 +1095,14 @@ "glob": "7.1.2", "graceful-fs": "4.1.11", "lru-cache": "4.1.1", - "mississippi": "2.0.0", + "mississippi": "1.3.0", "mkdirp": "0.5.1", "move-concurrently": "1.0.1", "promise-inflight": "1.0.1", "rimraf": "2.6.2", - "ssri": "5.2.4", + "ssri": "5.0.0", "unique-filename": "1.1.0", - "y18n": "4.0.0" + "y18n": "3.2.1" } }, "callsite": { @@ -1147,15 +1144,15 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000809", + "caniuse-db": "1.0.30000787", "lodash.memoize": "4.1.2", "lodash.uniq": "4.5.0" } }, "caniuse-db": { - "version": "1.0.30000809", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000809.tgz", - "integrity": "sha1-sLiENKWY9AtUbUak29g5sP95j00=", + "version": "1.0.30000787", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000787.tgz", + "integrity": "sha1-ygeigb5Taoi9f6yWuolfPPU/gRs=", "dev": true }, "caseless": { @@ -1200,7 +1197,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -1241,9 +1237,9 @@ } }, "circular-dependency-plugin": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-4.4.0.tgz", - "integrity": "sha512-yEFtUNUYT4jBykEX5ZOHw+5goA3glGZr9wAXIQqoyakjz5H5TeUmScnWRc52douAhb9eYzK3s7V6bXfNnjFdzg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-4.3.0.tgz", + "integrity": "sha512-L3W9L1S0wC64rq+QSaZzmWnJW7cVBgimxI2lNEFEX5biwlRG8EHRM68JFi+CX5ZkCGUWJHIpnhdVs181Zlq3wA==", "dev": true }, "clap": { @@ -1430,9 +1426,9 @@ "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==" }, "common-tags": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.7.2.tgz", - "integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.6.0.tgz", + "integrity": "sha512-sgmgEodNLbxnSSoR5a2xH23CoDJ9J5MKsJS/tqplfmJLpikG0oWMpAb+tM8ERQCMpp9I+ERf6SYl158G6GwX0w==", "dev": true, "requires": { "babel-runtime": "6.26.0" @@ -1463,31 +1459,23 @@ "dev": true }, "compressible": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz", - "integrity": "sha1-DRAgq5JLL9tNYnmHXH1tq6a6p6k=", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.12.tgz", + "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=", "dev": true, "requires": { - "mime-db": "1.33.0" - }, - "dependencies": { - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true - } + "mime-db": "1.30.0" } }, "compression": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.2.tgz", - "integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", + "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", "dev": true, "requires": { "accepts": "1.3.4", "bytes": "3.0.0", - "compressible": "2.0.13", + "compressible": "2.0.12", "debug": "2.6.9", "on-headers": "1.0.1", "safe-buffer": "5.1.1", @@ -1611,18 +1599,20 @@ } }, "copy-webpack-plugin": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.4.1.tgz", - "integrity": "sha512-ojaz8MpS3zoLJT/JbYMusYM+dCEArhW24hGAUPYPydTCS+87NFh2TWr85sywG3So4Q4E68QoerqQ+Ns1g0fhDg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.3.1.tgz", + "integrity": "sha512-xlcFiW/U7KrpS6dFuWq3r8Wb7koJx7QVc7LDFCosqkikaVSxkaYOnwDLwilbjrszZ0LYZXThDAJKcQCSrvdShQ==", "dev": true, "requires": { - "cacache": "10.0.4", + "cacache": "10.0.1", "find-cache-dir": "1.0.0", "globby": "7.1.1", "is-glob": "4.0.0", "loader-utils": "0.2.17", + "lodash": "4.17.4", "minimatch": "3.0.4", "p-limit": "1.2.0", + "pify": "3.0.0", "serialize-javascript": "1.4.0" }, "dependencies": { @@ -1693,7 +1683,7 @@ "cipher-base": "1.0.4", "inherits": "2.0.3", "ripemd160": "2.0.1", - "sha.js": "2.4.10" + "sha.js": "2.4.9" } }, "create-hmac": { @@ -1707,7 +1697,7 @@ "inherits": "2.0.3", "ripemd160": "2.0.1", "safe-buffer": "5.1.1", - "sha.js": "2.4.10" + "sha.js": "2.4.9" } }, "cross-spawn": { @@ -1745,8 +1735,8 @@ "inherits": "2.0.3", "pbkdf2": "3.0.14", "public-encrypt": "4.0.0", - "randombytes": "2.0.6", - "randomfill": "1.0.4" + "randombytes": "2.0.5", + "randomfill": "1.0.3" } }, "css-color-names": { @@ -1756,9 +1746,9 @@ "dev": true }, "css-loader": { - "version": "0.28.9", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.9.tgz", - "integrity": "sha512-r3dgelMm/mkPz5Y7m9SeiGE46i2VsEU/OYbez+1llfxtv8b2y5/b5StaeEvPK3S5tlNQI+tDW/xDIhKJoZgDtw==", + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz", + "integrity": "sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==", "dev": true, "requires": { "babel-code-frame": "6.26.0", @@ -1769,7 +1759,7 @@ "lodash.camelcase": "4.3.0", "object-assign": "4.1.1", "postcss": "5.2.18", - "postcss-modules-extract-imports": "1.2.0", + "postcss-modules-extract-imports": "1.1.0", "postcss-modules-local-by-default": "1.2.0", "postcss-modules-scope": "1.1.0", "postcss-modules-values": "1.3.0", @@ -1910,7 +1900,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.39" + "es5-ext": "0.10.37" } }, "dashdash": { @@ -2094,7 +2084,7 @@ "requires": { "bn.js": "4.11.8", "miller-rabin": "4.0.1", - "randombytes": "2.0.6" + "randombytes": "2.0.5" } }, "dir-glob": { @@ -2114,9 +2104,9 @@ "dev": true }, "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.2.2.tgz", + "integrity": "sha512-kN+DjfGF7dJGUL7nWRktL9Z18t1rWP3aQlyZdY8XlpvU3Nc6GeFTQApftcjtWKxAZfiggZSGrCEoszNgvnpwDg==", "dev": true, "requires": { "ip": "1.1.5", @@ -2180,9 +2170,9 @@ } }, "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", "dev": true }, "domelementtype": { @@ -2211,12 +2201,12 @@ } }, "duplexify": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.3.tgz", - "integrity": "sha512-g8ID9OroF9hKt2POf8YLayy+9594PzmM3scI00/uBXocX3TWNgoB67hjzkFe9ITAbQOne/lLdBxHXvYUM4ZgGA==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz", + "integrity": "sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==", "dev": true, "requires": { - "end-of-stream": "1.4.1", + "end-of-stream": "1.4.0", "inherits": "2.0.3", "readable-stream": "2.3.3", "stream-shift": "1.0.0" @@ -2244,12 +2234,21 @@ "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=", "dev": true }, - "electron-to-chromium": { - "version": "1.3.33", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz", - "integrity": "sha1-vwBwPWKnxlI4E2V4w1LWxcBCpUU=", + "electron-releases": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/electron-releases/-/electron-releases-2.1.0.tgz", + "integrity": "sha512-cyKFD1bTE/UgULXfaueIN1k5EPFzs+FRc/rvCY5tIynefAPqopQEgjr0EzY+U3Dqrk/G4m9tXSPuZ77v6dL/Rw==", "dev": true }, + "electron-to-chromium": { + "version": "1.3.30", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.30.tgz", + "integrity": "sha512-zx1Prv7kYLfc4OA60FhxGbSo4qrEjgSzpo1/37i7l9ltXPYOoQBtjQxY9KmsgfHnBxHlBGXwLlsbt/gub1w5lw==", + "dev": true, + "requires": { + "electron-releases": "2.1.0" + } + }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", @@ -2284,9 +2283,9 @@ "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", "dev": true, "requires": { "once": "1.4.0" @@ -2415,9 +2414,9 @@ "dev": true }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz", + "integrity": "sha512-IsORQDpaaSwcDP4ZZnHxgE85werpo34VYn1Ud3mq+eUsF593faR8oCZNXrROVkpFu2TsbrNhHin0aUrTsQ9vNw==", "dev": true, "requires": { "prr": "1.0.1" @@ -2457,9 +2456,9 @@ } }, "es5-ext": { - "version": "0.10.39", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.39.tgz", - "integrity": "sha512-AlaXZhPHl0po/uxMx1tyrlt1O86M6D5iVaDH8UgLfgek4kXTX6vzsRfJQWC2Ku+aG8pkw1XWzh9eTkwfVrsD5g==", + "version": "0.10.37", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz", + "integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=", "dev": true, "requires": { "es6-iterator": "2.0.3", @@ -2473,7 +2472,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.39", + "es5-ext": "0.10.37", "es6-symbol": "3.1.1" } }, @@ -2484,7 +2483,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.39", + "es5-ext": "0.10.37", "es6-iterator": "2.0.3", "es6-set": "0.1.5", "es6-symbol": "3.1.1", @@ -2498,7 +2497,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.39", + "es5-ext": "0.10.37", "es6-iterator": "2.0.3", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" @@ -2511,7 +2510,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.39" + "es5-ext": "0.10.37" } }, "es6-weak-map": { @@ -2521,7 +2520,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.39", + "es5-ext": "0.10.37", "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } @@ -2591,7 +2590,7 @@ "dev": true, "requires": { "d": "1.0.0", - "es5-ext": "0.10.39" + "es5-ext": "0.10.37" } }, "eventemitter3": { @@ -2914,7 +2913,7 @@ "dev": true, "requires": { "commondir": "1.0.1", - "make-dir": "1.2.0", + "make-dir": "1.1.0", "pkg-dir": "2.0.0" } }, @@ -2969,866 +2968,77 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", - "dev": true, - "requires": { - "null-check": "1.0.0" - } - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.3" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "optional": true, - "requires": { - "nan": "2.8.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": 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-fs": { - "version": "4.1.11", - "bundled": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - } + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "1.0.0" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.3" } }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -4291,27 +3501,19 @@ "dev": true }, "html-minifier": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.9.tgz", - "integrity": "sha512-EZqO91XJwkj8BeLx9C12sKB/AHoTANaZax39vEOP9f/X/9jgJ3r1O2+neabuHqpz5kJO71TapP9JrtCY39su1A==", + "version": "3.5.8", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.8.tgz", + "integrity": "sha512-WX7D6PB9PFq05fZ1/CyxPUuyqXed6vh2fGOM80+zJT5wAO93D/cUjLs0CcbBFjQmlwmCgRvl97RurtArIpOnkw==", "dev": true, "requires": { "camel-case": "3.0.0", "clean-css": "4.1.9", - "commander": "2.14.1", + "commander": "2.12.2", "he": "1.1.1", "ncname": "1.0.0", "param-case": "2.1.1", "relateurl": "0.2.7", - "uglify-js": "3.3.11" - }, - "dependencies": { - "commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", - "dev": true - } + "uglify-js": "3.3.4" } }, "html-webpack-plugin": { @@ -4321,7 +3523,7 @@ "dev": true, "requires": { "bluebird": "3.5.1", - "html-minifier": "3.5.9", + "html-minifier": "3.5.8", "loader-utils": "0.2.17", "lodash": "4.17.4", "pretty-error": "2.1.1", @@ -4416,9 +3618,9 @@ } }, "http-parser-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.9.tgz", + "integrity": "sha1-6hoE+2St/wJC6ZdPKX3Uw8rSceE=", "dev": true }, "http-proxy": { @@ -4500,35 +3702,40 @@ "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", "dev": true, "requires": { - "postcss": "6.0.19" + "postcss": "6.0.15" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -4538,12 +3745,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -4783,23 +3990,15 @@ "is-extglob": "2.1.1" } }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true, - "optional": true - }, "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz", + "integrity": "sha512-Q2khNw+oBlWuaYvEEHtKSw/pCxD2L5Rc1C+UQme9X6JdRDh7m5D7HkozA0qa3DUkQ6VzCnEm8mVIQPyIRkI5sQ==", "dev": true, "optional": true, "requires": { "generate-function": "2.0.0", "generate-object-property": "1.2.0", - "is-my-ip-valid": "1.0.0", "jsonpointer": "4.0.1", "xtend": "4.0.1" } @@ -5133,9 +4332,9 @@ "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" }, "js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz", + "integrity": "sha512-Wehd+7Pf9tFvGb+ydPm9TjYjV8X1YHOVyG8QyELZxEMqOhemVwGRmoG8iQ/soqI3n8v4xn59zaLxiCJiaaRzKA==", "dev": true }, "js-tokens": { @@ -5393,7 +4592,7 @@ "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", "dev": true, "requires": { - "errno": "0.1.7", + "errno": "0.1.6", "graceful-fs": "4.1.11", "image-size": "0.5.5", "mime": "1.6.0", @@ -5516,9 +4715,9 @@ "dev": true }, "lodash.mergewith": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", - "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", + "integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=", "dev": true, "optional": true }, @@ -5577,9 +4776,9 @@ } }, "loglevel": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", - "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.0.tgz", + "integrity": "sha1-rgyqVhERSYxboTcj1vtjHSQAOTQ=", "dev": true }, "longest": { @@ -5639,9 +4838,9 @@ } }, "make-dir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", - "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz", + "integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==", "dev": true, "requires": { "pify": "3.0.0" @@ -5699,7 +4898,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "1.1.0" } }, "memory-fs": { @@ -5708,7 +4907,7 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "0.1.7", + "errno": "0.1.6", "readable-stream": "2.3.3" } }, @@ -5809,9 +5008,9 @@ } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", "dev": true }, "minimalistic-assert": { @@ -5841,19 +5040,19 @@ "dev": true }, "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-1.3.0.tgz", + "integrity": "sha1-0gFYPrEjJ+PFwWQqQEqcrPlONPU=", "dev": true, "requires": { "concat-stream": "1.6.0", - "duplexify": "3.5.3", - "end-of-stream": "1.4.1", + "duplexify": "3.5.1", + "end-of-stream": "1.4.0", "flush-write-stream": "1.0.2", "from2": "2.3.0", "parallel-transform": "1.1.0", - "pump": "2.0.1", - "pumpify": "1.4.0", + "pump": "1.0.3", + "pumpify": "1.3.5", "stream-each": "1.2.2", "through2": "2.0.3" } @@ -5914,13 +5113,13 @@ "dev": true }, "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.1.tgz", + "integrity": "sha512-uV3/ckdsffHx9IrGQrx613mturMdMqQ06WTq+C09NsStJ9iNG6RcUWgPKs1Rfjy+idZT6tfQoXEusGNnEZhT3w==", "dev": true, "requires": { - "dns-packet": "1.3.1", - "thunky": "1.0.2" + "dns-packet": "1.2.2", + "thunky": "0.1.0" } }, "multicast-dns-service-types": { @@ -5933,6 +5132,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "dev": true, "optional": true }, "ncname": { @@ -5965,9 +5165,9 @@ } }, "node-forge": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz", - "integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA=", + "version": "0.6.33", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.33.tgz", + "integrity": "sha1-RjgRh59XPUUVWtap9D3ClujoXrw=", "dev": true }, "node-gyp": { @@ -5984,7 +5184,7 @@ "mkdirp": "0.5.1", "nopt": "3.0.6", "npmlog": "4.1.2", - "osenv": "0.1.5", + "osenv": "0.1.4", "request": "2.81.0", "rimraf": "2.6.2", "semver": "5.3.0", @@ -6023,7 +5223,7 @@ "console-browserify": "1.1.0", "constants-browserify": "1.0.0", "crypto-browserify": "3.12.0", - "domain-browser": "1.2.0", + "domain-browser": "1.1.7", "events": "1.1.1", "https-browserify": "1.0.0", "os-browserify": "0.3.0", @@ -6033,9 +5233,9 @@ "querystring-es3": "0.2.1", "readable-stream": "2.3.3", "stream-browserify": "2.0.1", - "stream-http": "2.8.0", + "stream-http": "2.7.2", "string_decoder": "1.0.3", - "timers-browserify": "2.0.6", + "timers-browserify": "2.0.4", "tty-browserify": "0.0.0", "url": "0.11.0", "util": "0.10.3", @@ -6064,7 +5264,7 @@ "in-publish": "2.0.0", "lodash.assign": "4.2.0", "lodash.clonedeep": "4.5.0", - "lodash.mergewith": "4.6.1", + "lodash.mergewith": "4.6.0", "meow": "3.7.0", "mkdirp": "0.5.1", "nan": "2.8.0", @@ -6111,7 +5311,7 @@ "requires": { "chalk": "1.1.3", "commander": "2.12.2", - "is-my-json-valid": "2.17.2", + "is-my-json-valid": "2.17.1", "pinkie-promise": "2.0.1" } }, @@ -6173,7 +5373,7 @@ "dev": true, "requires": { "abbrev": "1.1.1", - "osenv": "0.1.5" + "osenv": "0.1.4" } }, "normalize-package-data": { @@ -6417,9 +5617,9 @@ "dev": true }, "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", "dev": true, "requires": { "os-homedir": "1.0.2", @@ -6494,7 +5694,7 @@ "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", "dev": true, "requires": { - "asn1.js": "4.10.1", + "asn1.js": "4.9.2", "browserify-aes": "1.1.1", "create-hash": "1.1.3", "evp_bytestokey": "1.0.3", @@ -6635,7 +5835,7 @@ "create-hmac": "1.1.6", "ripemd160": "2.0.1", "safe-buffer": "5.1.1", - "sha.js": "2.4.10" + "sha.js": "2.4.9" } }, "performance-now": { @@ -6700,7 +5900,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.0", "source-map": "0.5.7", "supports-color": "3.2.3" }, @@ -6782,41 +5982,46 @@ } }, "postcss-custom-properties": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-6.3.1.tgz", - "integrity": "sha512-zoiwn4sCiUFbr4KcgcNZLFkR6gVQom647L+z1p/KBVHZ1OYwT87apnS42atJtx6XlX2yI7N5fjXbFixShQO2QQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-6.2.0.tgz", + "integrity": "sha512-eNR2h9T9ciKMoQEORrPjH33XeN/nuvVuxArOKmHtsFbGbNss631tgTrKou3/pmjAZbA4QQkhLIkPQkIk3WW+8w==", "dev": true, "requires": { "balanced-match": "1.0.0", - "postcss": "6.0.19" + "postcss": "6.0.15" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -6826,12 +6031,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -6925,64 +6130,48 @@ } }, "postcss-loader": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.0.tgz", - "integrity": "sha512-S/dKzpDwGFmP9g8eyCu9sUIV+/+3UooeTpYlsKf23qKDdrhHuA4pTSfytVu0rEJ0iDqUavXrgtOPq5KhNyNMOw==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.0.10.tgz", + "integrity": "sha512-xQaDcEgJ/2JqFY18zpFkik8vyYs7oS5ZRbrjvDqkP97k2wYWfPT4+qA0m4o3pTSCsz0u26PNqs8ZO9FRUWAqrA==", "dev": true, "requires": { "loader-utils": "1.1.0", - "postcss": "6.0.19", + "postcss": "6.0.15", "postcss-load-config": "1.2.0", - "schema-utils": "0.4.5" + "schema-utils": "0.3.0" }, "dependencies": { - "ajv": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", - "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", - "dev": true, - "requires": { - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" - } - }, - "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", - "dev": true, - "requires": { - "ajv": "6.1.1", - "ajv-keywords": "3.1.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -6992,12 +6181,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -7087,40 +6276,45 @@ } }, "postcss-modules-extract-imports": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz", - "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", + "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", "dev": true, "requires": { - "postcss": "6.0.19" + "postcss": "6.0.15" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -7130,12 +6324,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -7147,35 +6341,40 @@ "dev": true, "requires": { "css-selector-tokenizer": "0.7.0", - "postcss": "6.0.19" + "postcss": "6.0.15" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -7185,12 +6384,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -7202,35 +6401,40 @@ "dev": true, "requires": { "css-selector-tokenizer": "0.7.0", - "postcss": "6.0.19" + "postcss": "6.0.15" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -7240,12 +6444,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -7257,35 +6461,40 @@ "dev": true, "requires": { "icss-replace-symbols": "1.1.0", - "postcss": "6.0.19" + "postcss": "6.0.15" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -7295,12 +6504,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -7409,36 +6618,41 @@ "mime": "1.6.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "postcss": "6.0.19", - "xxhashjs": "0.2.2" + "postcss": "6.0.15", + "xxhashjs": "0.2.1" }, "dependencies": { "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" + "supports-color": "4.5.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "postcss": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", - "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.15.tgz", + "integrity": "sha512-v/SpyMzLbtkmh45zUdaqLAaqXqzPdSrw8p4cQVO0/w6YiYfpj4k+Wkzhn68qk9br+H+0qfddhdPEVnbmBPfXVQ==", "dev": true, "requires": { - "chalk": "2.3.1", + "chalk": "2.3.0", "source-map": "0.6.1", - "supports-color": "5.2.0" + "supports-color": "5.1.0" } }, "source-map": { @@ -7448,12 +6662,12 @@ "dev": true }, "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "2.0.0" } } } @@ -7665,28 +6879,28 @@ "browserify-rsa": "4.0.1", "create-hash": "1.1.3", "parse-asn1": "5.1.0", - "randombytes": "2.0.6" + "randombytes": "2.0.5" } }, "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", "dev": true, "requires": { - "end-of-stream": "1.4.1", + "end-of-stream": "1.4.0", "once": "1.4.0" } }, "pumpify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.4.0.tgz", - "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.3.5.tgz", + "integrity": "sha1-G2ccYZlAq8rqwK0OOjwWS+dgmTs=", "dev": true, "requires": { - "duplexify": "3.5.3", + "duplexify": "3.5.1", "inherits": "2.0.3", - "pump": "2.0.1" + "pump": "1.0.3" } }, "punycode": { @@ -7779,21 +6993,21 @@ } }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", "dev": true, "requires": { "safe-buffer": "5.1.1" } }, "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz", + "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==", "dev": true, "requires": { - "randombytes": "2.0.6", + "randombytes": "2.0.5", "safe-buffer": "5.1.1" } }, @@ -8241,7 +7455,7 @@ "dev": true, "optional": true, "requires": { - "js-base64": "2.4.3", + "js-base64": "2.4.0", "source-map": "0.4.4" }, "dependencies": { @@ -8287,12 +7501,12 @@ } }, "selfsigned": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.2.tgz", - "integrity": "sha1-tESVgNmZKbZbEKSDiTAaZZIIh1g=", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.1.tgz", + "integrity": "sha1-v4y3uDJWxFUeMTR8YxF3jbme7FI=", "dev": true, "requires": { - "node-forge": "0.7.1" + "node-forge": "0.6.33" } }, "semver": { @@ -8396,9 +7610,9 @@ "dev": true }, "sha.js": { - "version": "2.4.10", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.10.tgz", - "integrity": "sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==", + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz", + "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==", "dev": true, "requires": { "inherits": "2.0.3", @@ -8799,9 +8013,9 @@ } }, "ssri": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.2.4.tgz", - "integrity": "sha512-UnEAgMZa15973iH7cUi0AHjJn1ACDIkaMyZILoqwN6yzt+4P81I8tBc5Hl+qwi5auMplZtPQsHrPBR5vJLcQtQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.0.0.tgz", + "integrity": "sha512-728D4yoQcQm1ooZvSbywLkV1RjfITZXh0oWrhM/lnsx3nAHx7LsRGJWB/YyvoceAYRq98xqbstiN4JBv1/wNHg==", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -8839,14 +8053,14 @@ "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", + "end-of-stream": "1.4.0", "stream-shift": "1.0.0" } }, "stream-http": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz", - "integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", "dev": true, "requires": { "builtin-status-codes": "3.0.0", @@ -9061,9 +8275,9 @@ } }, "thunky": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", - "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", + "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=", "dev": true }, "time-stamp": { @@ -9073,9 +8287,9 @@ "dev": true }, "timers-browserify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz", - "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz", + "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==", "dev": true, "requires": { "setimmediate": "1.0.5" @@ -9300,21 +8514,15 @@ "dev": true }, "uglify-js": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.11.tgz", - "integrity": "sha512-AKLsYcdV+sS5eAE4NtVXF6f2u/DCQynQm0jTGxF261+Vltu1dYNuHzjqDmk11gInj+H/zJIM2EAwXG3MzPb3VA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.4.tgz", + "integrity": "sha512-hfIwuAQI5dlXP30UtdmWoYF9k+ypVqBXIdmd6ZKBiaNHHvA8ty7ZloMe3+7S5AEKVkxHbjByl4DfRHQ7QpZquw==", "dev": true, "requires": { - "commander": "2.14.1", + "commander": "2.12.2", "source-map": "0.6.1" }, "dependencies": { - "commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9331,48 +8539,21 @@ "optional": true }, "uglifyjs-webpack-plugin": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.0.tgz", - "integrity": "sha512-Bc2NeyTTSJAy2JuKaBpdvWyuySPSPHNcj70KFqu7FhfrfsjPo0Kta9jgAvPrQxnz86mOH1tk4n/I8wvZrXvetA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.5.tgz", + "integrity": "sha512-YBGc9G7dv12Vjx8vUQs54DZgAXVf04LlG6dNNiEbTZjL3PbUqiY4uPB9Kv+fUJaqRskEGva/lS7sh08yJr7jnA==", "dev": true, "requires": { - "cacache": "10.0.4", + "cacache": "10.0.1", "find-cache-dir": "1.0.0", - "schema-utils": "0.4.5", + "schema-utils": "0.3.0", "serialize-javascript": "1.4.0", "source-map": "0.6.1", - "uglify-es": "3.3.9", + "uglify-es": "3.2.2", "webpack-sources": "1.1.0", "worker-farm": "1.5.2" }, "dependencies": { - "ajv": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", - "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", - "dev": true, - "requires": { - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - }, - "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", - "dev": true, - "requires": { - "ajv": "6.1.1", - "ajv-keywords": "3.1.0" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9380,12 +8561,12 @@ "dev": true }, "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.2.2.tgz", + "integrity": "sha512-l+s5VLzFwGJfS+fbqaGf/Dfwo1MF13jLOF2ekL0PytzqEqQ6cVppvHf4jquqFok+35USMpKjqkYxy6pQyUcuug==", "dev": true, "requires": { - "commander": "2.13.0", + "commander": "2.12.2", "source-map": "0.6.1" } } @@ -9709,7 +8890,7 @@ "integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==", "dev": true, "requires": { - "acorn": "5.4.1", + "acorn": "5.3.0", "acorn-dynamic-import": "2.0.2", "ajv": "5.5.2", "ajv-keywords": "2.1.1", @@ -9733,12 +8914,6 @@ "yargs": "8.0.2" }, "dependencies": { - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true - }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -9896,12 +9071,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, "yargs": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", @@ -10024,7 +9193,7 @@ "array-includes": "3.0.3", "bonjour": "3.5.0", "chokidar": "1.7.0", - "compression": "1.7.2", + "compression": "1.7.1", "connect-history-api-fallback": "1.5.0", "debug": "3.1.0", "del": "3.0.0", @@ -10035,10 +9204,10 @@ "internal-ip": "1.2.0", "ip": "1.1.5", "killable": "1.0.0", - "loglevel": "1.6.1", + "loglevel": "1.6.0", "opn": "5.1.0", "portfinder": "1.0.13", - "selfsigned": "1.10.2", + "selfsigned": "1.10.1", "serve-index": "1.9.1", "sockjs": "0.3.18", "sockjs-client": "1.1.4", @@ -10064,12 +9233,6 @@ "ms": "2.0.0" } }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, "yargs": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", @@ -10130,9 +9293,9 @@ } }, "webpack-subresource-integrity": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.4.tgz", - "integrity": "sha1-j6yKfo61n8ahZ2ioXJ2U7n+dDts=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.3.tgz", + "integrity": "sha1-wGBtQAkLBwzeQovsjfNgMhbkcus=", "dev": true, "requires": { "webpack-core": "0.6.9" @@ -10144,7 +9307,7 @@ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "http-parser-js": "0.4.10", + "http-parser-js": "0.4.9", "websocket-extensions": "0.1.3" } }, @@ -10208,7 +9371,7 @@ "integrity": "sha512-XxiQ9kZN5n6mmnW+mFJ+wXjNNI/Nx4DIdaAKLX1Bn6LYBWlN/zaBhu34DQYPZ1AJobQuu67S2OfDdNSVULvXkQ==", "dev": true, "requires": { - "errno": "0.1.7", + "errno": "0.1.6", "xtend": "4.0.1" } }, @@ -10279,18 +9442,18 @@ "dev": true }, "xxhashjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", - "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.1.tgz", + "integrity": "sha1-m76b6JYUKXbfo0wGGy0GjEPTDeA=", "dev": true, "requires": { "cuint": "0.2.2" } }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { @@ -10327,13 +9490,6 @@ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", "dev": true, "optional": true - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true, - "optional": true } } }, diff --git a/ui-src/package.json b/ui-src/package.json index 7ff693e..3063ceb 100644 --- a/ui-src/package.json +++ b/ui-src/package.json @@ -11,10 +11,11 @@ "e2e": "ng e2e --delete-output-path=false" }, "private": true, - "dependencies": { - "@angular-devkit/core": "^0.4.0", + + "dependencies": { "@angular/animations": "^5.1.3", "@angular/cdk": "^5.0.3", + "@angular-devkit/core": "^5.0.0", "@angular/common": "^5.0.0", "@angular/compiler": "^5.0.0", "@angular/core": "^5.0.0", @@ -37,7 +38,7 @@ "zone.js": "^0.8.14" }, "devDependencies": { - "@angular/cli": "1.6.8", + "@angular/cli": "1.6.3", "@angular/compiler-cli": "^5.0.0", "@angular/language-service": "^5.0.0", "@types/jasmine": "~2.5.53", diff --git a/ui-src/src/app/app.component.html b/ui-src/src/app/app.component.html index e9dfcd9..72f7448 100644 --- a/ui-src/src/app/app.component.html +++ b/ui-src/src/app/app.component.html @@ -12,4 +12,5 @@

Automated Performance Testing

+ \ No newline at end of file diff --git a/ui-src/src/app/app.module.ts b/ui-src/src/app/app.module.ts index 9a158df..9131d86 100644 --- a/ui-src/src/app/app.module.ts +++ b/ui-src/src/app/app.module.ts @@ -9,16 +9,22 @@ import { AppRoutingModule } from "./app-routing.module"; import { JsonSchemaFormModule } from "angular2-json-schema-form"; import { ConfigurationsComponent } from "./configurations/configurations.component"; import { ToastModule } from "ng2-toastr/ng2-toastr"; -import { AutomatedUIServices } from "./automated-ui-services"; +import { ConfigurationService } from "./configurations/configuration.service"; +import { TestCaseService } from "./test-cases/test-case.service"; +import { TestSuiteService } from "./test-suites/test-suite.service"; import { HttpClientModule, HttpClient } from "@angular/common/http"; import { FormsModule } from "@angular/forms"; +import { TestCasesSelectionComponent } from "./shared/test-cases-selection/test-cases-selection.component"; +import { TestCasesListComponent } from "./shared/test-cases-list/test-cases-list.component"; @NgModule({ declarations: [ AppComponent, TestCasesComponent, TestSuitesComponent, - ConfigurationsComponent + ConfigurationsComponent, + TestCasesSelectionComponent, + TestCasesListComponent ], imports: [ FormsModule, @@ -30,7 +36,7 @@ import { FormsModule } from "@angular/forms"; AppRoutingModule, HttpClientModule ], - providers: [AutomatedUIServices], + providers: [ConfigurationService, TestCaseService, TestSuiteService], bootstrap: [AppComponent] }) -export class AppModule {} +export class AppModule { } diff --git a/ui-src/src/app/automated-ui-services.ts b/ui-src/src/app/automated-ui-services.ts deleted file mode 100644 index 8cadf9e..0000000 --- a/ui-src/src/app/automated-ui-services.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Injectable } from "@angular/core"; -import { HttpModule } from "@angular/http"; -import { Http } from "@angular/http"; -import { HttpClient, HttpHeaders } from "@angular/common/http"; -import { ConfigurationsComponent } from "./configurations/configurations.component"; -import { Headers } from "@angular/http/src/headers"; -import { Observable } from "rxjs/Observable"; -import { environment } from "../environments/environment.prod"; -import { $ } from "protractor"; - -@Injectable() -export class AutomatedUIServices { - private headers: HttpHeaders; - constructor(private http: HttpClient) { - this.headers = new HttpHeaders({ "Content-Type": "application/json" }); - } - - postConfig$(configData, configPath): Observable { - this.headers = this.headers.set("configPathDir", configPath); - return this.http.post(`${environment.apiBaseUrl}configs`, configData, { - headers: this.headers - }); - - - } - getConfig$(configPath, xmlFileName): Observable { - this.headers = this.headers.set("configPathDir", configPath); - return this.http.get(`${environment.apiBaseUrl}configs/${xmlFileName}`, { - headers: this.headers - }); - } - putConfig$(configData, configPath, xmlFileName): Observable { - this.headers = this.headers.set("configPathDir", configPath); - return this.http.put( - `${environment.apiBaseUrl}configs/${xmlFileName}`, - configData, - { headers: this.headers } - ); - } - getSchema$(location: string): Observable { - return this.http - .get(`${environment.apiBaseUrl}${location}`, { headers: this.headers }) - .map((data: any) => data); - } -} diff --git a/ui-src/src/app/automated-ui-services.spec.ts b/ui-src/src/app/configurations/configuration.service.spec.ts similarity index 75% rename from ui-src/src/app/automated-ui-services.spec.ts rename to ui-src/src/app/configurations/configuration.service.spec.ts index 803952c..2e619bb 100644 --- a/ui-src/src/app/automated-ui-services.spec.ts +++ b/ui-src/src/app/configurations/configuration.service.spec.ts @@ -1,15 +1,15 @@ import {TestBed, inject, getTestBed} from "@angular/core/testing"; import {HttpClientModule} from "@angular/common/http"; -import {AutomatedUIServices} from "./automated-ui-services"; -import { HttpClient, HttpHeaders } from "@angular/common/http"; -import {environment} from "../environments/environment.prod"; +import {HttpClient, HttpHeaders} from "@angular/common/http"; +import {environment} from "../../environments/environment"; import { HttpClientTestingModule, HttpTestingController } from "@angular/common/http/testing"; -describe("AutomatedUIServices", () => { +import {ConfigurationService} from "./configuration.service"; +describe("ConfigurationService", () => { let injector; let service; let httpInterceptor: HttpTestingController; @@ -17,11 +17,11 @@ describe("AutomatedUIServices", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientModule, HttpClientTestingModule], - providers: [AutomatedUIServices] + providers: [ConfigurationService] }); injector = getTestBed(); - service = injector.get(AutomatedUIServices); + service = injector.get(ConfigurationService); httpInterceptor = injector.get(HttpTestingController); }); @@ -37,10 +37,10 @@ describe("AutomatedUIServices", () => { headers = headers.set("Content-Type", "application/json;"); headers = headers.append("configPathDir", "data2"); - const req = httpInterceptor.expectOne(`${environment.apiBaseUrl}configs`); + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}configs`); expect(req.request.method).toBe("POST"); expect(req.request.headers.getAll).toBe(headers.getAll); - expect(req.request.body).toEqual({ data: "data1" }); + expect(req.request.body).toEqual({data: "data1"}); req.flush({}); }); @@ -52,10 +52,10 @@ describe("AutomatedUIServices", () => { headers = headers.set("Content-Type", "application/json;"); headers = headers.append("configPathDir", "direct path"); - const req = httpInterceptor.expectOne(`${environment.apiBaseUrl}configs/fileName.xml`); + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}configs/fileName.xml`); expect(req.request.method).toBe("PUT"); expect(req.request.headers.getAll).toBe(headers.getAll); - expect(req.request.body).toEqual({ data: "data1" }); + expect(req.request.body).toEqual({data: "data1"}); req.flush({}); }); @@ -67,7 +67,7 @@ describe("AutomatedUIServices", () => { headers = headers.set("Content-Type", "application/json;"); headers = headers.append("configPathDir", "direct path"); - const req = httpInterceptor.expectOne(`${environment.apiBaseUrl}configs/fileName.xml`); + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}configs/fileName.xml`); expect(req.request.method).toBe("GET"); expect(req.request.headers.getAll).toBe(headers.getAll); expect(req.request.body).toBeNull(); diff --git a/ui-src/src/app/configurations/configuration.service.ts b/ui-src/src/app/configurations/configuration.service.ts new file mode 100644 index 0000000..8a54e39 --- /dev/null +++ b/ui-src/src/app/configurations/configuration.service.ts @@ -0,0 +1,43 @@ +import {Injectable} from "@angular/core"; +import {HttpClient, HttpHeaders} from "@angular/common/http"; +import {ConfigurationsComponent} from "./configurations.component"; +import {Observable} from "rxjs/Observable"; +import { environment } from '../../environments/environment'; + + +@Injectable() +export class ConfigurationService { + private headers: HttpHeaders; + constructor(private http: HttpClient) { + this.headers = new HttpHeaders({"Content-Type": "application/json"}); + } + + postConfig$(configData, configPath): Observable { + this.headers = this.headers.set("path", configPath); + return this.http.post(`${environment.API_BASE_URL}configs`, configData, { + headers: this.headers + }); + } + + getConfig$(configPath, xmlFileName): Observable { + this.headers = this.headers.set("path", configPath); + return this.http.get(`${environment.API_BASE_URL}configs/${xmlFileName}`, { + headers: this.headers + }); + } + + putConfig$(configData, configPath, xmlFileName): Observable { + this.headers = this.headers.set("path", configPath); + return this.http.put( + `${environment.API_BASE_URL}configs/${xmlFileName}`, + configData, + {headers: this.headers} + ); + } + + getSchema$(location: string): Observable { + return this.http + .get(`${environment.ASSESTS_BASE_URL}${location}`, {headers: this.headers}) + .map((data: any) => data); + } +} diff --git a/ui-src/src/app/configurations/configurations.component.css b/ui-src/src/app/configurations/configurations.component.css index e293af1..840ba30 100644 --- a/ui-src/src/app/configurations/configurations.component.css +++ b/ui-src/src/app/configurations/configurations.component.css @@ -8,7 +8,7 @@ background-color: #337ab7; border-color: #2e6da4; } - +.btn { margin-top: -12px;} .btn-info{ visibility: hidden; } @@ -18,9 +18,9 @@ } .button { display: inline-block; - padding: 6px 12px; + padding: 7px 18px; margin-bottom: 0; - margin-top: 25px; + margin-top: 0px; font-size: 14px; font-weight: 400; line-height: 1.42857143; @@ -43,4 +43,9 @@ filter: alpha(opacity=65); box-shadow: none; opacity: .65; -} \ No newline at end of file +} +submit-widget{ + display : none; +} + + diff --git a/ui-src/src/app/configurations/configurations.component.html b/ui-src/src/app/configurations/configurations.component.html index 31521e0..c100cad 100644 --- a/ui-src/src/app/configurations/configurations.component.html +++ b/ui-src/src/app/configurations/configurations.component.html @@ -1,22 +1,25 @@
-
-
- - - -
-
- - - - -
- +
+
+ +
- - - - +
+ + +
+
+ + +
+
+ + + + + +
\ No newline at end of file diff --git a/ui-src/src/app/configurations/configurations.component.spec.ts b/ui-src/src/app/configurations/configurations.component.spec.ts index b484fcd..f4eff9d 100644 --- a/ui-src/src/app/configurations/configurations.component.spec.ts +++ b/ui-src/src/app/configurations/configurations.component.spec.ts @@ -3,8 +3,8 @@ import {ConfigurationsComponent} from "./configurations.component"; import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from "@angular/core"; import {ToastModule} from "ng2-toastr/ng2-toastr"; -import {AutomatedUIServices} from "../automated-ui-services"; - +import {ConfigurationService} from "./configuration.service"; +import {TestSuiteService} from "../test-suites/test-suite.service"; import {HttpClientModule} from "@angular/common/http"; import {FormsModule} from "@angular/forms"; import {ToastsManager, ToastOptions} from "ng2-toastr/ng2-toastr"; @@ -20,7 +20,7 @@ describe("ConfigurationsComponent", () => { beforeEach( async(() => { TestBed.configureTestingModule({ - providers: [AutomatedUIServices, ToastsManager, ToastOptions], + providers: [ConfigurationService, ToastsManager, ToastOptions, TestSuiteService], declarations: [ConfigurationsComponent], imports: [FormsModule, HttpClientModule, ToastModule.forRoot()], schemas: [NO_ERRORS_SCHEMA, @@ -31,7 +31,7 @@ describe("ConfigurationsComponent", () => { component = fixture.componentInstance; fixture.detectChanges(); - configurationService = TestBed.get(AutomatedUIServices); + configurationService = TestBed.get(ConfigurationService); toastr = TestBed.get(ToastsManager); })); diff --git a/ui-src/src/app/configurations/configurations.component.ts b/ui-src/src/app/configurations/configurations.component.ts index cc8ad23..404f16b 100644 --- a/ui-src/src/app/configurations/configurations.component.ts +++ b/ui-src/src/app/configurations/configurations.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit } from "@angular/core"; -import { HttpClient } from "@angular/common/http"; -import { AutomatedUIServices } from "../automated-ui-services"; -import { JsonSchemaFormModule } from "angular2-json-schema-form"; -import { ToastsManager } from "ng2-toastr/ng2-toastr"; +import {Component, OnInit} from "@angular/core"; +import {HttpClient} from "@angular/common/http"; +import {ConfigurationService} from "./configuration.service"; +import {TestSuiteService} from "../test-suites/test-suite.service"; +import {JsonSchemaFormModule} from "angular2-json-schema-form"; +import {ToastsManager} from "ng2-toastr/ng2-toastr"; import "rxjs/add/operator/map"; @Component({ @@ -12,21 +13,23 @@ import "rxjs/add/operator/map"; }) export class ConfigurationsComponent implements OnInit { formData = {}; + test = []; + test2 = []; + testArary = []; configPath = undefined; xmlFileName = undefined; fileName = undefined; - // needed for layout to load - configSchema = { layout: true }; + configSchema = {}; constructor( - private automatedUIServices: AutomatedUIServices, + private configurationService: ConfigurationService, + private testSuiteService: TestSuiteService, private toastr: ToastsManager, - private http: HttpClient ) {} ngOnInit() { - this.automatedUIServices + this.configurationService .getSchema$("assets/schema.json") .subscribe((data: any) => { this.configSchema = data; @@ -34,7 +37,7 @@ export class ConfigurationsComponent implements OnInit { } onSubmit(configData) { - this.automatedUIServices.postConfig$(configData, this.configPath).subscribe( + this.configurationService.postConfig$(configData, this.configPath).subscribe( data => { this.toastr.success("Your data has been saved!", "Success!"); }, @@ -65,7 +68,7 @@ export class ConfigurationsComponent implements OnInit { } onCancel() { - this.automatedUIServices + this.configurationService .getConfig$(this.configPath, this.xmlFileName) .subscribe( data => { @@ -80,13 +83,24 @@ export class ConfigurationsComponent implements OnInit { ); } + fileSelector(event) { this.fileName = event.srcElement.files[0].name; this.xmlFileName = this.fileName; + this.xmlFileName = this.xmlFileName.substring( + 0, + this.xmlFileName.length - 4); + this.onGetFile(); + (document.getElementById("file")).value = ""; } + + onClearFile() { + this.xmlFileName = undefined; + } + onGetFile() { - this.automatedUIServices + this.configurationService .getConfig$(this.configPath, this.xmlFileName) .subscribe( data => { @@ -120,8 +134,9 @@ export class ConfigurationsComponent implements OnInit { } ); } + onUpdate(configData) { - this.automatedUIServices + this.configurationService .putConfig$(this.formData, this.configPath, this.xmlFileName) .subscribe( data => { @@ -141,7 +156,7 @@ export class ConfigurationsComponent implements OnInit { break; } case 500: { - this.toastr.error("Internal server error!"); + this.toastr.error("An error has occurred!", "Check the logs!"); break; } default: { diff --git a/ui-src/src/app/shared/test-cases-list/test-cases-list.component.css b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.css new file mode 100644 index 0000000..6ee5204 --- /dev/null +++ b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.css @@ -0,0 +1,5 @@ +td, th { + border: 1px solid #dddddd; + padding: 8px; + width: 100%; +} \ No newline at end of file diff --git a/ui-src/src/app/shared/test-cases-list/test-cases-list.component.html b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.html new file mode 100644 index 0000000..f24e860 --- /dev/null +++ b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.html @@ -0,0 +1,17 @@ +
+ + + + + + + + + + + + + +
DescriptionPre-ThinkPost-ThinkExec-Weight
{{testCase.description}}{{testCase.preThinkTime}}{{testCase.postThinkTime}}{{testCase.execWeight}}
+
+ \ No newline at end of file diff --git a/ui-src/src/app/shared/test-cases-list/test-cases-list.component.spec.ts b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.spec.ts new file mode 100644 index 0000000..dac8ea6 --- /dev/null +++ b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { TestCasesListComponent } from "./test-cases-list.component"; + +describe("TestCasesListComponent", () => { + let component: TestCasesListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TestCasesListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TestCasesListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ui-src/src/app/shared/test-cases-list/test-cases-list.component.ts b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.ts new file mode 100644 index 0000000..7027a80 --- /dev/null +++ b/ui-src/src/app/shared/test-cases-list/test-cases-list.component.ts @@ -0,0 +1,19 @@ +import {Component, Input, Output, EventEmitter} from "@angular/core"; + +@Component({ + selector: "app-test-cases-list", + templateUrl: "./test-cases-list.component.html", + styleUrls: ["./test-cases-list.component.css"] +}) +export class TestCasesListComponent { + selectedTestCaseData = []; + @Input() testCases; + @Output() addToSelected = new EventEmitter(); + @Output() reverse = new EventEmitter(); + + selectedCase(testCase, i) { + this.selectedTestCaseData = testCase; + this.addToSelected.emit(this.selectedTestCaseData); + this.reverse.emit(i); + } +} diff --git a/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.css b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.css new file mode 100644 index 0000000..e69de29 diff --git a/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.html b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.html new file mode 100644 index 0000000..60b7d73 --- /dev/null +++ b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.html @@ -0,0 +1,10 @@ +
+
+

Available

+ +
+
+

Selected

+ +
+
\ No newline at end of file diff --git a/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.spec.ts b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.spec.ts new file mode 100644 index 0000000..f0862ad --- /dev/null +++ b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.spec.ts @@ -0,0 +1,31 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import {TestCaseService} from "../../test-cases/test-case.service"; +import { TestCasesSelectionComponent } from "./test-cases-selection.component"; +import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from "@angular/core"; +import {HttpClientModule} from "@angular/common/http"; + +describe("TestCasesSelectionComponent", () => { + let component: TestCasesSelectionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TestCasesSelectionComponent ], + providers: [TestCaseService], + imports: [HttpClientModule], + schemas: [NO_ERRORS_SCHEMA, + CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TestCasesSelectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.ts b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.ts new file mode 100644 index 0000000..7d3d4e0 --- /dev/null +++ b/ui-src/src/app/shared/test-cases-selection/test-cases-selection.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core"; +import { TestCaseService } from "../../test-cases/test-case.service"; + +@Component({ + selector: "app-test-cases-selection", + templateUrl: "./test-cases-selection.component.html", + styleUrls: ["./test-cases-selection.component.css"] +}) +export class TestCasesSelectionComponent implements OnInit { + @Input() testSuiteDirPath; + @Input() availableTestCases; + @Input() selectedTestCaseData = []; + @Output() addToSelected = new EventEmitter(); + @Output() reverse = new EventEmitter(); + + constructor(private testCaseService: TestCaseService) {} + + ngOnInit() {} + onReverse(selectedIndex) { + this.reverse.emit(selectedIndex); + } + onAddToSelected(testCase, selectedIndex) { + this.addToSelected.emit(testCase); + } +} diff --git a/ui-src/src/app/test-cases/test-case.service.spec.ts b/ui-src/src/app/test-cases/test-case.service.spec.ts new file mode 100644 index 0000000..792c304 --- /dev/null +++ b/ui-src/src/app/test-cases/test-case.service.spec.ts @@ -0,0 +1,91 @@ +import {TestBed, inject, getTestBed} from "@angular/core/testing"; +import {HttpClientModule} from "@angular/common/http"; +import {HttpClient, HttpHeaders} from "@angular/common/http"; +import {environment} from "../../environments/environment"; +import { + HttpClientTestingModule, + HttpTestingController +} from "@angular/common/http/testing"; + +import { TestCaseService } from "./test-case.service"; + +describe("TestCaseService", () => { + let injector; + let service; + let httpInterceptor: HttpTestingController; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientModule, HttpClientTestingModule], + providers: [TestCaseService] + }); + + injector = getTestBed(); + service = injector.get(TestCaseService); + httpInterceptor = injector.get(HttpTestingController); + }); + + it("should be created", () => { + expect(service).toBeTruthy(); + }); + + it("should make post test case request", () => { + // TODO add mock so it is no longer calling the real service + service.postTestCase$({data: "data1"}, "data2").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "data2"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-cases`); + expect(req.request.method).toBe("POST"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toEqual({data: "data1"}); + req.flush({}); + }); + + it("should make put test case request", () => { + // TODO add mock so it is no longer calling the real service + service.putTestCase$({data: "data1"}, "direct path", "fileName.xml").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "direct path"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-cases/fileName.xml`); + expect(req.request.method).toBe("PUT"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toEqual({data: "data1"}); + req.flush({}); + }); + + it("should make get test case request", () => { + // TODO add mock so it is no longer calling the real service + service.getTestCase$("direct path", "fileName.xml").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "direct path"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-cases/fileName.xml`); + expect(req.request.method).toBe("GET"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toBeNull(); + req.flush({}); + }); + + it("should make get all test case request", () => { + // TODO add mock so it is no longer calling the real service + service.getTestCases$("direct path", "fileName.xml").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "direct path"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-cases`); + expect(req.request.method).toBe("GET"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toBeNull(); + req.flush({}); + }); +}); diff --git a/ui-src/src/app/test-cases/test-case.service.ts b/ui-src/src/app/test-cases/test-case.service.ts new file mode 100644 index 0000000..53c6b0a --- /dev/null +++ b/ui-src/src/app/test-cases/test-case.service.ts @@ -0,0 +1,44 @@ +import {Injectable} from "@angular/core"; +import {HttpClient, HttpHeaders} from "@angular/common/http"; +import {TestCasesComponent} from "./test-cases.component"; +import {Observable} from "rxjs/Observable"; +import { environment } from '../../environments/environment'; + +@Injectable() +export class TestCaseService { + + private headers: HttpHeaders; + constructor(private http: HttpClient) { + this.headers = new HttpHeaders({"Content-Type": "application/json"}); + } + + getTestCases$(testCasePath): Observable { + this.headers = this.headers.set("path", testCasePath); + return this.http.get(`${environment.API_BASE_URL}test-cases`, { + headers: this.headers + }); + } + + postTestCase$(testCaseData, testCasePath): Observable { + this.headers = this.headers.set("path", testCasePath); + return this.http.post(`${environment.API_BASE_URL}test-cases`, testCaseData, { + headers: this.headers + }); + } + + getTestCase$(testCasePath, testCaseFileName): Observable { + this.headers = this.headers.set("path", testCasePath); + return this.http.get(`${environment.API_BASE_URL}test-cases/${testCaseFileName}`, { + headers: this.headers + }); + } + + putTestCase$(testCaseData, testCasePath, testCaseFileName): Observable { + this.headers = this.headers.set("path", testCasePath); + return this.http.put( + `${environment.API_BASE_URL}test-cases/${testCaseFileName}`, + testCaseData, + { headers: this.headers } + ); + } +} diff --git a/ui-src/src/app/test-cases/test-cases.component.css b/ui-src/src/app/test-cases/test-cases.component.css index 8b13789..95792d7 100644 --- a/ui-src/src/app/test-cases/test-cases.component.css +++ b/ui-src/src/app/test-cases/test-cases.component.css @@ -1 +1,69 @@ +.row { + margin-top: 25px; + margin-bottom: 25px; + } + .button-row { margin-top: 25px;} + .column { + + padding: 0px; + } + + table { + + font-family: arial, sans-serif; + border-collapse: collapse; + width: 100%; + margin-bottom: 25px; + +} + +td, th { + border: 1px solid #dddddd; + text-align: left; + padding: 8px; +} + +tr:nth-child(even) { + background-color: #dddddd; +} + +.btn{ + margin-bottom: 25px; +} + +submit-widget{ + display : none; +} + +h1{ + font-family: arial, sans-serif; + font-weight: bold; + margin-top: 0px; + font-size: 16px; + line-height: 1.42857143; + color: #333; +} + +.load-button { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + margin-top: 18px; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 1px; +} diff --git a/ui-src/src/app/test-cases/test-cases.component.html b/ui-src/src/app/test-cases/test-cases.component.html index ec92454..48014c9 100644 --- a/ui-src/src/app/test-cases/test-cases.component.html +++ b/ui-src/src/app/test-cases/test-cases.component.html @@ -1 +1,42 @@ -

test-cases works

\ No newline at end of file +
+
+
+ + +
+
+ +
+
+
+ +
+

Existing Test Cases

+ + + + + + + + + + + + + +
Name DescriptionHttp Method
{{testCase.testname}}{{testCase.description}}{{testCase.httpMethod}}
+
+
+ + + + +
+ + + +
+
+
+
\ No newline at end of file diff --git a/ui-src/src/app/test-cases/test-cases.component.spec.ts b/ui-src/src/app/test-cases/test-cases.component.spec.ts index 161be17..db68d9d 100644 --- a/ui-src/src/app/test-cases/test-cases.component.spec.ts +++ b/ui-src/src/app/test-cases/test-cases.component.spec.ts @@ -1,24 +1,39 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; - -import { TestCasesComponent } from "./test-cases.component"; +import {async, fakeAsync, ComponentFixture, TestBed} from "@angular/core/testing"; +import {TestCasesComponent} from "./test-cases.component"; +import {TestSuiteService} from "../test-suites/test-suite.service"; +import {ConfigurationService} from "../configurations/configuration.service"; +import {TestCaseService} from "../test-cases/test-case.service"; +import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from "@angular/core"; +import {ToastModule} from "ng2-toastr/ng2-toastr"; +import {HttpClientModule} from "@angular/common/http"; +import {FormsModule} from "@angular/forms"; +import {ToastsManager, ToastOptions} from "ng2-toastr/ng2-toastr"; +import {Observable} from "rxjs/Observable"; +import "rxjs/add/observable/of"; +import "rxjs/add/observable/throw"; describe("TestCasesComponent", () => { let component: TestCasesComponent; let fixture: ComponentFixture; + let testSuiteService, toastr; beforeEach( async(() => { TestBed.configureTestingModule({ - declarations: [TestCasesComponent] + providers: [ConfigurationService, ToastsManager, ToastOptions, TestSuiteService, TestCaseService], + declarations: [TestCasesComponent], + imports: [FormsModule, HttpClientModule, ToastModule.forRoot()], + schemas: [NO_ERRORS_SCHEMA, + CUSTOM_ELEMENTS_SCHEMA] }).compileComponents(); - }) - ); - beforeEach(() => { - fixture = TestBed.createComponent(TestCasesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TestCasesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + testSuiteService = TestBed.get(TestSuiteService); + toastr = TestBed.get(ToastsManager); + })); it("should create", () => { expect(component).toBeTruthy(); diff --git a/ui-src/src/app/test-cases/test-cases.component.ts b/ui-src/src/app/test-cases/test-cases.component.ts index 977b195..919cb9d 100644 --- a/ui-src/src/app/test-cases/test-cases.component.ts +++ b/ui-src/src/app/test-cases/test-cases.component.ts @@ -1,8 +1,155 @@ import { Component, OnInit } from "@angular/core"; +import { ConfigurationService } from "../configurations/configuration.service"; +import { TestCaseService } from "./test-case.service"; +import { ToastsManager } from "ng2-toastr/ng2-toastr"; +import { JsonSchemaFormModule } from "angular2-json-schema-form"; +import { HttpClient } from "@angular/common/http"; +import "rxjs/add/operator/map"; @Component({ selector: "app-test-cases", templateUrl: "./test-cases.component.html", styleUrls: ["./test-cases.component.css"] }) -export class TestCasesComponent {} +export class TestCasesComponent implements OnInit { + testCaseData = {}; + testCasePath = undefined; + testCaseSchema = { layout: true }; + testCaseFileName = undefined; + testCases = []; + + + constructor( + private configurationService: ConfigurationService, + private testCaseService: TestCaseService, + private toastr: ToastsManager, + private http: HttpClient + ) { } + + ngOnInit() { + this.configurationService + .getSchema$("assets/testCase_schema.json") + .subscribe((data: any) => { + this.testCaseSchema = data; + }); + } + + onLoad() { + this.testCaseService.getTestCases$(this.testCasePath).subscribe( + (data: any) => { + this.testCases = data; + this.toastr.success("Your Test Cases have loaded!", "Success!"); + }, + error => { + switch (error.status) { + case 500: { + this.toastr.error("An error has occurred!", "Check the logs!"); + break; + } + case 400: { + this.toastr.error( + "No Test Case Directory added", + "An error occurred!" + ); + break; + } + default: { + this.toastr.error("An error occurred!"); + } + } + } + ); + } + + onSelectCase(testCase, i) { + this.testCaseData = testCase; + this.testCaseFileName = testCase.testname; + } + + onAdd() { + this.testCaseData = undefined; + this.testCaseFileName = undefined; + } + + onDelete() { } + + onSave(testCaseData) { + this.testCaseService.postTestCase$(testCaseData, this.testCasePath).subscribe( + data => { + this.toastr.success("Your data has been saved!", "Success!"); + }, + + error => { + switch (error.status) { + case 500: { + this.toastr.error("An error has occurred!", "Check the logs!"); + break; + } + case 409: { + this.toastr.error("File already exists!", "An error occurred!"); + break; + } + case 400: { + this.toastr.error( + "Some of the fields do not conform to the schema!", + "An error occurred!" + ); + break; + } + default: { + this.toastr.error("Your data did not save!", "An error occurred!"); + } + } + } + ); + } + + + onUpdate(testCaseData) { + this.testCaseService + .putTestCase$(testCaseData, this.testCasePath, this.testCaseFileName) + .subscribe( + data => { + this.toastr.success("Success!"); + this.onLoad(); + }, + error => { + switch (error.status) { + case 404: { + this.toastr.error("File not found", "An error occured!"); + + break; + } + case 400: { + this.toastr.error( + "File must be specified!", + "An error occurred!" + ); + break; + } + case 500: { + this.toastr.error("Internal server error!"); + break; + } + default: { + this.toastr.error("File was not updated!", "An error occurred!"); + } + } + } + ); + } + + onCancel() { + this.testCaseService + .getTestCase$(this.testCasePath, this.testCaseFileName) + .subscribe( + data => { + this.testCaseData = data; + this.toastr.success("Previous data reloaded!"); + }, + error => { + this.onAdd(); + } + ); + } +} diff --git a/ui-src/src/app/test-suites/test-suite.service.spec.ts b/ui-src/src/app/test-suites/test-suite.service.spec.ts new file mode 100644 index 0000000..36e36a2 --- /dev/null +++ b/ui-src/src/app/test-suites/test-suite.service.spec.ts @@ -0,0 +1,91 @@ +import {TestBed, inject, getTestBed} from "@angular/core/testing"; +import {HttpClientModule} from "@angular/common/http"; +import {HttpClient, HttpHeaders} from "@angular/common/http"; +import {environment} from "../../environments/environment"; +import { + HttpClientTestingModule, + HttpTestingController +} from "@angular/common/http/testing"; + +import {TestSuiteService} from "./test-suite.service"; + +describe("TestSuiteService", () => { + let injector; + let service; + let httpInterceptor: HttpTestingController; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientModule, HttpClientTestingModule], + providers: [TestSuiteService] + }); + + injector = getTestBed(); + service = injector.get(TestSuiteService); + httpInterceptor = injector.get(HttpTestingController); + }); + + it("should be created", () => { + expect(service).toBeTruthy(); + }); + + it("should make post test suite request", () => { + // TODO add mock so it is no longer calling the real service + service.postTestSuite$({data: "data1"}, "data2").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "data2"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-suites`); + expect(req.request.method).toBe("POST"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toEqual({data: "data1"}); + req.flush({}); + }); + + it("should make put test suite request", () => { + // TODO add mock so it is no longer calling the real service + service.putTestSuite$({data: "data1"}, "direct path", "fileName.xml").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "direct path"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-suites/fileName.xml`); + expect(req.request.method).toBe("PUT"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toEqual({data: "data1"}); + req.flush({}); + }); + + it("should make get test suite request", () => { + // TODO add mock so it is no longer calling the real service + service.getTestSuite$("direct path", "fileName.xml").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "direct path"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-suites/fileName.xml`); + expect(req.request.method).toBe("GET"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toBeNull(); + req.flush({}); + }); + + it("should make get all test suites request", () => { + // TODO add mock so it is no longer calling the real service + service.getTestSuites$("direct path", "fileName.xml").subscribe(() => {}); + + let headers = new HttpHeaders(); + headers = headers.set("Content-Type", "application/json;"); + headers = headers.append("configPathDir", "direct path"); + + const req = httpInterceptor.expectOne(`${environment.API_BASE_URL}test-suites`); + expect(req.request.method).toBe("GET"); + expect(req.request.headers.getAll).toBe(headers.getAll); + expect(req.request.body).toBeNull(); + req.flush({}); + }); +}); diff --git a/ui-src/src/app/test-suites/test-suite.service.ts b/ui-src/src/app/test-suites/test-suite.service.ts new file mode 100644 index 0000000..f13803d --- /dev/null +++ b/ui-src/src/app/test-suites/test-suite.service.ts @@ -0,0 +1,44 @@ +import {Injectable} from "@angular/core"; +import {HttpClient, HttpHeaders} from "@angular/common/http"; +import {TestSuitesComponent} from "./test-suites.component"; +import {Observable} from "rxjs/Observable"; +import {environment} from "../../environments/environment"; + +@Injectable() +export class TestSuiteService { + + private headers: HttpHeaders; + constructor(private http: HttpClient) { + this.headers = new HttpHeaders({"Content-Type": "application/json"}); + } + + postTestSuite$(testSuiteData, testSuitePath): Observable { + this.headers = this.headers.set("path", testSuitePath); + return this.http.post(`${environment.API_BASE_URL}test-suites`, testSuiteData, { + headers: this.headers + }); + } + + getTestSuite$(testSuitePath, testSuiteFileName): Observable { + this.headers = this.headers.set("path", testSuitePath); + return this.http.get(`${environment.API_BASE_URL}test-suites/${testSuiteFileName}`, { + headers: this.headers + }); + } + + getTestSuites$(testSuitePath): Observable { + this.headers = this.headers.set("path", testSuitePath); + return this.http.get(`${environment.API_BASE_URL}test-suites`, { + headers: this.headers + }); + } + + putTestSuite$(testSuiteData, testSuitePath, testSuiteFileName): Observable { + this.headers = this.headers.set("path", testSuitePath); + return this.http.put( + `${environment.API_BASE_URL}test-suites/${testSuiteFileName}`, + testSuiteData, + {headers: this.headers} + ); + } +} diff --git a/ui-src/src/app/test-suites/test-suites.component.css b/ui-src/src/app/test-suites/test-suites.component.css index e69de29..d0c6fff 100644 --- a/ui-src/src/app/test-suites/test-suites.component.css +++ b/ui-src/src/app/test-suites/test-suites.component.css @@ -0,0 +1,40 @@ +.row { + margin-top: 25px; + margin-bottom: 25px; + padding: 10px; +} +.button-row { + margin-top: 25px; +} +.column { + padding: 0px; +} + +table { + font-family: arial, sans-serif; + border-collapse: collapse; + width: 90%; + margin-bottom: 25px; + padding-right: 5px; +} + +td, +th { + border: 1px solid #dddddd; + text-align: left; + padding: 8px; +} + +tr:nth-child(even) { + background-color: #dddddd; +} + +.btn { + margin-bottom: 25px; +} +fieldset { + display: none; +} +submit-widget { + display: none; +} diff --git a/ui-src/src/app/test-suites/test-suites.component.html b/ui-src/src/app/test-suites/test-suites.component.html index 8f39c17..b491270 100644 --- a/ui-src/src/app/test-suites/test-suites.component.html +++ b/ui-src/src/app/test-suites/test-suites.component.html @@ -1 +1,38 @@ -

test-suite works

\ No newline at end of file +
+
+ + +
+ +
+
+ + + + + + + + + + +
Name Description
{{testSuite.name}}{{testSuite.description}}
+
+ +
+
+ + + + + +
+ + + +
+ +
+
+
\ No newline at end of file diff --git a/ui-src/src/app/test-suites/test-suites.component.spec.ts b/ui-src/src/app/test-suites/test-suites.component.spec.ts index a7d333c..14aaeba 100644 --- a/ui-src/src/app/test-suites/test-suites.component.spec.ts +++ b/ui-src/src/app/test-suites/test-suites.component.spec.ts @@ -1,24 +1,39 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; - -import { TestSuitesComponent } from "./test-suites.component"; +import {async, fakeAsync, ComponentFixture, TestBed} from "@angular/core/testing"; +import {TestSuitesComponent} from "./test-suites.component"; +import {TestSuiteService} from "./test-suite.service"; +import {ConfigurationService} from "../configurations/configuration.service"; +import {TestCaseService} from "../test-cases/test-case.service"; +import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from "@angular/core"; +import {ToastModule} from "ng2-toastr/ng2-toastr"; +import {HttpClientModule} from "@angular/common/http"; +import {FormsModule} from "@angular/forms"; +import {ToastsManager, ToastOptions} from "ng2-toastr/ng2-toastr"; +import {Observable} from "rxjs/Observable"; +import "rxjs/add/observable/of"; +import "rxjs/add/observable/throw"; describe("TestSuitesComponent", () => { let component: TestSuitesComponent; let fixture: ComponentFixture; + let testSuiteService, toastr; beforeEach( async(() => { TestBed.configureTestingModule({ - declarations: [TestSuitesComponent] + providers: [ConfigurationService, ToastsManager, ToastOptions, TestSuiteService, TestCaseService], + declarations: [TestSuitesComponent], + imports: [FormsModule, HttpClientModule, ToastModule.forRoot()], + schemas: [NO_ERRORS_SCHEMA, + CUSTOM_ELEMENTS_SCHEMA] }).compileComponents(); - }) - ); - beforeEach(() => { - fixture = TestBed.createComponent(TestSuitesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TestSuitesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + testSuiteService = TestBed.get(TestSuiteService); + toastr = TestBed.get(ToastsManager); + })); it("should create", () => { expect(component).toBeTruthy(); diff --git a/ui-src/src/app/test-suites/test-suites.component.ts b/ui-src/src/app/test-suites/test-suites.component.ts index 5e5db2f..73bff17 100644 --- a/ui-src/src/app/test-suites/test-suites.component.ts +++ b/ui-src/src/app/test-suites/test-suites.component.ts @@ -1,8 +1,166 @@ -import { Component, OnInit } from "@angular/core"; - +import {Component, OnInit, Input, Output, EventEmitter} from "@angular/core"; +import {TestSuiteService} from "./test-suite.service"; +import {TestCaseService} from "../test-cases/test-case.service"; +import {ConfigurationService} from "../configurations/configuration.service"; +import {ToastsManager} from "ng2-toastr/ng2-toastr"; +import {TestCasesSelectionComponent} from "../shared/test-cases-selection/test-cases-selection.component"; @Component({ selector: "app-test-suites", templateUrl: "./test-suites.component.html", styleUrls: ["./test-suites.component.css"] }) -export class TestSuitesComponent {} +export class TestSuitesComponent implements OnInit { + testSuitePath = undefined; + testCaseArray = []; + testSuites = []; + selectedTestCaseData = []; + testSuiteData = {}; + testCases = []; + testSuiteFileName = undefined; + testSuiteFileNameTruncated = undefined; + testSuiteSchema = {layout: true}; + + constructor( + private testSuiteService: TestSuiteService, + private testCaseService: TestCaseService, + private configurationService: ConfigurationService, + private toastr: ToastsManager + ) {} + + ngOnInit() { + this.configurationService + .getSchema$("assets/testSuite_schema.json") + .subscribe((data: any) => { + this.testSuiteSchema = data; + }); + } + + onAdd() { + this.testSuiteService.getTestSuites$(this.testSuitePath).subscribe( + data => { + this.testSuites = data; + }, + + error => { + switch (error.status) { + case 500: { + this.toastr.error("An error has occurred!", "Check the logs!"); + break; + } + case 400: { + this.toastr.error( + "No Test Suite Directory added", + "An error occurred!" + ); + break; + } + default: { + this.toastr.error("An error occurred!"); + } + } + } + ); + } + + getTestCases() { + this.testCaseService + .getTestCases$(this.testSuitePath) + .subscribe((data: any) => (this.testCases = data)); + } + + onCancel() { + this.toastr.success("Your data has been cleared", "Success!"); + this.testSuiteData = undefined; + this.selectedTestCaseData = []; + this.testSuiteFileName = undefined; + this.onAdd(); + } + + truncateFileName() { + if (this.testSuiteFileName) { + this.testSuiteFileNameTruncated = this.testSuiteFileName.substring( + 0, + this.testSuiteFileName.length - 4 + ); + } + } + + onUpdate(formData) { + this.truncateFileName(); + this.testCaseArray["testCases"] = this.selectedTestCaseData; + Object.assign(formData, this.testCaseArray); + this.testSuiteService + .putTestSuite$(formData, this.testSuitePath, this.testSuiteFileNameTruncated) + .subscribe( + data => { + this.toastr.success("Success!"); + this.onAdd(); + }, + error => { + switch (error.status) { + case 404: { + this.toastr.error("File not found", "An error occured!"); + break; + } + case 400: { + this.toastr.error( + "File must be specified!", + "An error occurred!" + ); + break; + } + case 500: { + this.toastr.error("Internal server error!"); + break; + } + default: { + this.toastr.error("File was not updated!", "An error occurred!"); + } + } + } + ); + } + + onSave(formData) { + this.testCaseArray["testCases"] = this.selectedTestCaseData; + Object.assign(formData, this.testCaseArray); + this.testSuiteService.postTestSuite$(formData, this.testSuitePath).subscribe( + data => { + this.toastr.success("Your data has been saved!", "Success!"); + this.onAdd(); + }, + error => { + switch (error.status) { + case 500: { + this.toastr.error("An error has occurred!", "Check the logs!"); + break; + } + case 400: { + this.toastr.error( + "Some of the fields do not conform to the schema!", + "An error occurred!" + ); + break; + } + default: { + this.toastr.error("Your data did not save!", "An error occurred!"); + } + } + } + ); + } + + onSelectSuite(testSuite, selectedIndex) { + this.onAdd(); + this.testSuiteData = testSuite; + this.selectedTestCaseData = testSuite.testCases; + this.testSuiteFileName = testSuite.file; + } + updateSelected(testCase) { + this.selectedTestCaseData.push(testCase); + + } + onReverse(selectedIndex) { + this.selectedTestCaseData.splice(selectedIndex, 1); + } +} diff --git a/ui-src/src/assets/schema.json b/ui-src/src/assets/schema.json index 50ec856..1109f1c 100644 --- a/ui-src/src/assets/schema.json +++ b/ui-src/src/assets/schema.json @@ -18,17 +18,30 @@ "baseStatsOutputDir", "reportOutputDir" ], + "additionalProperties": false, "properties": { - "apiName": { "type": "string" }, - "targetHost": { "type": "string" }, + "apiName": { + "type": "string" + }, + "targetHost": { + "type": "string" + }, "targetPort": { "type": "string", "minimum": 1, "maximum": 65535 }, - "memoryEndpoint": { "type": "string" }, - "numIterations": { "type": "integer", "minimum": 1 }, - "concurrentUsers": { "type": "integer", "minimum": 1 }, + "memoryEndpoint": { + "type": "string" + }, + "numIterations": { + "type": "integer", + "minimum": 1 + }, + "concurrentUsers": { + "type": "integer", + "minimum": 1 + }, "allowablePeakMemoryVariance": { "type": "number", "minimum": 0, @@ -41,24 +54,54 @@ }, "testSuite": { "type": "string", - "enum": ["Default-1", "Default-2", "Default-3"] - }, - "requestDelay": { "type": "integer", "minimum": 1 }, - "TPSFreq": { "type": "integer", "minimum": 1 }, - "rampUsers": { "type": "integer", "minimum": 1 }, - "rampDelay": { "type": "integer", "minimum": 0 }, - "testCaseDir": { "type": "string" }, - "testSuiteDir": { "type": "string" }, - "baseStatsOutputDir": { "type": "string" }, - "reportOutputDir": { "type": "string" } + "enum": [ + "Default-1", + "Default-2", + "Default-3" + ] + }, + "requestDelay": { + "type": "integer", + "minimum": 1 + }, + "TPSFreq": { + "type": "integer", + "minimum": 1 + }, + "rampUsers": { + "type": "integer", + "minimum": 1 + }, + "rampDelay": { + "type": "integer", + "minimum": 0 + }, + "testCaseDir": { + "type": "string" + }, + "testSuiteDir": { + "type": "string" + }, + "baseStatsOutputDir": { + "type": "string" + }, + "reportOutputDir": { + "type": "string" + } }, - "layout" : [ + "layout": [ { "type": "flex", "flex-flow": "row wrap", "items": [ "apiName", + { + "md": 4 + }, "numIterations", + { + "md": 4 + }, { "key": "requestDelay", "title": "Request Delay (ms)" @@ -70,7 +113,13 @@ "flex-flow": "row wrap", "items": [ "targetHost", + { + "md": 4 + }, "concurrentUsers", + { + "md": 4 + }, { "key": "TPSFreq", "title": "TPS Frequency (s)" @@ -82,10 +131,16 @@ "flex-flow": "row wrap", "items": [ "targetPort", + { + "md": 4 + }, { "key": "allowablePeakMemoryVariance", "title": "Memory Variance (%)" }, + { + "md": 4 + }, "rampUsers" ] }, @@ -94,21 +149,43 @@ "flex-flow": "row wrap", "items": [ "memoryEndpoint", + { + "md": 4 + }, { "key": "allowableServiceResponseTimeVariance", "title": "Service Variance (%)" }, + { + "md": 4 + }, { "key": "rampDelay", "title": "Ramp Delay (s)" } ] }, - { "key": "testSuite" }, - { "key": "testCaseDir", "title": "Test Case Directory" }, - { "key": "testSuiteDir", "title": "Test Suites Directory" }, - { "key": "baseStatsOutputDir", "title": "Base Stats Output Directory" }, - { "key": "reportOutputDir", "title": "Report Output Directory" } - + { + "key": "testSuite" + }, + { + "key": "testCaseDir", + "title": "Test Case Directory" + }, + { + "key": "testSuiteDir", + "title": "Test Suites Directory" + }, + { + "key": "baseStatsOutputDir", + "title": "Base Stats Output Directory" + }, + { + "key": "reportOutputDir", + "title": "Report Output Directory" + } ] -} \ No newline at end of file +} + + + diff --git a/ui-src/src/assets/testCase_schema.json b/ui-src/src/assets/testCase_schema.json index 401a5f0..2b8da10 100644 --- a/ui-src/src/assets/testCase_schema.json +++ b/ui-src/src/assets/testCase_schema.json @@ -4,50 +4,69 @@ "testname", "overridePort", "overrideHost", - "HttpMethod", - "BaseURI", + "httpMethod", + "baseUri", "multipart", + "multipartPayload", "payload", "responseStatusCode", "responseContentType", "preThinkTime", "postThinkTime", "execWeight", - "Headers", - "ResponseValues", - "MultipartPayload" + "headers", + "responseValues" ], + "additionalProperties": false, "properties": { - "overridePort": { - "type": "string" - }, "testname": { "type": "string" }, "description": { "type": "string" }, - "overrideHost": { + "baseUri": { "type": "string" }, - "HttpMethod": { - "type": "string", - "enum": ["POST","GET","PUT","DELETE"] - }, - "BaseURI": { + "overrideHost": { "type": "string" }, "multipart": { "type": "boolean" }, + "overridePort": { + "type": "string" + }, "payload": { "type": "string" }, - "responseStatusCode": { - "type": "number" + "httpMethod": { + "type": "string", + "enum": [ + "POST", + "GET", + "PUT", + "DELETE" + ] }, - "responseContentType": { - "type": "string" + "headers": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } }, "preThinkTime": { "type": "number" @@ -57,56 +76,52 @@ }, "execWeight": { "type": "string", - "enum": ["Sparse","Infrequent"] + "enum": [ + "Sparse", + "Infrequent" + ] + }, + "responseStatusCode": { + "type": "number" + }, + "responseContentType": { + "type": "string" }, - "Headers": { + "multipartPayload": { "type": "array", "items": { "type": "object", "additionalProperties": false, - "required": ["Key", "Value"], "properties": { - "Key": { + "fieldName": { "type": "string" }, - "Value": { + "fieldValue":{ + "type": "string" + }, + "fileName": { "type": "string" } } } }, - "ResponseValues": { + "responseValues": { "type": "array", "items": { "type": "object", "additionalProperties": false, - "required": ["Value", "ExtractionKey"], + "required": [ + "value", + "extractionKey" + ], "properties": { - "Value": { + "extractionKey": { "type": "string" }, - "ExtractionKey": { + "value": { "type": "string" } } - }, - "MultipartPayload": { - "type": "array", - "items": { - "type": "object", - "required": ["FieldName", "FieldValue","FileName", "FileContent"], - "properties": { - "fieldName": { - "type": "string" - }, - "FieldValue": { - "type": "string" - }, - "FileName": { - "type": "string" - } - } - } } } } diff --git a/ui-src/src/assets/testSuite_schema.json b/ui-src/src/assets/testSuite_schema.json index 745e1a3..28274d9 100644 --- a/ui-src/src/assets/testSuite_schema.json +++ b/ui-src/src/assets/testSuite_schema.json @@ -15,28 +15,30 @@ }, "testCases": { "type": "array", - "items": { + "testCases": { "type": "object", "additionalProperties": false, - "required": ["name"], + "required": [ + "name", + "preThinkTime", + "postThinkTime", + "execWeight" + ], "properties": { - "preThinkTime": { - "type": "integer", - "minimum": 0 - }, - "postThinkTime": { - "type": "integer", - "minimum": 0 - }, - "execWeight": { - "type": "string", - "enum": ["Infrequent", "Sparse"] + "key": { + "type": "string" }, - "name": { + "value": { "type": "string" } } } } - } -} + }} + + + + + + + diff --git a/ui-src/src/environments/environment.prod.ts b/ui-src/src/environments/environment.prod.ts index da91497..6ae38d1 100644 --- a/ui-src/src/environments/environment.prod.ts +++ b/ui-src/src/environments/environment.prod.ts @@ -1,6 +1,5 @@ export const environment = { production: true, - - apiBaseUrl: "http://localhost:9191/" - + API_BASE_URL: "http://localhost:9191/", + ASSESTS_BASE_URL: "http://localhost:9191/" }; diff --git a/ui-src/src/environments/environment.ts b/ui-src/src/environments/environment.ts index b7f639a..dc92f2b 100644 --- a/ui-src/src/environments/environment.ts +++ b/ui-src/src/environments/environment.ts @@ -4,5 +4,7 @@ // The list of which env maps to which file can be found in `.angular-cli.json`. export const environment = { - production: false + production: false, + API_BASE_URL: "http://localhost:9191/", + ASSESTS_BASE_URL: "http://localhost:4200/" }; diff --git a/ui-src/src/styles.css b/ui-src/src/styles.css index dba64b8..5e244ec 100644 --- a/ui-src/src/styles.css +++ b/ui-src/src/styles.css @@ -2,7 +2,9 @@ /* You can add global styles to this file, and also import other style files */ @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700'); @import url('https://fonts.googleapis.com/icon?family=Material+Icons'); -@import "~@angular/material/prebuilt-themes/indigo-pink.css"; +@import './app/configurations/configurations.component.css'; +@import './app/test-suites/test-suites.component.css'; +@import "./app/test-cases/test-cases.component.css"; diff --git a/ui-src/tslint.json b/ui-src/tslint.json index 09f179b..2517c6a 100644 --- a/ui-src/tslint.json +++ b/ui-src/tslint.json @@ -1,22 +1,37 @@ { - "rulesDirectory": ["node_modules/codelyzer"], + "rulesDirectory": [ + "node_modules/codelyzer" + ], "rules": { "arrow-return-shorthand": true, "callable-types": true, "class-name": true, - "comment-format": [true, "check-space"], + "comment-format": [ + true, + "check-space" + ], "curly": true, "deprecation": { "severity": "warn" }, "eofline": true, "forin": true, - "import-blacklist": [true, "rxjs", "rxjs/Rx"], + "import-blacklist": [ + true, + "rxjs", + "rxjs/Rx" + ], "import-spacing": true, - "indent": [true, "spaces"], + "indent": [ + true, + "spaces" + ], "interface-over-type-literal": true, "label-position": true, - "max-line-length": [true, 140], + "max-line-length": [ + true, + 140 + ], "member-access": false, "member-ordering": [ true, @@ -31,14 +46,24 @@ ], "no-arg": true, "no-bitwise": true, - "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-empty": false, "no-empty-interface": true, "no-eval": true, - "no-inferrable-types": [true, "ignore-params"], + "no-inferrable-types": [ + true, + "ignore-params" + ], "no-misused-new": true, "no-non-null-assertion": true, "no-shadowed-variable": true, @@ -59,10 +84,19 @@ "check-whitespace" ], "prefer-const": true, - "quotemark": [true, "double"], + "quotemark": [ + true, + "double" + ], "radix": true, - "semicolon": [true, "always"], - "triple-equals": [true, "allow-null-check"], + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], "typedef-whitespace": [ true, { @@ -84,8 +118,18 @@ "check-separator", "check-type" ], - "directive-selector": [true, "attribute", "app", "camelCase"], - "component-selector": [true, "element", "app", "kebab-case"], + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], "no-output-on-prefix": true, "use-input-property-decorator": true, "use-output-property-decorator": true, @@ -97,4 +141,4 @@ "component-class-suffix": true, "directive-class-suffix": true } -} +} \ No newline at end of file diff --git a/uiServices/src/configServices.go b/uiServices/src/configServices.go index fe6b204..2ee1ec4 100644 --- a/uiServices/src/configServices.go +++ b/uiServices/src/configServices.go @@ -15,17 +15,10 @@ import ( "github.com/xtracdev/automated-perf-test/perfTestUtils" ) -var schemaFilename string = "schema.json" -var structName string = "Config" - -func getConfigHeader(req *http.Request) string { - configPathDir := req.Header.Get("configPathDir") - - if !strings.HasSuffix(configPathDir, "/") { - configPathDir = configPathDir + "/" - } - return configPathDir -} +const ( + configSchema = "schema.json" + configStruct = "Config" +) func IsHeaderValid(header string) error { if len(header) <= 1 { @@ -43,13 +36,12 @@ func IsNameValid(name string) error { return nil } -func IsPathDirValid(name string, rw http.ResponseWriter) bool { +func IsPathDirValid(name string) error { if len(name) <= 1 { - logrus.Error("No file directory entered") - rw.WriteHeader(http.StatusBadRequest) - return false + logrus.Error("No directory path entered") + return fmt.Errorf("No directory path entered") } - return true + return nil } func ConfigCtx(next http.Handler) http.Handler { @@ -59,11 +51,12 @@ func ConfigCtx(next http.Handler) http.Handler { } func postConfigs(rw http.ResponseWriter, req *http.Request) { - configPathDir := req.Header.Get("configPathDir") + rw.Header().Set("Access-Control-Allow-Origin", "*") + configPathDir := getPathHeader(req) buf := new(bytes.Buffer) buf.ReadFrom(req.Body) - if !ValidateJSONWithSchema(buf.Bytes(), "schema.json", "Configurations") { + if !validateJSONWithSchema(buf.Bytes(), "schema.json", "Configurations") { rw.WriteHeader(http.StatusBadRequest) return } @@ -102,7 +95,7 @@ func postConfigs(rw http.ResponseWriter, req *http.Request) { } - if !configWriterXML(config, configPathDir+config.APIName+".xml") { + if !writeXML(config, configPathDir+config.APIName+".xml") { rw.WriteHeader(http.StatusInternalServerError) return @@ -111,14 +104,9 @@ func postConfigs(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusCreated) } -func FilePathExist(path string) bool { - _, err := os.Stat(path) - return !os.IsNotExist(err) -} - func getConfigs(rw http.ResponseWriter, req *http.Request) { - - configPathDir := getConfigHeader(req) + rw.Header().Set("Access-Control-Allow-Origin", "*") + configPathDir := getPathHeader(req) configName := chi.URLParam(req, "configName") if err := IsHeaderValid(configPathDir); err != nil { @@ -152,14 +140,14 @@ func getConfigs(rw http.ResponseWriter, req *http.Request) { err = xml.Unmarshal(byteValue, &config) if err != nil { rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot Unmarshall") + logrus.Error("Cannot Unmarshall XML ", err) return } configJson, err := json.MarshalIndent(config, "", "") if err != nil { rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot Marshall") + logrus.Error("Cannot Marshall JSON", err) return } @@ -170,7 +158,7 @@ func getConfigs(rw http.ResponseWriter, req *http.Request) { } func putConfigs(rw http.ResponseWriter, req *http.Request) { - path := getConfigHeader(req) + path := getPathHeader(req) configName := chi.URLParam(req, "configName") if err := IsHeaderValid(path); err != nil { @@ -187,7 +175,7 @@ func putConfigs(rw http.ResponseWriter, req *http.Request) { buf := new(bytes.Buffer) buf.ReadFrom(req.Body) - if !ValidateJSONWithSchema(buf.Bytes(), schemaFilename, structName) { + if !validateJSONWithSchema(buf.Bytes(), configSchema, configStruct) { rw.WriteHeader(http.StatusBadRequest) return } @@ -207,7 +195,7 @@ func putConfigs(rw http.ResponseWriter, req *http.Request) { } - if !configWriterXML(config, configPathDir) { + if !writeXML(config, configPathDir) { rw.WriteHeader(http.StatusInternalServerError) return } @@ -216,7 +204,7 @@ func putConfigs(rw http.ResponseWriter, req *http.Request) { } func putConfigFileName(rw http.ResponseWriter, req *http.Request) { - path := getConfigHeader(req) + path := getPathHeader(req) configFileName := chi.URLParam(req, "configFileName") newConfigFileName := chi.URLParam(req, "newConfigFileName") diff --git a/uiServices/src/configServices_test.go b/uiServices/src/configServices_test.go index c538322..e9fac6a 100644 --- a/uiServices/src/configServices_test.go +++ b/uiServices/src/configServices_test.go @@ -1,8 +1,6 @@ package services import ( - "fmt" - "net/http" "net/http/httptest" "os" @@ -14,7 +12,7 @@ import ( "github.com/xtracdev/automated-perf-test/perfTestUtils" ) -const validJSON = `{ +const validJson = `{ "apiName": "ServiceTestConfig", "targetHost": "localhost", "targetPort": "9191", @@ -94,22 +92,6 @@ const validJsonWithOneCharName = `{ "rampDelay": 15 }` -func TestFilePathExist(t *testing.T) { - path := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" - actual := false - fmt.Println(path) - actual = FilePathExist(path) - expected := true - assert.Equal(t, expected, actual) -} - -func TestFilePathDoesNotExist(t *testing.T) { - path := "(((((((" - actual := FilePathExist(path) - expected := false - assert.Equal(t, expected, actual) -} - func TestInvalidJsonPostMissingRequiredField(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) @@ -119,7 +101,7 @@ func TestInvalidJsonPostMissingRequiredField(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPost, "/configs", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -138,25 +120,23 @@ func TestValidJsonPost(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", postConfigs) os.Remove(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/ServiceTestConfig.xml") filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/configs", reader) - request.Header.Set("configPathDir", filePath) + + assert.NoError(t, err) + + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) - if err != nil { - t.Error(err) - } + assert.Equal(t, http.StatusCreated, w.Code) - if w.Code != http.StatusCreated { - t.Error("TestValidJsonPost. Expected:", http.StatusCreated, " Got:", w.Code, " Error. Did not succesfully post") - } } func TestPostWithOneCharName(t *testing.T) { @@ -170,7 +150,7 @@ func TestPostWithOneCharName(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/configs", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -187,12 +167,12 @@ func TestPostWithInvalidHeader(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", postConfigs) filePath := "xxxxxx" request, err := http.NewRequest(http.MethodPost, "/configs", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -227,11 +207,11 @@ func TestInvalidJsonPost(t *testing.T) { } } -func TestWhenConfigPathDirEmpty(t *testing.T) { +func TestWhenpathEmpty(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", postConfigs) request, err := http.NewRequest(http.MethodPost, "/configs", reader) @@ -244,13 +224,13 @@ func TestWhenConfigPathDirEmpty(t *testing.T) { } if w.Code != http.StatusBadRequest { - t.Error("TestWhenConfigPathDirEmpty. Expected:", http.StatusBadRequest, " Got:", w.Code, "Error. ConfigPathDir is Empty ") + t.Error("TestWhenpathEmpty. Expected:", http.StatusBadRequest, " Got:", w.Code, "Error. path is Empty ") } } func TestInvalidURL(t *testing.T) { pt := perfTestUtils.Config{} - configWriterXML(pt, "/path/xxx") + writeXML(pt, "/path/xxx") } func TestSuccessfulGet(t *testing.T) { @@ -258,12 +238,12 @@ func TestSuccessfulGet(t *testing.T) { r.Mount("/", GetIndexPage()) // create file to GET - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", postConfigs) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPost, "/configs", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -271,8 +251,8 @@ func TestSuccessfulGet(t *testing.T) { filePath = os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err = http.NewRequest(http.MethodGet, "/configs/ServiceTestConfig", nil) - request.Header.Set("configPathDir", filePath) - request.Header.Get("configPathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w = httptest.NewRecorder() r.ServeHTTP(w, request) @@ -295,8 +275,8 @@ func TestSuccessfulGetPathWihoutSlash(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodGet, "/configs/ServiceTestConfig", nil) - request.Header.Set("configPathDir", filePath) - request.Header.Get("configPathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -319,8 +299,8 @@ func TestGetNoHeaderPath(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodGet, "/configs/serviceTestConfig", nil) - request.Header.Set("configPathDir", filePath) - request.Header.Get("configPathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -343,8 +323,8 @@ func TestGetFileNotFound(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodGet, "/configs/xxx.java", nil) - request.Header.Set("configPathDir", filePath) - request.Header.Get("configPathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -362,12 +342,12 @@ func TestValidJsonPut(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", putConfigs) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/configs/ServiceTestConfig", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -388,7 +368,7 @@ func TestMissingFieldPut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/configs/ServiceTestConfig", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -409,7 +389,7 @@ func TestInvalidJsonPut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/configs/ServiceTestConfig", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -425,12 +405,12 @@ func TestInvalidUrlPut(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", putConfigs) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/configs/xxx", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -446,12 +426,12 @@ func TestNoUrlPut(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", putConfigs) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -467,12 +447,12 @@ func TestSuccessfulPutWithNoPathSlash(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", putConfigs) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPut, "/configs/ServiceTestConfig", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -487,12 +467,12 @@ func TestNoPathPut(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", putConfigs) filePath := "" request, err := http.NewRequest(http.MethodPut, "/configs/ServiceTestConfig", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -508,12 +488,12 @@ func TestNoFileNamePut(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validJSON) + reader := strings.NewReader(validJson) r.HandleFunc("/configs", putConfigs) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPut, "/configs", reader) - request.Header.Set("configPathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) diff --git a/uiServices/src/homepage.go b/uiServices/src/homepage.go index b2b0bb2..0dab8c3 100644 --- a/uiServices/src/homepage.go +++ b/uiServices/src/homepage.go @@ -1,25 +1,21 @@ package services import ( - "io/ioutil" - "net/http" - "path/filepath" -<<<<<<< HEAD - "github.com/go-chi/cors" -======= - "github.com/Sirupsen/logrus" "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" + "github.com/go-chi/cors" + "io/ioutil" + "net/http" + "path/filepath" ->>>>>>> 3739ecf74b1ebdd56489c07d1e556eb8b43fb1fd "os" ) const contentTypeHeader = `Content-Type` const htmlType = `text/html` -func StartUiMode() { +func StartUIMode() { http.ListenAndServe(":9191", GetRouter()) } @@ -78,9 +74,9 @@ func GetIndexPage() *chi.Mux { router.Get("/*", func(w http.ResponseWriter, r *http.Request) { - resourceUrl := r.URL.String() + resourceURL := r.URL.String() - path := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/ui/" + resourceUrl + path := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/ui/" + resourceURL absPath, err := filepath.Abs(path) @@ -118,6 +114,7 @@ func routeConfigs() http.Handler { router.Post("/", postConfigs) router.Get("/{configName}", getConfigs) router.Put("/{configName}", putConfigs) + router.Put("/filename/{configFileName}/{newConfigFileName}", putConfigFileName) return router } @@ -142,6 +139,7 @@ func routeTestCases() http.Handler { router.Get("/", getAllTestCases) router.Get("/{testCaseName}", getTestCase) router.Delete("/{testCaseName}", deleteTestCase) + router.Delete("/", deleteAllTestCases) return router } diff --git a/uiServices/src/homepage_test.go b/uiServices/src/homepage_test.go deleted file mode 100644 index 85961c3..0000000 --- a/uiServices/src/homepage_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package services - -import ( - "github.com/go-chi/chi" - "github.com/stretchr/testify/assert" - "net/http" - "net/http/httptest" - "testing" -) - -func TestStartUiModeSuccesfully(t *testing.T) { - - r := chi.NewRouter() - - r.Mount("/", GetIndexPage()) - - assert.IsType(t, &chi.Mux{}, r) - - resp := httptest.NewRecorder() - - req, _ := http.NewRequest(http.MethodGet, "/", nil) - r.ServeHTTP(resp, req) - - assert.Equal(t, http.StatusOK, resp.Code) - assert.Equal(t, htmlType, resp.Header().Get(contentTypeHeader)) - -} - -func TestStartUiModeWithInvalidURL(t *testing.T) { - - r := chi.NewRouter() - - r.Mount("/", GetIndexPage()) - - assert.IsType(t, &chi.Mux{}, r) - - resp := httptest.NewRecorder() - - req, _ := http.NewRequest(http.MethodGet, "/xxx", nil) - r.ServeHTTP(resp, req) - - assert.Equal(t, http.StatusNotFound, resp.Code) -} - -func TestStartUiModeWithResource(t *testing.T) { - - r := chi.NewRouter() - - r.Mount("/", GetIndexPage()) - - assert.IsType(t, &chi.Mux{}, r) - - resp := httptest.NewRecorder() - - req, _ := http.NewRequest(http.MethodGet, "/index.html", nil) - r.ServeHTTP(resp, req) - - assert.Equal(t, http.StatusOK, resp.Code) - assert.Equal(t, htmlType, resp.Header().Get(contentTypeHeader)) - -} diff --git a/uiServices/src/testCaseServices.go b/uiServices/src/testCaseServices.go index 10aeac7..be977b7 100644 --- a/uiServices/src/testCaseServices.go +++ b/uiServices/src/testCaseServices.go @@ -9,62 +9,59 @@ import ( "net/http" "os" "path/filepath" - "strings" "github.com/Sirupsen/logrus" "github.com/go-chi/chi" "github.com/xtracdev/automated-perf-test/testStrategies" ) -const testCaseSchema string = "testCase_schema.json" -const structTypeName string = "TestCase " +const ( + testCaseSchema = "testCase_Schema.json" + testCaseStruct = "testDefinition" +) type Case struct { - HttpMethod string `json:"httpMethod"` - Name string `json:"name"` - Description string `json:"description"` + HttpMethod string `json:"httpMethod"` + Name string `json:"name"` + Description string `json:"description"` + PreThinkTime int64 `json:"preThinkTime"` + PostThinkTime int64 `json:"postThinkTime"` + ExecWeight string `json:"execWeight"` } func TestCaseCtx(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) }) - -} -func getTestCaseHeader(req *http.Request) string { - testCasePathDir := req.Header.Get("testCasePathDir") - - if !strings.HasSuffix(testCasePathDir, "/") { - testCasePathDir = testCasePathDir + "/" - } - return testCasePathDir } func postTestCase(rw http.ResponseWriter, req *http.Request) { - testCasePathDir := getTestCaseHeader(req) + testCasePathDir := getPathHeader(req) buf := new(bytes.Buffer) buf.ReadFrom(req.Body) testCase := testStrategies.TestDefinition{} err := json.Unmarshal(buf.Bytes(), &testCase) if err != nil { - logrus.Error("Failed to unmarshall json body") + logrus.Error("Failed to unmarshall json body", err) rw.WriteHeader(http.StatusBadRequest) return } if err := IsHeaderValid(testCasePathDir); err != nil { + logrus.Error("No header path found", err) rw.WriteHeader(http.StatusBadRequest) return } if err := IsNameValid(testCase.TestName); err != nil { + logrus.Error("File name is empty", err) rw.WriteHeader(http.StatusBadRequest) return } if !FilePathExist(testCasePathDir) { - logrus.Error("Directory path does not exist") + logrus.Error("No directory path entered") rw.WriteHeader(http.StatusBadRequest) return @@ -77,7 +74,13 @@ func postTestCase(rw http.ResponseWriter, req *http.Request) { } - if !testCaseWriterXml(testCase, testCasePathDir+testCase.TestName+".xml") { + if !validateJSONWithSchema(buf.Bytes(), testCaseSchema, testCaseStruct) { + rw.WriteHeader(http.StatusBadRequest) + return + } + + if !writeXML(testCase, testCasePathDir+testCase.TestName+".xml") { + logrus.Error("Error writing to the file") rw.WriteHeader(http.StatusInternalServerError) return } @@ -86,21 +89,23 @@ func postTestCase(rw http.ResponseWriter, req *http.Request) { } func putTestCase(rw http.ResponseWriter, req *http.Request) { - path := getTestCaseHeader(req) + path := getPathHeader(req) testCaseName := chi.URLParam(req, "testCaseName") if err := IsHeaderValid(path); err != nil { + logrus.Error("No header path found", err) rw.WriteHeader(http.StatusBadRequest) return } if err := IsNameValid(testCaseName); err != nil { + logrus.Error("File name is empty", err) rw.WriteHeader(http.StatusBadRequest) return } testCasePathDir := fmt.Sprintf("%s%s.xml", path, testCaseName) - buf := new(bytes.Buffer) - buf.ReadFrom(req.Body) + + logrus.Error("testCasePathDir", testCasePathDir) if !FilePathExist(testCasePathDir) { logrus.Error("File path does not exist") @@ -109,7 +114,10 @@ func putTestCase(rw http.ResponseWriter, req *http.Request) { } - if !ValidateJSONWithSchema(buf.Bytes(), testCaseSchema, structTypeName) { + buf := new(bytes.Buffer) + buf.ReadFrom(req.Body) + + if !validateJSONWithSchema(buf.Bytes(), testCaseSchema, testCaseStruct) { rw.WriteHeader(http.StatusBadRequest) return } @@ -118,7 +126,7 @@ func putTestCase(rw http.ResponseWriter, req *http.Request) { err := json.Unmarshal(buf.Bytes(), &testCase) if err != nil { - logrus.Error("Cannot Unmarshall Json") + logrus.Error("Error unmarshalling Json", err) rw.WriteHeader(http.StatusBadRequest) return } @@ -129,7 +137,8 @@ func putTestCase(rw http.ResponseWriter, req *http.Request) { return } - if !testCaseWriterXml(testCase, testCasePathDir) { + if !writeXML(testCase, testCasePathDir) { + logrus.Error("Error writing to the file") rw.WriteHeader(http.StatusInternalServerError) return } @@ -138,16 +147,20 @@ func putTestCase(rw http.ResponseWriter, req *http.Request) { } func getAllTestCases(rw http.ResponseWriter, req *http.Request) { + rw.Header().Set("Access-Control-Allow-Origin", "*") + testCasePathDir := getPathHeader(req) - testCasePathDir := getTestCaseHeader(req) - - if !IsPathDirValid(testCasePathDir, rw) { + if err := IsPathDirValid(testCasePathDir); err != nil { + logrus.Error("Path Directory is not valid", err) + rw.WriteHeader(http.StatusBadRequest) return } files, err := ioutil.ReadDir(testCasePathDir) if err != nil { - logrus.Error(err) + logrus.Error("Error reading the directory ", err) + rw.WriteHeader(http.StatusInternalServerError) + return } testCases := make([]Case, 0) @@ -161,28 +174,34 @@ func getAllTestCases(rw http.ResponseWriter, req *http.Request) { file, err := os.Open(fmt.Sprintf("%s%s", testCasePathDir, filename)) if err != nil { - logrus.Error("Cannot Open File: " + filename) + logrus.Error("Cannot open file: ", filename, err) + logrus.Error("Error opening the file: " + filename) continue } byteValue, err := ioutil.ReadAll(file) if err != nil { - logrus.Error("Cannot Read File: " + filename) + logrus.Error("Cannot Read File: ", filename, err) + logrus.Error("Error reading the file: " + filename) continue } err = xml.Unmarshal(byteValue, testCase) if err != nil { - logrus.Error("Cannot Unmarshall File: " + filename) + logrus.Error("Cannot Unmarshall: ", filename, err) + + logrus.Error("Error unmarshalling the file: " + filename) continue } - //if a Test Case Name can't be assigned, it isn't a Test Case object if testCase.TestName != "" { testCases = append(testCases, Case{ - Name: testCase.TestName, - Description: testCase.Description, - HttpMethod: testCase.HTTPMethod, + Name: testCase.TestName, + Description: testCase.Description, + HttpMethod: testCase.HTTPMethod, + PostThinkTime: testCase.PostThinkTime, + PreThinkTime: testCase.PreThinkTime, + ExecWeight: testCase.ExecWeight, }) } } @@ -190,7 +209,7 @@ func getAllTestCases(rw http.ResponseWriter, req *http.Request) { err = json.NewEncoder(rw).Encode(testCases) if err != nil { - logrus.Error("Could not enocde Test Cases") + logrus.Error("Error encoding Test Cases", err) rw.WriteHeader(http.StatusInternalServerError) return } @@ -199,20 +218,25 @@ func getAllTestCases(rw http.ResponseWriter, req *http.Request) { } func getTestCase(rw http.ResponseWriter, req *http.Request) { - - testCasePathDir := getTestCaseHeader(req) + rw.Header().Set("Access-Control-Allow-Origin", "*") + testCasePathDir := getPathHeader(req) testCaseName := chi.URLParam(req, "testCaseName") if err := IsHeaderValid(testCasePathDir); err != nil { + logrus.Error("No header path found", err) rw.WriteHeader(http.StatusBadRequest) return } if err := IsNameValid(testCaseName); err != nil { + logrus.Error("File name is empty", err) rw.WriteHeader(http.StatusBadRequest) return } + filePath := fmt.Sprintf("%s%s.xml", testCasePathDir, testCaseName) + logrus.Info("FilePath: ", filePath) + if _, err := os.Stat(fmt.Sprintf("%s%s.xml", testCasePathDir, testCaseName)); err != nil { if os.IsNotExist(err) { logrus.Error("Test Case File Not Found: " + testCaseName) @@ -223,8 +247,8 @@ func getTestCase(rw http.ResponseWriter, req *http.Request) { file, err := os.Open(fmt.Sprintf("%s%s.xml", testCasePathDir, testCaseName)) if err != nil { - logrus.Error("Cannot open: " + testCaseName) - rw.WriteHeader(http.StatusInternalServerError) + logrus.Error("Test Case Name Not Found: " + testCasePathDir + testCaseName) + rw.WriteHeader(http.StatusNotFound) return } defer file.Close() @@ -233,22 +257,23 @@ func getTestCase(rw http.ResponseWriter, req *http.Request) { byteValue, err := ioutil.ReadAll(file) if err != nil { + logrus.Error("Error reading from file", err) rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot Read File", err) + logrus.Error("Cannot Read File") return } err = xml.Unmarshal(byteValue, &testCase) if err != nil { + logrus.Error("Error unmarshalling from XML", err) rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot Unmarshall from XML", err) return } testSuiteJSON, err := json.MarshalIndent(testCase, "", "") if err != nil { + logrus.Error("Error marshalling to JSON", err) rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot marshall to JSON", err) return } @@ -258,15 +283,17 @@ func getTestCase(rw http.ResponseWriter, req *http.Request) { } func deleteTestCase(rw http.ResponseWriter, req *http.Request) { - testCasePathDir := getTestCaseHeader(req) + testCasePathDir := getPathHeader(req) testCaseName := chi.URLParam(req, "testCaseName") if err := IsHeaderValid(testCasePathDir); err != nil { + logrus.Error("No header path found", err) rw.WriteHeader(http.StatusBadRequest) return } if err := IsNameValid(testCaseName); err != nil { + logrus.Error("File name is empty", err) rw.WriteHeader(http.StatusBadRequest) return } @@ -283,8 +310,8 @@ func deleteTestCase(rw http.ResponseWriter, req *http.Request) { err := os.Remove(filepath) if err != nil { - logrus.Println("File was not deleted", err) - rw.WriteHeader(http.StatusInternalServerError) + logrus.Println("Error deleting the file", err) + rw.WriteHeader(http.StatusNoContent) return } @@ -292,3 +319,31 @@ func deleteTestCase(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusNoContent) } +func deleteAllTestCases(rw http.ResponseWriter, req *http.Request) { + testCasePathDir := getPathHeader(req) + + if err := IsHeaderValid(testCasePathDir); err != nil { + logrus.Error("No heared path found", err) + rw.WriteHeader(http.StatusBadRequest) + return + } + + files, err := ioutil.ReadDir(testCasePathDir) + if err != nil { + logrus.Error("Error reading the directory ", err) + rw.WriteHeader(http.StatusInternalServerError) + return + } + + for _, file := range files { + filepath := fmt.Sprintf("%s%s", testCasePathDir, file.Name()) + + err := os.Remove(filepath) + if err != nil { + logrus.Error("Error removing the files from directory", err) + rw.WriteHeader(http.StatusNoContent) + return + } + } + rw.WriteHeader(http.StatusOK) +} diff --git a/uiServices/src/testCaseServices_test.go b/uiServices/src/testCaseServices_test.go index d3d8c69..bd7bc2d 100644 --- a/uiServices/src/testCaseServices_test.go +++ b/uiServices/src/testCaseServices_test.go @@ -1,12 +1,15 @@ package services import ( + "fmt" + "io/ioutil" "net/http" "net/http/httptest" "os" "strings" "testing" + "github.com/Sirupsen/logrus" "github.com/go-chi/chi" "github.com/stretchr/testify/assert" ) @@ -17,8 +20,8 @@ const validTestCase = ` "description":"desc", "overrideHost":"host", "overridePort":"9191", - "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -26,18 +29,18 @@ const validTestCase = ` "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } ` @@ -48,8 +51,8 @@ const TestCaseNoName = ` "description":"desc", "overrideHost":"host", "overridePort":"9191", - "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -57,18 +60,18 @@ const TestCaseNoName = ` "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } ` @@ -79,7 +82,7 @@ const TestCaseMissingRequired = ` "description":"", "overrideHost":"", "overridePort":"", - "BaseURI": "path/to/URI", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -90,14 +93,14 @@ const TestCaseMissingRequired = ` } ` -const TestCaseForDeletion = ` +const testCaseForDeletion = ` { "testname":"TestCaseService2", "description":"desc", "overrideHost":"host", "overridePort":"9191", - "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -105,18 +108,18 @@ const TestCaseForDeletion = ` "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } ` @@ -132,7 +135,7 @@ func TestValidTestCasePost(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-cases", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -151,7 +154,7 @@ func TestCasePostWithExistingFileName(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-cases", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -170,7 +173,7 @@ func TestCasePostNoHeader(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodPost, "/test-cases", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -189,7 +192,7 @@ func TestPostTestCaseMissingRequiredValues(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-cases", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -202,21 +205,20 @@ func TestPostTestCaseMissingRequiredValues(t *testing.T) { func TestValidTestCasePut(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(validTestCase) - r.HandleFunc("/test-cases", putTestCase) + + //r.HandleFunc("/test-cases", putTestCase) filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-cases/TestCaseService", reader) - request.Header.Set("testCasePathDir", filePath) + + assert.NoError(t, err) + + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) - if err != nil { - t.Error(err) - } - assert.Equal(t, http.StatusNoContent, w.Code, "Did Not successfully Update") } @@ -229,7 +231,7 @@ func TestTestCasePutMissingRequired(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-cases/TestCaseService", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -250,7 +252,7 @@ func TestInvalidUrlTestCasePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-cases/xxxxxxxxxxxzzx", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -271,7 +273,7 @@ func TestNoUrlTestCasePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -292,7 +294,7 @@ func TestCasePutWithNoPathSlash(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPut, "/test-cases/TestCaseService", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -313,7 +315,7 @@ func TestNoPathTestCasePut(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodPut, "/test-cases/TestCaseService", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -334,7 +336,7 @@ func TestNoNameTestCasePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPut, "/test-cases/TestCaseService", reader) - request.Header.Set("testCasePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -350,47 +352,45 @@ func TestSuccessfulGetAllCases(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - DirectoryPath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" + directoryPath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodGet, "/test-cases", nil) + assert.NoError(t, err) - request.Header.Set("testCasePathDir", DirectoryPath) - request.Header.Get("testCasePathDir") + request.Header.Set("path", directoryPath) w := httptest.NewRecorder() r.ServeHTTP(w, request) - if assert.NoError(t, err) { - assert.Equal(t, http.StatusOK, w.Code, "Did not get all test cases") - } + assert.Equal(t, http.StatusOK, w.Code, "Did not get all test casess") } func TestGetAllCasesNoHeader(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - DircetoryPath := "" request, err := http.NewRequest(http.MethodGet, "/test-cases", nil) - request.Header.Set("testCasePathDir", DircetoryPath) - request.Header.Get("testCasePathDir") + request.Header.Set("path", "") w := httptest.NewRecorder() r.ServeHTTP(w, request) - if assert.NoError(t, err) { - assert.Equal(t, http.StatusBadRequest, w.Code, "Did not get all test cases") + if err != nil { + t.Error(err) } + + assert.Equal(t, http.StatusBadRequest, w.Code, "Should not have retrieved all test cases") } -func TestSuccessfulGetTestCase(t *testing.T) { +func TestGetTestCaseNoHeader(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" - request, err := http.NewRequest(http.MethodGet, "/test-cases/TestCaseService", nil) + filePath := "" + request, err := http.NewRequest(http.MethodGet, "/test-cases/Case1", nil) - request.Header.Set("testCasePathDir", filePath) - request.Header.Get("testCasePathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -399,18 +399,18 @@ func TestSuccessfulGetTestCase(t *testing.T) { t.Error(err) } - assert.Equal(t, http.StatusOK, w.Code, "Error. Did not successfully GET") + assert.Equal(t, http.StatusBadRequest, w.Code, "Should not return data") } -func TestGetTestCaseNoHeader(t *testing.T) { +func TestGetTestCaseFileNotFound(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - filePath := "" - request, err := http.NewRequest(http.MethodGet, "/test-cases/TestCaseService", nil) + filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/cases" + request, err := http.NewRequest(http.MethodGet, "/test-cases/xxx", nil) - request.Header.Set("testCasePathDir", filePath) - request.Header.Get("testCasePathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -419,39 +419,79 @@ func TestGetTestCaseNoHeader(t *testing.T) { t.Error(err) } - assert.Equal(t, http.StatusBadRequest, w.Code, "Should not return data") + assert.Equal(t, http.StatusNotFound, w.Code, "Should not return data") } -func TestGetTestCaseFileNotFound(t *testing.T) { +func TestDeleteAllCasesSuccess(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" - request, err := http.NewRequest(http.MethodGet, "/test-cases/xxx", nil) + directory := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/cases" + err := ioutil.WriteFile(fmt.Sprintf("%s%s.xml", directory, "test"), nil, 0666) + if err != nil { + logrus.Errorf("Error trying to create a file: %s", err) + } + + request, err := http.NewRequest(http.MethodDelete, "/test-cases", nil) + assert.NoError(t, err) + + request.Header.Set("path", directory) - request.Header.Set("testCasePathDir", filePath) - request.Header.Get("testCasePathDir") + w := httptest.NewRecorder() + r.ServeHTTP(w, request) + + assert.Equal(t, http.StatusOK, w.Code, "All files have been DELETED") + +} + +func TestDeleteAllCasesNoHeader(t *testing.T) { + r := chi.NewRouter() + r.Mount("/", GetIndexPage()) + + DirectoryPath := "" + request, err := http.NewRequest(http.MethodDelete, "/test-cases", nil) + if err != nil { + logrus.Warnf("Error creating the request %s", err) + } + + request.Header.Set("path", DirectoryPath) w := httptest.NewRecorder() r.ServeHTTP(w, request) + assert.Equal(t, http.StatusBadRequest, w.Code, "Did not DELETE the files") +} + +func TestDeleteAllCasesEmptyDirectory(t *testing.T) { + r := chi.NewRouter() + r.Mount("/", GetIndexPage()) + + DirectoryPath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/cases/" + request, err := http.NewRequest(http.MethodDelete, "/test-cases/", nil) if err != nil { - t.Error(err) + logrus.Warnf("Error creating the request %s", err) + return } - assert.Equal(t, http.StatusNotFound, w.Code, "Should not return data") + request.Header.Set("path", DirectoryPath) + + w := httptest.NewRecorder() + r.ServeHTTP(w, request) + + assert.Equal(t, http.StatusNotFound, w.Code, "Empty Directory") } func TestSuccessfulCaseDelete(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) - reader := strings.NewReader(TestCaseForDeletion) + reader := strings.NewReader(testCaseForDeletion) r.HandleFunc("/test-cases", postTestCase) - filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" + filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPost, "/test-cases", reader) - request.Header.Set("testCasePathDir", filePath) + assert.NoError(t, err) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -460,19 +500,16 @@ func TestSuccessfulCaseDelete(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code, "Error: Did Not Successfully Post") + r.HandleFunc("/test-cases", deleteTestCase) + filePath = os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err = http.NewRequest(http.MethodDelete, "/test-cases/TestCaseService2", nil) - - request.Header.Set("testCasePathDir", filePath) - request.Header.Get("testCasePathDir") + assert.NoError(t, err) + request.Header.Set("path", filePath) w = httptest.NewRecorder() r.ServeHTTP(w, request) - if err != nil { - t.Error(err) - } - assert.Equal(t, http.StatusNoContent, w.Code, "Error. Did not successfully Delete") } @@ -483,8 +520,8 @@ func TestDeleteCaseFileNotFound(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodDelete, "/test-cases/xxx", nil) - request.Header.Set("testCasePathDir", filePath) - request.Header.Get("testCasePathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -503,8 +540,8 @@ func TestDeleteCaseWithNoHeader(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodDelete, "/test-cases/TestCaseService", nil) - request.Header.Set("testCasePathDir", filePath) - request.Header.Get("testCasePathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) diff --git a/uiServices/src/testSuiteServices.go b/uiServices/src/testSuiteServices.go index 72ce528..34d2557 100644 --- a/uiServices/src/testSuiteServices.go +++ b/uiServices/src/testSuiteServices.go @@ -10,16 +10,16 @@ import ( "net/http" "os" "path/filepath" - "strings" "github.com/Sirupsen/logrus" "github.com/go-chi/chi" - "github.com/xeipuuv/gojsonschema" "github.com/xtracdev/automated-perf-test/testStrategies" ) -var schemaFile string = "testSuite_schema.json" -var structType string = "TestSuite" +const ( + schemaFile = "testSuite_schema.json" + structType = "testSuite" +) type Suite struct { File string `json:"file"` @@ -33,19 +33,10 @@ func TestSuiteCtx(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) }) - -} -func getTestSuiteHeader(req *http.Request) string { - testSuitePathDir := req.Header.Get("testSuitePathDir") - - if !strings.HasSuffix(testSuitePathDir, "/") { - testSuitePathDir = testSuitePathDir + "/" - } - return testSuitePathDir } func postTestSuites(rw http.ResponseWriter, req *http.Request) { - testSuitePathDir := getTestSuiteHeader(req) + testSuitePathDir := getPathHeader(req) buf := new(bytes.Buffer) buf.ReadFrom(req.Body) @@ -67,7 +58,7 @@ func postTestSuites(rw http.ResponseWriter, req *http.Request) { return } - if !ValidateJSONWithSchema(buf.Bytes(), schemaFile, structType) { + if !validateJSONWithSchema(buf.Bytes(), schemaFile, structType) { rw.WriteHeader(http.StatusBadRequest) return } @@ -79,14 +70,15 @@ func postTestSuites(rw http.ResponseWriter, req *http.Request) { } - if FilePathExist(fmt.Sprintf("%s%s.xml", testSuitePathDir, testSuite.Name)) { + filePath := fmt.Sprintf("%s%s.xml", testSuitePathDir, testSuite.Name) + + if FilePathExist(filePath) { logrus.Error("File already exists") rw.WriteHeader(http.StatusBadRequest) return - } - if !testSuiteWriterXML(testSuite, testSuitePathDir+testSuite.Name+".xml") { + if !writeXML(testSuite, filePath) { rw.WriteHeader(http.StatusInternalServerError) return } @@ -94,30 +86,8 @@ func postTestSuites(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusCreated) } -func ValidateJSONWithSchema(testSuite []byte, schemaName, structType string) bool { - goPath := os.Getenv("GOPATH") - schemaLoader := gojsonschema.NewReferenceLoader("file:///" + goPath + "/src/github.com/xtracdev/automated-perf-test/ui-src/src/assets/" + schemaName) - documentLoader := gojsonschema.NewBytesLoader(testSuite) - logrus.Info(schemaLoader) - result, error := gojsonschema.Validate(schemaLoader, documentLoader) - - if error != nil { - return false - } - if !result.Valid() { - logrus.Errorf("%sdocument is not valid. see errors :", structType) - for _, desc := range result.Errors() { - logrus.Error("- ", desc) - return false - } - } - - logrus.Infof("%s document is valid", structType) - return true -} - func putTestSuites(rw http.ResponseWriter, req *http.Request) { - path := getTestSuiteHeader(req) + path := getPathHeader(req) testSuiteName := chi.URLParam(req, "testSuiteName") if err := IsHeaderValid(path); err != nil { @@ -138,10 +108,9 @@ func putTestSuites(rw http.ResponseWriter, req *http.Request) { logrus.Error("File path does not exist") rw.WriteHeader(http.StatusNotFound) return - } - if !ValidateJSONWithSchema(buf.Bytes(), schemaFile, structType) { + if !validateJSONWithSchema(buf.Bytes(), schemaFile, structType) { rw.WriteHeader(http.StatusBadRequest) return } @@ -155,7 +124,7 @@ func putTestSuites(rw http.ResponseWriter, req *http.Request) { return } - if !testSuiteWriterXML(testSuite, testSuitePathDir) { + if !writeXML(testSuite, testSuitePathDir) { rw.WriteHeader(http.StatusInternalServerError) return } @@ -164,7 +133,7 @@ func putTestSuites(rw http.ResponseWriter, req *http.Request) { } func deleteTestSuite(rw http.ResponseWriter, req *http.Request) { - testSuitePathDir := getTestSuiteHeader(req) + testSuitePathDir := getPathHeader(req) testSuiteName := chi.URLParam(req, "testSuiteName") if err := IsHeaderValid(testSuitePathDir); err != nil { @@ -177,15 +146,18 @@ func deleteTestSuite(rw http.ResponseWriter, req *http.Request) { return } - if _, err := os.Stat(fmt.Sprintf("%s%s.xml", testSuitePathDir, testSuiteName)); err != nil { + filepath := fmt.Sprintf("%s%s.xml", testSuitePathDir, testSuiteName) + + if _, err := os.Stat(filepath); err != nil { if os.IsNotExist(err) { - logrus.Error("Test Suite File Not Found: " + testSuitePathDir + testSuiteName) + logrus.Error("Test Suite File Not Found: ", err) rw.WriteHeader(http.StatusNotFound) return } } - err := os.Remove(fmt.Sprintf("%s%s.xml", testSuitePathDir, testSuiteName)) + filePath := fmt.Sprintf("%s%s.xml", testSuitePathDir, testSuiteName) + err := os.Remove(filePath) if err != nil { logrus.Errorf("Error deleting the file from filesystem: %s", err) rw.WriteHeader(http.StatusInternalServerError) @@ -196,8 +168,7 @@ func deleteTestSuite(rw http.ResponseWriter, req *http.Request) { } func getTestSuite(rw http.ResponseWriter, req *http.Request) { - - testSuitePathDir := getTestSuiteHeader(req) + testSuitePathDir := getPathHeader(req) testSuiteName := chi.URLParam(req, "testSuiteName") if err := IsHeaderValid(testSuitePathDir); err != nil { @@ -230,14 +201,14 @@ func getTestSuite(rw http.ResponseWriter, req *http.Request) { err = xml.Unmarshal(byteValue, &testSuite) if err != nil { rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot Unmarshall from XML") + logrus.Error("Cannot Unmarshall from XML", err) return } testSuiteJSON, err := json.MarshalIndent(testSuite, "", "") if err != nil { rw.WriteHeader(http.StatusInternalServerError) - logrus.Error("Cannot marshall to JSON") + logrus.Error("Cannot marshall to JSON", err) return } @@ -247,8 +218,7 @@ func getTestSuite(rw http.ResponseWriter, req *http.Request) { } func getAllTestSuites(rw http.ResponseWriter, req *http.Request) { - - testSuitePathDir := getTestSuiteHeader(req) + testSuitePathDir := getPathHeader(req) if len(testSuitePathDir) <= 1 { logrus.Error("No file directory entered") rw.WriteHeader(http.StatusBadRequest) diff --git a/uiServices/src/testSuiteServices_test.go b/uiServices/src/testSuiteServices_test.go index 7c38abc..45b674d 100644 --- a/uiServices/src/testSuiteServices_test.go +++ b/uiServices/src/testSuiteServices_test.go @@ -2,12 +2,15 @@ package services import ( "github.com/go-chi/chi" - "github.com/stretchr/testify/assert" + "net/http" "net/http/httptest" "os" + "strings" "testing" + + "github.com/stretchr/testify/assert" ) const validTestSuite = ` @@ -78,25 +81,6 @@ const TestSuiteNoName = ` } ` -const validTestSuiteForDelete = ` -{ - "name": "TestSuiteA", - "testStrategy": "SuiteBased", - "description": "Services for XYZ", - "testCases": [ - { - "name":"file1", - "preThinkTime": 1000, - "postThinkTime": 2000, - "execWeight": "Infrequent" - }, - { - "name":"file2" - } - ] -} -` - func TestValidTestSuitePost(t *testing.T) { r := chi.NewRouter() r.Mount("/", GetIndexPage()) @@ -108,7 +92,7 @@ func TestValidTestSuitePost(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -129,7 +113,7 @@ func TestFileExistsPost(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -150,7 +134,7 @@ func TestMissingRequiredTestSuitePost(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -172,7 +156,7 @@ func TestIncorrectDataTypePost(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -194,7 +178,7 @@ func TestValidTestSuitePostNoConfigPathDir(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -216,7 +200,7 @@ func TestValidTestSuitePostConfigPathDirNotExist(t *testing.T) { filePath := "C:/a/b/c/d/////" request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -238,7 +222,7 @@ func TestValidTestSuitePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-suites/TestSuiteService", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -259,7 +243,7 @@ func TestTestSuiteMissingFieldPut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-suites/TestSuiteService", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -280,7 +264,7 @@ func TestInvalidTestSuitePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-suites/TestSuiteService", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -301,7 +285,7 @@ func TestInvalidUrlTestSuitePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "/test-suites/xxx", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -322,7 +306,7 @@ func TestNoUrlTestSuitePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodPut, "", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -343,7 +327,7 @@ func TestPutWithNoPathSlash(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPut, "/test-suites/TestSuiteService", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -364,7 +348,7 @@ func TestNoPathTestSuitePut(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodPut, "/test-suites/TestSuiteService", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -385,7 +369,7 @@ func TestNoFileNameTestSuitePut(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" request, err := http.NewRequest(http.MethodPut, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -404,8 +388,7 @@ func TestSuccessfulGetTestSuite(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodGet, "/test-suites/TestSuiteService", nil) - request.Header.Set("testSuitePathDir", filePath) - request.Header.Get("testSuitePathDir") + request.Header.Set("path", filePath) w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -424,8 +407,8 @@ func TestGetTestSuiteNoPath(t *testing.T) { filePath := "" request, err := http.NewRequest(http.MethodGet, "/test-suites/TestSuiteService.xml", nil) - request.Header.Set("testSuitePathDir", filePath) - request.Header.Get("testSuitePathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -444,8 +427,8 @@ func TestGetTestSuiteFileNotFound(t *testing.T) { filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodGet, "/test-suites/xxx", nil) - request.Header.Set("testSuitePathDir", filePath) - request.Header.Get("testSuitePathDir") + request.Header.Set("path", filePath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -464,8 +447,8 @@ func TestSuccessfulGetAllSuites(t *testing.T) { DirectoryPath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" request, err := http.NewRequest(http.MethodGet, "/test-suites", nil) - request.Header.Set("testSuitePathDir", DirectoryPath) - request.Header.Get("testSuitePathDir") + request.Header.Set("path", DirectoryPath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -484,8 +467,8 @@ func TestGetAllSuitesNoHeader(t *testing.T) { DircetoryPath := "" request, err := http.NewRequest(http.MethodGet, "/test-suites", nil) - request.Header.Set("testSuitePathDir", DircetoryPath) - request.Header.Get("testSuitePathDir") + request.Header.Set("path", DircetoryPath) + request.Header.Get("path") w := httptest.NewRecorder() r.ServeHTTP(w, request) @@ -496,80 +479,3 @@ func TestGetAllSuitesNoHeader(t *testing.T) { assert.Equal(t, http.StatusBadRequest, w.Code, "Did not get all test suites") } - -func TestSuccessfulDeleteTestSuite(t *testing.T) { - r := chi.NewRouter() - r.Mount("/", GetIndexPage()) - - //create file to be deleted - reader := strings.NewReader(validTestSuiteForDelete) - r.HandleFunc("/test-suites", postTestSuites) - - filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" - request, err := http.NewRequest(http.MethodPost, "/test-suites", reader) - request.Header.Set("testSuitePathDir", filePath) - - w := httptest.NewRecorder() - r.ServeHTTP(w, request) - - if err != nil { - t.Error(err) - } - - assert.Equal(t, http.StatusCreated, w.Code, "Error: Did Not Successfully Post") - - filePath = os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" - request, err = http.NewRequest(http.MethodDelete, "/test-suites/TestSuiteA", nil) - - request.Header.Set("testSuitePathDir", filePath) - request.Header.Get("testSuitePathDir") - - w = httptest.NewRecorder() - r.ServeHTTP(w, request) - - if err != nil { - t.Error(err) - } - - assert.Equal(t, http.StatusNoContent, w.Code, "Error. Did not successfully Delete") -} - -func TestDeleteTestSuiteNoHeader(t *testing.T) { - r := chi.NewRouter() - r.Mount("/", GetIndexPage()) - - filePath := "" - request, err := http.NewRequest(http.MethodDelete, "/test-suites/TestSuiteService", nil) - - request.Header.Set("testSuitePathDir", filePath) - request.Header.Get("testSuitePathDir") - - w := httptest.NewRecorder() - r.ServeHTTP(w, request) - - if err != nil { - t.Error(err) - } - - assert.Equal(t, http.StatusBadRequest, w.Code, "Deleted. But SHould Not Have") -} - -func TestDeleteTestSuiteNotFound(t *testing.T) { - r := chi.NewRouter() - r.Mount("/", GetIndexPage()) - - filePath := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" - request, err := http.NewRequest(http.MethodDelete, "/test-suites/xxx", nil) - - request.Header.Set("testSuitePathDir", filePath) - request.Header.Get("testSuitePathDir") - - w := httptest.NewRecorder() - r.ServeHTTP(w, request) - - if err != nil { - t.Error(err) - } - - assert.Equal(t, http.StatusNotFound, w.Code, "Deleted. But should not have") -} diff --git a/uiServices/src/util.go b/uiServices/src/util.go new file mode 100644 index 0000000..4961bcf --- /dev/null +++ b/uiServices/src/util.go @@ -0,0 +1,45 @@ +package services + +import ( + "net/http" + "os" + "strings" + + "github.com/Sirupsen/logrus" + "github.com/xeipuuv/gojsonschema" +) + +func getPathHeader(req *http.Request) string { + pathHeader := req.Header.Get("path") + + if !strings.HasSuffix(pathHeader, "/") { + pathHeader = pathHeader + "/" + } + return pathHeader +} + +func validateJSONWithSchema(testSuite []byte, schemaName, structType string) bool { + goPath := os.Getenv("GOPATH") + schemaLoader := gojsonschema.NewReferenceLoader("file:///" + goPath + "/src/github.com/xtracdev/automated-perf-test/ui-src/src/assets/" + schemaName) + documentLoader := gojsonschema.NewBytesLoader(testSuite) + logrus.Info(schemaLoader) + result, error := gojsonschema.Validate(schemaLoader, documentLoader) + + if error != nil { + return false + } + if !result.Valid() { + logrus.Errorf("%sdocument is not valid. see errors :", structType) + for _, desc := range result.Errors() { + logrus.Error("- ", desc) + return false + } + } + + logrus.Infof("%s document is valid", structType) + return true +} +func FilePathExist(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) +} diff --git a/uiServices/src/util_test.go b/uiServices/src/util_test.go new file mode 100644 index 0000000..21ffdd0 --- /dev/null +++ b/uiServices/src/util_test.go @@ -0,0 +1,25 @@ +package services + +import ( + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFilePathExist(t *testing.T) { + path := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" + actual := false + fmt.Println(path) + actual = FilePathExist(path) + expected := true + assert.Equal(t, expected, actual) +} + +func TestFilePathDoesNotExist(t *testing.T) { + path := "(((((((" + actual := FilePathExist(path) + expected := false + assert.Equal(t, expected, actual) +} diff --git a/uiServices/src/xmlWriter.go b/uiServices/src/xmlWriter.go index 71415d4..683e6a2 100644 --- a/uiServices/src/xmlWriter.go +++ b/uiServices/src/xmlWriter.go @@ -7,14 +7,12 @@ import ( "os" log "github.com/Sirupsen/logrus" - "github.com/xtracdev/automated-perf-test/perfTestUtils" - "github.com/xtracdev/automated-perf-test/testStrategies" ) -func configWriterXML(config perfTestUtils.Config, configPathDir string) bool { - filename := fmt.Sprintf("%s", configPathDir) +func writeXML(definition interface{}, path string) bool { + filename := fmt.Sprintf("%s", path) - configAsXML, err := xml.MarshalIndent(config, " ", " ") + payloadXML, err := xml.MarshalIndent(definition, " ", " ") if err != nil { log.Error("Failed to marshal to XML. Error:", err) return false @@ -28,47 +26,7 @@ func configWriterXML(config perfTestUtils.Config, configPathDir string) bool { } if file != nil { defer file.Close() - file.Write(configAsXML) - } - return true -} - -func testSuiteWriterXML(testSuite testStrategies.TestSuite, configPathDir string) bool { - filename := fmt.Sprintf("%s", configPathDir) - - testSuiteAsXML, err := xml.MarshalIndent(testSuite, " ", " ") - if err != nil { - log.Error("Failed to marshal to XML. Error:", err) - return false - } - - file, err := os.Create(filename) - if err != nil { - log.Error("Failed to create output file. Error:", err) - return false - } - if file != nil { - defer file.Close() - file.Write(testSuiteAsXML) - } - return true -} - -func testCaseWriterXml(testSuite testStrategies.TestDefinition, path string) bool { - filename := fmt.Sprintf("%s", path) - - testCaseAsXml, err := xml.MarshalIndent(testSuite, " ", " ") - if err != nil { - log.Error("Failed to marshal to XML. Error:", err) - return false - } - - file, err := os.Create(filename) - if err != nil { - log.Error("Failed to create output file. Error:", err) - return false + file.Write(payloadXML) } - defer file.Close() - file.Write(testCaseAsXml) return true } diff --git a/uiServices/test/configFile.feature b/uiServices/test/configFile.feature index 2787caa..3421228 100644 --- a/uiServices/test/configFile.feature +++ b/uiServices/test/configFile.feature @@ -1,66 +1,90 @@ Feature: Create Configuration File - As an API user - I want to be able to create a configuration file - So that I can test my application using custom metrics +As an API user +I want to be able to create a configuration file +So that I can test my application using custom metrics - ################################### - ####### POST REQUESTS ########## - ################################### + ################################### + ####### POST REQUESTS ########## + ################################### Scenario: Successful creation of config file - Given there is no existing test file "GodogConfig.xml" + Given there is no existing test file "ConfigSAMPLE.xml" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/GodogConfig.xml" + And the header "path" is "/uiServices/test" When I send "POST" request to "/configs" with a body: - """ + """ { - "apiName": "GodogConfig", - "targetHost": "localhost", - "targetPort":"9191", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 1000, - "allowablePeakMemoryVariance": 30, - "allowableServiceResponseTimeVariance": 30, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 5000, - "TPSFreq": 30, - "rampUsers": 5, - "rampDelay": 15 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost", + "targetPort":"9191", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 1000, + "allowablePeakMemoryVariance": 30, + "allowableServiceResponseTimeVariance": 30, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 5, + "rampDelay": 15 } """ Then the response code should be 201 And the response body should be empty - And the config file was created at location defined by configsPathDir -# + Scenario: Unsuccessful creation of config file (file already exists) Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/GodogConfig.xml" + Given there is no existing test file "ConfigSAMPLE.xml" + And the header "path" is "/uiServices/test" + When I send "POST" request to "/configs" with a body: + """ + { + "apiName": "ConfigSAMPLE", + "targetHost": "localhost", + "targetPort":"9191", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 1000, + "allowablePeakMemoryVariance": 30, + "allowableServiceResponseTimeVariance": 30, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 5, + "rampDelay": 15 + } + """ + Then the response code should be 201 + And the header "path" is "/uiServices/test" When I send "POST" request to "/configs" with a body: - """ + """ { - "apiName": "GodogConfig", - "targetHost": "localhost", - "targetPort":"9191", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 1000, - "allowablePeakMemoryVariance": 30, - "allowableServiceResponseTimeVariance": 30, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 5000, - "TPSFreq": 30, - "rampUsers": 5, - "rampDelay": 15 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost", + "targetPort":"9191", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 1000, + "allowablePeakMemoryVariance": 30, + "allowableServiceResponseTimeVariance": 30, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 5, + "rampDelay": 15 } """ Then the response code should be 400 @@ -68,321 +92,360 @@ Feature: Create Configuration File Scenario: Unsuccessful creation of config file (Missing required field) Given the automated performance ui server is available When I send "POST" request to "/configs" with a body: - """ + """ { - "apiName": "GodogConfig2", - "targetHost": "localhost", - "targetPort":"9191", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 1000, - "allowablePeakMemoryVariance": 30, - "allowableServiceResponseTimeVariance": 30, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "", - "requestDelay": 5000, - "TPSFreq": 30, - "rampUsers": 5, - "rampDelay": 15 + "apiName": "ConfigSAMPLE2", + "targetHost": "localhost", + "targetPort":"9191", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 1000, + "allowablePeakMemoryVariance": 30, + "allowableServiceResponseTimeVariance": 30, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 5, + "rampDelay": 15 } """ - And the header "configPathDir" is "/uiServices/test/GodogConfig.xml" + And the header "path" is "/uiServices/test" Then the response code should be 400 Scenario: Unsuccessful creation of config file (Missing Header) Given the automated performance ui server is available - And the header "configPathDir" is "" + And the header "path" is "" When I send "POST" request to "/configs" with a body: - """ + """ { - "apiName": "GodogConfig3", - "targetHost": "localhost", - "targetPort":"9191", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 1000, - "allowablePeakMemoryVariance": 30, - "allowableServiceResponseTimeVariance": 30, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-1", - "requestDelay": 5000, - "TPSFreq": 30, - "rampUsers": 5, - "rampDelay": 15 + "apiName": "ConfigSAMPLE3", + "targetHost": "localhost", + "targetPort":"9191", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 1000, + "allowablePeakMemoryVariance": 30, + "allowableServiceResponseTimeVariance": 30, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-1", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 5, + "rampDelay": 15 } """ Then the response code should be 400 - ################################### - ####### GET REQUESTS ######## - ################################### + ################################### + ####### GET REQUESTS ######## + ################################### Scenario: Try to retrieve config file with valid "GET" request - Given the file "GodogConfig.xml" exists at "/uiServices/test/" - Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" - And the file name is "GodogConfig.xml" - When I send a "GET" request to "/configs/GodogConfig" + Given the file "testConfig.xml" exists at "/uiServices/test/samples" + And the header "path" is "/uiServices/test/samples" + And the file name is "testConfig.xml" + When I send a "GET" request to "/configs/testConfig" Then the response code should be 200 And the response body should match json: - """ + """ { - "apiName": "GodogConfig", - "targetHost": "localhost", - "targetPort":"9191", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 1000, - "allowablePeakMemoryVariance": 30, - "allowableServiceResponseTimeVariance": 30, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 5000, - "TPSFreq": 30, - "rampUsers": 5, - "rampDelay": 15 + "apiName": "testConfig", + "targetHost": "localhost", + "targetPort": "8080", + "numIterations": 55, + "allowablePeakMemoryVariance": 12, + "allowableServiceResponseTimeVariance": 15, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": ".efreefef", + "concurrentUsers": 50, + "testSuite": "Default-1", + "memoryEndpoint": "/alt/debug/vars", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 15, + "rampDelay": 15, + "GBS": false, + "ReBaseMemory": false, + "ReBaseAll": false, + "ExecutionHost": "", + "ReportTemplateFile": "" } """ Scenario: Unsuccessful retrieval of config file (File Not Found) Given the automated performance ui server is available - Given the file "GodogConfig.xml" exists at "/uiServices/test/" + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send a "GET" request to "/configs/xxx" Then the response code should be 404 - ################################## - ###### PUT REQUESTS ########### - ################################## + ################################## + ###### PUT REQUESTS ########### + ################################## Scenario: Unsuccessful update of config file with PUT request (No File Path) - Given the file "GodogConfig.xml" exists at "/uiServices/test/" + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "" - When I send "PUT" request to "/configs/GodogConfig" with body: - """ + And the header "path" is "" + When I send "PUT" request to "/configs/ConfigSAMPLE" with body: + """ { - "apiName": "GodogConfig", - "targetHost": "localhost2", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost2", + "targetPort":"1001", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10 } """ Then the response code should be 400 Scenario: Unsuccessful update of config file with PUT request (Incorrect File Name) - Given the file "GodogConfig.xml" exists at "/uiServices/test/" + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "PUT" request to "/configs/xxx" with body: - """ + """ { - "apiName": "GodogConfig", - "targetHost": "localhost", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost", + "targetPort":"1001", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10 } """ Then the response code should be 404 Scenario: Unsuccessful update of config file with PUT request (No File Name) - Given the file "GodogConfig.xml" exists at "/uiServices/test/" + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "PUT" request to "/configs/" with body: - """ + """ { - "apiName": "GodogConfig", - "targetHost": "localhost", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost", + "targetPort":"1001", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10 } """ Then the response code should be 404 Scenario: Unsuccessful update of config file with PUT request (Missing Required Fields) - Given the file "GodogConfig.xml" exists at "/uiServices/test/" + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" - When I send "PUT" request to "/configs/GodogConfig" with body: - """ + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/configs/ConfigSAMPLE" with body: + """ { - "apiName": "GodogConfig", - "targetHost": "", - "targetPort":"", - "memoryEndpoint": , - "numIterations": , - "allowablePeakMemoryVariance": , - "allowableServiceResponseTimeVariance": , - "testCaseDir": "", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": , - "testSuite": "", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "ConfigSAMPLE", + "targetHost": "", + "targetPort":"", + "memoryEndpoint": , + "numIterations": , + "allowablePeakMemoryVariance": , + "allowableServiceResponseTimeVariance": , + "testCaseDir": "", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": , + "testSuite": "", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10 } """ Then the response code should be 400 Scenario: Successful update of config file with PUT request - Given the file "GodogConfig.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" - When I send "PUT" request to "/configs/GodogConfig" with body: - """ + Given there is no existing test file "ConfigSAMPLE.xml" + And the header "path" is "/uiServices/test" + When I send "POST" request to "/configs" with a body: + """ { - "apiName": "GodogConfig", - "targetHost": "localhost2", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost", + "targetPort":"9191", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 1000, + "allowablePeakMemoryVariance": 30, + "allowableServiceResponseTimeVariance": 30, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 5000, + "TPSFreq": 30, + "rampUsers": 5, + "rampDelay": 15 + } + """ + Then the response code should be 201 + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/configs/ConfigSAMPLE" with body: + """ + { + "apiName": "ConfigSAMPLE", + "targetHost": "localhost2", + "targetPort":"1001", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10 } """ Then the response code should be 204 And the response body should be empty - When I send a "GET" request to "/configs/GodogConfig" + When I send a "GET" request to "/configs/ConfigSAMPLE" And the updated file should match json: - """ + """ { - "apiName": "GodogConfig", - "targetHost": "localhost2", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "ConfigSAMPLE", + "targetHost": "localhost2", + "targetPort": "1001", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "memoryEndpoint": "/alt/debug/vars", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10, + "GBS": false, + "ReBaseMemory": false, + "ReBaseAll": false, + "ExecutionHost": "", + "ReportTemplateFile": "" } """ Scenario: Successful update of config file with PUT request (Update API Name to not match Filename) - Given the file "GodogConfig.xml" exists at "/uiServices/test/" + Given the file "ConfigSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "configPathDir" is "/uiServices/test/" - When I send "PUT" request to "/configs/GodogConfig" with body: - """ + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/configs/ConfigSAMPLE" with body: + """ { - "apiName": "GodogAPI", - "targetHost": "localhost", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "newTest", + "targetHost": "localhost", + "targetPort":"1001", + "memoryEndpoint": "/alt/debug/vars", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10 } """ Then the response code should be 204 And the response body should be empty - When I send a "GET" request to "/configs/GodogConfig" + When I send a "GET" request to "/configs/ConfigSAMPLE" And the updated file should match json: - """ + """ { - "apiName": "GodogAPI", - "targetHost": "localhost", - "targetPort":"1001", - "memoryEndpoint": "/alt/debug/vars", - "numIterations": 4000, - "allowablePeakMemoryVariance": 50, - "allowableServiceResponseTimeVariance": 50, - "testCaseDir": "./definitions/testCases", - "testSuiteDir": "./definitions/testSuites", - "baseStatsOutputDir": "./envStats", - "reportOutputDir": "./report", - "concurrentUsers": 50, - "testSuite": "Default-3", - "requestDelay": 1000, - "TPSFreq": 10, - "rampUsers": 10, - "rampDelay": 10 + "apiName": "newTest", + "targetHost": "localhost", + "targetPort": "1001", + "numIterations": 4000, + "allowablePeakMemoryVariance": 50, + "allowableServiceResponseTimeVariance": 50, + "testCaseDir": "./definitions/testCases", + "testSuiteDir": "./definitions/testSuites", + "baseStatsOutputDir": "./envStats", + "reportOutputDir": "./report", + "concurrentUsers": 50, + "testSuite": "Default-3", + "memoryEndpoint": "/alt/debug/vars", + "requestDelay": 1000, + "TPSFreq": 10, + "rampUsers": 10, + "rampDelay": 10, + "GBS": false, + "ReBaseMemory": false, + "ReBaseAll": false, + "ExecutionHost": "", + "ReportTemplateFile": "" } """ \ No newline at end of file diff --git a/uiServices/test/godog_test.go b/uiServices/test/godog_test.go index acd8dcc..e37469f 100644 --- a/uiServices/test/godog_test.go +++ b/uiServices/test/godog_test.go @@ -10,6 +10,7 @@ import ( "net/http" "net/http/httptest" "os" + "path/filepath" "reflect" "strings" @@ -31,15 +32,13 @@ type apiFeature struct { headerName string } -var suitDir = os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" - func (a *apiFeature) resetResponse() { a.client = &http.Client{} a.resp = nil } func (a *apiFeature) iSendrequestTo(method, endpoint string) (err error) { - response, err := makePostRequest(a.client, method, endpoint, "", "", "") + response, err := makeRequest(a.client, method, endpoint, "", "", "") if err != nil { return err } @@ -59,7 +58,8 @@ func (a *apiFeature) theResponseBodyShouldMatchJSON(body *gherkin.DocString) (er var expectedConfig perfTestUtils.Config var actualConfig perfTestUtils.Config - file, _ := os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath + a.filename) + file, _ := + os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath + "/" + a.filename + ".xml") byteValue, err := ioutil.ReadAll(file) xml.Unmarshal(byteValue, &expectedConfig) @@ -76,7 +76,9 @@ func (a *apiFeature) theTestSuiteResponseBodyShouldMatchJSON(body *gherkin.DocSt var expectedSuite testStrategies.TestSuite var actualSuite testStrategies.TestSuite - file, _ := os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath + a.filename) + file, _ := + os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath + "/" + a.filename + ".xml") + byteValue, err := ioutil.ReadAll(file) xml.Unmarshal(byteValue, &expectedSuite) @@ -92,7 +94,6 @@ func (a *apiFeature) theTestSuiteResponseBodyShouldMatchJSON(body *gherkin.DocSt func (a *apiFeature) theTestSuiteCollectionResponseBodyShouldMatchJSON(body *gherkin.DocString) (err error) { var expectedSuite testStrategies.TestSuite var actualSuite testStrategies.TestSuite - exp := `""" [ @@ -211,15 +212,13 @@ func (a *apiFeature) theHeaderIs(name string, path string) error { func (a *apiFeature) theConfigFileWasCreatedAtLocationDefinedByConfigsPathDir() error { configsPathDir := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath - fileExists := services.FilePathExist(configsPathDir) - if !fileExists { return fmt.Errorf("File Does Not Exist") } logrus.Println("File Exists") - if !IsValidXml(a.requestbody, a.headerPath) { + if !IsValidXML(a.requestbody, a.headerPath) { return fmt.Errorf("File is not a valid XML file") } logrus.Println("File is a valid XML file") @@ -227,7 +226,7 @@ func (a *apiFeature) theConfigFileWasCreatedAtLocationDefinedByConfigsPathDir() } func (a *apiFeature) iSendRequestToWithABody(method, endpoint string, body *gherkin.DocString) error { - response, err := makePostRequest(a.client, method, endpoint, body.Content, a.headerPath, a.headerName) + response, err := makeRequest(a.client, method, endpoint, body.Content, a.headerPath, a.headerName) a.requestbody = body.Content if err != nil { return err @@ -236,73 +235,17 @@ func (a *apiFeature) iSendRequestToWithABody(method, endpoint string, body *gher return nil } -func makePostRequest(client *http.Client, method, endpoint, body string, headerPath string, headerName string) (*http.Response, error) { - - var reqBody io.Reader - if body != "" { - reqBody = strings.NewReader(body) - } - - req, err := http.NewRequest(method, "http://localhost:9191"+endpoint, reqBody) - - if headerPath == "" { - req.Header.Set(headerName, "") - } else { - req.Header.Set(headerName, fmt.Sprintf("%s/src/github.com/xtracdev/automated-perf-test/uiServices/test/", os.Getenv("GOPATH"))) - } - if err != nil { - return nil, err - } - - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - return resp, nil -} - -func FeatureContext(s *godog.Suite) { - api := &apiFeature{} - - s.BeforeScenario(func(interface{}) { - - api.resetResponse() - - }) - - s.Step(`^I send "(GET|POST|PUT|DELETE)" request to "([^"]*)"$`, api.iSendrequestTo) - s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) - s.Step(`^the header "([^"]*)" is "([^"]*)"$`, api.theHeaderIs) - s.Step(`^the response body should match json:$`, api.theResponseBodyShouldMatchJSON) - s.Step(`^the response body should be empty$`, api.theResponseBodyShouldBeEmpty) - s.Step(`^the config file was created at location defined by configsPathDir$`, api.theConfigFileWasCreatedAtLocationDefinedByConfigsPathDir) - s.Step(`^the automated performance ui server is available$`, theAutomatedPerformanceUiServerIsAvailable) - s.Step(`^I send "([^"]*)" request to "([^"]*)" with a body:$`, api.iSendRequestToWithABody) - s.Step(`^the file name is "([^"]*)"$`, api.theFileNameis) - s.Step(`^I send a "([^"]*)" request to "([^"]*)"$`, api.iSendARequestTo) - s.Step(`^the file "([^"]*)" exists at "([^"]*)"$`, theFileExistsAt) - s.Step(`^I send "([^"]*)" request to "([^"]*)" with body:$`, api.iSendRequestToWithBody) - s.Step(`^the updated file should match json:$`, api.theUpdatedFileShouldMatchJSON) - s.Step(`^there is no existing test file "([^"]*)"$`, api.thereIsNoExistingTestFile) - s.Step(`^the test suite response body should match json:$`, api.theTestSuiteResponseBodyShouldMatchJSON) - s.Step(`^the test suite collection response body should match json:$`, api.theTestSuiteCollectionResponseBodyShouldMatchJSON) - s.Step(`^the "([^"]*)" has been created at "([^"]*)"$`, createNewFile) - s.Step(`^the test case collection response body should match json:$`, api.theTestSuiteCollectionResponseBodyShouldMatchJSON) - s.Step(`^the test case response body should match json:$`, api.theTestSuiteCollectionResponseBodyShouldMatchJSON) -} - func (a *apiFeature) thereIsNoExistingTestFile(file string) error { os.Remove(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test/" + file) return nil } -func theAutomatedPerformanceUiServerIsAvailable() error { +func theAutomatedPerformanceUIServerIsAvailable() error { go http.ListenAndServe(":9191", services.GetRouter()) return nil } -func IsValidXml(config string, header string) bool { +func IsValidXML(config string, header string) bool { file, err := os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + header) if err != nil { fmt.Println(err) @@ -343,36 +286,23 @@ func (a *apiFeature) theFileNameis(filename string) error { } func (a *apiFeature) iSendARequestTo(method, endpoint string) error { - response, err := makeGetRequest(a.client, method, endpoint, a.filename, a.headerPath, a.headerName) + response, err := makeRequest(a.client, method, endpoint, a.filename, a.headerPath, a.headerName) if err != nil { return err } - + // TODO this can be removed + pathSplit := strings.Split(endpoint, "/") + if len(pathSplit) >= 3 { + a.filename = pathSplit[2] + } a.resp = response return nil } -func makeGetRequest(client *http.Client, method, endpoint string, filename string, headerPath, headerName string) (*http.Response, error) { - req, err := http.NewRequest(method, "http://localhost:9191"+endpoint, nil) - - if headerPath == "" { - req.Header.Set(headerName, "") - } else { - req.Header.Set(headerName, fmt.Sprintf("%s/src/github.com/xtracdev/automated-perf-test/uiServices/test/", os.Getenv("GOPATH"))) - } - if err != nil { - return nil, err - } - - resp, err := client.Do(req) - if err != nil { - return nil, err - } +func theFileExistsAt(filename, path string) error { - return resp, nil -} + os.Create(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + path + filename) -func theFileExistsAt(filename, path string) error { _, err := os.Stat(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + path + filename) if err != nil { fmt.Println("Error. File Not Found at location : " + path + filename) @@ -382,7 +312,7 @@ func theFileExistsAt(filename, path string) error { } func (a *apiFeature) iSendRequestToWithBody(method, endpoint string, body *gherkin.DocString) error { - response, err := makePutRequest(a.client, method, endpoint, body.Content, a.headerPath, a.headerName) + response, err := makeRequest(a.client, method, endpoint, body.Content, a.headerPath, a.headerName) a.requestbody = body.Content if err != nil { return err @@ -391,7 +321,7 @@ func (a *apiFeature) iSendRequestToWithBody(method, endpoint string, body *gherk return nil } -func makePutRequest(client *http.Client, method, endpoint, body string, headerPath, headerName string) (*http.Response, error) { +func makeRequest(client *http.Client, method string, endpoint string, body string, headerPath string, headerName string) (*http.Response, error) { var reqBody io.Reader if body != "" { @@ -403,7 +333,7 @@ func makePutRequest(client *http.Client, method, endpoint, body string, headerPa if headerPath == "" { req.Header.Set(headerName, "") } else { - req.Header.Set(headerName, fmt.Sprintf("%s/src/github.com/xtracdev/automated-perf-test/uiServices/test/", os.Getenv("GOPATH"))) + req.Header.Set(headerName, fmt.Sprintf("%s/src/github.com/xtracdev/automated-perf-test/%s", os.Getenv("GOPATH"), headerPath)) } if err != nil { return nil, err @@ -421,7 +351,8 @@ func (a *apiFeature) theUpdatedFileShouldMatchJSON(body *gherkin.DocString) (err var expectedConfig perfTestUtils.Config var actualConfig perfTestUtils.Config - file, _ := os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath + a.filename) + file, _ := + os.Open(os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test" + a.headerPath + a.filename + ".xml") byteValue, err := ioutil.ReadAll(file) xml.Unmarshal(byteValue, &expectedConfig) @@ -434,12 +365,57 @@ func (a *apiFeature) theUpdatedFileShouldMatchJSON(body *gherkin.DocString) (err return nil } -func createNewFile(fileName, path string) error { +func FeatureContext(s *godog.Suite) { + api := &apiFeature{} - err := ioutil.WriteFile(fmt.Sprintf("%s%s/%s", suitDir, path, fileName), nil, 0666) - if err != nil { - logrus.Error(" error creating file ", err) - return err - } - return err + s.AfterScenario(func(interface{}, error) { + dirname := os.Getenv("GOPATH") + "/src/github.com/xtracdev/automated-perf-test/uiServices/test" + + d, err := os.Open(dirname) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + defer d.Close() + + files, err := d.Readdir(-1) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println("Reading " + dirname) + + for _, file := range files { + if file.Mode().IsRegular() { + if filepath.Ext(file.Name()) == ".xml" { + os.Remove(file.Name()) + fmt.Println("Deleted ", file.Name()) + } + } + } + }) + + s.BeforeScenario(func(interface{}) { + api.resetResponse() + }) + + s.Step(`^I send "(GET|POST|PUT|DELETE)" request to "([^"]*)"$`, api.iSendrequestTo) + s.Step(`^the response code should be (\d+)$`, api.theResponseCodeShouldBe) + s.Step(`^the header "([^"]*)" is "([^"]*)"$`, api.theHeaderIs) + s.Step(`^the response body should match json:$`, api.theResponseBodyShouldMatchJSON) + s.Step(`^the response body should be empty$`, api.theResponseBodyShouldBeEmpty) + s.Step(`^the config file was created at location defined by path`, api.theConfigFileWasCreatedAtLocationDefinedByConfigsPathDir) + s.Step(`^the automated performance ui server is available$`, theAutomatedPerformanceUIServerIsAvailable) + s.Step(`^I send "([^"]*)" request to "([^"]*)" with a body:$`, api.iSendRequestToWithABody) + s.Step(`^the file name is "([^"]*)"$`, api.theFileNameis) + s.Step(`^I send a "([^"]*)" request to "([^"]*)"$`, api.iSendARequestTo) + s.Step(`^the file "([^"]*)" exists at "([^"]*)"$`, theFileExistsAt) + s.Step(`^I send "([^"]*)" request to "([^"]*)" with body:$`, api.iSendRequestToWithBody) + s.Step(`^the updated file should match json:$`, api.theUpdatedFileShouldMatchJSON) + s.Step(`^there is no existing test file "([^"]*)"$`, api.thereIsNoExistingTestFile) + s.Step(`^the test suite response body should match json:$`, api.theTestSuiteResponseBodyShouldMatchJSON) + s.Step(`^the test suite collection response body should match json:$`, api.theTestSuiteCollectionResponseBodyShouldMatchJSON) + s.Step(`^the test case collection response body should match json:$`, api.theTestSuiteCollectionResponseBodyShouldMatchJSON) + s.Step(`^the test case response body should match json:$`, api.theTestSuiteCollectionResponseBodyShouldMatchJSON) } diff --git a/uiServices/test/samples/TestCaseSAMPLE.xml b/uiServices/test/samples/TestCaseSAMPLE.xml new file mode 100644 index 0000000..e69de29 diff --git a/uiServices/test/samples/testCase.json b/uiServices/test/samples/testCase.json new file mode 100644 index 0000000..e69de29 diff --git a/uiServices/test/samples/testCase.xml b/uiServices/test/samples/testCase.xml new file mode 100644 index 0000000..89fda5b --- /dev/null +++ b/uiServices/test/samples/testCase.xml @@ -0,0 +1,22 @@ + + testCase + host + x + GET + desciiii + path/to/URI + false + payload + + 200 + ccccc + +
Header-Value
+
+ + Res-Valueeee + + 55 + 0 + Infrequent +
\ No newline at end of file diff --git a/uiServices/test/samples/testConfig.xml b/uiServices/test/samples/testConfig.xml new file mode 100644 index 0000000..39e8b9c --- /dev/null +++ b/uiServices/test/samples/testConfig.xml @@ -0,0 +1,19 @@ + + testConfig + localhost + 8080 + 55 + 12 + 15 + ./definitions/testCases + ./definitions/testSuites + ./envStats + .efreefef + 50 + Default-1 + /alt/debug/vars + 5000 + 30 + 15 + 15 + \ No newline at end of file diff --git a/uiServices/test/samples/testSuite.json b/uiServices/test/samples/testSuite.json new file mode 100644 index 0000000..e69de29 diff --git a/uiServices/test/samples/testSuite.xml b/uiServices/test/samples/testSuite.xml new file mode 100644 index 0000000..cbf9494 --- /dev/null +++ b/uiServices/test/samples/testSuite.xml @@ -0,0 +1,7 @@ + + testSuite + Services for XYZrrr + SuiteBased + + + \ No newline at end of file diff --git a/uiServices/test/testCase.feature b/uiServices/test/testCase.feature index 771bdcf..dcff5bc 100644 --- a/uiServices/test/testCase.feature +++ b/uiServices/test/testCase.feature @@ -9,18 +9,18 @@ Feature: Test Case Scenarios ################################### Scenario: Successful creation of Test Case - Given there is no existing test file "GodogTestCase.xml" + Given there is no existing test file "TestCaseSAMPLE.xml" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test" When I send "POST" request to "/test-cases" with a body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", "httpMethod":"GET", - "baseURI": "path/to/URI", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -48,16 +48,49 @@ Feature: Test Case Scenarios Scenario: Unsuccessful creation of Test Case (file already exists ) Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test" When I send "POST" request to "/test-cases" with a body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", "httpMethod":"GET", - "baseURI": "path/to/URI", + "baseUri": "path/to/URI", + "multipart":false, + "payload": "payload", + "responseStatusCode":200, + "responseContentType": "JSON" , + "preThinkTime": 1000, + "postThinkTime":2000, + "execWeight": "Sparse", + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" + }], + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" + }], + "multipartPayload":[{ + "fieldName": "F-Name", + "fieldValue":"PayloadName", + "fileName": "file-name" + }] + } + """ + Then the response code should be 201 + And the header "path" is "/uiServices/test/" + When I send "POST" request to "/test-cases" with a body: + """ + { + "testname":"TestCaseSAMPLE", + "description":"desc", + "overrideHost":"host", + "overridePort":"9191", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -85,16 +118,16 @@ Feature: Test Case Scenarios Scenario: Unsuccessful creation of test Case ( Missing Required Fields ) Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "POST" request to "/test-suites" with a body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", - "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -102,18 +135,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ - "FieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "multipartPayload":[{ + "fieldName": "F-Name", + "fieldValue":"PayloadName", + "fileName": "file-name" }] } """ @@ -122,16 +155,16 @@ Feature: Test Case Scenarios Scenario: Unsuccessful creation of Test Case ( No header defined ) Given the automated performance ui server is available - And the header "testCasePathDir" is "" + And the header "path" is "" When I send "POST" request to "/test-cases" with a body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -139,18 +172,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ + "headers":[{ "Key": "Authorization", "Value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ - "FieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "multipartPayload":[{ + "fieldName": "F-Name", + "fieldValue":"PayloadName", + "fileName": "file-name" }] } """ @@ -163,18 +196,18 @@ Feature: Test Case Scenarios ################################### Scenario: Unsuccessful update of test-case file with PUT request (No File Path) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "" + And the header "path" is "" When I send "PUT" request to "/test-suites/GodogTestSuite" with body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", - "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -182,18 +215,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ - "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "multipartPayload":[{ + "fieldName": "F-Name", + "fieldValue":"PayloadName", + "fileName": "file-name" }] } @@ -202,18 +235,18 @@ Feature: Test Case Scenarios Scenario: Unsuccessful update of test-case file with PUT request (Incorrect File Name) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "PUT" request to "/test-cases/xxx" with body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -221,18 +254,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } @@ -241,18 +274,18 @@ Feature: Test Case Scenarios Scenario: Unsuccessful update of test-case file with PUT request (No File Name) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "PUT" request to "/test-suites/" with body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", - "HttpMethod":"GET", - "BaseURI": "path/to/URI", + "httpMethod":"GET", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -260,18 +293,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } @@ -279,17 +312,17 @@ Feature: Test Case Scenarios Then the response code should be 404 Scenario: Unsuccessful update of test-suite file with PUT request (Missing Required Fields) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - When I send "PUT" request to "/test-suites/GodogTestCase" with body: + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/test-suites/TestCaseSAMPLE" with body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"", "overridePort":"", - "HttpMethod":"", - "BaseURI": "path/to/URI", + "httpMethod":"", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -297,18 +330,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } @@ -317,18 +350,18 @@ Feature: Test Case Scenarios Scenario: Successful update of test-case file with PUT request - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - When I send "PUT" request to "/test-cases/GodogTestCase" with body: + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/test-cases/TestCaseSAMPLE" with body: """ { - "testname":"GodogTestCase", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"1001", - "HttpMethod":"POST", - "BaseURI": "path/to/URI", + "httpMethod":"POST", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -336,18 +369,18 @@ Feature: Test Case Scenarios "preThinkTime": 1000, "postThinkTime":2000, "execWeight": "Sparse", - "Headers":[{ - "Key": "Authorization", - "Value" :"Header-Value" + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" }], - "ResponseValues":[{ - "Value":"Res-Value", - "ExtractionKey": "Res-Key" + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" }], - "MultipartPayload":[{ + "multipartPayload":[{ "fieldName": "F-Name", - "FieldValue":"PayloadName", - "FileName": "file-name" + "fieldValue":"PayloadName", + "fileName": "file-name" }] } @@ -361,18 +394,18 @@ Feature: Test Case Scenarios ################################### Scenario: Successful retrieval all test cases with valid "GET" request ##Add additional file first so there are multiple files to GET - Given there is no existing test file "GodogTestCase2.xml" + Given there is no existing test file "TestCaseSAMPLE2.xml" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "POST" request to "/test-cases" with a body: """ { - "testname":"GodogTestCase2", + "testname":"TestCaseSAMPLE2", "description":"desc2", "overrideHost":"host", "overridePort":"9191", "httpMethod":"PUT", - "baseURI": "path/to/URI", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -398,19 +431,19 @@ Feature: Test Case Scenarios Then the response code should be 201 And the response body should be empty Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send a "GET" request to "/test-cases" Then the response code should be 200 And the test case collection response body should match json: """ [ { - "name": "GodogTestCase, + "name": "TestCaseSAMPLE, "description": "Case Desc", "httpMethod": "GET" }, { - "name": "GodogTestCase2, + "name": "TestCaseSAMPLE2, "description": "Case Desc2", "httpMethod": "PUT" } @@ -418,99 +451,127 @@ Feature: Test Case Scenarios """ - Scenario: Unsuccessful retrieval of test-cases (No Header) Given the automated performance ui server is available - And the header "testSuitePathDir" is "" + And the header "path" is "" When I send a "GET" request to "/test-cases" Then the response code should be 400 - - - ################################### ####### GET REQUESTS ####### ################################### Scenario: Unsuccessful retrieval of test-Cases file (File Not Found) Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send a "GET" request to "/test-cases/xxx" Then the response code should be 404 Scenario: Unsuccessful retrieval of test-suites file (No Header) Given the automated performance ui server is available - And the header "testCasePathDir" is "" - When I send a "GET" request to "/test-suites/GodogTestCase" + And the header "path" is "" + When I send a "GET" request to "/test-suites/TestCaseSAMPLE" Then the response code should be 400 Scenario: Retrieve Test Case file with valid "GET" request - Given the file "GodogTestCase2.xml" exists at "/uiServices/test/" + Given there is no existing test file "TestCaseSAMPLE.xml" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - And the file name is "Case1.xml" - When I send a "GET" request to "/test-cases/GodogTestCase2" + And the header "path" is "/uiServices/test" + When I send "POST" request to "/test-cases" with a body: + """ + { + "testname":"TestCaseSAMPLE", + "description":"desc", + "overrideHost":"host", + "overridePort":"9191", + "httpMethod":"GET", + "baseUri": "path/to/URI", + "multipart":false, + "payload": "payload", + "responseStatusCode":200, + "responseContentType": "JSON" , + "preThinkTime": 1000, + "postThinkTime":2000, + "execWeight": "Sparse", + "headers":[{ + "key": "Authorization", + "value" :"Header-Value" + }], + "responseValues":[{ + "value":"Res-Value", + "extractionKey": "Res-Key" + }], + "multipartPayload":[{ + "fieldName": "F-Name", + "fieldValue":"PayloadName", + "fileName": "file-name" + }] + } + """ + Then the response code should be 201 + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/samples/" + Given the automated performance ui server is available + And the header "path" is "/uiServices/test/samples/" + And the file name is "TestCaseSAMPLE.xml" + When I send a "GET" request to "/test-cases/testCase" Then the response code should be 200 And the test case response body should match json: """ { - "XMLName": { - "Space": "", - "Local": "testDefinition" - }, - "TestName": GodogTestCase", + "TestName": TestCaseSAMPLE", "OverrideHost": "host", "OverridePort": "9191", "HTTPMethod": "GET", "Description": "desc", - "BaseURI": "", + "baseUri": "", "Multipart": false, "Payload": "", "MultipartPayload": null, "ResponseStatusCode": 0, "ResponseContentType": "", - "Headers": null, - "ResponseValues": null, + "headers": null, + "responseValues": null, "PreThinkTime": 0, "PostThinkTime": 0, "ExecWeight": "" } """ - - ################################### - ####### DELETE REQUESTS ####### ################################### + ####### DELETE REQUESTS ######## + ################################### + + Scenario: Fail to remove Test Case file with "DELETE" request (File Not Found) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send a "DELETE" request to "/test-cases/xxxx" Then the response code should be 404 Scenario: Fail to remove Test Case file with "DELETE" request (No Header) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "" + And the header "path" is "" When I send a "DELETE" request to "/test-cases/xxxx" Then the response code should be 400 Scenario: Successful removal Test Case file with "DELETE" request #create file to delete - Given there is no existing test file "GodogTestCase3.xml" + Given there is no existing test file "TestCaseSAMPLE.xml" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "POST" request to "/test-cases" with a body: """ { - "testname":"GodogTestCase3", + "testname":"TestCaseSAMPLE", "description":"desc", "overrideHost":"host", "overridePort":"9191", "httpMethod":"GET", - "baseURI": "path/to/URI", + "baseUri": "path/to/URI", "multipart":false, "payload": "payload", "responseStatusCode":200, @@ -535,9 +596,30 @@ Feature: Test Case Scenarios """ Then the response code should be 201 #Delete - Given the file "GodogTestCase3.xml" exists at "/uiServices/test/" + Given the file "TestCaseSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - When I send a "DELETE" request to "/test-cases/GodogTestCase3" + And the header "path" is "/uiServices/test/" + When I send a "DELETE" request to "/test-cases/TestCaseSAMPLE" Then the response code should be 204 + +Scenario: Unsuccessful deleting of test-case (No Header) + Given the automated performance ui server is available + And the header "path" is "" + When I send a "DELETE" request to "/test-cases" + Then the response code should be 400 + + +Scenario: Unsuccessful deleting of test-case file (Empty Directory) + Given the automated performance ui server is available + And the header "path" is "/uiServices/test/cases" + When I send a "DELETE" request to "/test-cases/" + Then the response code should be 404 + + +Scenario: Successful deleting of test-case file with DELETE request + Given the file "deleteTest.xml" exists at "/uiServices/test/cases" + Given the automated performance ui server is available + And the header "path" is "/uiServices/test/cases" + When I send a "DELETE" request to "/test-cases" + Then the response code should be 200 \ No newline at end of file diff --git a/uiServices/test/testSuite.feature b/uiServices/test/testSuite.feature index 0fd6478..e540e4c 100644 --- a/uiServices/test/testSuite.feature +++ b/uiServices/test/testSuite.feature @@ -8,13 +8,13 @@ Feature: Test Suite Creation ################################### Scenario: Successful creation of test Suite - Given there is no existing test file "GodogTestSuite.xml" + Given there is no existing test file "TestSuiteSAMPLE.xml" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "POST" request to "/test-suites" with a body: """ { - "name": "GodogTestSuite", + "name": "TestSuiteSAMPLE", "testStrategy": "SuiteBased", "description": "Services for XYZ", "testCases":[ @@ -32,11 +32,30 @@ Feature: Test Suite Creation Scenario: Unsuccessful creation of test Suite (file already exists ) Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + Given there is no existing test file "TestSuiteSAMPLE.xml" + And the header "path" is "/uiServices/test/" When I send "POST" request to "/test-suites" with a body: """ { - "name": "GodogTestSuite", + "name": "TestSuiteSAMPLE", + "testStrategy": "SuiteBased", + "description": "Services for XYZ", + "testCases":[ + { + "name":"file1", + "preThinkTime": 1000, + "postThinkTime": 2000, + "execWeight": "Infrequent" + } + ] + } + """ + Then the response code should be 201 + And the header "path" is "/uiServices/test/" + When I send "POST" request to "/test-suites" with a body: + """ + { + "name": "TestSuiteSAMPLE", "testStrategy": "SuiteBased", "description": "Services for XYZ", "testCases":[ @@ -60,7 +79,7 @@ Feature: Test Suite Creation Scenario: Unsuccessful creation of test Suite ( Missing Required Fields ) Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "POST" request to "/test-suites" with a body: """ { @@ -79,11 +98,11 @@ Feature: Test Suite Creation Scenario: Unsuccessful creation of test Suite ( No header defined ) Given the automated performance ui server is available - And the header "testSuitePathDir" is "" + And the header "path" is "" When I send "POST" request to "/test-suites" with a body: """ { - "name": "GodogTestSuite", + "name": "TestSuiteSAMPLE", "testStrategy": "SuiteBased", "description": "Services for XYZ", "testCases":[ @@ -101,11 +120,11 @@ Feature: Test Suite Creation Scenario: Unsuccessful creation of test Suite ( Incorrect URL ) Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/GodogTestSuite.xml" + And the header "path" is "/uiServices/test/TestSuiteSAMPLE.xml" When I send "POST" request to "/xxxx" with a body: """ { - "name": "GodogTestSuite", + "name": "TestSuiteSAMPLE", "testStrategy": "SuiteBased", "description": "Services for XYZ", "testCases":[ @@ -122,7 +141,7 @@ Feature: Test Suite Creation Scenario: Unsuccessful creation of test Suite(No Name defined) Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/GodogTestSuite.xml" + And the header "path" is "/uiServices/test/TestSuiteSAMPLE.xml" When I send "POST" request to "/test-suites" with a body: """ { @@ -147,13 +166,13 @@ Feature: Test Suite Creation ################################### Scenario: Unsuccessful update of test-suite file with PUT request (No File Path) - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "" - When I send "PUT" request to "/test-suites/GodogTestSuite" with body: + And the header "path" is "" + When I send "PUT" request to "/test-suites/TestSuiteSAMPLE" with body: """ { - "name": "GodogTestSuite", + "name": "TestSuiteSAMPLE", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -170,13 +189,13 @@ Feature: Test Suite Creation Scenario: Unsuccessful update of test-suite file with PUT request (Incorrect File Name) - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "PUT" request to "/test-suites/xxx" with body: """ { - "name": "GodogTestSuite2", + "name": "TestSuiteSAMPLE2", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -193,13 +212,13 @@ Feature: Test Suite Creation Scenario: Unsuccessful update of test-suite file with PUT request (No File Name) - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send "PUT" request to "/test-suites/" with body: """ { - "name": "GodogTestSuite2", + "name": "TestSuiteSAMPLE2", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -215,10 +234,10 @@ Feature: Test Suite Creation Then the response code should be 404 Scenario: Unsuccessful update of test-suite file with PUT request (Missing Required Fields) - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" - When I send "PUT" request to "/test-suites/GodogTestSuite" with body: + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/test-suites/TestSuiteSAMPLE" with body: """ { "testCases":[ @@ -235,13 +254,13 @@ Feature: Test Suite Creation Scenario: Successful update of test-suite file with PUT request - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" - When I send "PUT" request to "/test-suites/GodogTestSuite" with body: + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/test-suites/TestSuiteSAMPLE" with body: """ { - "name": "GodogTestSuite2", + "name": "TestSuiteSAMPLE2", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -256,11 +275,11 @@ Feature: Test Suite Creation """ Then the response code should be 204 And the response body should be empty - When I send a "GET" request to "/test-suites/GodogTestSuite" + When I send a "GET" request to "/test-suites/TestSuiteSAMPLE" And the updated file should match json: """ { - "name": "GodogTestSuite2", + "name": "TestSuiteSAMPLE2", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -274,13 +293,13 @@ Feature: Test Suite Creation } """ Scenario: Successful update of test-suite file with PUT request (Update API Name to not match Filename) - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" - When I send "PUT" request to "/test-suites/GodogTestSuite" with body: + And the header "path" is "/uiServices/test/" + When I send "PUT" request to "/test-suites/TestSuiteSAMPLE" with body: """ { - "name": "GodogTestSuite2", + "name": "TestSuiteSAMPLE2", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -295,11 +314,11 @@ Feature: Test Suite Creation """ Then the response code should be 204 And the response body should be empty - When I send a "GET" request to "/test-suites/GodogTestSuite" + When I send a "GET" request to "/test-suites/TestSuiteSAMPLE" And the updated file should match json: """ { - "name": "GodogTestSuite2", + "name": "TestSuiteSAMPLE2", "testStrategy": "SuiteBased", "description": "ServiceDesc", "testCases":[ @@ -320,52 +339,39 @@ Feature: Test Suite Creation ################################### Scenario: Try to retrieve test-suite file with valid "GET" request - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" - And the file name is "GodogTestSuite.xml" - When I send a "GET" request to "/test-suites/GodogTestSuite" + Given the file "testSuite.xml" exists at "/uiServices/test/samples" + And the header "path" is "/uiServices/test/samples" + And the file name is "testSuite.xml" + When I send a "GET" request to "/test-suites/testSuite" Then the response code should be 200 And the test suite response body should match json: """ - { - "XMLName": { - "Space": "", - "Local": "testSuite" - }, - "name": "GodogTestSuite2", - "description": "ServiceDesc", - "testStrategy": "SuiteBased", - "testCases": [ - { - "testCase": { - "Space": "", - "Local": "testCase" - }, - "Name": "file1", - "preThinkTime": 2000, - "postThinkTime": 5000, - "execWeight": "Infrequent" - } - ], - "TestDefinitions": null - } + { + "XMLName": { + "Space": "", + "Local": "testSuite" + }, + "name": "testSuite", + "description": "Services for XYZrrr", + "testStrategy": "SuiteBased" + } """ Scenario: Unsuccessful retrieval of test-suites file (File Not Found) Given the automated performance ui server is available - Given the file "GodogTestSuite.xml" exists at "/uiServices/test/" + Given the file "TestSuiteSAMPLE.xml" exists at "/uiServices/test/" Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send a "GET" request to "/test-suites/xxx" Then the response code should be 404 Scenario: Unsuccessful retrieval of test-suites file (No Header) Given the automated performance ui server is available - And the header "testSuitePathDir" is "" - When I send a "GET" request to "/test-suites/GodogTestSuite" + And the header "path" is "" + When I send a "GET" request to "/test-suites/TestSuiteSAMPLE" Then the response code should be 400 @@ -375,15 +381,15 @@ Feature: Test Suite Creation Scenario: Try to retrieve all test suites with valid "GET" request Given the automated performance ui server is available - And the header "testSuitePathDir" is "/uiServices/test/" + And the header "path" is "/uiServices/test/" When I send a "GET" request to "/test-suites" Then the response code should be 200 And the test suite collection response body should match json: """ [ { - "file": "GodogTestSuite.xml", - "name": "GodogTestSuite2, + "file": "TestSuiteSAMPLE.xml", + "name": "TestSuiteSAMPLE2, "description": "ServiceDesc", } ] @@ -392,71 +398,6 @@ Feature: Test Suite Creation Scenario: Unsuccessful retrieval of test-suites (No Header) Given the automated performance ui server is available - And the header "testSuitePathDir" is "" + And the header "path" is "" When I send a "GET" request to "/test-suites" - Then the response code should be 400 - - - - ################################### - ####### DELETE REQUESTS ######## - ################################### - - Scenario: Fail to remove Test Case file with "DELETE" request (File Not Found) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" - Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - When I send a "DELETE" request to "/test-cases/xxxx" - Then the response code should be 404 - - Scenario: Fail to remove Test Case file with "DELETE" request (No Header) - Given the file "GodogTestCase.xml" exists at "/uiServices/test/" - Given the automated performance ui server is available - And the header "testCasePathDir" is "" - When I send a "DELETE" request to "/test-cases/xxxx" - Then the response code should be 400 - - Scenario: Successful removal Test Case file with "DELETE" request - #create file to delete - Given there is no existing test file "GodogTestCase3.xml" - Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - When I send "POST" request to "/test-cases" with a body: - """ - { - "testname":"GodogTestCase3", - "description":"desc", - "overrideHost":"host", - "overridePort":"9191", - "httpMethod":"GET", - "baseURI": "path/to/URI", - "multipart":false, - "payload": "payload", - "responseStatusCode":200, - "responseContentType": "JSON" , - "preThinkTime": 1000, - "postThinkTime":2000, - "execWeight": "Sparse", - "headers":[{ - "key": "Authorization", - "value" :"Header-Value" - }], - "responseValues":[{ - "value":"Res-Value", - "extractionKey": "Res-Key" - }], - "multipartPayload":[{ - "fieldName": "F-Name", - "fieldValue":"PayloadName", - "fileName": "file-name" - }] - } - """ - Then the response code should be 201 - #Delete - Given the file "GodogTestCase3.xml" exists at "/uiServices/test/" - Given the automated performance ui server is available - And the header "testCasePathDir" is "/uiServices/test/" - When I send a "DELETE" request to "/test-cases/GodogTestCase3" - Then the response code should be 204 - + Then the response code should be 400 \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..da9527e --- /dev/null +++ b/yarn.lock @@ -0,0 +1,844 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ajv@^5.2.3: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1@0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +async@~0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-runtime@^6.11.6: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +bl@~0.9.0: + version "0.9.5" + resolved "https://registry.yarnpkg.com/bl/-/bl-0.9.5.tgz#c06b797af085ea00bc527afc8efcf11de2232054" + dependencies: + readable-stream "~1.0.26" + +boom@0.4.x: + version "0.4.2" + resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + dependencies: + hoek "0.9.x" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +caseless@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.6.0.tgz#8167c1ab8397fb5bb95f96d28e5a81c50f247ac4" + +chain-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" + +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +classnames@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +codecov.io@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/codecov.io/-/codecov.io-0.1.6.tgz#59dfd02da1ff31c2fb2b952ad8ad16fd3781b728" + dependencies: + request "2.42.0" + urlgrey "0.4.0" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +combined-stream@~0.0.4: + version "0.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + dependencies: + delayed-stream "0.0.5" + +commander@^2.9.0: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.4.0: + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +coveralls@^2.11.16: + version "2.13.3" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.3.tgz#9ad7c2ae527417f361e8b626483f48ee92dd2bc7" + dependencies: + js-yaml "3.6.1" + lcov-parse "0.0.10" + log-driver "1.2.5" + minimist "1.2.0" + request "2.79.0" + +cryptiles@0.2.x: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + dependencies: + boom "0.4.x" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +ctype@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +deep-equal@~0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.1.2.tgz#b246c2b80a570a47c11be1d9bd1070ec878b87ce" + +defined@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" + +delayed-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +dom-helpers@^3.2.0, dom-helpers@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +extend@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fbjs@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + +forever-agent@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~0.1.0: + version "0.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + dependencies: + async "~0.9.0" + combined-stream "~0.0.4" + mime "~1.2.11" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +hawk@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + dependencies: + boom "0.4.x" + cryptiles "0.2.x" + hoek "0.9.x" + sntp "0.2.x" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@0.9.x: + version "0.9.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +http-signature@~0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + dependencies: + asn1 "0.1.11" + assert-plus "^0.1.5" + ctype "0.5.3" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@~0.4.13: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +invariant@^2.1.0, invariant@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" + dependencies: + loose-envify "^1.0.0" + +is-my-ip-valid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" + +is-my-json-valid@^2.12.4: + version "2.17.2" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + is-my-ip-valid "^1.0.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +js-tokens@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keycode@^2.1.2: + version "2.1.9" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" + +lcov-parse@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" + +lodash.topath@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" + +log-driver@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" + +loose-envify@^1.0.0, loose-envify@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@~2.1.7: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mime-types@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + +mime@~1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +minimist@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-uuid@~1.4.0: + version "1.4.8" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + +oauth-sign@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.4.0.tgz#f22956f31ea7151a821e5f2fb32c113cad8b9f69" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + +prop-types-extra@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.0.1.tgz#a57bd4810e82d27a3ff4317ecc1b4ad005f79a82" + dependencies: + warning "^3.0.0" + +prop-types@^15.5.10, prop-types@^15.5.8: + version "15.6.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.2.tgz#19b57ff24dc2a99ce1f8bdf6afcda59f8ef61f88" + +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + +"react-bootstrap@>= 0.30.7": + version "0.32.1" + resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.32.1.tgz#60624c1b48a39d773ef6cce6421a4f33ecc166bb" + dependencies: + babel-runtime "^6.11.6" + classnames "^2.2.5" + dom-helpers "^3.2.0" + invariant "^2.2.1" + keycode "^2.1.2" + prop-types "^15.5.10" + prop-types-extra "^1.0.1" + react-overlays "^0.8.0" + react-prop-types "^0.4.0" + react-transition-group "^2.0.0" + uncontrollable "^4.1.0" + warning "^3.0.0" + +react-jsonschema-form-layout-grid@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-jsonschema-form-layout-grid/-/react-jsonschema-form-layout-grid-2.1.0.tgz#1caf8d579aea2c22edcae9e8d89f46353187421b" + dependencies: + codecov.io "^0.1.6" + coveralls "^2.11.16" + react-bootstrap ">= 0.30.7" + react-jsonschema-form ">= 0.43.0" + +"react-jsonschema-form@>= 0.43.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-jsonschema-form/-/react-jsonschema-form-1.0.1.tgz#1b83ad5a71458100367c29bef68b5c38d65fbeab" + dependencies: + ajv "^5.2.3" + lodash.topath "^4.5.2" + prop-types "^15.5.8" + setimmediate "^1.0.5" + +react-overlays@^0.8.0: + version "0.8.3" + resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.8.3.tgz#fad65eea5b24301cca192a169f5dddb0b20d3ac5" + dependencies: + classnames "^2.2.5" + dom-helpers "^3.2.1" + prop-types "^15.5.10" + prop-types-extra "^1.0.1" + react-transition-group "^2.2.0" + warning "^3.0.0" + +react-prop-types@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0" + dependencies: + warning "^3.0.0" + +react-transition-group@^2.0.0, react-transition-group@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10" + dependencies: + chain-function "^1.0.0" + classnames "^2.2.5" + dom-helpers "^3.2.0" + loose-envify "^1.3.1" + prop-types "^15.5.8" + warning "^3.0.0" + +readable-stream@~1.0.26: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +request@2.42.0: + version "2.42.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.42.0.tgz#572bd0148938564040ac7ab148b96423a063304a" + dependencies: + bl "~0.9.0" + caseless "~0.6.0" + forever-agent "~0.5.0" + json-stringify-safe "~5.0.0" + mime-types "~1.0.1" + node-uuid "~1.4.0" + qs "~1.2.0" + tunnel-agent "~0.4.0" + optionalDependencies: + aws-sign2 "~0.5.0" + form-data "~0.1.0" + hawk "1.1.1" + http-signature "~0.10.0" + oauth-sign "~0.4.0" + stringstream "~0.0.4" + tough-cookie ">=0.12.0" + +request@2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +sntp@0.2.x: + version "0.2.4" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + dependencies: + hoek "0.9.x" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +split@~0.2.10: + version "0.2.10" + resolved "https://registry.yarnpkg.com/split/-/split-0.2.10.tgz#67097c601d697ce1368f418f06cd201cf0521a57" + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stream-combiner@~0.0.2: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +tape@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tape/-/tape-2.3.0.tgz#0dfeec709227fbcc9170abe7f046962b271431db" + dependencies: + deep-equal "~0.1.0" + defined "~0.0.0" + inherits "~2.0.1" + jsonify "~0.0.0" + resumer "~0.0.0" + split "~0.2.10" + stream-combiner "~0.0.2" + through "~2.3.4" + +through@2, through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tough-cookie@>=0.12.0, tough-cookie@~2.3.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +ua-parser-js@^0.7.9: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + +uncontrollable@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-4.1.0.tgz#e0358291252e1865222d90939b19f2f49f81c1a9" + dependencies: + invariant "^2.1.0" + +urlgrey@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.0.tgz#f065357040fb35c3b311d4e5dc36484d96dbea06" + dependencies: + tape "2.3.0" + +uuid@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + +whatwg-fetch@>=0.10.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"