Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS engine refactor - graal upgrade - JS functions can be passed around safely #2081

Merged
merged 10 commits into from
Aug 2, 2022
10 changes: 10 additions & 0 deletions karate-core/src/main/java/com/intuit/karate/JsonUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ public static String toCsv(List<Map<String, Object>> list) {
return sw.toString();
}

public static Object shallowCopy(Object o) {
if (o instanceof List) {
return new ArrayList((List) o);
} else if (o instanceof Map) {
return new LinkedHashMap((Map) o);
} else {
return o;
}
}

public static Object deepCopy(Object o) {
// anti recursion / back-references
Set<Object> seen = Collections.newSetFromMap(new IdentityHashMap());
Expand Down
35 changes: 0 additions & 35 deletions karate-core/src/main/java/com/intuit/karate/core/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@
import com.intuit.karate.StringUtils;
import com.intuit.karate.driver.DockerTarget;
import com.intuit.karate.driver.Target;
import com.intuit.karate.graal.JsEngine;
import com.intuit.karate.graal.JsFunction;
import com.intuit.karate.http.Cookies;
import com.intuit.karate.http.HttpLogModifier;
import org.graalvm.polyglot.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -110,38 +107,6 @@ public Config() {
// zero arg constructor
}

private static Variable attach(Variable v, JsEngine je) {
if (v.isJsFunctionWrapper()) {
JsFunction jf = v.getValue();
Value attached = je.attachSource(jf.source);
return new Variable(attached);
} else {
return v;
}
}

private static Variable detach(Variable v) {
if (v.isJsFunction()) {
return new Variable(new JsFunction(v.getValue()));
} else {
return v;
}
}

protected void attach(JsEngine je) {
afterScenario = attach(afterScenario, je);
afterFeature = attach(afterFeature, je);
headers = attach(headers, je);
cookies = attach(cookies, je);
}

protected void detach() {
afterScenario = detach(afterScenario);
afterFeature = detach(afterFeature);
headers = detach(headers);
cookies = detach(cookies);
}

private static <T> T get(Map<String, Object> map, String key, T defaultValue) {
Object o = map.get(key);
return o == null ? defaultValue : (T) o;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public MockHandler(String prefix, List<Feature> features, Map<String, Object> ar
}
}
corsEnabled = corsEnabled || runtime.engine.getConfig().isCorsEnabled();
globals.putAll(runtime.engine.detachVariables());
globals.putAll(runtime.engine.shallowCloneVariables());
runtime.logger.info("mock server initialized: {}", feature);
this.features.put(feature, runtime);
}
Expand Down Expand Up @@ -187,7 +187,7 @@ public synchronized Response handle(Request req) { // note the [synchronized]
responseStatus = engine.vars.remove(ScenarioEngine.RESPONSE_STATUS);
responseHeaders = engine.vars.remove(ScenarioEngine.RESPONSE_HEADERS);
responseDelay = engine.vars.remove(RESPONSE_DELAY);
globals.putAll(engine.detachVariables());
globals.putAll(engine.shallowCloneVariables());
Response res = new Response(200);
if (result.isFailed()) {
response = new Variable(result.getError().getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import com.intuit.karate.http.HttpRequest;
import com.intuit.karate.http.HttpRequestBuilder;
import com.intuit.karate.http.ResourceType;
import com.intuit.karate.http.Response;
import com.intuit.karate.http.WebSocketClient;
import com.intuit.karate.http.WebSocketOptions;
import com.intuit.karate.shell.Command;
Expand Down Expand Up @@ -180,9 +179,8 @@ private static Object callSingleResult(ScenarioEngine engine, Object o) throws E
engine.logger.warn("callSingle() cached result is an exception");
throw (Exception) o;
}
// if we don't clone, an attach operation would update the tree within the cached value
// causing future cache hit + attach attempts to fail !
o = engine.recurseAndAttachAndShallowClone(o);
// shallow clone so that threads see the same data snapshot
o = JsonUtils.shallowCopy(o);
return JsValue.fromJava(o);
}

Expand Down Expand Up @@ -257,8 +255,7 @@ public Object callSingle(String fileName, Value arg) throws Exception {
engine.logger.warn("callSingleCache write failed, not json-like: {}", resultVar);
}
}
// functions have to be detached so that they can be re-hydrated in another js context
result = engine.recurseAndDetachAndShallowClone(resultVar.getValue());
result = resultVar.getValue();
}
CACHE.put(fileName, result);
engine.logger.info("<< lock released, cached callSingle: {}", fileName);
Expand Down Expand Up @@ -739,10 +736,10 @@ public Object repeat(int n, Value f) {
}
return new JsList(list);
}

public String responseHeader(String name) {
return getEngine().getResponse().getHeader(name);
}
}

// set multiple variables in one shot
public void set(Map<String, Object> map) {
Expand Down Expand Up @@ -879,12 +876,7 @@ public String toCsv(Object o) {
}

public Object toJava(Value value) {
if (value.canExecute()) {
JsEngine copy = getEngine().JS.copy();
return new JsLambda(copy.attach(value));
} else {
return new JsValue(value).getValue();
}
return new JsValue(value).getValue();
}

public File toJavaFile(String path) {
Expand Down Expand Up @@ -980,8 +972,7 @@ public WebSocketClient webSocket(String url, Value listener, Value value) {
if (listener == null || !listener.canExecute()) {
handler = m -> true;
} else {
JsEngine copy = engine.JS.copy();
handler = new JsLambda(copy.attach(listener));
handler = new JsLambda(listener);
}
WebSocketOptions options = new WebSocketOptions(url, value == null ? null : new JsValue(value).getValue());
options.setTextHandler(handler);
Expand All @@ -1002,8 +993,7 @@ public WebSocketClient webSocketBinary(String url, Value listener, Value value)
if (listener == null || !listener.canExecute()) {
handler = m -> true;
} else {
JsEngine copy = engine.JS.copy();
handler = new JsLambda(copy.attach(listener));
handler = new JsLambda(listener);
}
WebSocketOptions options = new WebSocketOptions(url, value == null ? null : new JsValue(value).getValue());
options.setBinaryHandler(handler);
Expand Down
Loading