From 277b3070740df7167f2178e11d87dfbc0b5ce94d Mon Sep 17 00:00:00 2001 From: SIX Date: Wed, 7 Oct 2020 07:47:09 +0200 Subject: [PATCH 01/31] Add support for Microsoft Edge Chromium browser --- .gitignore | 1 + .../intuit/karate/driver/DriverOptions.java | 4 +- .../karate/driver/microsoft/EdgeChromium.java | 138 ++++++++++++++++++ .../driver/microsoft/EdgeDevToolsDriver.java | 91 ------------ .../java/driver/demo/Demo01JavaRunner.java | 24 ++- .../EdgeChromiumFullPageRunner.java | 31 ++++ .../screenshot/EdgeChromiumPdfRunner.java | 25 ++++ 7 files changed, 220 insertions(+), 94 deletions(-) create mode 100644 karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeDevToolsDriver.java create mode 100644 karate-demo/src/test/java/driver/screenshot/EdgeChromiumFullPageRunner.java create mode 100644 karate-demo/src/test/java/driver/screenshot/EdgeChromiumPdfRunner.java diff --git a/.gitignore b/.gitignore index 3bb33c383..03d05e299 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ target/ .settings .classpath .vscode +.java-version *.iml build/ bin/ diff --git a/karate-core/src/main/java/com/intuit/karate/driver/DriverOptions.java b/karate-core/src/main/java/com/intuit/karate/driver/DriverOptions.java index 53860c3ff..c2081feef 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/DriverOptions.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/DriverOptions.java @@ -33,7 +33,7 @@ import com.intuit.karate.driver.appium.AndroidDriver; import com.intuit.karate.driver.chrome.Chrome; import com.intuit.karate.driver.chrome.ChromeWebDriver; -import com.intuit.karate.driver.microsoft.EdgeDevToolsDriver; +import com.intuit.karate.driver.microsoft.EdgeChromium; import com.intuit.karate.driver.microsoft.IeWebDriver; import com.intuit.karate.driver.microsoft.MsWebDriver; import com.intuit.karate.driver.firefox.GeckoWebDriver; @@ -300,7 +300,7 @@ public static Driver start(ScenarioContext context, Map options, case "chrome": return Chrome.start(context, options, appender); case "msedge": - return EdgeDevToolsDriver.start(context, options, appender); + return EdgeChromium.start(context, options, appender); case "chromedriver": return ChromeWebDriver.start(context, options, appender); case "geckodriver": diff --git a/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java b/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java new file mode 100644 index 000000000..8c97f1d82 --- /dev/null +++ b/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java @@ -0,0 +1,138 @@ +/* + * The MIT License + * + * Copyright 2018 Intuit Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.intuit.karate.driver.microsoft; + +import com.intuit.karate.FileUtils; +import com.intuit.karate.Http; +import com.intuit.karate.LogAppender; +import com.intuit.karate.core.ScenarioContext; +import com.intuit.karate.driver.DevToolsDriver; +import com.intuit.karate.driver.DriverOptions; +import com.intuit.karate.shell.Command; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * chrome devtools protocol - the "preferred" driver: + * https://chromedevtools.github.io/devtools-protocol/ + * + * @author sixdouglas + */ +public class EdgeChromium extends DevToolsDriver { + + public static final String DEFAULT_PATH_MAC = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"; + public static final String DEFAULT_PATH_WIN = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"; + public static final String DEFAULT_PATH_LINUX = "/dev/null"; + + public EdgeChromium(DriverOptions options, Command command, String webSocketUrl) { + super(options, command, webSocketUrl); + } + + public static EdgeChromium start(ScenarioContext context, Map map, LogAppender appender) { + if (! FileUtils.isOsWindows() && ! FileUtils.isOsMacOsX()) { + throw new UnsupportedOperationException("Edge browser is not yet available on linux!"); + } + DriverOptions options = new DriverOptions(context, map, appender, 9222, + FileUtils.isOsWindows() ? DEFAULT_PATH_WIN : FileUtils.isOsMacOsX() ? DEFAULT_PATH_MAC : DEFAULT_PATH_LINUX); + options.arg("--remote-debugging-port=" + options.port); + options.arg("--no-first-run"); + if (options.userDataDir != null) { + options.arg("--user-data-dir=" + options.userDataDir); + } + options.arg("--disable-popup-blocking"); + if (options.headless) { + options.arg("--headless"); + } + Command command = options.startProcess(); + Http http = options.getHttp(); + Command.waitForHttp(http.urlBase); + Http.Response res = http.path("json").get(); + if (res.body().asList().isEmpty()) { + if (command != null) { + command.close(true); + } + throw new RuntimeException("edge server returned empty list from " + http.urlBase); + } + String attachUrl = null; + String webSocketUrl = null; + List> targets = res.body().asList(); + for (Map target : targets) { + String targetUrl = (String) target.get("url"); + if (targetUrl == null || targetUrl.startsWith("edge-")) { + continue; + } + String targetType = (String) target.get("type"); + if (!"page".equals(targetType)) { + continue; + } + webSocketUrl = (String) target.get("webSocketDebuggerUrl"); + if (options.attach == null) { // take the first + break; + } + if (targetUrl.contains(options.attach)) { + attachUrl = targetUrl; + break; + } + } + if (webSocketUrl == null) { + throw new RuntimeException("failed to attach to Edge-Chromium debug server"); + } + EdgeChromium edgeChromium = new EdgeChromium(options, command, webSocketUrl); + edgeChromium.activate(); + edgeChromium.enablePageEvents(); + edgeChromium.enableRuntimeEvents(); + edgeChromium.enableTargetEvents(); + if (!options.headless) { + edgeChromium.initWindowIdAndState(); + } + return edgeChromium; + } + + public static EdgeChromium start(String chromeExecutablePath, boolean headless) { + Map options = new HashMap<>(); + options.put("executable", chromeExecutablePath); + options.put("headless", headless); + return EdgeChromium.start(null, options, null); + } + + public static EdgeChromium start(Map options) { + if (options == null) { + options = new HashMap<>(); + } + return EdgeChromium.start(null, options, null); + } + + public static EdgeChromium start() { + return start(null); + } + + public static EdgeChromium startHeadless() { + return start(Collections.singletonMap("headless", true)); + } + +} diff --git a/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeDevToolsDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeDevToolsDriver.java deleted file mode 100644 index 1a2835a6a..000000000 --- a/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeDevToolsDriver.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.driver.microsoft; - -import com.intuit.karate.Http; -import com.intuit.karate.LogAppender; -import com.intuit.karate.core.ScenarioContext; -import com.intuit.karate.shell.Command; -import com.intuit.karate.driver.DevToolsDriver; -import com.intuit.karate.driver.DriverElement; -import com.intuit.karate.driver.DriverOptions; -import com.intuit.karate.driver.Element; - -import java.util.Map; - -/** - * - * @author pthomas3 - */ -public class EdgeDevToolsDriver extends DevToolsDriver { - - public EdgeDevToolsDriver(DriverOptions options, Command command, String webSocketUrl) { - super(options, command, webSocketUrl); - } - - public static EdgeDevToolsDriver start(ScenarioContext context, Map map, LogAppender appender) { - DriverOptions options = new DriverOptions(context, map, appender, 9222, "MicrosoftEdge"); - options.arg("--devtools-server-port"); - options.arg(options.port + ""); - options.arg("about:blank"); - Command command = options.startProcess(); - Http http = options.getHttp(); - String webSocketUrl = http.path("json", "list").get() - .jsonPath("get[0] $[?(@.type=='Page')].webSocketDebuggerUrl").asString(); - EdgeDevToolsDriver edge = new EdgeDevToolsDriver(options, command, webSocketUrl); - // edge.activate(); // not supported - edge.enablePageEvents(); - return edge; - } - - @Override - public void activate() { - // not supported apparently - } - - @Override - public void setUrl(String url) { - method("Page.navigate").param("url", url).send(); - } - - @Override - public Element input(String locator, String value) { - eval(DriverOptions.selector(locator) + ".value = \"" + value + "\""); - return DriverElement.locatorExists(this, locator); - } - - @Override - public void close() { - // eval("window.close()", null); // this brings up an alert - } - - @Override - public void quit() { - close(); - if (command != null) { - // TODO this does not work because the command never blocks on windows - command.close(true); - } - } -} diff --git a/karate-demo/src/test/java/driver/demo/Demo01JavaRunner.java b/karate-demo/src/test/java/driver/demo/Demo01JavaRunner.java index 76cdc9337..242fd6ad1 100644 --- a/karate-demo/src/test/java/driver/demo/Demo01JavaRunner.java +++ b/karate-demo/src/test/java/driver/demo/Demo01JavaRunner.java @@ -3,6 +3,8 @@ import com.intuit.karate.FileUtils; import com.intuit.karate.driver.chrome.Chrome; import java.io.File; + +import com.intuit.karate.driver.microsoft.EdgeChromium; import org.junit.Test; import static org.junit.Assert.*; import org.slf4j.Logger; @@ -35,5 +37,25 @@ public void testChrome() throws Exception { FileUtils.writeToFile(new File("target/screenshot.png"), bytes); driver.quit(); } - + + @Test + public void testEdge() throws Exception { + + EdgeChromium driver = EdgeChromium.start(); + driver.setUrl("https://github.com/login"); + driver.input("#login_field", "dummy"); + driver.input("#password", "world"); + driver.submit().click("input[name=commit]"); + String html = driver.html("#js-flash-container"); + assertTrue(html.contains("Incorrect username or password.")); + driver.setUrl("https://google.com"); + driver.input("input[name=q]", "karate dsl"); + driver.submit().click("input[name=btnI]"); + assertEquals("https://github.com/intuit/karate", driver.getUrl()); + byte[] bytes = driver.screenshot(); + // byte[] bytes = driver.screenshotFull(); + FileUtils.writeToFile(new File("target/screenshot.png"), bytes); + driver.quit(); + } + } diff --git a/karate-demo/src/test/java/driver/screenshot/EdgeChromiumFullPageRunner.java b/karate-demo/src/test/java/driver/screenshot/EdgeChromiumFullPageRunner.java new file mode 100644 index 000000000..395b58e5f --- /dev/null +++ b/karate-demo/src/test/java/driver/screenshot/EdgeChromiumFullPageRunner.java @@ -0,0 +1,31 @@ +package driver.screenshot; + +import com.intuit.karate.FileUtils; +import com.intuit.karate.driver.microsoft.EdgeChromium; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Collections; + +/** + * + * @author sixdouglas + */ +public class EdgeChromiumFullPageRunner { + + private static final Logger logger = LoggerFactory.getLogger(EdgeChromiumFullPageRunner.class); + + @Test + public void testEdge() throws Exception { + EdgeChromium edgeChromium = EdgeChromium.startHeadless(); + edgeChromium.setUrl("https://github.com/intuit/karate/graphs/contributors"); + byte[] bytes = edgeChromium.pdf(Collections.EMPTY_MAP); + FileUtils.writeToFile(new File("target/fullscreen.pdf"), bytes); + bytes = edgeChromium.screenshot(true); + FileUtils.writeToFile(new File("target/fullscreen.png"), bytes); + edgeChromium.quit(); + } + +} diff --git a/karate-demo/src/test/java/driver/screenshot/EdgeChromiumPdfRunner.java b/karate-demo/src/test/java/driver/screenshot/EdgeChromiumPdfRunner.java new file mode 100644 index 000000000..e76a02ed0 --- /dev/null +++ b/karate-demo/src/test/java/driver/screenshot/EdgeChromiumPdfRunner.java @@ -0,0 +1,25 @@ +package driver.screenshot; + +import com.intuit.karate.FileUtils; +import com.intuit.karate.driver.microsoft.EdgeChromium; + +import java.io.File; +import java.util.Collections; + +/** + * + * @author sixdouglas + */ +public class EdgeChromiumPdfRunner { + + public static void main(String[] args) { + EdgeChromium edgeChromium = EdgeChromium.startHeadless(); + edgeChromium.setUrl("https://github.com/login"); + byte[] bytes = edgeChromium.pdf(Collections.EMPTY_MAP); + FileUtils.writeToFile(new File("target/github.pdf"), bytes); + bytes = edgeChromium.screenshot(); + FileUtils.writeToFile(new File("target/github.png"), bytes); + edgeChromium.quit(); + } + +} From 53eff3239fd74331e256842d9b6007d924071777 Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Wed, 7 Oct 2020 16:16:18 +0530 Subject: [PATCH 02/31] update + docs after #1302 #1303 --- karate-core/README.md | 4 ++-- .../java/com/intuit/karate/driver/microsoft/EdgeChromium.java | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/karate-core/README.md b/karate-core/README.md index b31e5c414..0c40284e2 100644 --- a/karate-core/README.md +++ b/karate-core/README.md @@ -491,15 +491,15 @@ The recommendation is that you prefer `chrome` for development, and once you hav type | default port | default executable | description ---- | ------------ | ------------------ | ----------- -[`chrome`](https://chromedevtools.github.io/devtools-protocol/) | 9222 | mac: `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`
win: `C:/Program Files (x86)/Google/Chrome/Application/chrome.exe` | "native" Chrome automation via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/) +[`chrome`](https://chromedevtools.github.io/devtools-protocol/) | 9222 | mac: `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`
win: `C:/Program Files (x86)/Google/Chrome/Application/chrome.exe` | "native" Chrome automation via the [DevTools protocol](https://chromedevtools.github.io/devtools-protocol/) [`playwright`](https://playwright.dev) | 4444 | `playwright` | see [`playwrightOptions`](#playwrightoptions) and [Playwright](#playwright) +[`msedge`](https://docs.microsoft.com/en-us/microsoft-edge/) | 9222 | mac: `/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge`
win: `C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe` | the new Chromium based Microsoft Edge, using the [DevTools protocol](https://docs.microsoft.com/en-us/microsoft-edge/devtools-protocol-chromium) [`chromedriver`](https://sites.google.com/a/chromium.org/chromedriver/home) | 9515 | `chromedriver` | W3C Chrome Driver [`geckodriver`](https://github.com/mozilla/geckodriver) | 4444 | `geckodriver` | W3C Gecko Driver (Firefox) [`safaridriver`](https://webkit.org/blog/6900/webdriver-support-in-safari-10/) | 5555 | `safaridriver` | W3C Safari Driver [`msedgedriver`](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/) | 9515 | `msedgedriver` | W3C Microsoft Edge WebDriver (the new one based on Chromium), also see [`webDriverSession`](#webdriversession) [`mswebdriver`](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/) | 17556 | `MicrosoftWebDriver` | Microsoft Edge "Legacy" WebDriver [`iedriver`](https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver) | 5555 | `IEDriverServer` | IE (11 only) Driver -[`msedge`](https://docs.microsoft.com/en-us/microsoft-edge/devtools-protocol/) | 9222 | `MicrosoftEdge` | *very* experimental - using the DevTools protocol [`winappdriver`](https://github.com/Microsoft/WinAppDriver) | 4727 | `C:/Program Files (x86)/Windows Application Driver/WinAppDriver` | Windows Desktop automation, similar to Appium [`android`](https://github.com/appium/appium/) | 4723 | `appium` | android automation via [Appium](https://github.com/appium/appium/) [`ios`](https://github.com/appium/appium/) | 4723 |`appium` | iOS automation via [Appium](https://github.com/appium/appium/) diff --git a/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java b/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java index 8c97f1d82..31ed14bce 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/microsoft/EdgeChromium.java @@ -37,9 +37,6 @@ import java.util.Map; /** - * - * chrome devtools protocol - the "preferred" driver: - * https://chromedevtools.github.io/devtools-protocol/ * * @author sixdouglas */ From 09f0a6e204be415b52f9334e03586028d6ea0120 Mon Sep 17 00:00:00 2001 From: Nishant-Sehgal Date: Thu, 8 Oct 2020 13:21:18 +0530 Subject: [PATCH 03/31] Issue-1076 Updating cucumber-reporting version to 5.3.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 29f25f82b..2feeb882b 100755 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 5.2.9.RELEASE 2.3.4.RELEASE 0.7.9 - 3.8.0 + 5.3.1 From 8b506060cdb62c38dbd7ddaab9575be81aaa5867 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Thu, 8 Oct 2020 12:32:22 -0400 Subject: [PATCH 04/31] Fixing issue that causes karate-config.js from loading an external file when packaged in Spring Boot (https://github.com/intuit/karate/issues/751#issuecomment-704926750) --- .../java/com/intuit/karate/FileUtils.java | 42 ++++++------------- .../main/java/com/intuit/karate/Resource.java | 28 ++++++++----- .../main/java/com/intuit/karate/Runner.java | 31 +++----------- .../karate/core/FeatureExecutionUnit.java | 2 + .../com/intuit/karate/core/FeatureParser.java | 32 +++++++------- .../karate/core/ScenarioExecutionUnit.java | 2 + .../intuit/karate/netty/FeatureServer.java | 7 ++-- .../java/com/intuit/karate/FileUtilsTest.java | 2 +- .../junit4/files/BootJarLoadingTest.java | 2 +- .../karate/junit4/files/JarLoadingTest.java | 2 +- 10 files changed, 64 insertions(+), 86 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/FileUtils.java b/karate-core/src/main/java/com/intuit/karate/FileUtils.java index 98dcb646f..695d4e2c3 100755 --- a/karate-core/src/main/java/com/intuit/karate/FileUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/FileUtils.java @@ -23,39 +23,23 @@ */ package com.intuit.karate; -import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeatureParser; +import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.exception.KarateFileNotFoundException; import com.jayway.jsonpath.DocumentContext; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; +import org.slf4j.LoggerFactory; + +import java.io.*; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.nio.file.*; +import java.util.*; import java.util.stream.Stream; -import org.slf4j.LoggerFactory; /** * @@ -187,17 +171,17 @@ public static Resource toResource(String path, ScenarioContext context) { return new Resource(context, path); } else if (isFilePath(path)) { String temp = removePrefix(path); - return new Resource(new File(temp), path); + return new Resource(new File(temp), path, context.classLoader); } else if (isThisPath(path)) { String temp = removePrefix(path); Path parentPath = context.featureContext.parentPath; Path childPath = parentPath.resolve(temp); - return new Resource(childPath); + return new Resource(childPath, context.classLoader); } else { try { Path parentPath = context.rootFeatureContext.parentPath; Path childPath = parentPath.resolve(path); - return new Resource(childPath); + return new Resource(childPath, context.classLoader); } catch (Exception e) { LOGGER.error("feature relative path resolution failed: {}", e.getMessage()); throw e; @@ -592,16 +576,16 @@ public static List scanForFeatureFiles(boolean classpath, String searc if (classpath) { searchPath = removePrefix(searchPath); for (URL url : getAllClassPathUrls(cl)) { - collectFeatureFiles(url, searchPath, files); + collectFeatureFiles(url, searchPath, files, cl); } return files; } else { - collectFeatureFiles(null, searchPath, files); + collectFeatureFiles(null, searchPath, files, cl); return files; } } - private static void collectFeatureFiles(URL url, String searchPath, List files) { + private static void collectFeatureFiles(URL url, String searchPath, List files, ClassLoader cl) { boolean classpath = url != null; int colonPos = searchPath.lastIndexOf(':'); int line = -1; @@ -654,7 +638,7 @@ private static void collectFeatureFiles(URL url, String searchPath, List tags, List paths, String scenarioName, - List hooks, int threadCount, String reportDir) { + List hooks, int threadCount, String reportDir) { Builder options = new Builder(); options.tags = tags; options.paths = paths; @@ -410,7 +391,7 @@ public static Map runFeature(Feature feature, Map runFeature(File file, Map vars, boolean evalKarateConfig) { - Feature feature = FeatureParser.parse(file); + Feature feature = FeatureParser.parse(file, Thread.currentThread().getContextClassLoader()); return runFeature(feature, vars, evalKarateConfig); } diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java index 7d8f40c56..f1f9d6f6e 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java @@ -102,12 +102,14 @@ public void onComplete() { @Override public Iterator process(ScenarioExecutionUnit unit) { if (isSelected(unit) && !unit.result.isFailed()) { // can happen for dynamic scenario outlines with a failed background ! + System.out.println("starting execution"); unit.run(); // we also hold a reference to the last scenario-context that executed // for cases where the caller needs a result lastContextExecuted = unit.getContext(); return Collections.singletonList(unit.result).iterator(); } else { + System.out.println("else execution"); return Collections.emptyIterator(); } } diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java index 3f08194df..24c9e61b7 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java @@ -27,9 +27,13 @@ import com.intuit.karate.Resource; import com.intuit.karate.StringUtils; import com.intuit.karate.exception.KarateException; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -38,16 +42,6 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.RuleContext; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.tree.ParseTreeWalker; -import org.antlr.v4.runtime.tree.TerminalNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * @@ -66,11 +60,15 @@ public class FeatureParser extends KarateParserBaseListener { public static Feature parse(String relativePath) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Path path = FileUtils.fromRelativeClassPath(relativePath, cl); - return parse(new Resource(path, relativePath, -1)); + return parse(new Resource(path, relativePath, -1, cl)); } public static Feature parse(File file) { - return parse(new Resource(file.toPath())); + return parse(file, Thread.currentThread().getContextClassLoader()); + } + + public static Feature parse(File file, ClassLoader cl) { + return parse(new Resource(file.toPath(), cl)); } public static Feature parse(Resource resource) { @@ -110,6 +108,7 @@ public static void updateStepFromText(Step step, String text) throws Exception { step.setDocString(temp.getDocString()); step.setTable(temp.getTable()); } +/* private static InputStream toStream(File file) { try { @@ -118,10 +117,13 @@ private static InputStream toStream(File file) { throw new RuntimeException(e); } } +*/ +/* private FeatureParser(File file, String relativePath, ClassLoader cl) { - this(new Feature(new Resource(file, relativePath)), toStream(file)); + this(new Feature(new Resource(file, relativePath, cl)), toStream(file)); } +*/ private FeatureParser(Resource resource) { this(new Feature(resource), resource.getStream()); diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java index f54f8eab4..b6518f5f5 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java @@ -192,6 +192,7 @@ private StepResult afterStep(StepResult result) { // extracted for debug public StepResult execute(Step step) { currentStep = step; + System.out.println("executing step " + step.getText()); actions.context.setExecutionUnit(this);// just for deriving call stack if (hooks != null) { boolean shouldExecute = true; @@ -300,6 +301,7 @@ public void run() { } int count = steps.size(); int index = 0; + System.out.println(count + " steps to execute"); while ((index = nextStepIndex()) < count) { Step step = steps.get(index); lastStepResult = execute(step); diff --git a/karate-core/src/main/java/com/intuit/karate/netty/FeatureServer.java b/karate-core/src/main/java/com/intuit/karate/netty/FeatureServer.java index 38b78f251..134a1bd7b 100644 --- a/karate-core/src/main/java/com/intuit/karate/netty/FeatureServer.java +++ b/karate-core/src/main/java/com/intuit/karate/netty/FeatureServer.java @@ -39,6 +39,8 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.SelfSignedCertificate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.InputStream; @@ -49,9 +51,6 @@ import java.util.Map; import java.util.function.Supplier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * @author pthomas3 */ @@ -183,7 +182,7 @@ private static Feature toFeature(File file) { if (parent == null) { // when running via command line and same dir file = new File(file.getAbsolutePath()); } - return FeatureParser.parse(file); + return FeatureParser.parse(file, Thread.currentThread().getContextClassLoader()); } private FeatureServer(Feature[] features, int requestedPort, boolean ssl, Supplier contextSupplier, Map arg) { diff --git a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java index 5b512a6e1..acfa8c6ee 100755 --- a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java +++ b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java @@ -231,7 +231,7 @@ public void testUsingKarateBase() throws Exception { String relativePath = "classpath:demo/jar1/caller.feature"; ClassLoader cl = getJarClassLoader(); Path path = FileUtils.fromRelativeClassPath(relativePath, cl); - Resource resource = new Resource(path, relativePath, -1); + Resource resource = new Resource(path, relativePath, -1, cl); Feature feature = FeatureParser.parse(resource); try { Map map = Runner.runFeature(feature, null, true); diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/BootJarLoadingTest.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/BootJarLoadingTest.java index b87cd8d4c..68c880ac2 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/BootJarLoadingTest.java +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/BootJarLoadingTest.java @@ -105,7 +105,7 @@ private static class SpringBootResource extends Resource { private static final String BOOT_INF_CLASS_DIRECTORY = "BOOT-INF/classes!/"; SpringBootResource(org.springframework.core.io.Resource resource) throws IOException { - super(resource.getURL()); + super(resource.getURL(), Thread.currentThread().getContextClassLoader()); } private static String getBootClassSubstring(String path) { diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java index 540a3a5cf..fa8aaf8f8 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java @@ -108,7 +108,7 @@ public void testUsingKarateBase() throws Exception { list.add(() -> { Path path = FileUtils.fromRelativeClassPath(relativePath, cl); logger.debug("path: {}", path); - Resource resource = new Resource(path, relativePath, -1); + Resource resource = new Resource(path, relativePath, -1, cl); Feature feature = FeatureParser.parse(resource); Map map = Runner.runFeature(feature, null, true); Boolean result = (Boolean) map.get("success"); From faa60053524c2769511508ec291af70149145c38 Mon Sep 17 00:00:00 2001 From: lzaltzberg Date: Fri, 9 Oct 2020 00:23:49 +0300 Subject: [PATCH 05/31] Issue #1306 Mock Jersey Servlet doesnt add query params to the requestURI --- .../java/com/intuit/karate/mock/servlet/MockHttpClient.java | 2 +- .../src/test/java/mock/jersey/HelloResource.java | 5 +++-- .../src/test/java/mock/jersey/hello-http.feature | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/karate-mock-servlet/src/main/java/com/intuit/karate/mock/servlet/MockHttpClient.java b/karate-mock-servlet/src/main/java/com/intuit/karate/mock/servlet/MockHttpClient.java index fd7fb332e..870162f1d 100644 --- a/karate-mock-servlet/src/main/java/com/intuit/karate/mock/servlet/MockHttpClient.java +++ b/karate-mock-servlet/src/main/java/com/intuit/karate/mock/servlet/MockHttpClient.java @@ -130,7 +130,7 @@ protected void buildParam(String name, Object... values) { for (Object o : values) { list.add(o == null ? null : o.toString()); } - requestBuilder.param(name, list.toArray(new String[]{})); + requestBuilder.queryParam(name, list.toArray(new String[]{})); } @Override diff --git a/karate-mock-servlet/src/test/java/mock/jersey/HelloResource.java b/karate-mock-servlet/src/test/java/mock/jersey/HelloResource.java index cceb76aa5..5a89e0ad4 100644 --- a/karate-mock-servlet/src/test/java/mock/jersey/HelloResource.java +++ b/karate-mock-servlet/src/test/java/mock/jersey/HelloResource.java @@ -27,6 +27,7 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,8 +42,8 @@ public class HelloResource { @GET @Produces("text/plain") - public String getHello() { - return "hello world"; + public String getHello(@QueryParam("hello") String hello) { + return hello + " world"; } @POST diff --git a/karate-mock-servlet/src/test/java/mock/jersey/hello-http.feature b/karate-mock-servlet/src/test/java/mock/jersey/hello-http.feature index fef874e6d..c03566590 100644 --- a/karate-mock-servlet/src/test/java/mock/jersey/hello-http.feature +++ b/karate-mock-servlet/src/test/java/mock/jersey/hello-http.feature @@ -4,9 +4,10 @@ Scenario: get hello When url demoBaseUrl And path 'hello' +And param hello = 'hey' When method get Then status 200 -And match response == 'hello world' +And match response == 'hey world' Scenario: post cat From 0a09ff3426be8729351c0b0c0dcfdead9d3c9acd Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Fri, 9 Oct 2020 18:44:24 -0400 Subject: [PATCH 06/31] Exposing a method that allows Nashorn to be initiated with a custom classLoader --- .../src/main/java/com/intuit/karate/ScriptBindings.java | 8 +++++++- .../java/com/intuit/karate/core/FeatureExecutionUnit.java | 2 -- .../com/intuit/karate/core/ScenarioExecutionUnit.java | 4 +--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java b/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java index f1f70af38..6bf616cdd 100644 --- a/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java +++ b/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java @@ -80,7 +80,13 @@ public class ScriptBindings implements Bindings { public static final String SERVER_PORT = "serverPort"; // all threads will share this ! thread isolation is via Bindings (this class) - private static final ScriptEngine NASHORN = new ScriptEngineManager(null).getEngineByName("nashorn"); + private static ScriptEngine NASHORN = new ScriptEngineManager().getEngineByName("nashorn"); + + public static ScriptEngine initNashorn(ClassLoader classLoader) { + NASHORN = new ScriptEngineManager(classLoader).getEngineByName("nashorn"); + return NASHORN; + } + public final ScriptBridge bridge; private final ScriptValueMap vars; diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java index f1f9d6f6e..7d8f40c56 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java @@ -102,14 +102,12 @@ public void onComplete() { @Override public Iterator process(ScenarioExecutionUnit unit) { if (isSelected(unit) && !unit.result.isFailed()) { // can happen for dynamic scenario outlines with a failed background ! - System.out.println("starting execution"); unit.run(); // we also hold a reference to the last scenario-context that executed // for cases where the caller needs a result lastContextExecuted = unit.getContext(); return Collections.singletonList(unit.result).iterator(); } else { - System.out.println("else execution"); return Collections.emptyIterator(); } } diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java index b6518f5f5..330e86a25 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java @@ -192,8 +192,7 @@ private StepResult afterStep(StepResult result) { // extracted for debug public StepResult execute(Step step) { currentStep = step; - System.out.println("executing step " + step.getText()); - actions.context.setExecutionUnit(this);// just for deriving call stack + actions.context.setExecutionUnit(this);// just for deriving call stack if (hooks != null) { boolean shouldExecute = true; for (ExecutionHook hook : hooks) { @@ -301,7 +300,6 @@ public void run() { } int count = steps.size(); int index = 0; - System.out.println(count + " steps to execute"); while ((index = nextStepIndex()) < count) { Step step = steps.get(index); lastStepResult = execute(step); From fa0fe85f699f1b9f26d84d0c77ddf7f4da410381 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Fri, 9 Oct 2020 20:51:53 -0400 Subject: [PATCH 07/31] Additional changes for class loader to support packaging as Spring Boot .jar --- karate-core/src/main/java/com/intuit/karate/FileUtils.java | 5 +++++ .../src/main/java/com/intuit/karate/http/HttpClient.java | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/karate-core/src/main/java/com/intuit/karate/FileUtils.java b/karate-core/src/main/java/com/intuit/karate/FileUtils.java index 695d4e2c3..ae03331aa 100755 --- a/karate-core/src/main/java/com/intuit/karate/FileUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/FileUtils.java @@ -198,6 +198,11 @@ public static InputStream readFileAsStream(String path, ScenarioContext context) return toResource(path, context).getStream(); } catch (Exception e) { InputStream inputStream = context.getResourceAsStream(removePrefix(path)); + if(inputStream == null) { + // attempt to get the file using the class classloader + // workaround for Spring Boot + inputStream = FileUtils.class.getClassLoader().getResourceAsStream(path); + } if (inputStream == null) { String message = String.format("could not find or read file: %s", path); context.logger.trace("{}", message); diff --git a/karate-core/src/main/java/com/intuit/karate/http/HttpClient.java b/karate-core/src/main/java/com/intuit/karate/http/HttpClient.java index 40b79aab7..d0d2f0ec2 100644 --- a/karate-core/src/main/java/com/intuit/karate/http/HttpClient.java +++ b/karate-core/src/main/java/com/intuit/karate/http/HttpClient.java @@ -279,6 +279,12 @@ public static HttpClient construct(Config config, ScenarioContext context) { className = config.getClientClass(); } else { InputStream is = context.getResourceAsStream(KARATE_HTTP_PROPERTIES); + if(is == null) { + // attempt to get the file using the class classloader + // workaround for Spring Boot + is = HttpClient.class.getClassLoader().getResourceAsStream(KARATE_HTTP_PROPERTIES); + } + if (is == null) { String msg = KARATE_HTTP_PROPERTIES + " not found"; throw new RuntimeException(msg); From 647572669be8112d5748accc283e5b9a6d5f1b09 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Sat, 10 Oct 2020 00:12:50 -0500 Subject: [PATCH 08/31] 1165 - initial commit --- .../karate/http/apache/ApacheHttpClient.java | 63 ++++++-------- .../http/apache/ApacheHttpClientTest.java | 83 +++++++++++++++++++ .../src/test/resources/karate-config.js | 3 + .../src/test/resources/karate-http.properties | 2 + .../java/com/intuit/karate/http/Cookie.java | 34 ++++++-- .../test/java/demo/cookies/cookies.feature | 64 ++++++++++++-- .../karate/http/jersey/JerseyHttpClient.java | 28 ++++++- 7 files changed, 224 insertions(+), 53 deletions(-) create mode 100644 karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpClientTest.java create mode 100755 karate-apache/src/test/resources/karate-config.js create mode 100644 karate-apache/src/test/resources/karate-http.properties diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java index c1a94819a..348214b4c 100644 --- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java +++ b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java @@ -26,37 +26,11 @@ import com.intuit.karate.Config; import com.intuit.karate.FileUtils; import com.intuit.karate.core.ScenarioContext; -import org.apache.http.conn.ssl.LenientSslConnectionSocketFactory; - -import static com.intuit.karate.http.Cookie.*; - -import com.intuit.karate.http.HttpClient; -import com.intuit.karate.http.HttpRequest; -import com.intuit.karate.http.HttpResponse; -import com.intuit.karate.http.HttpUtils; -import com.intuit.karate.http.MultiPartItem; -import com.intuit.karate.http.MultiValuedMap; -import java.io.IOException; - -import java.io.InputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.ProxySelector; -import java.net.SocketAddress; -import java.net.URI; -import java.nio.charset.Charset; -import java.security.KeyStore; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map.Entry; -import java.util.Objects; -import javax.net.ssl.SSLContext; - +import com.intuit.karate.http.*; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; +import org.apache.http.ParseException; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CookieStore; @@ -67,22 +41,28 @@ import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.utils.URIBuilder; import org.apache.http.config.SocketConfig; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.TrustAllStrategy; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.conn.ssl.*; import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.LaxRedirectStrategy; +import org.apache.http.impl.client.*; import org.apache.http.impl.conn.SystemDefaultRoutePlanner; import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.SSLContexts; +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.net.*; +import java.nio.charset.Charset; +import java.security.KeyStore; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.*; +import java.util.Map.Entry; + +import static com.intuit.karate.http.Cookie.*; + /** * @author pthomas3 */ @@ -269,6 +249,15 @@ protected void buildCookie(com.intuit.karate.http.Cookie c) { case PATH: cookie.setPath(entry.getValue()); break; + case EXPIRES: + try { + cookie.setExpiryDate(Date.from(ZonedDateTime.parse(entry.getValue(), DTFMTR_RFC1123).toInstant())); + } + catch ( DateTimeParseException ex) + { + System.err.println("ex ->" + ex.getLocalizedMessage()); + } + break; } } if (cookie.getDomain() == null) { diff --git a/karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpClientTest.java b/karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpClientTest.java new file mode 100644 index 000000000..1fc56ac3d --- /dev/null +++ b/karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpClientTest.java @@ -0,0 +1,83 @@ +package com.intuit.karate.http.apache; + +import com.intuit.karate.CallContext; +import com.intuit.karate.Config; +import com.intuit.karate.core.FeatureContext; +import com.intuit.karate.core.ScenarioContext; +import com.intuit.karate.http.Cookie; +import org.apache.http.client.CookieStore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.time.ZonedDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +import static com.intuit.karate.http.Cookie.*; +import static com.intuit.karate.http.HttpClient.construct; +import static org.junit.Assert.assertEquals; + +public class ApacheHttpClientTest { + + private static final Logger logger = LoggerFactory.getLogger(ApacheHttpClientTest.class); + + private ScenarioContext getContext() { + FeatureContext featureContext = FeatureContext.forEnv(); + CallContext callContext = new CallContext(null, true); + return new ScenarioContext(featureContext, callContext, null, null); + } + + private Config getConfig() { + return new Config(); + } + + private Map getCookieMapWithExpiredDate() { + ZonedDateTime currentDate = ZonedDateTime.now(); + Map cookieMap = new LinkedHashMap<>(); + cookieMap.put(NAME, "testCookie"); + cookieMap.put(VALUE, "tck"); + cookieMap.put(DOMAIN, ".com"); + cookieMap.put(PATH, "/"); + cookieMap.put(EXPIRES,currentDate.minusDays(1).format(DTFMTR_RFC1123)); + return cookieMap; + } + + private Map getCookieMapWithNonExpiredDate() { + ZonedDateTime currentDate = ZonedDateTime.now(); + Map cookieMap = new LinkedHashMap<>(); + cookieMap.put(NAME, "testCookie"); + cookieMap.put(VALUE, "tck"); + cookieMap.put(DOMAIN, ".com"); + cookieMap.put(PATH, "/"); + cookieMap.put(EXPIRES, currentDate.plusDays(1).format(DTFMTR_RFC1123)); + return cookieMap; + } + + @Test + public void testExpiredCookieIsRemoved() throws NoSuchFieldException, IllegalAccessException { + com.intuit.karate.http.Cookie c = new Cookie(getCookieMapWithExpiredDate()); + ApacheHttpClient httpClient = (ApacheHttpClient) construct(getConfig(), getContext()); + httpClient.buildCookie(c); + + Field cookieStoreField = httpClient.getClass().getDeclaredField("cookieStore"); + cookieStoreField.setAccessible(true); + CookieStore fieldValue = (CookieStore) cookieStoreField.get(httpClient); + assertEquals(0, fieldValue.getCookies().size()); + } + + @Test + public void testNonExpiredCookieIsPersisted() throws NoSuchFieldException, IllegalAccessException { + com.intuit.karate.http.Cookie c = new Cookie(getCookieMapWithNonExpiredDate()); + ApacheHttpClient httpClient = (ApacheHttpClient) construct(getConfig(), getContext()); + httpClient.buildCookie(c); + + Field cookieStoreField = httpClient.getClass().getDeclaredField("cookieStore"); + cookieStoreField.setAccessible(true); + CookieStore fieldValue = (CookieStore) cookieStoreField.get(httpClient); + assertEquals(1, fieldValue.getCookies().size()); + } +} + + diff --git a/karate-apache/src/test/resources/karate-config.js b/karate-apache/src/test/resources/karate-config.js new file mode 100755 index 000000000..dea6405ed --- /dev/null +++ b/karate-apache/src/test/resources/karate-config.js @@ -0,0 +1,3 @@ +function fn() { + return { someConfig: 'someValue' } +} \ No newline at end of file diff --git a/karate-apache/src/test/resources/karate-http.properties b/karate-apache/src/test/resources/karate-http.properties new file mode 100644 index 000000000..cd3832389 --- /dev/null +++ b/karate-apache/src/test/resources/karate-http.properties @@ -0,0 +1,2 @@ +client.class=com.intuit.karate.http.apache.ApacheHttpClient + diff --git a/karate-core/src/main/java/com/intuit/karate/http/Cookie.java b/karate-core/src/main/java/com/intuit/karate/http/Cookie.java index 1f3011999..d20d9ee25 100644 --- a/karate-core/src/main/java/com/intuit/karate/http/Cookie.java +++ b/karate-core/src/main/java/com/intuit/karate/http/Cookie.java @@ -23,11 +23,13 @@ */ package com.intuit.karate.http; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.util.*; /** * @@ -44,7 +46,10 @@ public class Cookie extends LinkedHashMap { public static final String MAX_AGE = "max-age"; public static final String SECURE = "secure"; public static final String PERSISTENT = "persistent"; - public static final String HTTP_ONLY = "http-only"; + public static final String HTTP_ONLY = "http-only"; + public static final DateTimeFormatter DT_FMT_V1 = DateTimeFormatter.ofPattern("EEE, dd-MMM-yy HH:mm:ss z"); + public static final DateTimeFormatter DT_FMT_V2 = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z"); + public static final DateTimeFormatter DTFMTR_RFC1123 = new DateTimeFormatterBuilder().appendOptional(DT_FMT_V1).appendOptional(DT_FMT_V2).toFormatter(); // cookies can be a map of maps, so some extra processing public static List toCookies(Map map) { @@ -82,6 +87,21 @@ public String getName() { public String getValue() { return get(VALUE); - } + } + + public boolean isCookieExpired() + { + String exprDat = get(EXPIRES); + Date expires = null; + if ( null != exprDat) { + try { + expires = Date.from(ZonedDateTime.parse(get(EXPIRES), DTFMTR_RFC1123).toInstant()); + } catch (DateTimeParseException ex) { + System.err.println("ex ->" + ex.getLocalizedMessage()); + } + } + return null != expires && !expires.after(new Date()); + + } } diff --git a/karate-demo/src/test/java/demo/cookies/cookies.feature b/karate-demo/src/test/java/demo/cookies/cookies.feature index 3aca80827..d5e0d5044 100644 --- a/karate-demo/src/test/java/demo/cookies/cookies.feature +++ b/karate-demo/src/test/java/demo/cookies/cookies.feature @@ -16,25 +16,25 @@ Scenario: one cookie, and it is sent automatically in the next request Then status 200 And match response == '#[1]' And match response[0] contains { name: 'foo', value: 'bar' } - + Given path 'search', 'cookies' And request {} When method post Then status 200 And match response == '#[1]' - And match response[0] contains { name: 'foo', value: 'bar' } - + And match response[0] contains { name: 'foo', value: 'bar' } + * print 'cookies: ', responseCookies # reset cookies * configure cookies = null - Given path 'search', 'cookies' + Given path 'search', 'cookies' When method get Then status 200 And match response == [] # modify cookies - Given path 'search', 'cookies' + Given path 'search', 'cookies' And cookie foo = 'blah' And request {} When method post @@ -43,15 +43,65 @@ Scenario: one cookie, and it is sent automatically in the next request Scenario: cookie as json Given path 'search', 'cookies' - And cookie foo = { value: 'bar' } + And cookie foo = { value: 'bar' } When method get Then status 200 And match response[0] contains { name: 'foo', value: 'bar' } Scenario: cookie returned has dots in the domain which violates RFC 2109 Given path 'search', 'cookies' - And cookie foo = { value: 'bar' } + And cookie foo = { value: 'bar' } + And param domain = '.abc.com' + When method get + Then status 200 + And match response[0] contains { name: 'foo', value: 'bar', domain: '.abc.com' } + +Scenario: cookie returned has dots in the domain which violates RFC 2109 + Given path 'search', 'cookies' + And cookie foo = { value: 'bar' } And param domain = '.abc.com' When method get Then status 200 And match response[0] contains { name: 'foo', value: 'bar', domain: '.abc.com' } + +@mock-servlet-todo +Scenario: expired cookie is not in response + * def prevDate = + """ + function() { + var SimpleDateFormat = Java.type('java.text.SimpleDateFormat'); + var Calendar = Java.type('java.util.Calendar'); + var currCalIns = Calendar.getInstance(); + currCalIns.add(java.util.Calendar.DATE, -1); + var sdf = new SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss z"); + return sdf.format(currCalIns.getTime()); + } + """ + * def date = prevDate() + Given path 'search', 'cookies' + And cookie foo = {value:'bar', expires: '#(date)'} + And param domain = '.abcdfdf.com' + When method get + Then status 200 + And match response == [] + +@mock-servlet-todo +Scenario: non-expired cookie is in response + * def futureDate = + """ + function() { + var SimpleDateFormat = Java.type('java.text.SimpleDateFormat'); + var Calendar = Java.type('java.util.Calendar'); + var currCalIns = Calendar.getInstance(); + currCalIns.add(java.util.Calendar.DATE, +1); + var sdf = new SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss z"); + return sdf.format(currCalIns.getTime()); + } + """ + * def date = futureDate() + Given path 'search', 'cookies' + And cookie foo = {value:'bar', expires:'#(date)', path:'/search'} + And param domain = '.abc.com' + When method get + Then status 200 + And match response[0] contains { name: 'foo', value: 'bar', domain: '.abc.com' } \ No newline at end of file diff --git a/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java b/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java index 568bb1483..394562f30 100644 --- a/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java +++ b/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java @@ -36,6 +36,10 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.security.KeyStore; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.Date; import java.util.List; import java.util.Map.Entry; import javax.net.ssl.HttpsURLConnection; @@ -59,6 +63,7 @@ import org.glassfish.jersey.media.multipart.MultiPart; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart; +import org.glassfish.jersey.message.internal.StringBuilderUtils; /** * @@ -144,8 +149,27 @@ public void buildHeader(String name, Object value, boolean replace) { @Override public void buildCookie(com.intuit.karate.http.Cookie c) { - Cookie cookie = new Cookie(c.getName(), c.getValue()); - builder.cookie(cookie); +// Date expires = null; +// +// for (Entry entry : c.entrySet()) { +// if (EXPIRES.equals(entry.getKey())) { +// try { +// expires = Date.from(ZonedDateTime.parse(entry.getValue(), DTFMTR_RFC1123).toInstant()); +// } catch (DateTimeParseException ex) { +// System.err.println("ex ->" + ex.getLocalizedMessage()); +// } +// } +// } +// if ( null == expires || expires.after(new Date())) { +// System.out.println(" ----> " + c.toString() + " -- " + expires); +// Cookie cookie = new Cookie(c.getName(), c.getValue()); +// builder.cookie(cookie); +// } + if ( !c.isCookieExpired() ) + { + Cookie cookie = new Cookie(c.getName(), c.getValue()); + builder.cookie(cookie); + } } private MediaType getMediaType(String mediaType) { From 0992955409f1cb70078492594e5ec05172532bc3 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Sat, 10 Oct 2020 00:19:39 -0500 Subject: [PATCH 09/31] 1165 - initial commit --- .../karate/http/apache/ApacheHttpClient.java | 2 +- .../karate/http/jersey/JerseyHttpClient.java | 17 +---------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java index 348214b4c..ee7b8a745 100644 --- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java +++ b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java @@ -249,7 +249,7 @@ protected void buildCookie(com.intuit.karate.http.Cookie c) { case PATH: cookie.setPath(entry.getValue()); break; - case EXPIRES: + case EXPIRES: // add expires field for cookie. try { cookie.setExpiryDate(Date.from(ZonedDateTime.parse(entry.getValue(), DTFMTR_RFC1123).toInstant())); } diff --git a/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java b/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java index 394562f30..8ad15b4e2 100644 --- a/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java +++ b/karate-jersey/src/main/java/com/intuit/karate/http/jersey/JerseyHttpClient.java @@ -149,22 +149,7 @@ public void buildHeader(String name, Object value, boolean replace) { @Override public void buildCookie(com.intuit.karate.http.Cookie c) { -// Date expires = null; -// -// for (Entry entry : c.entrySet()) { -// if (EXPIRES.equals(entry.getKey())) { -// try { -// expires = Date.from(ZonedDateTime.parse(entry.getValue(), DTFMTR_RFC1123).toInstant()); -// } catch (DateTimeParseException ex) { -// System.err.println("ex ->" + ex.getLocalizedMessage()); -// } -// } -// } -// if ( null == expires || expires.after(new Date())) { -// System.out.println(" ----> " + c.toString() + " -- " + expires); -// Cookie cookie = new Cookie(c.getName(), c.getValue()); -// builder.cookie(cookie); -// } + // only add the cookie from request, if it isnt already expired. if ( !c.isCookieExpired() ) { Cookie cookie = new Cookie(c.getName(), c.getValue()); From cdb10a77f2993f4691ed2f550192d42c2cd03be9 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Sat, 10 Oct 2020 23:06:41 -0500 Subject: [PATCH 10/31] #1211 Standard delete Cookie behaviour does not work in Karate --- .../karate/http/apache/ApacheHttpClient.java | 21 +++++++++++++++++-- .../test/java/demo/cookies/cookies.feature | 18 ++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java index ee7b8a745..edaaedef3 100644 --- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java +++ b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java @@ -258,6 +258,12 @@ protected void buildCookie(com.intuit.karate.http.Cookie c) { System.err.println("ex ->" + ex.getLocalizedMessage()); } break; + case MAX_AGE: // set max age + int maxAge = Integer.parseInt(entry.getValue()); + if (maxAge >= 0) { // only for valid maxAge for cookie expiration. + cookie.setExpiryDate(new Date(System.currentTimeMillis() + (maxAge * 1000))); + } + break; } } if (cookie.getDomain() == null) { @@ -327,8 +333,19 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex response.addCookie(cookie); } cookieStore.clear(); // we rely on the StepDefs for cookie 'persistence' - for (Header header : httpResponse.getAllHeaders()) { - response.addHeader(header.getName(), header.getValue()); + for (Header header : httpResponse.getAllHeaders()) { // rely on setting cookies from set-cookie header, else these will be skipped. + if( header.getName().contains("Set-Cookie")) + { + List cookieMap = HttpCookie.parse(header.getValue()); + cookieMap.forEach( ck -> { + com.intuit.karate.http.Cookie cookie = new com.intuit.karate.http.Cookie(ck.getName(), ck.getValue()); + cookie.put(DOMAIN, ck.getDomain()); + cookie.put(PATH, ck.getPath()); + cookie.put(MAX_AGE, ck.getMaxAge() + ""); + response.addCookie(cookie); + }); + } + response.addHeader(header.getName(), header.getValue()); } return response; } diff --git a/karate-demo/src/test/java/demo/cookies/cookies.feature b/karate-demo/src/test/java/demo/cookies/cookies.feature index d5e0d5044..974b1080a 100644 --- a/karate-demo/src/test/java/demo/cookies/cookies.feature +++ b/karate-demo/src/test/java/demo/cookies/cookies.feature @@ -104,4 +104,22 @@ Scenario: non-expired cookie is in response And param domain = '.abc.com' When method get Then status 200 + And match response[0] contains { name: 'foo', value: 'bar', domain: '.abc.com' } + +@apache @mock-servlet-todo +Scenario: manually expire cookie by setting max-age to 0. + Given path 'search', 'cookies' + And cookie foo = {value:'bar', max-age:'0', path:'/search'} + And param domain = '.abc.com' + When method get + Then status 200 + And match response == [] + +@apache @mock-servlet-todo +Scenario: max-age is -1, cookie should persist. + Given path 'search', 'cookies' + And cookie foo = {value:'bar', max-age:'-1', path:'/search'} + And param domain = '.abc.com' + When method get + Then status 200 And match response[0] contains { name: 'foo', value: 'bar', domain: '.abc.com' } \ No newline at end of file From e252cbf9f5305bf026bcfcc3b0c301357b7eaa6d Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Sun, 11 Oct 2020 00:27:29 -0500 Subject: [PATCH 11/31] ##1211 Standard delete Cookie behaviour does not work in Karateapplied reviee comment --- .../java/com/intuit/karate/http/apache/ApacheHttpClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java index edaaedef3..1f5b0eb2d 100644 --- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java +++ b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java @@ -334,7 +334,7 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex } cookieStore.clear(); // we rely on the StepDefs for cookie 'persistence' for (Header header : httpResponse.getAllHeaders()) { // rely on setting cookies from set-cookie header, else these will be skipped. - if( header.getName().contains("Set-Cookie")) + if( header.getName().equalsIgnoreCase("Set-Cookie")) { List cookieMap = HttpCookie.parse(header.getValue()); cookieMap.forEach( ck -> { @@ -345,7 +345,7 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex response.addCookie(cookie); }); } - response.addHeader(header.getName(), header.getValue()); + response.addHeader(header.getName(), header.getValue()); } return response; } From 8503a2ee786a53c0b2d1ed548ae96d3548b42b12 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 11 Oct 2020 09:59:59 -0400 Subject: [PATCH 12/31] Apply changes from rewrite branch onto changes to workaround issues with loading files from Spring Boot classpath. Making Nashorn lazy-init and synchronized to avoid parallel() test execution concurrency issues (keeping function to allow external override). --- .../java/com/intuit/karate/FileUtils.java | 87 +++++++++++++++++-- .../main/java/com/intuit/karate/Resource.java | 26 ++++-- .../com/intuit/karate/ScriptBindings.java | 20 ++++- .../com/intuit/karate/core/FeatureParser.java | 4 +- .../java/com/intuit/karate/FileUtilsTest.java | 3 +- 5 files changed, 117 insertions(+), 23 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/FileUtils.java b/karate-core/src/main/java/com/intuit/karate/FileUtils.java index ae03331aa..810f66968 100755 --- a/karate-core/src/main/java/com/intuit/karate/FileUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/FileUtils.java @@ -23,23 +23,42 @@ */ package com.intuit.karate; +import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeatureParser; -import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.exception.KarateFileNotFoundException; import com.jayway.jsonpath.DocumentContext; -import org.slf4j.LoggerFactory; - -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; -import java.nio.file.*; -import java.util.*; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Stream; +import org.slf4j.LoggerFactory; /** * @@ -59,7 +78,8 @@ public class FileUtils { public static final String THIS_COLON = "this:"; public static final String FILE_COLON = "file:"; public static final String SRC_TEST_JAVA = "src/test/java"; - public static final String SRC_TEST_RESOURCES = "src/test/resources"; + public static final String SRC_TEST_RESOURCES = "src/test/resources"; + private static final ClassLoader CLASS_LOADER = FileUtils.class.getClassLoader(); private FileUtils() { // only static methods @@ -147,7 +167,7 @@ public static String removePrefix(String text) { return pos == -1 ? text : text.substring(pos + 1); } - private static StringUtils.Pair parsePathAndTags(String text) { + public static StringUtils.Pair parsePathAndTags(String text) { int pos = text.indexOf('@'); if (pos == -1) { text = StringUtils.trimToEmpty(text); @@ -168,7 +188,7 @@ public static Feature parseFeatureAndCallTag(String path) { public static Resource toResource(String path, ScenarioContext context) { if (isClassPath(path)) { - return new Resource(context, path); + return new Resource(context.classLoader, path); } else if (isFilePath(path)) { String temp = removePrefix(path); return new Resource(new File(temp), path, context.classLoader); @@ -647,6 +667,55 @@ private static void collectFeatureFiles(URL url, String searchPath, List based and tighter routine for feature files above + private static void walkPath(Path root, Set results, Predicate predicate) { + Stream stream; + try { + stream = Files.walk(root); + for (Iterator paths = stream.iterator(); paths.hasNext();) { + Path path = paths.next(); + Path fileName = path.getFileName(); + if (predicate.test(fileName)) { + String relativePath = root.relativize(path.toAbsolutePath()).toString(); + results.add(relativePath); + } + } + } catch (IOException e) { // NoSuchFileException + LOGGER.trace("unable to walk path: {} - {}", root, e.getMessage()); + } + } + + private static final Predicate IS_JS_FILE = p -> p != null && p.toString().endsWith(".js"); + + public static Set jsFiles(File baseDir) { + Set results = new HashSet(); + walkPath(baseDir.toPath().toAbsolutePath(), results, IS_JS_FILE); + return results; + } + + public static Set jsFiles(String basePath) { + Set results = new HashSet(); + try { + Enumeration urls = CLASS_LOADER.getResources(basePath); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + Path path = urlToPath(url, null); + walkPath(path, results, IS_JS_FILE); + } + } catch (Exception e) { + LOGGER.warn("unable to scan for js files at: {}", basePath); + } + return results; + } + + public static InputStream resourceAsStream(String resourcePath) { + InputStream is = CLASS_LOADER.getResourceAsStream(resourcePath); + if (is == null) { + throw new RuntimeException("failed to read: " + resourcePath); + } + return is; + } public static String getBuildDir() { String temp = System.getProperty("karate.output.dir"); diff --git a/karate-core/src/main/java/com/intuit/karate/Resource.java b/karate-core/src/main/java/com/intuit/karate/Resource.java index 1a932c6ef..a81b0b379 100644 --- a/karate-core/src/main/java/com/intuit/karate/Resource.java +++ b/karate-core/src/main/java/com/intuit/karate/Resource.java @@ -23,8 +23,6 @@ */ package com.intuit.karate; -import com.intuit.karate.core.ScenarioContext; - import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -51,10 +49,25 @@ public class Resource { public static final Resource EMPTY = new Resource(Paths.get(""), "", -1, Thread.currentThread().getContextClassLoader()); + public static Resource of(Path path, String text) { + return new Resource(path, null, -1, Thread.currentThread().getContextClassLoader()) { + final InputStream is = FileUtils.toInputStream(text); + + @Override + public InputStream getStream() { + return is; + } + }; + } + public Resource(File file, String relativePath, ClassLoader cl) { this(file.toPath(), relativePath, -1, cl); } + public Resource(String relativePath) { + this(Thread.currentThread().getContextClassLoader(), relativePath); + } + public Resource(Path path, String relativePath, int line, ClassLoader cl) { this.path = path; this.line = line; @@ -76,10 +89,9 @@ public Resource(Path path, ClassLoader cl) { this(path, null, -1, cl); } - public Resource(ScenarioContext sc, String relativePath) { - this.classLoader = sc.classLoader; + public Resource(ClassLoader cl, String relativePath) { String strippedPath = FileUtils.removePrefix(relativePath); - URL url = sc.getResource(strippedPath); + URL url = cl.getResource(strippedPath); if (url != null) { this.path = FileUtils.urlToPath(url, strippedPath); } else { @@ -129,11 +141,11 @@ public InputStream getStream() { } // since the nio newInputStream has concurrency problems :( // plus a performance boost for karate-base.js if in JAR - InputStream tempStream = this.classLoader.getResourceAsStream(relativePath.replace(FileUtils.CLASSPATH_COLON, "")); ;//Files.newInputStream(path); + ClassLoader cl = this.classLoader != null ? this.classLoader : Resource.class.getClassLoader(); + InputStream tempStream = cl.getResourceAsStream(relativePath.replace(FileUtils.CLASSPATH_COLON, ""));//Files.newInputStream(path); if(tempStream == null) { tempStream = Files.newInputStream(path); } - bytes = FileUtils.toBytes(tempStream); STREAM_CACHE.put(relativePath, bytes); return new ByteArrayInputStream(bytes); diff --git a/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java b/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java index 6bf616cdd..c0d4ec4f8 100644 --- a/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java +++ b/karate-core/src/main/java/com/intuit/karate/ScriptBindings.java @@ -80,7 +80,21 @@ public class ScriptBindings implements Bindings { public static final String SERVER_PORT = "serverPort"; // all threads will share this ! thread isolation is via Bindings (this class) - private static ScriptEngine NASHORN = new ScriptEngineManager().getEngineByName("nashorn"); + private static final Object NASHORN_LOCK = new Object(); + private static ScriptEngine NASHORN; + + private static ScriptEngine getNashorn() { + if(NASHORN == null) { + synchronized (NASHORN_LOCK) { + // ensure if there are parallel threads that only the first one creates the instance of Nashorn + if(NASHORN == null) { + NASHORN = new ScriptEngineManager().getEngineByName("nashorn"); + } + } + } + + return NASHORN; + } public static ScriptEngine initNashorn(ClassLoader classLoader) { NASHORN = new ScriptEngineManager(classLoader).getEngineByName("nashorn"); @@ -151,7 +165,7 @@ private ScriptValue updateBindingsAndEval(String exp, ScriptEvalContext ec) { public static ScriptValue eval(String exp, Bindings bindings) { try { - Object o = bindings == null ? NASHORN.eval(exp) : NASHORN.eval(exp, bindings); + Object o = bindings == null ? ScriptBindings.getNashorn().eval(exp) : ScriptBindings.getNashorn().eval(exp, bindings); return new ScriptValue(o); } catch (KarateFailException | KarateAbortException | KarateFileNotFoundException ke) { throw ke; // reduce log bloat for common file-not-found situation / handle karate.abort() / karate.fail() @@ -163,7 +177,7 @@ public static ScriptValue eval(String exp, Bindings bindings) { } public static Bindings createBindings() { - return NASHORN.createBindings(); + return ScriptBindings.getNashorn().createBindings(); } public void putAdditionalVariable(String name, Object value) { diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java index 24c9e61b7..25d38152c 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java @@ -58,9 +58,7 @@ public class FeatureParser extends KarateParserBaseListener { private static final List PREFIXES = Arrays.asList("*", "Given", "When", "Then", "And", "But"); public static Feature parse(String relativePath) { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Path path = FileUtils.fromRelativeClassPath(relativePath, cl); - return parse(new Resource(path, relativePath, -1, cl)); + return parse(new Resource(relativePath)); } public static Feature parse(File file) { diff --git a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java index acfa8c6ee..3c8ac4b70 100755 --- a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java +++ b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java @@ -248,7 +248,8 @@ public void testUsingBadPath() { FeatureParser.parse(relativePath); fail("we should not have reached here"); } catch (Exception e) { - assertEquals("file does not exist: /foo/bar/feeder.feature", e.getMessage()); + assertEquals(e.getCause().getClass(), java.io.FileNotFoundException.class); + assertEquals("java.io.FileNotFoundException: \\foo\\bar\\feeder.feature (The system cannot find the path specified)", e.getMessage()); } } From 7ebcbfa03c1d0ecba41e1b31f7495e0ee0513d3c Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 11 Oct 2020 11:06:32 -0400 Subject: [PATCH 13/31] Fixing unit test --- karate-core/src/main/java/com/intuit/karate/Resource.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/karate-core/src/main/java/com/intuit/karate/Resource.java b/karate-core/src/main/java/com/intuit/karate/Resource.java index a81b0b379..0b039a822 100644 --- a/karate-core/src/main/java/com/intuit/karate/Resource.java +++ b/karate-core/src/main/java/com/intuit/karate/Resource.java @@ -23,6 +23,8 @@ */ package com.intuit.karate; +import com.intuit.karate.core.ScenarioContext; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -89,6 +91,10 @@ public Resource(Path path, ClassLoader cl) { this(path, null, -1, cl); } + public Resource(ScenarioContext scenarioContext, String relativePath) { + this(scenarioContext.classLoader, relativePath); + } + public Resource(ClassLoader cl, String relativePath) { String strippedPath = FileUtils.removePrefix(relativePath); URL url = cl.getResource(strippedPath); From efb6451569b545afd8f57836bcbc2c65e78116f3 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 11 Oct 2020 12:02:09 -0400 Subject: [PATCH 14/31] Fixing unit test for CI/CD pipeline --- karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java index 3c8ac4b70..6c69c5be5 100755 --- a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java +++ b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java @@ -249,7 +249,6 @@ public void testUsingBadPath() { fail("we should not have reached here"); } catch (Exception e) { assertEquals(e.getCause().getClass(), java.io.FileNotFoundException.class); - assertEquals("java.io.FileNotFoundException: \\foo\\bar\\feeder.feature (The system cannot find the path specified)", e.getMessage()); } } From 0cdaa471cd1f0a10facac9dbeb1877be876b1291 Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Mon, 12 Oct 2020 12:05:16 +0530 Subject: [PATCH 15/31] refactor over pr #1317 --- .../java/com/intuit/karate/FileUtils.java | 28 +++++++-------- .../main/java/com/intuit/karate/Resource.java | 36 ++++++------------- .../com/intuit/karate/core/FeatureParser.java | 16 --------- .../karate/junit4/files/JarLoadingTest.java | 2 +- 4 files changed, 25 insertions(+), 57 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/FileUtils.java b/karate-core/src/main/java/com/intuit/karate/FileUtils.java index 810f66968..db7c37562 100755 --- a/karate-core/src/main/java/com/intuit/karate/FileUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/FileUtils.java @@ -78,7 +78,7 @@ public class FileUtils { public static final String THIS_COLON = "this:"; public static final String FILE_COLON = "file:"; public static final String SRC_TEST_JAVA = "src/test/java"; - public static final String SRC_TEST_RESOURCES = "src/test/resources"; + public static final String SRC_TEST_RESOURCES = "src/test/resources"; private static final ClassLoader CLASS_LOADER = FileUtils.class.getClassLoader(); private FileUtils() { @@ -188,7 +188,7 @@ public static Feature parseFeatureAndCallTag(String path) { public static Resource toResource(String path, ScenarioContext context) { if (isClassPath(path)) { - return new Resource(context.classLoader, path); + return new Resource(path, context.classLoader); } else if (isFilePath(path)) { String temp = removePrefix(path); return new Resource(new File(temp), path, context.classLoader); @@ -218,9 +218,9 @@ public static InputStream readFileAsStream(String path, ScenarioContext context) return toResource(path, context).getStream(); } catch (Exception e) { InputStream inputStream = context.getResourceAsStream(removePrefix(path)); - if(inputStream == null) { + if (inputStream == null) { // attempt to get the file using the class classloader - // workaround for Spring Boot + // workaround for spring boot inputStream = FileUtils.class.getClassLoader().getResourceAsStream(path); } if (inputStream == null) { @@ -328,7 +328,7 @@ public static void writeToFile(File file, byte[] data) { } // try with resources, so will be closed automatically try (FileOutputStream fos = new FileOutputStream(file)) { - fos.write(data); + fos.write(data); } } catch (IOException e) { throw new RuntimeException(e); @@ -459,8 +459,8 @@ public static String toRelativeClassPath(Class clazz) { public static Path fromRelativeClassPath(String relativePath, ClassLoader cl) { relativePath = removePrefix(relativePath); URL url = cl.getResource(relativePath); - if (url == null) { - throw new RuntimeException("file does not exist: " + relativePath); + if (url == null) { // assume this is a "real" path to a file + return new File(relativePath).toPath(); } return urlToPath(url, relativePath); } @@ -667,7 +667,7 @@ private static void collectFeatureFiles(URL url, String searchPath, List based and tighter routine for feature files above private static void walkPath(Path root, Set results, Predicate predicate) { Stream stream; @@ -684,10 +684,10 @@ private static void walkPath(Path root, Set results, Predicate pre } catch (IOException e) { // NoSuchFileException LOGGER.trace("unable to walk path: {} - {}", root, e.getMessage()); } - } - + } + private static final Predicate IS_JS_FILE = p -> p != null && p.toString().endsWith(".js"); - + public static Set jsFiles(File baseDir) { Set results = new HashSet(); walkPath(baseDir.toPath().toAbsolutePath(), results, IS_JS_FILE); @@ -707,15 +707,15 @@ public static Set jsFiles(String basePath) { LOGGER.warn("unable to scan for js files at: {}", basePath); } return results; - } - + } + public static InputStream resourceAsStream(String resourcePath) { InputStream is = CLASS_LOADER.getResourceAsStream(resourcePath); if (is == null) { throw new RuntimeException("failed to read: " + resourcePath); } return is; - } + } public static String getBuildDir() { String temp = System.getProperty("karate.output.dir"); diff --git a/karate-core/src/main/java/com/intuit/karate/Resource.java b/karate-core/src/main/java/com/intuit/karate/Resource.java index 0b039a822..c1b5d1bd2 100644 --- a/karate-core/src/main/java/com/intuit/karate/Resource.java +++ b/karate-core/src/main/java/com/intuit/karate/Resource.java @@ -23,8 +23,6 @@ */ package com.intuit.karate; -import com.intuit.karate.core.ScenarioContext; - import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -52,7 +50,7 @@ public class Resource { public static final Resource EMPTY = new Resource(Paths.get(""), "", -1, Thread.currentThread().getContextClassLoader()); public static Resource of(Path path, String text) { - return new Resource(path, null, -1, Thread.currentThread().getContextClassLoader()) { + return new Resource(path, Thread.currentThread().getContextClassLoader()) { final InputStream is = FileUtils.toInputStream(text); @Override @@ -67,8 +65,12 @@ public Resource(File file, String relativePath, ClassLoader cl) { } public Resource(String relativePath) { - this(Thread.currentThread().getContextClassLoader(), relativePath); + this(relativePath, Thread.currentThread().getContextClassLoader()); } + + public Resource(String relativePath, ClassLoader cl) { + this(FileUtils.fromRelativeClassPath(relativePath, cl), relativePath, -1, cl); + } public Resource(Path path, String relativePath, int line, ClassLoader cl) { this.path = path; @@ -88,26 +90,8 @@ public Resource(URL url, ClassLoader cl) { } public Resource(Path path, ClassLoader cl) { - this(path, null, -1, cl); - } - - public Resource(ScenarioContext scenarioContext, String relativePath) { - this(scenarioContext.classLoader, relativePath); - } - - public Resource(ClassLoader cl, String relativePath) { - String strippedPath = FileUtils.removePrefix(relativePath); - URL url = cl.getResource(strippedPath); - if (url != null) { - this.path = FileUtils.urlToPath(url, strippedPath); - } else { - this.path = new File(strippedPath).toPath(); - } - this.line = -1; - file = !path.toUri().getScheme().equals("jar"); - this.relativePath = relativePath; - packageQualifiedName = FileUtils.toPackageQualifiedName(relativePath); - } + this(path, FileUtils.toRelativeClassPath(path, cl), -1, cl); + } public String getFileNameWithoutExtension() { return FileUtils.removeFileExtension(path.getFileName().toString()); @@ -148,8 +132,8 @@ public InputStream getStream() { // since the nio newInputStream has concurrency problems :( // plus a performance boost for karate-base.js if in JAR ClassLoader cl = this.classLoader != null ? this.classLoader : Resource.class.getClassLoader(); - InputStream tempStream = cl.getResourceAsStream(relativePath.replace(FileUtils.CLASSPATH_COLON, ""));//Files.newInputStream(path); - if(tempStream == null) { + InputStream tempStream = cl.getResourceAsStream(relativePath.replace(FileUtils.CLASSPATH_COLON, "")); + if (tempStream == null) { tempStream = Files.newInputStream(path); } bytes = FileUtils.toBytes(tempStream); diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java index 25d38152c..3faa007ae 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java @@ -106,22 +106,6 @@ public static void updateStepFromText(Step step, String text) throws Exception { step.setDocString(temp.getDocString()); step.setTable(temp.getTable()); } -/* - - private static InputStream toStream(File file) { - try { - return new FileInputStream(file); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - } -*/ - -/* - private FeatureParser(File file, String relativePath, ClassLoader cl) { - this(new Feature(new Resource(file, relativePath, cl)), toStream(file)); - } -*/ private FeatureParser(Resource resource) { this(new Feature(resource), resource.getStream()); diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java index fa8aaf8f8..d7d61fc22 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java @@ -93,7 +93,7 @@ private ScenarioContext getContext() throws Exception { @Test public void testClassPathJarResource() throws Exception { String relativePath = "classpath:example/dependency.feature"; - Resource resource = new Resource(getContext(), relativePath); + Resource resource = new Resource(relativePath, getContext().classLoader); String temp = resource.getAsString(); logger.debug("string: {}", temp); } From 62c779b6c13a810b8e1f936072d2df2aeea6b896 Mon Sep 17 00:00:00 2001 From: Nishant-Sehgal Date: Mon, 12 Oct 2020 17:39:57 +0530 Subject: [PATCH 16/31] Issue-1175 null error message handling in Result failure --- .../src/main/java/com/intuit/karate/core/Result.java | 4 +++- .../src/test/java/com/intuit/karate/RunnerTest.java | 5 +++-- .../java/com/intuit/karate/core/FeatureResultTest.java | 7 +++++++ .../com/intuit/karate/core/stackoverflow-error.feature | 4 ++++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100755 karate-core/src/test/java/com/intuit/karate/core/stackoverflow-error.feature diff --git a/karate-core/src/main/java/com/intuit/karate/core/Result.java b/karate-core/src/main/java/com/intuit/karate/core/Result.java index 2bd663a55..b8387059d 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/Result.java +++ b/karate-core/src/main/java/com/intuit/karate/core/Result.java @@ -23,7 +23,9 @@ */ package com.intuit.karate.core; +import com.intuit.karate.StringUtils; import com.intuit.karate.exception.KarateException; + import java.util.HashMap; import java.util.Map; @@ -93,7 +95,7 @@ public static Result passed(long nanos) { public static Result failed(long nanos, Throwable error, Step step) { String featureName = Engine.getFeatureName(step); - error = new KarateException(featureName + ":" + step.getLine() + " - " + error.getMessage()); + error = new KarateException(featureName + ":" + step.getLine() + " - " + (StringUtils.isBlank(error.getMessage()) ? error : error.getMessage())); StackTraceElement[] newTrace = new StackTraceElement[]{ new StackTraceElement("✽", step.getPrefix() + ' ' + step.getText() + ' ', featureName, step.getLine()) }; diff --git a/karate-core/src/test/java/com/intuit/karate/RunnerTest.java b/karate-core/src/test/java/com/intuit/karate/RunnerTest.java index 847d3b809..f171f6564 100644 --- a/karate-core/src/test/java/com/intuit/karate/RunnerTest.java +++ b/karate-core/src/test/java/com/intuit/karate/RunnerTest.java @@ -71,16 +71,17 @@ public void testScenarioOutline() throws Exception { @Test public void testParallel() { Results results = Runner.parallel(getClass(), 1); - assertEquals(2, results.getFailCount()); + assertEquals(3, results.getFailCount()); String pathBase = "target/surefire-reports/com.intuit.karate."; assertTrue(contains(pathBase + "core.scenario.xml", "Then match b == { foo: 'bar'}")); assertTrue(contains(pathBase + "core.outline.xml", "Then assert a == 55")); assertTrue(contains(pathBase + "multi-scenario.xml", "Then assert a != 2")); // a scenario failure should not stop other features from running assertTrue(contains(pathBase + "multi-scenario-fail.xml", "Then assert a != 2 ........................................................ passed")); - assertEquals(2, results.getFailedMap().size()); + assertEquals(3, results.getFailedMap().size()); assertTrue(results.getFailedMap().keySet().contains("com.intuit.karate.no-scenario-name")); assertTrue(results.getFailedMap().keySet().contains("com.intuit.karate.multi-scenario-fail")); + assertTrue(results.getFailedMap().keySet().contains("com.intuit.karate.core.stackoverflow-error")); } @Test diff --git a/karate-core/src/test/java/com/intuit/karate/core/FeatureResultTest.java b/karate-core/src/test/java/com/intuit/karate/core/FeatureResultTest.java index bee0013e3..1a06e691e 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/FeatureResultTest.java +++ b/karate-core/src/test/java/com/intuit/karate/core/FeatureResultTest.java @@ -116,4 +116,11 @@ public void testLambdaFunctionsInScenarioFeature() throws Exception { assertTrue( ((Map) dataArr.get(0)).get("javaSum") instanceof IntBinaryOperator); System.out.println(); } + + @Test + public void testStackOverFlowError() { + FeatureResult result = result("stackoverflow-error.feature"); + assertTrue(result.isFailed()); + assertTrue(result.getScenarioResults().get(0).getError().getMessage().contains("StackOverflowError")); + } } diff --git a/karate-core/src/test/java/com/intuit/karate/core/stackoverflow-error.feature b/karate-core/src/test/java/com/intuit/karate/core/stackoverflow-error.feature new file mode 100755 index 000000000..2fe3d1a2a --- /dev/null +++ b/karate-core/src/test/java/com/intuit/karate/core/stackoverflow-error.feature @@ -0,0 +1,4 @@ +Feature: + Scenario: StackOverflowError + * def s = "\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + * match s == "#regex (.|\n)*" \ No newline at end of file From 8a4d4a807c625160825670de9f81cbc186046649 Mon Sep 17 00:00:00 2001 From: SIX Date: Mon, 12 Oct 2020 19:18:35 +0200 Subject: [PATCH 17/31] Upgrade Spring Boot version in Examples --- examples/consumer-driven-contracts/pom.xml | 4 ++-- examples/gatling/pom.xml | 2 +- examples/mobile-test/pom.xml | 2 +- examples/mock-servlet/pom.xml | 4 ++-- examples/robot-test/pom.xml | 2 +- examples/ui-test/pom.xml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/consumer-driven-contracts/pom.xml b/examples/consumer-driven-contracts/pom.xml index 7e95bb80f..2d05d8df2 100755 --- a/examples/consumer-driven-contracts/pom.xml +++ b/examples/consumer-driven-contracts/pom.xml @@ -16,8 +16,8 @@ UTF-8 1.8 3.6.0 - 2.2.0.RELEASE - 0.9.6 + 2.3.4.RELEASE + 2.0.0 diff --git a/examples/gatling/pom.xml b/examples/gatling/pom.xml index 515aba47d..ce8ebdfe0 100755 --- a/examples/gatling/pom.xml +++ b/examples/gatling/pom.xml @@ -11,7 +11,7 @@ UTF-8 1.8 3.6.0 - 0.9.6 + 2.0.0 3.0.2 diff --git a/examples/mobile-test/pom.xml b/examples/mobile-test/pom.xml index 10f0734b0..4dba5e60d 100644 --- a/examples/mobile-test/pom.xml +++ b/examples/mobile-test/pom.xml @@ -11,7 +11,7 @@ UTF-8 1.8 3.6.0 - 0.9.6 + 2.0.0 diff --git a/examples/mock-servlet/pom.xml b/examples/mock-servlet/pom.xml index 619f11388..0e965fc31 100755 --- a/examples/mock-servlet/pom.xml +++ b/examples/mock-servlet/pom.xml @@ -11,8 +11,8 @@ UTF-8 1.8 3.6.0 - 2.2.0.RELEASE - 0.9.6 + 2.3.4.RELEASE + 2.0.0 diff --git a/examples/robot-test/pom.xml b/examples/robot-test/pom.xml index 34ff33b53..f1826ece4 100644 --- a/examples/robot-test/pom.xml +++ b/examples/robot-test/pom.xml @@ -11,7 +11,7 @@ UTF-8 1.8 3.6.0 - 0.9.6 + 2.0.0 diff --git a/examples/ui-test/pom.xml b/examples/ui-test/pom.xml index df1e47483..3b58f9fe9 100644 --- a/examples/ui-test/pom.xml +++ b/examples/ui-test/pom.xml @@ -11,7 +11,7 @@ UTF-8 1.8 3.6.0 - 0.9.6 + 2.0.0 From 7f70e216b3b2052e5bb5f3af9307281d0665c429 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Tue, 13 Oct 2020 03:05:18 -0500 Subject: [PATCH 18/31] amend username --- .../karate/http/apache/ApacheHttpClient.java | 9 +++++--- .../java/com/intuit/karate/UICookieUtils.java | 21 +++++++++++++++++++ .../intuit/karate/driver/DevToolsDriver.java | 15 ++++++++----- .../java/com/intuit/karate/driver/Driver.java | 6 ++++++ .../com/intuit/karate/driver/WebDriver.java | 20 +++++++++++------- .../driver/playwright/PlaywrightDriver.java | 15 ++++++++----- .../test/java/driver/demo/Demo01Runner.java | 17 +++++++++++++-- .../src/test/java/driver/demo/demo-01.feature | 16 +++++++++++++- 8 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 karate-core/src/main/java/com/intuit/karate/UICookieUtils.java diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java index 1f5b0eb2d..a1361f31b 100644 --- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java +++ b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java @@ -323,8 +323,9 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex response.setStatus(httpResponse.getStatusLine().getStatusCode()); for (Cookie c : cookieStore.getCookies()) { com.intuit.karate.http.Cookie cookie = new com.intuit.karate.http.Cookie(c.getName(), c.getValue()); - cookie.put(DOMAIN, c.getDomain()); - cookie.put(PATH, c.getPath()); + BasicClientCookie cc = (BasicClientCookie) c; + cookie.put(DOMAIN, cc.getDomain()); + cookie.put(PATH, cc.getPath()); if (c.getExpiryDate() != null) { cookie.put(EXPIRES, c.getExpiryDate().getTime() + ""); } @@ -342,7 +343,9 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex cookie.put(DOMAIN, ck.getDomain()); cookie.put(PATH, ck.getPath()); cookie.put(MAX_AGE, ck.getMaxAge() + ""); - response.addCookie(cookie); + if ( null != ck.getPath()) { + response.addCookie(cookie); + } }); } response.addHeader(header.getName(), header.getValue()); diff --git a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java new file mode 100644 index 000000000..93d766651 --- /dev/null +++ b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java @@ -0,0 +1,21 @@ +package com.intuit.karate; + +import com.intuit.karate.http.Cookie; + +import java.util.HashMap; +import java.util.Map; + +public class UICookieUtils { + + public static Map convertCookieToActualMap(Cookie karateCookie) + { + Map cookieMap = new HashMap(); + cookieMap.put(Cookie.NAME, karateCookie.getName()); + cookieMap.put(Cookie.VALUE, karateCookie.getValue()); + cookieMap.put(Cookie.PATH, karateCookie.get(Cookie.PATH)); + cookieMap.put(Cookie.DOMAIN, karateCookie.get(Cookie.DOMAIN)); + cookieMap.put(Cookie.SECURE, Boolean.valueOf(karateCookie.get(Cookie.SECURE))); + cookieMap.put(Cookie.PERSISTENT, Boolean.valueOf(karateCookie.get(Cookie.PERSISTENT))); + return cookieMap; + } +} diff --git a/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java index 49cd35c44..5f2fe205a 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java @@ -23,15 +23,12 @@ */ package com.intuit.karate.driver; -import com.intuit.karate.FileUtils; -import com.intuit.karate.JsonUtils; -import com.intuit.karate.Logger; -import com.intuit.karate.ScriptValue; -import com.intuit.karate.StringUtils; +import com.intuit.karate.*; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeaturesBackend; import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.core.ScriptBridge; +import com.intuit.karate.http.Cookie; import com.intuit.karate.http.HttpRequest; import com.intuit.karate.http.HttpResponse; import com.intuit.karate.http.MultiValuedMap; @@ -968,4 +965,12 @@ public void inputFile(String locator, String... relativePaths) { method("DOM.setFileInputFiles").param("files", files).param("nodeId", nodeId).send(); } + @Override + public void setCookies(Map cookie) { + System.out.println("got this cookie: " + cookie); + cookie.forEach( (k,v) ->{ + cookie(UICookieUtils.convertCookieToActualMap(v)); + }); + } + } diff --git a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java index 08fc826e8..b4c65f897 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java @@ -27,6 +27,9 @@ import com.intuit.karate.core.AutoDef; import com.intuit.karate.core.Plugin; import com.intuit.karate.core.ScenarioContext; +import com.intuit.karate.http.Cookie; +import net.minidev.json.JSONArray; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -107,6 +110,9 @@ default byte[] screenshot() { @AutoDef Map cookie(String name); + @AutoDef + void setCookies(Map cookie); + @AutoDef void cookie(Map cookie); diff --git a/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java index d1cff76db..796709b88 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java @@ -23,15 +23,11 @@ */ package com.intuit.karate.driver; -import com.intuit.karate.Http; -import com.intuit.karate.Json; -import com.intuit.karate.Logger; -import com.intuit.karate.ScriptValue; +import com.intuit.karate.*; +import com.intuit.karate.http.Cookie; import com.intuit.karate.shell.Command; -import java.util.Base64; -import java.util.Collections; -import java.util.List; -import java.util.Map; + +import java.util.*; import java.util.function.Supplier; /** @@ -593,4 +589,12 @@ public byte[] pdf(Map printOptions){ return Base64.getDecoder().decode(temp); } + @Override + public void setCookies(Map cookie) { + System.out.println("got this cookie: " + cookie); + cookie.forEach( (k,v) ->{ + cookie(UICookieUtils.convertCookieToActualMap(v)); + }); + } + } diff --git a/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java index 0df02f424..00b010301 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java @@ -23,11 +23,7 @@ */ package com.intuit.karate.driver.playwright; -import com.intuit.karate.Json; -import com.intuit.karate.JsonUtils; -import com.intuit.karate.LogAppender; -import com.intuit.karate.Logger; -import com.intuit.karate.StringUtils; +import com.intuit.karate.*; import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.driver.Driver; import com.intuit.karate.driver.DriverElement; @@ -36,6 +32,7 @@ import com.intuit.karate.driver.Element; import com.intuit.karate.driver.Input; import com.intuit.karate.driver.Keys; +import com.intuit.karate.http.Cookie; import com.intuit.karate.netty.WebSocketClient; import com.intuit.karate.netty.WebSocketOptions; import com.intuit.karate.shell.Command; @@ -848,4 +845,12 @@ public boolean isTerminated() { return terminated; } + @Override + public void setCookies(Map cookie) { + System.out.println("got this cookie: " + cookie); + cookie.forEach( (k,v) ->{ + cookie(UICookieUtils.convertCookieToActualMap(v)); + }); + } + } diff --git a/karate-demo/src/test/java/driver/demo/Demo01Runner.java b/karate-demo/src/test/java/driver/demo/Demo01Runner.java index 88d906431..d16ea5a49 100644 --- a/karate-demo/src/test/java/driver/demo/Demo01Runner.java +++ b/karate-demo/src/test/java/driver/demo/Demo01Runner.java @@ -4,14 +4,27 @@ import com.intuit.karate.KarateOptions; import org.junit.BeforeClass; import org.junit.runner.RunWith; +import test.ServerStart; @RunWith(Karate.class) @KarateOptions(features = "classpath:driver/demo/demo-01.feature") public class Demo01Runner { - + + private static ServerStart server; + + public static int startServer() throws Exception { + if (server == null) { // keep spring boot side alive for all tests including package 'mock' + server = new ServerStart(); + server.start(new String[]{"--server.port=0"}, false); + } + System.setProperty("demo.server.port", server.getPort() + ""); + return server.getPort(); + } + @BeforeClass - public static void beforeClass() { + public static void beforeClass() throws Exception { System.setProperty("karate.env", "mock"); + startServer(); } } \ No newline at end of file diff --git a/karate-demo/src/test/java/driver/demo/demo-01.feature b/karate-demo/src/test/java/driver/demo/demo-01.feature index 73b869e44..a5a5eb3c4 100644 --- a/karate-demo/src/test/java/driver/demo/demo-01.feature +++ b/karate-demo/src/test/java/driver/demo/demo-01.feature @@ -8,6 +8,7 @@ Background: # * configure driver = { type: 'geckodriver', showDriverLog: true } # * configure driver = { type: 'safaridriver', showDriverLog: true } # * configure driver = { type: 'iedriver', showDriverLog: true, httpConfig: { readTimeout: 120000 } } + * url demoBaseUrl Scenario: try to login to github and then do a google search @@ -17,8 +18,21 @@ Scenario: try to login to github And input('#password', 'world') When submit().click("input[name=commit]") Then match html('#js-flash-container') contains 'Incorrect username or password.' - + Given driver 'https://google.com' And input("input[name=q]", 'karate dsl') When submit().click("input[name=btnI]") Then waitForUrl('https://github.com/intuit/karate') + +Scenario: pass cookie from API call to UI call + Given path 'search', 'cookies' + And cookie foo = {value:'bar', path:'/search'} + When method get + Then status 200 + And match response == '#[1]' + And match response[0] contains { name: 'foo', value: 'bar' } + + Given driver demoBaseUrl + '/search/cookies' + * print responseCookies + When setCookies(responseCookies) + Then match driver.cookies == '#[1]' From ccdc835e3385cbfa1f78900922b2516614549833 Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Tue, 13 Oct 2020 22:01:29 +0530 Subject: [PATCH 19/31] do not reset vars in a callonce #1322 --- .../src/main/java/com/intuit/karate/Script.java | 3 ++- .../karate/junit4/demos/CallonceBgRunner.java | 11 +++++++++++ .../junit4/demos/callonce-bg-called.feature | 5 +++++ .../junit4/demos/callonce-bg-outline.feature | 6 ++++++ .../karate/junit4/demos/callonce-bg.feature | 15 +++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/demos/CallonceBgRunner.java create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-called.feature create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature diff --git a/karate-core/src/main/java/com/intuit/karate/Script.java b/karate-core/src/main/java/com/intuit/karate/Script.java index 9c369918a..f536e0874 100755 --- a/karate-core/src/main/java/com/intuit/karate/Script.java +++ b/karate-core/src/main/java/com/intuit/karate/Script.java @@ -210,7 +210,8 @@ private static ScriptValue result(ScriptValue called, CallResult result, boolean if (reuseParentConfig) { // if shared scope context.configure(new Config(result.config)); // re-apply config from time of snapshot if (result.vars != null) { - context.vars.clear(); + // don't clear vars because karate-config.js or background or scenario outline may have set some ! + // context.vars.clear(); context.vars.putAll(result.vars.copy(false)); // clone for safety } } diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/CallonceBgRunner.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/CallonceBgRunner.java new file mode 100644 index 000000000..7bf02f927 --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/CallonceBgRunner.java @@ -0,0 +1,11 @@ +package com.intuit.karate.junit4.demos; + +import com.intuit.karate.junit4.Karate; +import com.intuit.karate.KarateOptions; +import org.junit.runner.RunWith; + +@RunWith(Karate.class) +@KarateOptions(features = "classpath:com/intuit/karate/junit4/demos/callonce-bg.feature") +public class CallonceBgRunner { + +} \ No newline at end of file diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-called.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-called.feature new file mode 100644 index 000000000..83355ef76 --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-called.feature @@ -0,0 +1,5 @@ +@ignore +Feature: + +Scenario: + * print 'in called' diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature new file mode 100644 index 000000000..bbe7b0ed6 --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature @@ -0,0 +1,6 @@ +@ignore +Feature: + +Scenario: + * print 'in called outline', value + * match value == '1' diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature new file mode 100644 index 000000000..3e229fc13 --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature @@ -0,0 +1,15 @@ +Feature: + +Background: + * callonce read('callonce-bg-called.feature') + +Scenario: first + * print 'in first' + +Scenario Outline: outline + * print 'in outline', value + * call read('callonce-bg-outline.feature') + + Examples: + | value | + | 1 | From 648552e361a9bc834071a71ea5a528d93aefb50f Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Wed, 14 Oct 2020 02:44:17 -0500 Subject: [PATCH 20/31] 1293 - pass cookies from UI to api calls --- .../intuit/karate/core/ScenarioContext.java | 37 ++++++++++++++---- .../src/test/java/driver/demo/demo-01.feature | 38 +++++++++++++------ 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java index b455b84b1..197d144b7 100755 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java @@ -463,6 +463,14 @@ public void configure(Config config) { public void configure(String key, ScriptValue value) { // TODO use enum key = StringUtils.trimToEmpty(key); + + if ( key.equalsIgnoreCase("cookiesx")) + { + key = "cookies"; + Map cookieMap = value.getAsMap(); + System.out.println("cookieMap"); + } + // if next line returns true, http-client needs re-building if (config.configure(key, value)) { if (key.startsWith("httpClient")) { // special case @@ -641,15 +649,28 @@ public void cookie(String name, String value) { } public void cookies(String expr) { - Map map = evalMapExpr(expr); - for (Map.Entry entry : map.entrySet()) { - String key = entry.getKey(); - Object temp = entry.getValue(); - if (temp == null) { - request.removeCookie(key); - } else { - request.setCookie(new Cookie(key, temp.toString())); + ScriptValue value = Script.evalKarateExpression(expr, this); + if (value.isListLike()) { + List mapList = value.getAsList(); + mapList.forEach(currCookieSet -> + { + Cookie cookie = new Cookie(String.valueOf(currCookieSet.get("name")), String.valueOf(currCookieSet.get("value"))); + request.setCookie(cookie); + } + ); + } else if (value.isMapLike()) { + Map map = value.getAsMap(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object temp = entry.getValue(); + if (temp == null) { + request.removeCookie(key); + } else { + request.setCookie(new Cookie(key, temp.toString())); + } } + } else { + throw new KarateException("cannot create cookie from this expression: " + expr + " of type: " + value.getType()); } } diff --git a/karate-demo/src/test/java/driver/demo/demo-01.feature b/karate-demo/src/test/java/driver/demo/demo-01.feature index a5a5eb3c4..650f2aad6 100644 --- a/karate-demo/src/test/java/driver/demo/demo-01.feature +++ b/karate-demo/src/test/java/driver/demo/demo-01.feature @@ -25,14 +25,30 @@ Scenario: try to login to github Then waitForUrl('https://github.com/intuit/karate') Scenario: pass cookie from API call to UI call - Given path 'search', 'cookies' - And cookie foo = {value:'bar', path:'/search'} - When method get - Then status 200 - And match response == '#[1]' - And match response[0] contains { name: 'foo', value: 'bar' } - - Given driver demoBaseUrl + '/search/cookies' - * print responseCookies - When setCookies(responseCookies) - Then match driver.cookies == '#[1]' + Given path 'search', 'cookies' + And cookie foo = {value:'bar', path:'/search'} + When method get + Then status 200 + And match response == '#[1]' + And match response[0] contains { name: 'foo', value: 'bar' } + + Given driver demoBaseUrl + '/search/cookies' + * print responseCookies + When setCookies(responseCookies) + Then match driver.cookies == '#[1]' + +Scenario: pass cookie from a UI call to a certain API call + Given driver demoBaseUrl + '/search/cookies' + Given def cookie2 = { name: 'hello', value: 'world' } + When cookie(cookie2) + Then match driver.cookies contains '#(^cookie2)' + + Given path 'search', 'cookies' + * cookies driver.cookies + When method get + Then status 200 + And match response == '#[1]' + And match response[0] contains { name: 'hello', value: 'world' } + + + From ab5ce1796887b721f5a82fe04dc983a57a957b40 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Wed, 14 Oct 2020 02:46:39 -0500 Subject: [PATCH 21/31] 1293 - pass cookies from UI to api calls --- .../main/java/com/intuit/karate/core/ScenarioContext.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java index 197d144b7..e713a0ec8 100755 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioContext.java @@ -464,13 +464,6 @@ public void configure(Config config) { public void configure(String key, ScriptValue value) { // TODO use enum key = StringUtils.trimToEmpty(key); - if ( key.equalsIgnoreCase("cookiesx")) - { - key = "cookies"; - Map cookieMap = value.getAsMap(); - System.out.println("cookieMap"); - } - // if next line returns true, http-client needs re-building if (config.configure(key, value)) { if (key.startsWith("httpClient")) { // special case From 90aa9cbc721d9eab461fe06750c71226a3092a3c Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Wed, 14 Oct 2020 03:13:52 -0500 Subject: [PATCH 22/31] 1293 - pass cookies from UI to api calls --- .../karate/http/apache/ApacheHttpClient.java | 6 ++--- .../java/com/intuit/karate/UICookieUtils.java | 8 +++++++ .../java/com/intuit/karate/driver/Driver.java | 2 +- .../src/test/java/driver/demo/demo-01.feature | 22 ++++++++++++++++--- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java index a1361f31b..4fba22772 100644 --- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java +++ b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java @@ -323,6 +323,7 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex response.setStatus(httpResponse.getStatusLine().getStatusCode()); for (Cookie c : cookieStore.getCookies()) { com.intuit.karate.http.Cookie cookie = new com.intuit.karate.http.Cookie(c.getName(), c.getValue()); + // while preparing the cookie in buildCookie method we used a BasicClientCookie. This conversion ensures we get path correctly. BasicClientCookie cc = (BasicClientCookie) c; cookie.put(DOMAIN, cc.getDomain()); cookie.put(PATH, cc.getPath()); @@ -341,11 +342,8 @@ protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext contex cookieMap.forEach( ck -> { com.intuit.karate.http.Cookie cookie = new com.intuit.karate.http.Cookie(ck.getName(), ck.getValue()); cookie.put(DOMAIN, ck.getDomain()); - cookie.put(PATH, ck.getPath()); + cookie.put(PATH, null != ck.getPath() ? ck.getPath() : "/"); // lets make sure path is not null. cookie.put(MAX_AGE, ck.getMaxAge() + ""); - if ( null != ck.getPath()) { - response.addCookie(cookie); - } }); } response.addHeader(header.getName(), header.getValue()); diff --git a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java index 93d766651..1217e12ff 100644 --- a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java @@ -5,8 +5,16 @@ import java.util.HashMap; import java.util.Map; +/** + * Cookie Utility method for UI calls. + */ public class UICookieUtils { + /** + * creates a map corresponding to cookie. This is used by appropriate drivers. + * @param karateCookie cookie + * @return Map + */ public static Map convertCookieToActualMap(Cookie karateCookie) { Map cookieMap = new HashMap(); diff --git a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java index b4c65f897..bfcddc99d 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java @@ -111,7 +111,7 @@ default byte[] screenshot() { Map cookie(String name); @AutoDef - void setCookies(Map cookie); + void setCookies(Map cookie); // method to allow cookies from feature file for UI tests. @AutoDef void cookie(Map cookie); diff --git a/karate-demo/src/test/java/driver/demo/demo-01.feature b/karate-demo/src/test/java/driver/demo/demo-01.feature index 650f2aad6..e1e2cf6fc 100644 --- a/karate-demo/src/test/java/driver/demo/demo-01.feature +++ b/karate-demo/src/test/java/driver/demo/demo-01.feature @@ -26,16 +26,16 @@ Scenario: try to login to github Scenario: pass cookie from API call to UI call Given path 'search', 'cookies' - And cookie foo = {value:'bar', path:'/search'} + * cookies { someKey: 'someValue', foo: 'bar' } When method get Then status 200 - And match response == '#[1]' + And match response == '#[2]' And match response[0] contains { name: 'foo', value: 'bar' } Given driver demoBaseUrl + '/search/cookies' * print responseCookies When setCookies(responseCookies) - Then match driver.cookies == '#[1]' + Then match driver.cookies == '#[2]' Scenario: pass cookie from a UI call to a certain API call Given driver demoBaseUrl + '/search/cookies' @@ -50,5 +50,21 @@ Scenario: pass cookie from a UI call to a certain API call And match response == '#[1]' And match response[0] contains { name: 'hello', value: 'world' } +Scenario: pass cookie from a UI call to a certain API call - negative + Given driver demoBaseUrl + '/search/cookies' + Given def cookie2 = { name: 'hello', value: 'world' } + When cookie(cookie2) + Then match driver.cookies contains '#(^cookie2)' + + When clearCookies() + Then match driver.cookies == '#[0]' + + Given path 'search', 'cookies' + * cookies driver.cookies + When method get + Then status 200 + And match response == '#[0]' + + From 15c1bf8333d2b5347200895c6d0df0b8fa35f6d0 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Wed, 14 Oct 2020 03:57:30 -0500 Subject: [PATCH 23/31] 1293 - pass cookies from UI to api calls - cleanup --- .../intuit/karate/driver/DevToolsDriver.java | 17 +++++-------- .../java/com/intuit/karate/driver/Driver.java | 9 +++++-- .../com/intuit/karate/driver/WebDriver.java | 24 ++++++++----------- .../driver/playwright/PlaywrightDriver.java | 19 ++++++--------- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java index 5f2fe205a..0f991327f 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/DevToolsDriver.java @@ -23,12 +23,15 @@ */ package com.intuit.karate.driver; -import com.intuit.karate.*; +import com.intuit.karate.FileUtils; +import com.intuit.karate.JsonUtils; +import com.intuit.karate.Logger; +import com.intuit.karate.ScriptValue; +import com.intuit.karate.StringUtils; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeaturesBackend; import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.core.ScriptBridge; -import com.intuit.karate.http.Cookie; import com.intuit.karate.http.HttpRequest; import com.intuit.karate.http.HttpResponse; import com.intuit.karate.http.MultiValuedMap; @@ -965,12 +968,4 @@ public void inputFile(String locator, String... relativePaths) { method("DOM.setFileInputFiles").param("files", files).param("nodeId", nodeId).send(); } - @Override - public void setCookies(Map cookie) { - System.out.println("got this cookie: " + cookie); - cookie.forEach( (k,v) ->{ - cookie(UICookieUtils.convertCookieToActualMap(v)); - }); - } - -} +} \ No newline at end of file diff --git a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java index bfcddc99d..6ab07d0a2 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java @@ -24,11 +24,11 @@ package com.intuit.karate.driver; import com.intuit.karate.Config; +import com.intuit.karate.UICookieUtils; import com.intuit.karate.core.AutoDef; import com.intuit.karate.core.Plugin; import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.http.Cookie; -import net.minidev.json.JSONArray; import java.util.ArrayList; import java.util.Collections; @@ -111,7 +111,12 @@ default byte[] screenshot() { Map cookie(String name); @AutoDef - void setCookies(Map cookie); // method to allow cookies from feature file for UI tests. + default void setCookies(Map cookies){ // method to allow cookies from feature file for UI tests. + System.out.println("got this cookie: " + cookies); + cookies.forEach( (k,v) ->{ + cookie(UICookieUtils.convertCookieToActualMap(v)); + }); + } @AutoDef void cookie(Map cookie); diff --git a/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java index 796709b88..e4ba3d6ff 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/WebDriver.java @@ -23,11 +23,15 @@ */ package com.intuit.karate.driver; -import com.intuit.karate.*; -import com.intuit.karate.http.Cookie; +import com.intuit.karate.Http; +import com.intuit.karate.Json; +import com.intuit.karate.Logger; +import com.intuit.karate.ScriptValue; import com.intuit.karate.shell.Command; - -import java.util.*; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.function.Supplier; /** @@ -107,7 +111,7 @@ protected T retryIfEnabled(String locator, Supplier action) { String before = options.getPreSubmitHash(); if (before != null) { logger.trace("submit requested, will wait for page load after next action on : {}", locator); - options.setPreSubmitHash(null); // clear the submit flag + options.setPreSubmitHash(null); // clear the submit flag T result = action.get(); Integer retryInterval = options.getRetryInterval(); options.setRetryInterval(500); // reduce retry interval for this special case @@ -589,12 +593,4 @@ public byte[] pdf(Map printOptions){ return Base64.getDecoder().decode(temp); } - @Override - public void setCookies(Map cookie) { - System.out.println("got this cookie: " + cookie); - cookie.forEach( (k,v) ->{ - cookie(UICookieUtils.convertCookieToActualMap(v)); - }); - } - -} +} \ No newline at end of file diff --git a/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java b/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java index 00b010301..0f9fefaba 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/playwright/PlaywrightDriver.java @@ -23,7 +23,11 @@ */ package com.intuit.karate.driver.playwright; -import com.intuit.karate.*; +import com.intuit.karate.Json; +import com.intuit.karate.JsonUtils; +import com.intuit.karate.LogAppender; +import com.intuit.karate.Logger; +import com.intuit.karate.StringUtils; import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.driver.Driver; import com.intuit.karate.driver.DriverElement; @@ -32,7 +36,6 @@ import com.intuit.karate.driver.Element; import com.intuit.karate.driver.Input; import com.intuit.karate.driver.Keys; -import com.intuit.karate.http.Cookie; import com.intuit.karate.netty.WebSocketClient; import com.intuit.karate.netty.WebSocketOptions; import com.intuit.karate.shell.Command; @@ -596,7 +599,7 @@ private void waitForFrame(String previousFrame) { options.setRetryInterval(1000); // reduce retry interval for this special case options.retry(() -> evalFrame(currentFrame, "document.location.href"), pwm -> !pwm.isError() && !pwm.getResultValue().equals(previousFrameUrl), "waiting for frame context", false); - options.setRetryInterval(retryInterval); // restore + options.setRetryInterval(retryInterval); // restore } @Override @@ -845,12 +848,4 @@ public boolean isTerminated() { return terminated; } - @Override - public void setCookies(Map cookie) { - System.out.println("got this cookie: " + cookie); - cookie.forEach( (k,v) ->{ - cookie(UICookieUtils.convertCookieToActualMap(v)); - }); - } - -} +} \ No newline at end of file From db1c77569be7c4e51b35cc12943dd99c1525be4e Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Wed, 14 Oct 2020 04:19:18 -0500 Subject: [PATCH 24/31] 1293 - pass cookies from UI to api calls - cleanup --- .../src/main/java/com/intuit/karate/UICookieUtils.java | 4 ++++ .../src/main/java/com/intuit/karate/driver/Driver.java | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java index 1217e12ff..41f4d1b7b 100644 --- a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java @@ -12,6 +12,10 @@ public class UICookieUtils { /** * creates a map corresponding to cookie. This is used by appropriate drivers. + * Karate Cookie Map is of type vs the internal framwork expects appropriate types - + * for ex boolean for secure and persistent keys. + * + * Solution is to use this utility or remove those keys from Karate Cookie Map. * @param karateCookie cookie * @return Map */ diff --git a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java index 6ab07d0a2..ab6bd4589 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java @@ -111,10 +111,15 @@ default byte[] screenshot() { Map cookie(String name); @AutoDef - default void setCookies(Map cookies){ // method to allow cookies from feature file for UI tests. + default void setCookies(Map cookies){ // method to allow set cookies from feature file for UI tests. System.out.println("got this cookie: " + cookies); cookies.forEach( (k,v) ->{ - cookie(UICookieUtils.convertCookieToActualMap(v)); + // either uncomment below to have correct cookie + //cookie(UICookieUtils.convertCookieToActualMap(v)); + // if above line uncommented, comment below 2 lines. + v.remove(Cookie.SECURE); + v.remove(Cookie.PERSISTENT); + cookie((Map)v); }); } From 47b3ed55a77c8f8ef300fbafd29f5889b2fac16c Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Wed, 14 Oct 2020 18:03:25 -0500 Subject: [PATCH 25/31] #1328 review comments --- .../java/com/intuit/karate/UICookieUtils.java | 33 --------- .../java/com/intuit/karate/driver/Driver.java | 4 +- .../com/intuit/karate/http/HttpUtils.java | 20 ++++++ .../test/java/driver/demo/Demo01Runner.java | 16 +---- .../test/java/driver/demo/Demo06Runner.java | 30 ++++++++ .../src/test/java/driver/demo/demo-01.feature | 72 ++++--------------- .../src/test/java/driver/demo/demo-06.feature | 58 +++++++++++++++ 7 files changed, 125 insertions(+), 108 deletions(-) delete mode 100644 karate-core/src/main/java/com/intuit/karate/UICookieUtils.java create mode 100644 karate-demo/src/test/java/driver/demo/Demo06Runner.java create mode 100644 karate-demo/src/test/java/driver/demo/demo-06.feature diff --git a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java b/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java deleted file mode 100644 index 41f4d1b7b..000000000 --- a/karate-core/src/main/java/com/intuit/karate/UICookieUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.intuit.karate; - -import com.intuit.karate.http.Cookie; - -import java.util.HashMap; -import java.util.Map; - -/** - * Cookie Utility method for UI calls. - */ -public class UICookieUtils { - - /** - * creates a map corresponding to cookie. This is used by appropriate drivers. - * Karate Cookie Map is of type vs the internal framwork expects appropriate types - - * for ex boolean for secure and persistent keys. - * - * Solution is to use this utility or remove those keys from Karate Cookie Map. - * @param karateCookie cookie - * @return Map - */ - public static Map convertCookieToActualMap(Cookie karateCookie) - { - Map cookieMap = new HashMap(); - cookieMap.put(Cookie.NAME, karateCookie.getName()); - cookieMap.put(Cookie.VALUE, karateCookie.getValue()); - cookieMap.put(Cookie.PATH, karateCookie.get(Cookie.PATH)); - cookieMap.put(Cookie.DOMAIN, karateCookie.get(Cookie.DOMAIN)); - cookieMap.put(Cookie.SECURE, Boolean.valueOf(karateCookie.get(Cookie.SECURE))); - cookieMap.put(Cookie.PERSISTENT, Boolean.valueOf(karateCookie.get(Cookie.PERSISTENT))); - return cookieMap; - } -} diff --git a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java index ab6bd4589..530513f8e 100644 --- a/karate-core/src/main/java/com/intuit/karate/driver/Driver.java +++ b/karate-core/src/main/java/com/intuit/karate/driver/Driver.java @@ -24,11 +24,11 @@ package com.intuit.karate.driver; import com.intuit.karate.Config; -import com.intuit.karate.UICookieUtils; import com.intuit.karate.core.AutoDef; import com.intuit.karate.core.Plugin; import com.intuit.karate.core.ScenarioContext; import com.intuit.karate.http.Cookie; +import com.intuit.karate.http.HttpUtils; import java.util.ArrayList; import java.util.Collections; @@ -115,7 +115,7 @@ default void setCookies(Map cookies){ // method to allow set coo System.out.println("got this cookie: " + cookies); cookies.forEach( (k,v) ->{ // either uncomment below to have correct cookie - //cookie(UICookieUtils.convertCookieToActualMap(v)); + // cookie(HttpUtils.convertCookieToActualMap(v)); // if above line uncommented, comment below 2 lines. v.remove(Cookie.SECURE); v.remove(Cookie.PERSISTENT); diff --git a/karate-core/src/main/java/com/intuit/karate/http/HttpUtils.java b/karate-core/src/main/java/com/intuit/karate/http/HttpUtils.java index 4371c942c..647eaa1ed 100644 --- a/karate-core/src/main/java/com/intuit/karate/http/HttpUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/http/HttpUtils.java @@ -274,4 +274,24 @@ public static String multiPartToString(List items, String boundar return sb.toString(); } + /** + * creates a map corresponding to cookie. This is used by appropriate drivers. + * Karate Cookie Map is of type vs the internal framework expects appropriate types - + * for ex boolean for secure and persistent keys. + * Solution is to use this utility method or remove those keys from Karate Cookie Map. + * + * @param karateCookie cookie + * @return Map + */ + public static Map convertCookieToActualMap(Cookie karateCookie) { + Map cookieMap = new HashMap(); + cookieMap.put(Cookie.NAME, karateCookie.getName()); + cookieMap.put(Cookie.VALUE, karateCookie.getValue()); + cookieMap.put(Cookie.PATH, karateCookie.get(Cookie.PATH)); + cookieMap.put(Cookie.DOMAIN, karateCookie.get(Cookie.DOMAIN)); + cookieMap.put(Cookie.SECURE, Boolean.valueOf(karateCookie.get(Cookie.SECURE))); + cookieMap.put(Cookie.PERSISTENT, Boolean.valueOf(karateCookie.get(Cookie.PERSISTENT))); + return cookieMap; + } + } diff --git a/karate-demo/src/test/java/driver/demo/Demo01Runner.java b/karate-demo/src/test/java/driver/demo/Demo01Runner.java index d16ea5a49..16739bcbe 100644 --- a/karate-demo/src/test/java/driver/demo/Demo01Runner.java +++ b/karate-demo/src/test/java/driver/demo/Demo01Runner.java @@ -1,30 +1,18 @@ + package driver.demo; import com.intuit.karate.junit4.Karate; import com.intuit.karate.KarateOptions; import org.junit.BeforeClass; import org.junit.runner.RunWith; -import test.ServerStart; @RunWith(Karate.class) @KarateOptions(features = "classpath:driver/demo/demo-01.feature") public class Demo01Runner { - private static ServerStart server; - - public static int startServer() throws Exception { - if (server == null) { // keep spring boot side alive for all tests including package 'mock' - server = new ServerStart(); - server.start(new String[]{"--server.port=0"}, false); - } - System.setProperty("demo.server.port", server.getPort() + ""); - return server.getPort(); - } - @BeforeClass - public static void beforeClass() throws Exception { + public static void beforeClass() { System.setProperty("karate.env", "mock"); - startServer(); } } \ No newline at end of file diff --git a/karate-demo/src/test/java/driver/demo/Demo06Runner.java b/karate-demo/src/test/java/driver/demo/Demo06Runner.java new file mode 100644 index 000000000..f09c8a48e --- /dev/null +++ b/karate-demo/src/test/java/driver/demo/Demo06Runner.java @@ -0,0 +1,30 @@ +package driver.demo; + +import com.intuit.karate.KarateOptions; +import com.intuit.karate.junit4.Karate; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import test.ServerStart; + +@RunWith(Karate.class) +@KarateOptions(features = "classpath:driver/demo/demo-06.feature") +public class Demo06Runner { + + private static ServerStart server; + + public static int startServer() throws Exception { + if (server == null) { // keep spring boot side alive for all tests including package 'mock' + server = new ServerStart(); + server.start(new String[]{"--server.port=0"}, false); + } + System.setProperty("demo.server.port", server.getPort() + ""); + return server.getPort(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + System.setProperty("karate.env", "mock"); + startServer(); + } + +} diff --git a/karate-demo/src/test/java/driver/demo/demo-01.feature b/karate-demo/src/test/java/driver/demo/demo-01.feature index e1e2cf6fc..cb40a4904 100644 --- a/karate-demo/src/test/java/driver/demo/demo-01.feature +++ b/karate-demo/src/test/java/driver/demo/demo-01.feature @@ -1,70 +1,24 @@ Feature: browser automation 1 -Background: - * configure driver = { type: 'chrome', showDriverLog: true } + Background: + * configure driver = { type: 'chrome', showDriverLog: true } # * configure driverTarget = { docker: 'justinribeiro/chrome-headless', showDriverLog: true } # * configure driverTarget = { docker: 'ptrthomas/karate-chrome', showDriverLog: true } # * configure driver = { type: 'chromedriver', showDriverLog: true } # * configure driver = { type: 'geckodriver', showDriverLog: true } # * configure driver = { type: 'safaridriver', showDriverLog: true } # * configure driver = { type: 'iedriver', showDriverLog: true, httpConfig: { readTimeout: 120000 } } - * url demoBaseUrl - -Scenario: try to login to github - and then do a google search - - Given driver 'https://github.com/login' - And input('#login_field', 'dummy') - And input('#password', 'world') - When submit().click("input[name=commit]") - Then match html('#js-flash-container') contains 'Incorrect username or password.' - - Given driver 'https://google.com' - And input("input[name=q]", 'karate dsl') - When submit().click("input[name=btnI]") - Then waitForUrl('https://github.com/intuit/karate') - -Scenario: pass cookie from API call to UI call - Given path 'search', 'cookies' - * cookies { someKey: 'someValue', foo: 'bar' } - When method get - Then status 200 - And match response == '#[2]' - And match response[0] contains { name: 'foo', value: 'bar' } - - Given driver demoBaseUrl + '/search/cookies' - * print responseCookies - When setCookies(responseCookies) - Then match driver.cookies == '#[2]' - -Scenario: pass cookie from a UI call to a certain API call - Given driver demoBaseUrl + '/search/cookies' - Given def cookie2 = { name: 'hello', value: 'world' } - When cookie(cookie2) - Then match driver.cookies contains '#(^cookie2)' - - Given path 'search', 'cookies' - * cookies driver.cookies - When method get - Then status 200 - And match response == '#[1]' - And match response[0] contains { name: 'hello', value: 'world' } - -Scenario: pass cookie from a UI call to a certain API call - negative - Given driver demoBaseUrl + '/search/cookies' - Given def cookie2 = { name: 'hello', value: 'world' } - When cookie(cookie2) - Then match driver.cookies contains '#(^cookie2)' - - When clearCookies() - Then match driver.cookies == '#[0]' - - Given path 'search', 'cookies' - * cookies driver.cookies - When method get - Then status 200 - And match response == '#[0]' - + Scenario: try to login to github + and then do a google search + Given driver 'https://github.com/login' + And input('#login_field', 'dummy') + And input('#password', 'world') + When submit().click("input[name=commit]") + Then match html('#js-flash-container') contains 'Incorrect username or password.' + Given driver 'https://google.com' + And input("input[name=q]", 'karate dsl') + When submit().click("input[name=btnI]") + Then waitForUrl('https://github.com/intuit/karate') \ No newline at end of file diff --git a/karate-demo/src/test/java/driver/demo/demo-06.feature b/karate-demo/src/test/java/driver/demo/demo-06.feature new file mode 100644 index 000000000..746b4f7cb --- /dev/null +++ b/karate-demo/src/test/java/driver/demo/demo-06.feature @@ -0,0 +1,58 @@ +Feature: browser automation 1 + +Background: + * configure driver = { type: 'chrome', showDriverLog: true } + # * configure driverTarget = { docker: 'justinribeiro/chrome-headless', showDriverLog: true } + # * configure driverTarget = { docker: 'ptrthomas/karate-chrome', showDriverLog: true } + # * configure driver = { type: 'chromedriver', showDriverLog: true } + # * configure driver = { type: 'geckodriver', showDriverLog: true } + # * configure driver = { type: 'safaridriver', showDriverLog: true } + # * configure driver = { type: 'iedriver', showDriverLog: true, httpConfig: { readTimeout: 120000 } } + * url demoBaseUrl + + Scenario: pass cookie from API call to UI call + Given path 'search', 'cookies' + * cookies { someKey: 'someValue', foo: 'bar' } + When method get + Then status 200 + And match response == '#[2]' + And match response[0] contains { name: 'foo', value: 'bar' } + + Given driver demoBaseUrl + '/search/cookies' + * print responseCookies + # set responseCookies from API call to UI(driver) + When setCookies(responseCookies) + Then match driver.cookies == '#[2]' + +Scenario: pass cookie from a UI call to a certain API call + Given driver demoBaseUrl + '/search/cookies' + Given def cookie2 = { name: 'hello', value: 'world' } + When cookie(cookie2) + Then match driver.cookies contains '#(^cookie2)' + + Given path 'search', 'cookies' + # set driver cookies for api call + * cookies driver.cookies + When method get + Then status 200 + And match response == '#[1]' + And match response[0] contains { name: 'hello', value: 'world' } + +Scenario: pass cookie from a UI call to a certain API call - negative + Given driver demoBaseUrl + '/search/cookies' + Given def cookie2 = { name: 'hello', value: 'world' } + When cookie(cookie2) + Then match driver.cookies contains '#(^cookie2)' + + When clearCookies() + Then match driver.cookies == '#[0]' + + Given path 'search', 'cookies' + * cookies driver.cookies + When method get + Then status 200 + And match response == '#[0]' + + + + From 758fe9fff17d79bc8d6b52aefa65e946241846b8 Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Thu, 15 Oct 2020 19:15:56 +0530 Subject: [PATCH 26/31] improve test to prove #1327 is a duplicate of #1322 --- .../com/intuit/karate/junit4/demos/callonce-bg-outline.feature | 2 +- .../java/com/intuit/karate/junit4/demos/callonce-bg.feature | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature index bbe7b0ed6..8f352682c 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg-outline.feature @@ -3,4 +3,4 @@ Feature: Scenario: * print 'in called outline', value - * match value == '1' + * match value == __num + 1 + '' diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature index 3e229fc13..fa86c2ecd 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/callonce-bg.feature @@ -13,3 +13,4 @@ Scenario Outline: outline Examples: | value | | 1 | + | 2 | From e38be4530d6c646fffb7cc219e4dc489ac5af902 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Fri, 16 Oct 2020 03:20:04 -0500 Subject: [PATCH 27/31] 1331 - karate-netty proxy sends previous request payload when dealing with next request --- .../src/main/java/com/intuit/karate/core/FeaturesBackend.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeaturesBackend.java b/karate-core/src/main/java/com/intuit/karate/core/FeaturesBackend.java index 3007e5bcc..d1d22c55c 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeaturesBackend.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeaturesBackend.java @@ -108,6 +108,10 @@ public HttpResponse buildResponse(HttpRequest request, long startTime) { } } match.def(ScriptValueMap.VAR_REQUEST, requestBody); + } else { + // fix for # 1331. If the incoming request body is empty, previous request body was getting used. This will force reset. + // or we should remove this from ScriptValueMap? + match.def(ScriptValueMap.VAR_REQUEST, null); } FeatureBackend.FeatureScenarioMatch matchingInfo = getMatchingScenario(match.vars()); From abe04356b9c977ce06456df6fb9f47e699742461 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Sat, 17 Oct 2020 00:52:31 -0500 Subject: [PATCH 28/31] 1329 - JUnit 5 TestSource --- .../com/intuit/karate/junit5/FeatureNode.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java b/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java index 13518dea0..343eea4f8 100644 --- a/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java +++ b/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java @@ -32,6 +32,9 @@ import com.intuit.karate.core.HtmlFeatureReport; import com.intuit.karate.core.HtmlSummaryReport; import com.intuit.karate.core.ScenarioExecutionUnit; + +import java.io.File; +import java.net.URI; import java.util.Iterator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DynamicTest; @@ -69,7 +72,7 @@ public boolean hasNext() { @Override public DynamicTest next() { ScenarioExecutionUnit unit = iterator.next(); - return DynamicTest.dynamicTest(unit.scenario.getNameForReport(), () -> { + return DynamicTest.dynamicTest(unit.scenario.getNameForReport(), getFeatureSrcURI(unit) ,() -> { if (featureUnit.isSelected(unit)) { unit.run(); } @@ -94,4 +97,14 @@ public Iterator iterator() { return this; } + // fetch src uri to point to scenario in feature file. + public URI getFeatureSrcURI(ScenarioExecutionUnit sunit) { + // this could be made conditional based on config - if navigating to feature file needed, then use below else return null. + String workingDir = System.getProperty("user.dir"); + // we can use getPath as well - though that will point to feature file from compiled location i.e. target + String featurePath = sunit.scenario.getFeature().getRelativePath().replace("classpath:", ""); + return URI.create(new File(workingDir + "/src/test/java/" + featurePath).toURI().toString() + "?line=" + + sunit.scenario.getLine()); + } + } From 48784055b580c11327963e6728424ccb6b6c7f92 Mon Sep 17 00:00:00 2001 From: Deepak Chaudhary Date: Sat, 17 Oct 2020 01:24:12 -0500 Subject: [PATCH 29/31] 1329 - JUnit 5 TestSource review --- .../main/java/com/intuit/karate/core/Scenario.java | 14 +++++++++++++- .../java/com/intuit/karate/junit5/FeatureNode.java | 13 +------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/Scenario.java b/karate-core/src/main/java/com/intuit/karate/core/Scenario.java index d7d475c32..ec69331b8 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/Scenario.java +++ b/karate-core/src/main/java/com/intuit/karate/core/Scenario.java @@ -23,6 +23,8 @@ */ package com.intuit.karate.core; +import java.io.File; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -284,6 +286,16 @@ public void setExampleIndex(int exampleIndex) { @Override public String toString() { return feature.toString() + getDisplayMeta(); - } + } + + // fetch src uri to point to scenario in feature file. + public URI getScenarioSrcUri() { + // this could be made conditional based on config - if navigating to feature file needed, then use below else return null. + String workingDir = System.getProperty("user.dir"); + // we can use getPath as well - though that will point to feature file from compiled location i.e. target + String featurePath = this.feature.getRelativePath().replace("classpath:", ""); + return URI.create(new File(workingDir + "/src/test/java/" + featurePath).toURI().toString() + "?line=" + + this.line); + } } diff --git a/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java b/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java index 343eea4f8..9c150caae 100644 --- a/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java +++ b/karate-junit5/src/main/java/com/intuit/karate/junit5/FeatureNode.java @@ -72,7 +72,7 @@ public boolean hasNext() { @Override public DynamicTest next() { ScenarioExecutionUnit unit = iterator.next(); - return DynamicTest.dynamicTest(unit.scenario.getNameForReport(), getFeatureSrcURI(unit) ,() -> { + return DynamicTest.dynamicTest(unit.scenario.getNameForReport(), unit.scenario.getScenarioSrcUri() ,() -> { if (featureUnit.isSelected(unit)) { unit.run(); } @@ -96,15 +96,4 @@ public DynamicTest next() { public Iterator iterator() { return this; } - - // fetch src uri to point to scenario in feature file. - public URI getFeatureSrcURI(ScenarioExecutionUnit sunit) { - // this could be made conditional based on config - if navigating to feature file needed, then use below else return null. - String workingDir = System.getProperty("user.dir"); - // we can use getPath as well - though that will point to feature file from compiled location i.e. target - String featurePath = sunit.scenario.getFeature().getRelativePath().replace("classpath:", ""); - return URI.create(new File(workingDir + "/src/test/java/" + featurePath).toURI().toString() + "?line=" - + sunit.scenario.getLine()); - } - } From e47012cf1859531da831d590908fb250cc2c215a Mon Sep 17 00:00:00 2001 From: SIX Date: Sat, 17 Oct 2020 08:50:59 +0200 Subject: [PATCH 30/31] feat : Bump up Gatling version --- karate-gatling/pom.xml | 4 ++-- .../main/scala/com/intuit/karate/gatling/KarateAction.scala | 2 +- .../main/scala/com/intuit/karate/gatling/KarateProtocol.scala | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/karate-gatling/pom.xml b/karate-gatling/pom.xml index d917fee56..a9bf6a369 100644 --- a/karate-gatling/pom.xml +++ b/karate-gatling/pom.xml @@ -19,7 +19,7 @@ io.gatling.highcharts gatling-charts-highcharts - 3.0.2 + 3.4.0 org.scala-lang @@ -79,7 +79,7 @@ io.gatling gatling-maven-plugin - 3.0.1 + 3.1.0 true ${skipTests} diff --git a/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateAction.scala b/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateAction.scala index ca2870cf7..70a0f143b 100644 --- a/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateAction.scala +++ b/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateAction.scala @@ -62,7 +62,7 @@ class KarateAction(val name: String, val tags: Seq[String], val protocol: Karate override def reportPerfEvent(event: PerfEvent): Unit = { val okOrNot = if (event.isFailed) KO else OK val message = if (event.getMessage == null) None else Option(event.getMessage) - statsEngine.logResponse(session, event.getName, event.getStartTime, event.getEndTime, okOrNot, Option(event.getStatusCode + ""), message) + statsEngine.logResponse(session.scenario, List.empty, event.getName, event.getStartTime, event.getEndTime, okOrNot, Option(event.getStatusCode + ""), message) } } diff --git a/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateProtocol.scala b/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateProtocol.scala index 0a3aaada0..8d7e51a09 100644 --- a/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateProtocol.scala +++ b/karate-gatling/src/main/scala/com/intuit/karate/gatling/KarateProtocol.scala @@ -35,6 +35,6 @@ object KarateProtocol { } case class KarateComponents(val protocol: KarateProtocol, val system: ActorSystem) extends ProtocolComponents { - override def onStart: Session => Session = ProtocolComponents.NoopOnStart + override def onStart: Session => Session = Session.Identity override def onExit: Session => Unit = ProtocolComponents.NoopOnExit } From 4084b35d010a0471d091051a1e55891cbd6079a2 Mon Sep 17 00:00:00 2001 From: Kruthika Manjunath Date: Sat, 17 Oct 2020 10:58:22 -0700 Subject: [PATCH 31/31] duplicate fix --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8c0e8f7df..6283efa8b 100755 --- a/README.md +++ b/README.md @@ -569,7 +569,7 @@ Note that this is currently not supported for [JUnit 5](#junit-5) `@Karate.Test ### Command Line - Gradle -For Gradle you must extend the test task to allow the `karate.options` to be passed to the runtime (otherwise they get consumed by Gradle itself). To do that, add the following: +For Gradle, you must extend the test task to allow the `karate.options` to be passed to the runtime (otherwise they get consumed by Gradle itself). To do that, add the following: ```yml test { @@ -585,7 +585,11 @@ test { And then the above command in Gradle would look like: ``` -./gradlew test -Dtest=CatsRunner +./gradlew test --tests *CatsRunner +``` +or +``` +./gradlew test -Dtest.single=CatsRunner ``` ### Test Suites