Skip to content

Commit

Permalink
fix regression in v0.2.5 added tests for these cases, and prep for v0…
Browse files Browse the repository at this point in the history
….2.6
  • Loading branch information
ptrthomas committed Mar 12, 2017
1 parent 190d708 commit 7420049
Show file tree
Hide file tree
Showing 21 changed files with 229 additions and 50 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ This is all that you need within your `<dependencies>`:
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit4</artifactId>
<version>0.2.5</version>
<version>0.2.6</version>
<scope>test</scope>
</dependency>
```
Expand All @@ -193,7 +193,7 @@ You can replace the values of 'com.mycompany' and 'myproject' as per your needs.
mvn archetype:generate \
-DarchetypeGroupId=com.intuit.karate \
-DarchetypeArtifactId=karate-archetype \
-DarchetypeVersion=0.2.5 \
-DarchetypeVersion=0.2.6 \
-DgroupId=com.mycompany \
-DartifactId=myproject
```
Expand Down Expand Up @@ -1493,7 +1493,7 @@ function() {
ip_header: '123.45.67.89',
};
var authString = '';
var authToken = karate.get('authToken'); // use the 'karate' helper to do a 'safe' get of a variable
var authToken = karate.get('authToken'); // use the 'karate' helper to do a 'safe' get of a 'dynamic' variable
if (authToken) { // and if 'authToken' is not null ...
authString = ',auth_type=MyAuthScheme'
+ ',auth_key=' + authToken.key
Expand Down
2 changes: 1 addition & 1 deletion karate-archetype/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-parent</artifactId>
<version>0.2.5</version>
<version>0.2.6</version>
</parent>
<artifactId>karate-archetype</artifactId>
<packaging>jar</packaging>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit4</artifactId>
<version>0.2.5</version>
<version>0.2.6</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
2 changes: 1 addition & 1 deletion karate-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-parent</artifactId>
<version>0.2.5</version>
<version>0.2.6</version>
</parent>
<artifactId>karate-core</artifactId>
<packaging>jar</packaging>
Expand Down
11 changes: 3 additions & 8 deletions karate-core/src/main/java/com/intuit/karate/RequestFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@
*/
public class RequestFilter implements ClientRequestFilter {

private static final Logger logger = LoggerFactory.getLogger(RequestFilter.class);

private final ScriptContext context;

public RequestFilter(ScriptContext context) {
this.context = context;
}
private static final Logger logger = LoggerFactory.getLogger(RequestFilter.class);

@Override
public void filter(ClientRequestContext ctx) throws IOException {
public void filter(ClientRequestContext ctx) throws IOException {
ScriptContext context = (ScriptContext) ctx.getProperty(ScriptContext.KARATE_DOT_CONTEXT);
ScriptValue headersFunction = context.headers;
if (headersFunction.getType() != JS_FUNCTION) {
logger.trace("configured 'headers' is not a js function: {}", headersFunction);
Expand Down
57 changes: 35 additions & 22 deletions karate-core/src/main/java/com/intuit/karate/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ public static ScriptValue evalInNashorn(String exp, ScriptContext context, Scrip
for (Map.Entry<String, Object> entry : map.entrySet()) {
bindings.put(entry.getKey(), entry.getValue());
}
bindings.put(ScriptContext.KARATE_NAME, new ScriptBridge(context));
}
if (selfValue != null) {
bindings.put(VAR_SELF, selfValue.getValue());
Expand Down Expand Up @@ -562,10 +563,15 @@ public static AssertionResult matchJsonPath(MatchType matchType, ScriptValue act
case JSON:
actualDoc = actual.getValue(DocumentContext.class);
break;
case JS_ARRAY: // happens for json resulting from nashorn
ScriptObjectMirror som = actual.getValue(ScriptObjectMirror.class);
actualDoc = JsonPath.parse(som.values());
break;
case JS_OBJECT: // is a map-like object, happens for json resulting from nashorn
case MAP: // this happens because some jsonpath operations result in Map
Map<String, Object> map = actual.getValue(Map.class);
actualDoc = JsonPath.parse(map);
break;
break;
case LIST: // this also happens because some jsonpath operations result in List
List list = actual.getValue(List.class);
actualDoc = JsonPath.parse(list);
Expand All @@ -583,6 +589,8 @@ public static AssertionResult matchJsonPath(MatchType matchType, ScriptValue act
} else {
return matchStringOrPattern('.', path, matchType, null, actual, expected.getValue(String.class), context);
}
case PRIMITIVE:
return matchPrimitive(path, actual.getValue(), eval(expression, context).getValue());
default:
throw new RuntimeException("not json, cannot do json path for value: " + actual + ", path: " + path);
}
Expand Down Expand Up @@ -702,29 +710,33 @@ public static AssertionResult matchNestedObject(char delimiter, String path, Mat
return AssertionResult.PASS; // lists (and order) are identical
}
} else if (ClassUtils.isPrimitiveOrWrapper(expObject.getClass())) {
if (actObject == null) {
return matchFailed(path, actObject, expObject, "actual value is null");
}
if (!expObject.getClass().equals(actObject.getClass())) {
// types are not the same, use the JS engine for a lenient equality check
String exp = actObject + " == " + expObject;
ScriptValue sv = evalInNashorn(exp, null);
if (sv.isBooleanTrue()) {
return AssertionResult.PASS;
} else {
return matchFailed(path, actObject, expObject, "not equal");
}
}
if (!expObject.equals(actObject)) {
return matchFailed(path, actObject, expObject, "not equal");
} else {
return AssertionResult.PASS; // primitives, are equal
}
return matchPrimitive(path, actObject, expObject);
} else { // this should never happen
throw new RuntimeException("unexpected type: " + expObject.getClass());
}
}

private static AssertionResult matchPrimitive(String path, Object actObject, Object expObject) {
if (actObject == null) {
return matchFailed(path, actObject, expObject, "actual value is null");
}
if (!expObject.getClass().equals(actObject.getClass())) {
// types are not the same, use the JS engine for a lenient equality check
String exp = actObject + " == " + expObject;
ScriptValue sv = evalInNashorn(exp, null);
if (sv.isBooleanTrue()) {
return AssertionResult.PASS;
} else {
return matchFailed(path, actObject, expObject, "not equal");
}
}
if (!expObject.equals(actObject)) {
return matchFailed(path, actObject, expObject, "not equal");
} else {
return AssertionResult.PASS; // primitives, are equal
}
}

public static void setValueByPath(String name, String path, String exp, ScriptContext context) {
name = StringUtils.trim(name);
path = StringUtils.trimToNull(path);
Expand Down Expand Up @@ -810,9 +822,10 @@ public static ScriptValue call(String name, String argString, ScriptContext cont
}

public static ScriptValue evalFunctionCall(ScriptObjectMirror som, Object callArg, ScriptContext context) {
for (Map.Entry<String, Object> entry : context.getVariableBindings().entrySet()) {
som.put(entry.getKey(), entry.getValue());
}
// ensure that things like 'karate.get' operate on the latest variable state
som.setMember(ScriptContext.KARATE_NAME, new ScriptBridge(context));
// convenience for users, can use 'karate' instead of 'this.karate'
som.eval(String.format("var %s = this.%s", ScriptContext.KARATE_NAME, ScriptContext.KARATE_NAME));
Object result;
if (callArg != null) {
result = som.call(som, callArg);
Expand Down
12 changes: 11 additions & 1 deletion karate-core/src/main/java/com/intuit/karate/ScriptBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public class ScriptBridge {
public ScriptBridge(ScriptContext context) {
this.context = context;
}

public ScriptContext getContext() {
return context;
}

public Object read(String fileName) {
ScriptValue sv = FileUtils.readFile(fileName, context);
Expand All @@ -30,7 +34,13 @@ public void set(String name, Object o) {
}

public Object get(String exp) {
ScriptValue sv = Script.eval(exp, context); // even json path expressions will work
ScriptValue sv;
try {
sv = Script.eval(exp, context); // even json path expressions will work
} catch (Exception e) {
logger.warn("karate.get failed for expression: '{}': {}", exp, e.getMessage());
return null;
}
if (sv != null) {
return sv.getAfterConvertingToMapIfNeeded();
} else {
Expand Down
13 changes: 5 additions & 8 deletions karate-core/src/main/java/com/intuit/karate/ScriptContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public class ScriptContext {

private static final Logger logger = LoggerFactory.getLogger(ScriptContext.class);

private static final String KARATE_NAME = "karate";
private static final String VAR_CONTEXT = "_context";
public static final String KARATE_DOT_CONTEXT = "karate.context";
public static final String KARATE_NAME = "karate";
private static final String VAR_READ = "read";

protected final ScriptValueMap vars;
Expand Down Expand Up @@ -89,7 +89,7 @@ public ScriptContext(ScriptEnv env, ScriptContext parent, Map<String, Object> ar
private static String getFileReaderFunction() {
return "function(path) {\n"
+ " var FileUtils = Java.type('" + FileUtils.class.getCanonicalName() + "');\n"
+ " return FileUtils.readFile(path, " + VAR_CONTEXT + ").value;\n"
+ " return FileUtils.readFile(path, " + KARATE_DOT_CONTEXT + ").value;\n"
+ "}";
}

Expand Down Expand Up @@ -137,7 +137,7 @@ public void buildClient() {
Level.SEVERE,
LoggingFeature.Verbosity.PAYLOAD_TEXT, null));
}
clientBuilder.register(new RequestFilter(this));
clientBuilder.register(new RequestFilter());
if (sslEnabled) {
logger.info("ssl enabled, initializing generic trusted certificate / key-store with algorithm: {}", sslAlgorithm);
SSLContext ssl = SslUtils.getSslContext(sslAlgorithm);
Expand Down Expand Up @@ -167,10 +167,7 @@ public Map<String, Object> getVariableBindings() {
Map<String, Object> map = Script.simplify(vars);
if (readFunction != null) {
map.put(VAR_READ, readFunction.getValue());
}
// for future function calls if needed, see getFileReaderFunction()
map.put(VAR_CONTEXT, this);
map.put(KARATE_NAME, new ScriptBridge(this));
}
return map;
}

Expand Down
5 changes: 4 additions & 1 deletion karate-core/src/main/java/com/intuit/karate/StepDefs.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ public void asssertBoolean(String expression) {
private Invocation.Builder prepare() {
hasUrlBeenSet();
Invocation.Builder builder = target.request();
builder.property(ScriptContext.KARATE_DOT_CONTEXT, context);
if (headers != null) {
for (Map.Entry<String, Object> entry : headers.entrySet()) {
builder = builder.header(entry.getKey(), entry.getValue());
Expand Down Expand Up @@ -351,7 +352,9 @@ public void soapAction(String action) {
xml = request.getAsString();
}
startTimer();
response = target.request().header("SOAPAction", action).method("POST", Entity.entity(xml, MediaType.TEXT_XML));
Invocation.Builder builder = target.request();
builder.property(ScriptContext.KARATE_DOT_CONTEXT, context);
response = builder.header("SOAPAction", action).method("POST", Entity.entity(xml, MediaType.TEXT_XML));
stopTimer();
String rawResponse = response.readEntity(String.class);
try {
Expand Down
30 changes: 30 additions & 0 deletions karate-core/src/test/java/com/intuit/karate/ScriptTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,36 @@ public void testFromJsKarateCallFeatureWithJsonArg() {
assertTrue(Script.matchNamed(MatchType.EQUALS, "res.a", null, "1", ctx).pass);
assertTrue(Script.matchNamed(MatchType.EQUALS, "res.b", null, "2", ctx).pass);
assertTrue(Script.matchNamed(MatchType.EQUALS, "res.c", null, "3", ctx).pass);
}

@Test
public void testFromJsKarateGetForNonExistentVariable() {
ScriptContext ctx = getContext();
Script.assign("fun", "function(){ var foo = karate.get('foo'); return foo ? true : false }", ctx);
Script.assign("res", "fun()", ctx);
assertTrue(Script.matchNamed(MatchType.EQUALS, "res", null, "false", ctx).pass);
}

@Test
public void testFromJsKarateGetForJsonArrayVariable() {
ScriptContext ctx = getContext();
Script.assign("fun", "function(){ return [1, 2, 3] }", ctx);
Script.assign("res", "call fun", ctx);
assertTrue(Script.matchNamed(MatchType.EQUALS, "res", null, "[1, 2, 3]", ctx).pass);
}

@Test
public void testFromJsKarateGetForJsonObjectVariableAndCallFeatureAndJs() {
ScriptContext ctx = getContext();
Script.assign("fun", "read('headers.js')", ctx);
Script.assign("res", "call fun", ctx);
assertTrue(Script.matchNamed(MatchType.EQUALS, "res", null, "{ foo: 'bar_someValue' }", ctx).pass);
Script.assign("signin", "call read('signin.feature')", ctx);
Script.assign("ticket", "signin.ticket", ctx);
assertTrue(Script.matchNamed(MatchType.EQUALS, "ticket", null, "{ foo: 'bar' }", ctx).pass);
Script.assign("res", "call fun", ctx);
assertTrue(Script.matchNamed(MatchType.EQUALS, "res", null, "{ foo: 'bar_someValue', baz: 'ban' }", ctx).pass);
}


}
10 changes: 10 additions & 0 deletions karate-core/src/test/java/com/intuit/karate/headers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function() {
var out = {
foo: 'bar_' + someConfig // someConfig is 'start-up' config, will never change
};
var ticket = karate.get('ticket'); // get can get the 'latest' values of variables
if (ticket) {
out.baz = 'ban'
}
return out;
}
6 changes: 6 additions & 0 deletions karate-core/src/test/java/com/intuit/karate/signin.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Feature:

Scenario:
* def iamTicket = { ticket: { foo: 'bar' } }
* def ticket = iamTicket.ticket

1 change: 1 addition & 0 deletions karate-demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ as well as demonstrate various Karate features and best-practices.
| Example | Demonstrates
----------| --------
[`greeting.feature`](src/test/java/demo/greeting/greeting.feature) | Simple GET requests and multiple scenarios in a test.
[`headers.feature`](src/test/java/demo/headers/headers.feature) | A simple example of header management using a js file ([`classpath:headers.js`](src/test/java/headers.js)), and also shows how cookies can be accessed and how path and query parameters can be specified.
[`cats.feature`](src/test/java/demo/cats/cats.feature) | Great example of [embedded-expressions](https://github.com/intuit/karate#embedded-expressions) (or JSON / XML templating). Also shows how to set the `Accept` [header](https://github.com/intuit/karate#header) for getting XML from the server.
[`kittens.feature`](src/test/java/demo/cats/kittens.feature) | Reading a complex payload expected response [from a file](https://github.com/intuit/karate#reading-files). You can do the same for request payloads as well. Observe how [JSON templating](https://github.com/intuit/karate#embedded-expressions) makes creating dynamic JSON super-easy, look at [line #24](src/test/java/demo/cats/kittens.feature#L24) for example.
[`upload.feature`](src/test/java/demo/upload/upload.feature) | [Multi-part](https://github.com/intuit/karate#multipart-field) file-upload example, as well as comparing the binary content of a download. Also shows how to assert for expected response [headers](https://github.com/intuit/karate#match-header).
Expand Down
2 changes: 1 addition & 1 deletion karate-demo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-parent</artifactId>
<version>0.2.5</version>
<version>0.2.6</version>
</parent>

<artifactId>karate-demo</artifactId>
Expand Down
Loading

0 comments on commit 7420049

Please sign in to comment.