From 788f053761359a62e2a91f6e485e5b4869e74bfa Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 7 Nov 2021 12:34:56 -0500 Subject: [PATCH 1/9] fixing issue 1766 --- .../src/main/java/com/intuit/karate/core/ScenarioEngine.java | 4 +++- .../java/com/intuit/karate/core/jscall/JsCallonceTest.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java index 8588afdce..a4b8c6397 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java @@ -2072,7 +2072,9 @@ private Variable callOnce(String cacheKey, Variable called, Variable arg, boolea result = new ScenarioCall.Result(new Variable(resultObject), clonedConfig, clonedVars); CACHE.put(cacheKey, result); logger.info("<< lock released, cached callonce: {}", cacheKey); - return resultValue; // another routine will apply globally if needed + // another routine will apply globally if needed + // wrap and attach if being used immediately in a Scenario + return callOnceResult(result, sharedScope); } } diff --git a/karate-core/src/test/java/com/intuit/karate/core/jscall/JsCallonceTest.java b/karate-core/src/test/java/com/intuit/karate/core/jscall/JsCallonceTest.java index 53cb9b377..b644ee2cb 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/jscall/JsCallonceTest.java +++ b/karate-core/src/test/java/com/intuit/karate/core/jscall/JsCallonceTest.java @@ -8,7 +8,7 @@ public class JsCallonceTest { - // @Test + @Test public void testParallel() { Results results = Runner.path("classpath:com/intuit/karate/core/jscall/js-callonce.feature") .configDir("classpath:com/intuit/karate/core/jscall") From 10795ff84beb9735ed25c5f262dc2527c49eb9ca Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 7 Nov 2021 13:17:52 -0500 Subject: [PATCH 2/9] fixing requestBuilder not reused in dynamic Scenario Outline --- .../main/java/com/intuit/karate/core/ScenarioEngine.java | 5 +++++ .../main/java/com/intuit/karate/core/ScenarioRuntime.java | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java index a4b8c6397..b7f556004 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java @@ -118,6 +118,10 @@ public ScenarioEngine(ScenarioRuntime runtime, Map vars) { } public ScenarioEngine(Config config, ScenarioRuntime runtime, Map vars, Logger logger) { + this(config, runtime, vars, logger, null); + } + + public ScenarioEngine(Config config, ScenarioRuntime runtime, Map vars, Logger logger, HttpRequestBuilder requestBuilder) { this.config = config; this.runtime = runtime; hooks = runtime.featureRuntime.suite.hooks; @@ -126,6 +130,7 @@ public ScenarioEngine(Config config, ScenarioRuntime runtime, Map Date: Sun, 7 Nov 2021 14:16:25 -0500 Subject: [PATCH 3/9] workaround to account for case where headers is a function and so it cannot be reused in multithread --- .../main/java/com/intuit/karate/core/ScenarioEngine.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java index b7f556004..dd278c138 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java @@ -564,7 +564,9 @@ private void httpInvokeOnce() { } Map headers; if (config.getHeaders().isJsOrJavaFunction()) { - headers = getOrEvalAsMap(config.getHeaders(), requestBuilder.build()); + synchronized (config.getHeaders()) { + headers = getOrEvalAsMap(config.getHeaders(), requestBuilder.build()); + } } else { headers = getOrEvalAsMap(config.getHeaders()); // avoid an extra http request build } @@ -1302,8 +1304,8 @@ protected Map getOrEvalAsMap(Variable var, Object... args) { public Variable executeFunction(Variable var, Object... args) { switch (var.type) { case JS_FUNCTION: - Value jsFunction = var.getValue(); - JsValue jsResult = executeJsValue(jsFunction, args); + Value jsFunction = var.getValue(); + JsValue jsResult = executeJsValue(JS.attach(jsFunction), args); return new Variable(jsResult); case JAVA_FUNCTION: // definitely a "call" with a single argument Function javaFunction = var.getValue(); From 413b769656046b1e8d0f1dc21be7ec9488d03d07 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 7 Nov 2021 17:35:45 -0500 Subject: [PATCH 4/9] Revert "Revert "Issue 1793"" This reverts commit 1b173851e981a8cbb74f299ec4a4757848e83b48. --- .../main/java/com/intuit/karate/core/ScenarioRuntime.java | 2 +- .../com/intuit/karate/core/runner/hooks/HooksTest.java | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java index 906251427..1fbbcc00a 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java @@ -359,7 +359,7 @@ public void beforeRun() { if (this.isDynamicBackground()) { steps = scenario.getBackgroundSteps(); } else { - steps = scenario.getStepsIncludingBackground(); + steps = background == null ? scenario.getStepsIncludingBackground() : scenario.getSteps(); } ScenarioEngine.set(engine); engine.init(); diff --git a/karate-core/src/test/java/com/intuit/karate/core/runner/hooks/HooksTest.java b/karate-core/src/test/java/com/intuit/karate/core/runner/hooks/HooksTest.java index 4f089cd80..0b25632ad 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/runner/hooks/HooksTest.java +++ b/karate-core/src/test/java/com/intuit/karate/core/runner/hooks/HooksTest.java @@ -145,12 +145,9 @@ void testDynamicOutlineHookNoScenarioExecution() { assertEquals(0, testRuntimeHook.getRuntimeHookTracker().get("beforeScenario").values().stream().mapToInt(Integer::intValue).sum()); assertEquals(0, testRuntimeHook.getRuntimeHookTracker().get("afterScenario").values().stream().mapToInt(Integer::intValue).sum()); - // 5 because steps are added again to each scenario outline to execute again ... - // background steps are re-run on each scenario outline - // so 2 steps per each scenario outline + 1 step that takes to compute the background section // needed to provide the value on the Examples table - assertEquals(5, testRuntimeHook.getRuntimeHookTracker().get("beforeStep").values().stream().mapToInt(Integer::intValue).sum()); - assertEquals(5, testRuntimeHook.getRuntimeHookTracker().get("afterStep").values().stream().mapToInt(Integer::intValue).sum()); + assertEquals(3, testRuntimeHook.getRuntimeHookTracker().get("beforeStep").values().stream().mapToInt(Integer::intValue).sum()); + assertEquals(3, testRuntimeHook.getRuntimeHookTracker().get("afterStep").values().stream().mapToInt(Integer::intValue).sum()); } @Test From 4128445cfd41c2db3db42ca86ef0f32f727da404 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sun, 7 Nov 2021 18:32:28 -0500 Subject: [PATCH 5/9] fixing case in which callonce is used to read a JSON file --- .../java/com/intuit/karate/core/ScenarioEngine.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java index dd278c138..2085a1bb6 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java @@ -2030,6 +2030,18 @@ private Variable callOnceResult(ScenarioCall.Result result, boolean sharedScope) logger.warn("[*** callonce result ***] ignoring non-json value: '{}' - {}", k, e.getMessage()); } }); + } else if (result.value != null) { + if (result.value.isMap()) { + ((Map) result.value.getValue()).forEach((k, v) -> { + try { + vars.put((String) k, new Variable(v)); + } catch (Exception e) { + logger.warn("[*** callonce result ***] ignoring non-json value from result.value: '{}' - {}", k, e.getMessage()); + } + }); + } else { + logger.warn("[*** callonce result ***] ignoring non-map value from result.value: {}", result.value); + } } init(); // this will attach and also insert magic variables // re-apply config from time of snapshot From a7e6e8559f70380d15d1111405dc318cb1c5ec9e Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sat, 13 Nov 2021 22:12:44 -0500 Subject: [PATCH 6/9] - fixing Config object not being rehydrated when: background is reused (dynamic scenario outline), shared scope, etc. - fixing sharing of HttpRequestBuilder --- .../com/intuit/karate/core/FeatureResult.java | 9 +++ .../intuit/karate/core/FeatureRuntime.java | 1 + .../intuit/karate/core/ScenarioBridge.java | 15 +++-- .../intuit/karate/core/ScenarioEngine.java | 67 ++++++++++++++++--- .../intuit/karate/core/ScenarioIterator.java | 1 + .../intuit/karate/core/ScenarioRuntime.java | 21 +++--- .../core/parallel/ParallelOutlineTest.java | 2 +- .../core/parallel/parallel-outline-1.feature | 29 ++++++++ .../parallel-outline-call-api.feature | 6 ++ 9 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-call-api.feature diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureResult.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureResult.java index 151dd488d..c29696e5c 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureResult.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureResult.java @@ -50,6 +50,7 @@ public class FeatureResult { private Map resultVariables; private Map callArg; + private Config config; private int loopIndex = -1; private int callDepth; @@ -309,6 +310,14 @@ public Map getVariables() { return resultVariables; } + public void setConfig(Config config) { + this.config = config; + } + + public Config getConfig() { + return config; + } + public void sortScenarioResults() { Collections.sort(scenarioResults); } diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureRuntime.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureRuntime.java index ef724c4f3..a27b35903 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureRuntime.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureRuntime.java @@ -196,6 +196,7 @@ public void afterFeature() { if (lastExecutedScenario != null) { lastExecutedScenario.engine.invokeAfterHookIfConfigured(true); result.setVariables(lastExecutedScenario.engine.getAllVariablesAsMap()); + result.setConfig(lastExecutedScenario.engine.getConfig()); } if (!result.isEmpty()) { for (RuntimeHook hook : suite.hooks) { diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java index abdf5446c..f72d0479a 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java @@ -162,10 +162,16 @@ public Object call(boolean sharedScope, String fileName, Value arg) { ScenarioEngine engine = getEngine(); Variable called = new Variable(engine.fileReader.readFile(fileName)); Variable result = engine.call(called, arg == null ? null : new Variable(arg), sharedScope); - if (sharedScope && result.isMap()) { - engine.setVariables(result.getValue()); + Variable resultVariables = engine.getCallFeatureVariables(result); + if (sharedScope) { + if (resultVariables.isMap()) { + engine.setVariables(resultVariables.getValue()); + } + if (result.getValue() instanceof FeatureResult) { + engine.setConfig(((FeatureResult) result.getValue()).getConfig()); + } } - return JsValue.fromJava(result.getValue()); + return JsValue.fromJava(resultVariables.getValue()); } private static Object callSingleResult(ScenarioEngine engine, Object o) throws Exception { @@ -232,7 +238,8 @@ public Object callSingle(String fileName, Value arg) throws Exception { } Variable resultVar; try { - resultVar = engine.call(called, argVar, false); + Variable featureResult = engine.call(called, argVar, false); + resultVar = engine.getCallFeatureVariables(featureResult); } catch (Exception e) { // don't retain any vestiges of graal-js RuntimeException re = new RuntimeException(e.getMessage()); diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java index 2085a1bb6..969849337 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java @@ -564,9 +564,7 @@ private void httpInvokeOnce() { } Map headers; if (config.getHeaders().isJsOrJavaFunction()) { - synchronized (config.getHeaders()) { - headers = getOrEvalAsMap(config.getHeaders(), requestBuilder.build()); - } + headers = getOrEvalAsMap(config.getHeaders(), requestBuilder.build()); } else { headers = getOrEvalAsMap(config.getHeaders()); // avoid an extra http request build } @@ -1992,14 +1990,54 @@ public Variable call(Variable called, Variable arg, boolean sharedScope) { case FEATURE: // will be always a map or a list of maps (loop call result) Object callResult = callFeature(called.getValue(), arg, -1, sharedScope); - Set seen = Collections.newSetFromMap(new IdentityHashMap()); - recurseAndAttach("", callResult, seen); + this.rehydrateCallFeatureResult(callResult); return new Variable(callResult); default: throw new RuntimeException("not a callable feature or js function: " + called); } } + private void rehydrateCallFeatureResult(Object callResult) { + Object callResultVariables = null; + if (callResult instanceof FeatureResult) { + callResultVariables = ((FeatureResult) callResult).getVariables(); + ((FeatureResult) callResult).getConfig().detach(); + } else if (callResult instanceof List) { + callResultVariables = new ArrayList>(); + final List> finalCallResultVariables = (List>)callResultVariables; + ((List) callResult).forEach(result -> { + if (result instanceof FeatureResult) { + finalCallResultVariables.add(((FeatureResult) result).getVariables()); + Config config = ((FeatureResult) result).getConfig(); + config.detach(); + } + }); + callResultVariables = finalCallResultVariables; + } else { + callResultVariables = callResult; + } + Set seen = Collections.newSetFromMap(new IdentityHashMap()); + recurseAndAttach("", callResultVariables, seen); + } + + public Variable getCallFeatureVariables(Variable featureResult) { + if (featureResult.getValue() instanceof FeatureResult) { + return new Variable(((FeatureResult) featureResult.getValue()).getVariables()); + } else if (featureResult.isList()) { + List resultVariables = new ArrayList(); + ((List) featureResult.getValue()).forEach(result -> { + if (result instanceof FeatureResult) { + resultVariables.add(this.getCallFeatureVariables(new Variable(result)).getValue()); + } else { + resultVariables.add(result); + } + }); + return new Variable(resultVariables); + } else { + return featureResult; + } + } + public Variable call(boolean callOnce, String exp, boolean sharedScope) { StringUtils.Pair pair = parseCallArgs(exp); Variable called = evalKarateExpression(pair.left); @@ -2010,10 +2048,17 @@ public Variable call(boolean callOnce, String exp, boolean sharedScope) { } else { result = call(called, arg, sharedScope); } - if (sharedScope && result.isMap()) { - setVariables(result.getValue()); + Variable resultVariables = this.getCallFeatureVariables(result); + if (sharedScope) { + //setVariables(result.getValue()); + if (resultVariables.isMap()) { + setVariables(resultVariables.getValue()); + } + if (result.getValue() instanceof FeatureResult) { + setConfig(((FeatureResult) result.getValue()).getConfig()); + } } - return result; + return new Variable(resultVariables.getValue()); } private Variable callOnceResult(ScenarioCall.Result result, boolean sharedScope) { @@ -2081,13 +2126,14 @@ private Variable callOnce(String cacheKey, Variable called, Variable arg, boolea // this thread is the 'winner' logger.info(">> lock acquired, begin callonce: {}", cacheKey); Variable resultValue = call(called, arg, sharedScope); + Variable resultVariables = this.getCallFeatureVariables(resultValue); // we clone result (and config) here, to snapshot state at the point the callonce was invoked // detaching is important (see JsFunction) so that we can keep the source-code aside // and use it to re-create functions in a new JS context - and work around graal-js limitations Map clonedVars = called.isFeature() && sharedScope ? detachVariables() : null; Config clonedConfig = new Config(config); clonedConfig.detach(); - Object resultObject = recurseAndDetachAndShallowClone(resultValue.getValue()); + Object resultObject = recurseAndDetachAndShallowClone(resultVariables.getValue()); result = new ScenarioCall.Result(new Variable(resultObject), clonedConfig, clonedVars); CACHE.put(cacheKey, result); logger.info("<< lock released, cached callonce: {}", cacheKey); @@ -2113,12 +2159,13 @@ public Object callFeature(Feature feature, Variable arg, int index, boolean shar // to polute parent scope/context runtime.engine.recurseAndAttach(runtime.magicVariables); runtime.engine.recurseAndAttach(runtime.engine.vars); + // todo: shared config } if (result.isFailed()) { KarateException ke = result.getErrorMessagesCombined(); throw ke; } else { - return result.getVariables(); + return result; } } else if (arg.isList() || arg.isJsOrJavaFunction()) { List result = new ArrayList(); diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioIterator.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioIterator.java index 36111a15b..581db24ea 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioIterator.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioIterator.java @@ -93,6 +93,7 @@ public boolean tryAdvance(Consumer action) { background = new ScenarioRuntime(featureRuntime, currentScenario); if (background.selectedForExecution) { background.run(); + background.engine.getConfig().detach(); } if (background.result.isFailed()) { // karate-config.js || background failed currentScenario = null; diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java index 1fbbcc00a..1e437102f 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioRuntime.java @@ -73,21 +73,23 @@ public ScenarioRuntime(FeatureRuntime featureRuntime, Scenario scenario, Scenari perfMode = featureRuntime.perfHook != null; if (caller.isNone()) { logAppender = new StringLogAppender(false); - if (background == null) { - engine = new ScenarioEngine(new Config(), this, new HashMap(), logger); - } else { - engine = new ScenarioEngine(background.engine.getConfig(), this, new HashMap(), logger, background.engine.requestBuilder.copy()); - } + Config config = background == null ? new Config() : new Config(background.engine.getConfig()); + config.detach(); + engine = new ScenarioEngine(config, this, new HashMap(), logger, background != null ? background.engine.requestBuilder.copy() : null); } else if (caller.isSharedScope()) { logAppender = caller.parentRuntime.logAppender; - Config config = background == null ? caller.parentRuntime.engine.getConfig() : background.engine.getConfig(); + ScenarioEngine parentEngine = background == null ? caller.parentRuntime.engine : background.engine; + Config config = parentEngine.getConfig(); + config.detach(); Map vars = caller.parentRuntime.engine.vars; - engine = new ScenarioEngine(config, this, vars, logger); + engine = new ScenarioEngine(config, this, vars, logger, parentEngine.requestBuilder.copy()); } else { // new, but clone and copy data logAppender = caller.parentRuntime.logAppender; - Config config = background == null ? new Config(caller.parentRuntime.engine.getConfig()) : background.engine.getConfig(); + ScenarioEngine parentEngine = background == null ? caller.parentRuntime.engine : background.engine; + Config config = new Config(parentEngine.getConfig()); + config.detach(); // in this case, parent variables are set via magic variables - engine = new ScenarioEngine(config, this, new HashMap(), logger, background != null ? caller.parentRuntime.engine.requestBuilder.copy() : null); + engine = new ScenarioEngine(config, this, new HashMap(), logger, parentEngine.requestBuilder.copy()); } logger.setAppender(logAppender); actions = new ScenarioActions(engine); @@ -363,6 +365,7 @@ public void beforeRun() { } ScenarioEngine.set(engine); engine.init(); + engine.getConfig().attach(engine.JS); if (this.background != null) { ScenarioEngine backgroundEngine = background.engine; if (backgroundEngine.driver != null) { diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/ParallelOutlineTest.java b/karate-core/src/test/java/com/intuit/karate/core/parallel/ParallelOutlineTest.java index 3790abf8a..75bcd9568 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/parallel/ParallelOutlineTest.java +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/ParallelOutlineTest.java @@ -36,7 +36,7 @@ void testParallelOutline() { .systemProperty("server.port", server.getPort() + "") .parallel(3); assertEquals(2, results.getFeaturesPassed()); - assertEquals(8, results.getScenariosPassed()); + assertEquals(12, results.getScenariosPassed()); assertEquals(0, results.getFailCount()); } diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-1.feature b/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-1.feature index 32a633727..58f4df094 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-1.feature +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-1.feature @@ -8,6 +8,20 @@ Background: # java object that comes from a callSingle in the config * def HelloBg = HelloConfigSingle * callonce read('call-once-from-feature.feature') + # cookies are normalized, so reading a JS function should have no impacts (will read as a null variable) + * configure cookies = read('cookies.js') + * configure afterFeature = + """ + function fn() { + console.log('afterFeature'); + } + """ + * configure afterScenario = + """ + function fn() { + console.log('afterScenario'); + } + """ Scenario Outline: * call read('called.feature') @@ -16,6 +30,7 @@ Scenario Outline: * method get * status 200 * match response == { message: 'from feature' } + * match HelloBg.sayHello('world') == 'hello world' * match HelloOnce.sayHello('world') == 'hello world' @@ -23,3 +38,17 @@ Scenario Outline: Examples: | data | + +Scenario Outline: validating background http context set in background will be shared in shared scope, with dynamic scenario outline + * call read('called.feature') + * match functionFromKarateBase() == 'fromKarateBase' + * call read('parallel-outline-call-api.feature') + * match response == { message: 'from feature' } + + + * match HelloBg.sayHello('world') == 'hello world' + * match HelloOnce.sayHello('world') == 'hello world' + * match sayHello('world') == 'hello world' + + Examples: + | data | \ No newline at end of file diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-call-api.feature b/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-call-api.feature new file mode 100644 index 000000000..c6054b8ee --- /dev/null +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/parallel-outline-call-api.feature @@ -0,0 +1,6 @@ +Feature: + +Scenario: + * path 'fromfeature' + * method get + * status 200 \ No newline at end of file From 7abb0eda7b9cdaedd00cdaa8c4674044a7292c9e Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sat, 13 Nov 2021 22:13:17 -0500 Subject: [PATCH 7/9] adding file missed in previous commit --- .../src/test/java/com/intuit/karate/core/parallel/cookies.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 karate-core/src/test/java/com/intuit/karate/core/parallel/cookies.js diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/cookies.js b/karate-core/src/test/java/com/intuit/karate/core/parallel/cookies.js new file mode 100644 index 000000000..e0c86fae6 --- /dev/null +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/cookies.js @@ -0,0 +1,3 @@ +function fn() { + return { 'cookie-id': java.lang.System.currentTimeMillis() + '' }; +} From 8d232b1ab902178c8d7e69823b24476e9937aa21 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sat, 13 Nov 2021 22:26:28 -0500 Subject: [PATCH 8/9] attempt at reproduce #1835 --- .../karate/core/parallel/call-single-from-config3.feature | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature b/karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature new file mode 100644 index 000000000..dfd20eed1 --- /dev/null +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature @@ -0,0 +1,7 @@ +Feature: +Background: + * url serverUrl + +Scenario: reproducing #1835 + * call read('parallel-outline-call-api.feature') + * def headers = response.headers From ea82eff73f2b1bc925addc4807e2b8f480f633c7 Mon Sep 17 00:00:00 2001 From: Joel Ramos Date: Sat, 13 Nov 2021 22:36:20 -0500 Subject: [PATCH 9/9] actual attempt at reproducing #1835 - works, hopefully from work of sharing config across shared contexts --- ...ll-single-from-config3.feature => call-from-config3.feature} | 2 +- .../test/java/com/intuit/karate/core/parallel/karate-config.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) rename karate-core/src/test/java/com/intuit/karate/core/parallel/{call-single-from-config3.feature => call-from-config3.feature} (68%) diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature b/karate-core/src/test/java/com/intuit/karate/core/parallel/call-from-config3.feature similarity index 68% rename from karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature rename to karate-core/src/test/java/com/intuit/karate/core/parallel/call-from-config3.feature index dfd20eed1..e0e2f10d0 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/parallel/call-single-from-config3.feature +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/call-from-config3.feature @@ -1,6 +1,6 @@ Feature: Background: - * url serverUrl + * url 'http://localhost:' + karate.properties['server.port'] Scenario: reproducing #1835 * call read('parallel-outline-call-api.feature') diff --git a/karate-core/src/test/java/com/intuit/karate/core/parallel/karate-config.js b/karate-core/src/test/java/com/intuit/karate/core/parallel/karate-config.js index 25f157ba6..2ae120e4e 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/parallel/karate-config.js +++ b/karate-core/src/test/java/com/intuit/karate/core/parallel/karate-config.js @@ -10,5 +10,7 @@ function fn() { config.message2 = result2.message; var result3 = karate.callSingle('call-single-from-config3.js'); config.sayHello = result3.sayHello; + // attempt at reproducing #1835 + karate.call('call-from-config3.feature'); return config; }