diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml
new file mode 100644
index 000000000..033d769e7
--- /dev/null
+++ b/.github/workflows/maven-build.yml
@@ -0,0 +1,29 @@
+name: maven-build
+
+on:
+ push:
+ branches: [ master, develop ]
+ pull_request:
+ branches: [ develop ]
+
+jobs:
+ build:
+ timeout-minutes: 10
+ runs-on: ubuntu-latest
+ steps:
+ - name: git checkout
+ uses: actions/checkout@v2
+ - name: set up jdk 8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: cache maven packages
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+ - name: build with maven
+ run: mvn -B clean install -P pre-release -Djavacpp.platform=linux-x86_64
+ - name: build and test with docker
+ run: ./build-docker.sh
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 03d05e299..dd2c7980c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,9 +19,9 @@ karate-demo/activemq-data/
karate-demo/*.pem
karate-demo/*.jks
karate-demo/*.der
-karate-netty/*.pem
-karate-netty/*.jks
-karate-netty/*.der
+karate-core/*.pem
+karate-core/*.jks
+karate-core/*.der
karate-robot/tessdata
karate-junit4/src/test/java/com/intuit/karate/junit4/dev
karate-robot/src/test/java/robot/dev
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index a838b08b7..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: java
-cache:
- directories:
- - "$HOME/.m2"
-jdk:
- - openjdk8
-script: mvn install -P pre-release -Dmaven.javadoc.skip=true -B -V -Djavacpp.platform=linux-x86_64
diff --git a/README.md b/README.md
index af127c161..6441d33fb 100755
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Karate
## Test Automation Made `Simple.`
-[![Maven Central](https://img.shields.io/maven-central/v/com.intuit.karate/karate-core.svg)](https://mvnrepository.com/artifact/com.intuit.karate/karate-core) [![Build Status](https://travis-ci.org/intuit/karate.svg?branch=master)](https://travis-ci.org/intuit/karate) [![GitHub release](https://img.shields.io/github/release/intuit/karate.svg)](https://github.com/intuit/karate/releases) [![Support Slack](https://img.shields.io/badge/support-slack-red.svg)](https://github.com/intuit/karate/wiki/Support) [![Twitter Follow](https://img.shields.io/twitter/follow/KarateDSL.svg?style=social&label=Follow)](https://twitter.com/KarateDSL)
+[![Maven Central](https://img.shields.io/maven-central/v/com.intuit.karate/karate-core.svg)](https://search.maven.org/artifact/com.intuit.karate/karate-core) [ ![build](https://github.com/intuit/karate/workflows/maven-build/badge.svg)](https://github.com/intuit/karate/actions?query=workflow%3Amaven-build) [![GitHub release](https://img.shields.io/github/release/intuit/karate.svg)](https://github.com/intuit/karate/releases) [![Support Slack](https://img.shields.io/badge/support-slack-red.svg)](https://github.com/intuit/karate/wiki/Support) [![Twitter Follow](https://img.shields.io/twitter/follow/KarateDSL.svg?style=social&label=Follow)](https://twitter.com/KarateDSL)
Karate is the only open-source tool to combine API test-automation, [mocks](karate-netty), [performance-testing](karate-gatling) and even [UI automation](karate-core) into a **single**, *unified* framework. The BDD syntax popularized by Cucumber is language-neutral, and easy for even non-programmers. Powerful JSON & XML assertions are built-in, and you can run tests in parallel for speed.
diff --git a/build-docker.sh b/build-docker.sh
new file mode 100755
index 000000000..828961852
--- /dev/null
+++ b/build-docker.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+set -x -e
+
+# assume that karate jars are installed in maven local repo
+# mvn clean install -P pre-release -DskipTests
+
+# copy only karate jars to a place where the docker image build can add from
+KARATE_REPO=karate-docker/karate-chrome/target/repository/com/intuit
+mkdir -p ${KARATE_REPO}
+cp -r ~/.m2/repository/com/intuit/karate ${KARATE_REPO}
+
+# create / copy the karate fatjar so that the docker image build can add it
+mvn -f karate-core/pom.xml package -P fatjar -DskipTests
+KARATE_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+cp karate-core/target/karate-${KARATE_VERSION}.jar karate-docker/karate-chrome/target/karate.jar
+
+# build karate-chrome docker image that includes karate fatjar + maven jars for convenience
+docker build -t karate-chrome karate-docker/karate-chrome
+
+# just in case a previous run had hung (likely only in local dev)
+docker stop karate || true
+
+# note that this command is run as a background process
+docker run --name karate --rm --cap-add=SYS_ADMIN -v "$PWD":/karate -v "$HOME"/.m2:/root/.m2 karate-chrome &
+
+# just ensure that the docker container named "karate" exists after the above command
+# it does not have to have completed startup, the command / karate test below will wait
+sleep 5
+
+# run tests against chrome
+docker exec -w /karate karate mvn test -f karate-e2e-tests/pom.xml -Dtest=driver.DockerRunner
+docker stop karate
+wait
diff --git a/examples/gatling/pom.xml b/examples/gatling/pom.xml
index ce8ebdfe0..17d7718da 100755
--- a/examples/gatling/pom.xml
+++ b/examples/gatling/pom.xml
@@ -12,15 +12,10 @@
1.8
3.6.0
2.0.0
- 3.0.2
+ 3.1.0
-
- com.intuit.karate
- karate-apache
- ${karate.version}
-
com.intuit.karate
karate-gatling
diff --git a/examples/gatling/src/test/java/mock/MockUtils.java b/examples/gatling/src/test/java/mock/MockUtils.java
index 560642753..d363ea615 100755
--- a/examples/gatling/src/test/java/mock/MockUtils.java
+++ b/examples/gatling/src/test/java/mock/MockUtils.java
@@ -1,11 +1,9 @@
package mock;
-import com.intuit.karate.FileUtils;
+import com.intuit.karate.core.MockServer;
import com.intuit.karate.PerfContext;
import com.intuit.karate.Runner;
-import com.intuit.karate.netty.FeatureServer;
-import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -18,8 +16,7 @@
public class MockUtils {
public static void startServer() {
- File file = FileUtils.getFileRelativeTo(MockUtils.class, "mock.feature");
- FeatureServer server = FeatureServer.start(file, 0, false, null);
+ MockServer server = MockServer.feature("classpath:mock/mock.feature").build();
System.setProperty("mock.cats.url", "http://localhost:" + server.getPort() + "/cats");
}
diff --git a/examples/jobserver/pom.xml b/examples/jobserver/pom.xml
index c6688de1b..6a4e6d4d3 100644
--- a/examples/jobserver/pom.xml
+++ b/examples/jobserver/pom.xml
@@ -10,17 +10,11 @@
UTF-8
1.8
- 3.6.0
- 0.9.6
+ 3.8.1
+ 2.0.0
-
-
- com.intuit.karate
- karate-apache
- ${karate.version}
- test
-
+
com.intuit.karate
karate-junit5
@@ -30,7 +24,7 @@
net.masterthought
cucumber-reporting
- 3.8.0
+ 5.3.1
test
diff --git a/examples/jobserver/src/test/java/jobtest/simple/SimpleDockerJobRunner.java b/examples/jobserver/src/test/java/jobtest/simple/SimpleDockerJobRunner.java
index 92cbdf865..604aa3d40 100644
--- a/examples/jobserver/src/test/java/jobtest/simple/SimpleDockerJobRunner.java
+++ b/examples/jobserver/src/test/java/jobtest/simple/SimpleDockerJobRunner.java
@@ -15,7 +15,7 @@ public class SimpleDockerJobRunner {
@Test
void testJobManager() {
MavenJobConfig config = new MavenJobConfig(2, "host.docker.internal", 0);
- Results results = Runner.path("classpath:jobtest/simple").startServerAndWait(config);
+ Results results = Runner.path("classpath:jobtest/simple").parallel(1); //.startServerAndWait(config);
ReportUtils.generateReport(results.getReportDir());
}
diff --git a/examples/jobserver/src/test/java/jobtest/simple/SimpleLocalJobRunner.java b/examples/jobserver/src/test/java/jobtest/simple/SimpleLocalJobRunner.java
index 978a2e58c..d8db6d78b 100644
--- a/examples/jobserver/src/test/java/jobtest/simple/SimpleLocalJobRunner.java
+++ b/examples/jobserver/src/test/java/jobtest/simple/SimpleLocalJobRunner.java
@@ -21,7 +21,7 @@ public class SimpleLocalJobRunner {
@Test
void testJobManager() {
- MavenJobConfig config = new MavenJobConfig(-1, "127.0.0.1", 0) {
+ MavenJobConfig config = new MavenJobConfig(2, "127.0.0.1", 0) {
@Override
public void startExecutors(String uniqueId, String serverUrl) throws Exception {
int executorCount = 2;
@@ -35,7 +35,7 @@ public void startExecutors(String uniqueId, String serverUrl) throws Exception {
};
// export KARATE_TEST="foo"
config.addEnvPropKey("KARATE_TEST");
- Results results = Runner.path("classpath:jobtest/simple").startServerAndWait(config);
+ Results results = Runner.path("classpath:jobtest/simple").jobManager(config);
ReportUtils.generateReport(results.getReportDir());
}
diff --git a/examples/jobserver/src/test/java/jobtest/simple/SimpleRunner.java b/examples/jobserver/src/test/java/jobtest/simple/SimpleRunner.java
index 5d2a2efba..5f0d669a8 100644
--- a/examples/jobserver/src/test/java/jobtest/simple/SimpleRunner.java
+++ b/examples/jobserver/src/test/java/jobtest/simple/SimpleRunner.java
@@ -14,7 +14,8 @@ public class SimpleRunner {
@Test
void test() {
- Results results = Runner.path("classpath:jobtest/simple").tags("~@ignore").parallel(1);
+ Results results = Runner.path("classpath:jobtest/simple")
+ .outputCucumberJson(true).tags("~@ignore").parallel(1);
ReportUtils.generateReport(results.getReportDir());
assertEquals(0, results.getFailCount(), results.getErrorMessages());
}
diff --git a/examples/jobserver/src/test/java/jobtest/simple/simple1.feature b/examples/jobserver/src/test/java/jobtest/simple/simple1.feature
index 1d0ae38c2..88dbac3c6 100644
--- a/examples/jobserver/src/test/java/jobtest/simple/simple1.feature
+++ b/examples/jobserver/src/test/java/jobtest/simple/simple1.feature
@@ -1,15 +1,7 @@
Feature: simple 1
Background:
-* configure responseDelay = 1000
+* print 'in background 1'
Scenario: 1-one
* print '1-one'
-* def karateTest = java.lang.System.getenv('KARATE_TEST')
-* print '*** KARATE_TEST: ', karateTest
-
-Scenario: 1-two
-* print '1-two'
-
-Scenario: 1-three
-* print '1-three'
diff --git a/examples/jobserver/src/test/java/jobtest/simple/simple3.feature b/examples/jobserver/src/test/java/jobtest/simple/simple3.feature
index 19a4f4aa5..b63321203 100644
--- a/examples/jobserver/src/test/java/jobtest/simple/simple3.feature
+++ b/examples/jobserver/src/test/java/jobtest/simple/simple3.feature
@@ -5,8 +5,3 @@ Scenario: 3-one
Scenario: 3-two
* print '3-two'
-
-Scenario: 3-three
-* print '3-three'
-Given url 'http://httpbin.org/get'
-When method get
diff --git a/examples/jobserver/src/test/java/jobtest/web/WebDockerJobRunner.java b/examples/jobserver/src/test/java/jobtest/web/WebDockerJobRunner.java
index 0f8e0b680..859d1bd72 100644
--- a/examples/jobserver/src/test/java/jobtest/web/WebDockerJobRunner.java
+++ b/examples/jobserver/src/test/java/jobtest/web/WebDockerJobRunner.java
@@ -16,7 +16,7 @@ public class WebDockerJobRunner {
void test() {
MavenChromeJobConfig config = new MavenChromeJobConfig(2, "host.docker.internal", 0);
System.setProperty("karate.env", "jobserver");
- Results results = Runner.path("classpath:jobtest/web").startServerAndWait(config);
+ Results results = Runner.path("classpath:jobtest/web").parallel(1);
ReportUtils.generateReport(results.getReportDir());
}
diff --git a/examples/jobserver/src/test/java/logback-test.xml b/examples/jobserver/src/test/java/logback-test.xml
index fea195eb0..d95a16ed2 100644
--- a/examples/jobserver/src/test/java/logback-test.xml
+++ b/examples/jobserver/src/test/java/logback-test.xml
@@ -16,7 +16,7 @@
-
+
diff --git a/karate-apache/pom.xml b/karate-apache/pom.xml
deleted file mode 100755
index fd523dd38..000000000
--- a/karate-apache/pom.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
- 4.0.0
-
-
- com.intuit.karate
- karate-parent
- 2.0.0
-
- karate-apache
- jar
-
-
- 4.5.12
-
-
-
-
-
- com.intuit.karate
- karate-core
- ${project.version}
-
-
-
- org.apache.httpcomponents
- httpclient
- ${apache.httpcomponents.version}
-
-
- commons-logging
- commons-logging
-
-
-
-
-
- org.apache.httpcomponents
- httpmime
- ${apache.httpcomponents.version}
-
-
-
- org.slf4j
- jcl-over-slf4j
-
- 1.7.25
- runtime
-
-
-
- junit
- junit
- ${junit.version}
- test
-
-
-
-
-
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
deleted file mode 100644
index 4fba22772..000000000
--- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpClient.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2017 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.http.apache;
-
-import com.intuit.karate.Config;
-import com.intuit.karate.FileUtils;
-import com.intuit.karate.core.ScenarioContext;
-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;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpUriRequest;
-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.*;
-import org.apache.http.cookie.Cookie;
-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
- */
-public class ApacheHttpClient extends HttpClient {
-
- public static final String URI_CONTEXT_KEY = ApacheHttpClient.class.getName() + ".URI";
-
- private HttpClientBuilder clientBuilder;
- private URIBuilder uriBuilder;
- private RequestBuilder requestBuilder;
- private CookieStore cookieStore;
- private Charset charset;
-
- private void build() {
- try {
- URI uri = uriBuilder.build();
- String method = request.getMethod();
- requestBuilder = RequestBuilder.create(method).setUri(uri);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void configure(Config config, ScenarioContext context) {
- clientBuilder = HttpClientBuilder.create();
- charset = config.getCharset();
- if (!config.isFollowRedirects()) {
- clientBuilder.disableRedirectHandling();
- } else { // support redirect on POST by default
- clientBuilder.setRedirectStrategy(new LaxRedirectStrategy());
- }
- clientBuilder.useSystemProperties();
- cookieStore = new BasicCookieStore();
- clientBuilder.setDefaultCookieStore(cookieStore);
- clientBuilder.setDefaultCookieSpecRegistry(LenientCookieSpec.registry());
- RequestLoggingInterceptor requestInterceptor = new RequestLoggingInterceptor(context);
- clientBuilder.addInterceptorLast(requestInterceptor);
- clientBuilder.addInterceptorLast(new ResponseLoggingInterceptor(requestInterceptor, context));
- if (config.isSslEnabled()) {
- // System.setProperty("jsse.enableSNIExtension", "false");
- String algorithm = config.getSslAlgorithm(); // could be null
- KeyStore trustStore = HttpUtils.getKeyStore(context,
- config.getSslTrustStore(), config.getSslTrustStorePassword(), config.getSslTrustStoreType());
- KeyStore keyStore = HttpUtils.getKeyStore(context,
- config.getSslKeyStore(), config.getSslKeyStorePassword(), config.getSslKeyStoreType());
- SSLContext sslContext;
- try {
- SSLContextBuilder builder = SSLContexts.custom()
- .setProtocol(algorithm); // will default to TLS if null
- if (trustStore == null && config.isSslTrustAll()) {
- builder = builder.loadTrustMaterial(new TrustAllStrategy());
- } else {
- if (config.isSslTrustAll()) {
- builder = builder.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy());
- } else {
- builder = builder.loadTrustMaterial(trustStore, null); // will use system / java default
- }
- }
- if (keyStore != null) {
- char[] keyPassword = config.getSslKeyStorePassword() == null ? null : config.getSslKeyStorePassword().toCharArray();
- builder = builder.loadKeyMaterial(keyStore, keyPassword);
- }
- sslContext = builder.build();
- SSLConnectionSocketFactory socketFactory;
- if (keyStore != null) {
- socketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
- } else {
- socketFactory = new LenientSslConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
- }
- clientBuilder.setSSLSocketFactory(socketFactory);
- } catch (Exception e) {
- context.logger.error("ssl context init failed: {}", e.getMessage());
- throw new RuntimeException(e);
- }
- }
- RequestConfig.Builder configBuilder = RequestConfig.custom()
- .setCookieSpec(LenientCookieSpec.KARATE)
- .setConnectTimeout(config.getConnectTimeout())
- .setSocketTimeout(config.getReadTimeout());
- if (config.getLocalAddress() != null) {
- try {
- InetAddress localAddress = InetAddress.getByName(config.getLocalAddress());
- configBuilder.setLocalAddress(localAddress);
- } catch (Exception e) {
- context.logger.warn("failed to resolve local address: {} - {}", config.getLocalAddress(), e.getMessage());
- }
- }
- clientBuilder.setDefaultRequestConfig(configBuilder.build());
- SocketConfig.Builder socketBuilder = SocketConfig.custom().setSoTimeout(config.getConnectTimeout());
- clientBuilder.setDefaultSocketConfig(socketBuilder.build());
- if (config.getProxyUri() != null) {
- try {
- URI proxyUri = new URIBuilder(config.getProxyUri()).build();
- clientBuilder.setProxy(new HttpHost(proxyUri.getHost(), proxyUri.getPort(), proxyUri.getScheme()));
- if (config.getProxyUsername() != null && config.getProxyPassword() != null) {
- CredentialsProvider credsProvider = new BasicCredentialsProvider();
- credsProvider.setCredentials(
- new AuthScope(proxyUri.getHost(), proxyUri.getPort()),
- new UsernamePasswordCredentials(config.getProxyUsername(), config.getProxyPassword()));
- clientBuilder.setDefaultCredentialsProvider(credsProvider);
- }
- if (config.getNonProxyHosts() != null) {
- ProxySelector proxySelector = new ProxySelector() {
- private final List proxyExceptions = config.getNonProxyHosts();
-
- @Override
- public List select(URI uri) {
- return Collections.singletonList(proxyExceptions.contains(uri.getHost())
- ? Proxy.NO_PROXY
- : new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyUri.getHost(), proxyUri.getPort())));
- }
-
- @Override
- public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
- context.logger.info("connect failed to uri: {}", uri, ioe);
- }
- };
- clientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(proxySelector));
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- @Override
- protected void buildUrl(String url) {
- try {
- uriBuilder = new URIBuilder(url);
- build();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- protected void buildPath(String path) {
- String temp = uriBuilder.getPath();
- if (temp == null) {
- temp = "";
- }
- if (!temp.endsWith("/")) {
- temp = temp + "/";
- }
- if (path.startsWith("/")) {
- path = path.substring(1);
- }
- uriBuilder.setPath(temp + path);
- build();
- }
-
- @Override
- protected void buildParam(String name, Object... values) {
- if (values.length == 1) {
- Object v = values[0];
- if (v != null) {
- uriBuilder.setParameter(name, v.toString());
- }
- } else {
- Arrays.stream(values)
- .filter(Objects::nonNull)
- .forEach(o -> uriBuilder.addParameter(name, o.toString()));
- }
- build();
- }
-
- @Override
- protected void buildHeader(String name, Object value, boolean replace) {
- if (replace) {
- requestBuilder.removeHeaders(name);
- }
- requestBuilder.addHeader(name, value == null ? null : value.toString());
- }
-
- @Override
- protected void buildCookie(com.intuit.karate.http.Cookie c) {
- BasicClientCookie cookie = new BasicClientCookie(c.getName(), c.getValue());
- for (Entry entry : c.entrySet()) {
- switch (entry.getKey()) {
- case DOMAIN:
- cookie.setDomain(entry.getValue());
- break;
- case PATH:
- cookie.setPath(entry.getValue());
- break;
- case EXPIRES: // add expires field for cookie.
- try {
- cookie.setExpiryDate(Date.from(ZonedDateTime.parse(entry.getValue(), DTFMTR_RFC1123).toInstant()));
- }
- catch ( DateTimeParseException ex)
- {
- 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) {
- cookie.setDomain(uriBuilder.getHost());
- }
- cookieStore.addCookie(cookie);
- }
-
- @Override
- protected HttpEntity getEntity(List items, String mediaType) {
- return ApacheHttpUtils.getEntity(items, mediaType, charset);
- }
-
- @Override
- protected HttpEntity getEntity(MultiValuedMap fields, String mediaType) {
- return ApacheHttpUtils.getEntity(fields, mediaType, charset);
- }
-
- @Override
- protected HttpEntity getEntity(String value, String mediaType) {
- return ApacheHttpUtils.getEntity(value, mediaType, charset);
- }
-
- @Override
- protected HttpEntity getEntity(InputStream value, String mediaType) {
- return ApacheHttpUtils.getEntity(value, mediaType, charset);
- }
-
- @Override
- protected HttpResponse makeHttpRequest(HttpEntity entity, ScenarioContext context) {
- if (entity != null) {
- requestBuilder.setEntity(entity);
- requestBuilder.setHeader(entity.getContentType());
- }
- HttpUriRequest httpRequest = requestBuilder.build();
- CloseableHttpClient client = clientBuilder.build();
- BasicHttpContext httpContext = new BasicHttpContext();
- httpContext.setAttribute(URI_CONTEXT_KEY, getRequestUri());
- CloseableHttpResponse httpResponse;
- byte[] bytes;
- try {
- httpResponse = client.execute(httpRequest, httpContext);
- HttpEntity responseEntity = httpResponse.getEntity();
- if (responseEntity == null || responseEntity.getContent() == null) {
- bytes = new byte[0];
- } else {
- InputStream is = responseEntity.getContent();
- bytes = FileUtils.toBytes(is);
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- HttpRequest actualRequest = context.getPrevRequest();
- HttpResponse response = new HttpResponse(actualRequest.getStartTime(), actualRequest.getEndTime());
- response.setUri(getRequestUri());
- response.setBody(bytes);
- 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());
- if (c.getExpiryDate() != null) {
- cookie.put(EXPIRES, c.getExpiryDate().getTime() + "");
- }
- cookie.put(PERSISTENT, c.isPersistent() + "");
- cookie.put(SECURE, c.isSecure() + "");
- response.addCookie(cookie);
- }
- 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().equalsIgnoreCase("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, null != ck.getPath() ? ck.getPath() : "/"); // lets make sure path is not null.
- cookie.put(MAX_AGE, ck.getMaxAge() + "");
- });
- }
- response.addHeader(header.getName(), header.getValue());
- }
- return response;
- }
-
- @Override
- protected String getRequestUri() {
- return requestBuilder.getUri().toString();
- }
-
-}
diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpUtils.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpUtils.java
deleted file mode 100644
index b9d274220..000000000
--- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ApacheHttpUtils.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2017 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.http.apache;
-
-import com.intuit.karate.ScriptValue;
-import com.intuit.karate.StringUtils;
-import com.intuit.karate.http.HttpBody;
-import com.intuit.karate.http.HttpUtils;
-import com.intuit.karate.http.MultiPartItem;
-import com.intuit.karate.http.MultiValuedMap;
-
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import io.netty.handler.codec.http.HttpUtil;
-import org.apache.http.HttpEntity;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.entity.ContentType;
-import org.apache.http.entity.InputStreamEntity;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.entity.mime.FormBodyPartBuilder;
-import org.apache.http.entity.mime.MultipartEntityBuilder;
-import org.apache.http.entity.mime.content.ByteArrayBody;
-import org.apache.http.entity.mime.content.ContentBody;
-import org.apache.http.entity.mime.content.InputStreamBody;
-import org.apache.http.entity.mime.content.StringBody;
-import org.apache.http.message.BasicNameValuePair;
-
-/**
- *
- * @author pthomas3
- */
-public class ApacheHttpUtils {
-
- private ApacheHttpUtils() {
- // only static methods
- }
-
- public static HttpBody toBody(HttpEntity entity) {
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- entity.writeTo(baos);
- return HttpBody.bytes(baos.toByteArray(), entity.getContentType().getValue());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- // all this complexity is to be able to support "bad" values such as an empty string
- private static ContentType getContentType(String mediaType, Charset charset) {
- if (!HttpUtils.isPrintable(mediaType)) {
- try {
- return ContentType.create(mediaType);
- } catch (Exception e) {
- return null;
- }
- }
- // if charset is null that means mediaType does not contains any charset
- Charset existingCharset = HttpUtil.getCharset(mediaType, null);
- // appending charset if not present
- if (Objects.isNull(existingCharset)) {
- StringBuilder sb = new StringBuilder(mediaType).append("; ").append(HttpUtils.CHARSET);
- if (charset != null) { // if user set configure charset = null (to omit that piece of the header)
- sb.append("=").append(charset.name());
- }
- mediaType = sb.toString();
- }
- return ContentType.parse(mediaType);
- }
-
- public static HttpEntity getEntity(InputStream is, String mediaType, Charset charset) {
- try {
- return new InputStreamEntity(is, is.available(), getContentType(mediaType, charset));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public static HttpEntity getEntity(String value, String mediaType, Charset charset) {
- try {
- ContentType ct = getContentType(mediaType, charset);
- if (ct == null) { // "bad" value such as an empty string
- StringEntity entity = new StringEntity(value);
- entity.setContentType(mediaType);
- return entity;
- } else {
- return new StringEntity(value, ct);
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public static HttpEntity getEntity(MultiValuedMap fields, String mediaType, Charset charset) {
- List list = new ArrayList<>(fields.size());
- for (Map.Entry entry : fields.entrySet()) {
- String stringValue;
- List values = entry.getValue();
- if (values == null) {
- stringValue = null;
- } else if (values.size() == 1) {
- Object value = values.get(0);
- if (value == null) {
- stringValue = null;
- } else if (value instanceof String) {
- stringValue = (String) value;
- } else {
- stringValue = value.toString();
- }
- } else {
- stringValue = StringUtils.join(values, ',');
- }
- list.add(new BasicNameValuePair(entry.getKey(), stringValue));
- }
- try {
- Charset cs = HttpUtils.parseContentTypeCharset(mediaType);
- if (cs == null) {
- cs = charset;
- }
- String raw = URLEncodedUtils.format(list, cs);
- int pos = mediaType.indexOf(';');
- if (pos != -1) { // strip out charset param from content-type
- mediaType = mediaType.substring(0, pos);
- }
- return new StringEntity(raw, ContentType.create(mediaType, cs));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public static HttpEntity getEntity(List items, String mediaType, Charset charset) {
- boolean hasNullName = false;
- for (MultiPartItem item : items) {
- if (item.getName() == null) {
- hasNullName = true;
- break;
- }
- }
- if (hasNullName) { // multipart/related
- String boundary = HttpUtils.generateMimeBoundaryMarker();
- String text = HttpUtils.multiPartToString(items, boundary);
- ContentType ct = ContentType.parse(mediaType).withParameters(new BasicNameValuePair("boundary", boundary));
- return new StringEntity(text, ct);
- } else {
- MultipartEntityBuilder builder = MultipartEntityBuilder.create().setContentType(ContentType.parse(mediaType));
- for (MultiPartItem item : items) {
- if (item.getValue() == null || item.getValue().isNull()) {
- continue;
- }
- String name = item.getName();
- if (name == null) {
- // will never happen because we divert this flow to the home-made multi-part builder above
- // builder.addPart(bodyPart);
- } else {
- ScriptValue sv = item.getValue();
- String ct = item.getContentType();
- if (ct == null) {
- ct = HttpUtils.getContentType(sv);
- }
- ContentType contentType = ContentType.create(ct);
- if (HttpUtils.isPrintable(ct)) {
- Charset cs = HttpUtils.parseContentTypeCharset(mediaType);
- if (cs == null) {
- cs = charset;
- }
- contentType = contentType.withCharset(cs);
- }
- FormBodyPartBuilder formBuilder = FormBodyPartBuilder.create().setName(name);
- ContentBody contentBody;
- String filename = item.getFilename();
- if (filename != null) {
- contentBody = new ByteArrayBody(sv.getAsByteArray(), contentType, filename);
- } else if (sv.isStream()) {
- contentBody = new InputStreamBody(sv.getAsStream(), contentType);
- } else {
- contentBody = new StringBody(sv.getAsString(), contentType);
- }
- formBuilder = formBuilder.setBody(contentBody);
- builder = builder.addPart(formBuilder.build());
- }
- }
- return builder.build();
- }
- }
-
-}
diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/LenientCookieSpec.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/LenientCookieSpec.java
deleted file mode 100644
index 9796598d1..000000000
--- a/karate-apache/src/main/java/com/intuit/karate/http/apache/LenientCookieSpec.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2017 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.http.apache;
-
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.cookie.Cookie;
-import org.apache.http.cookie.CookieOrigin;
-import org.apache.http.cookie.CookieSpecProvider;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.impl.cookie.DefaultCookieSpec;
-import org.apache.http.impl.cookie.NetscapeDraftSpec;
-import org.apache.http.protocol.HttpContext;
-
-/**
- *
- * @author pthomas3
- */
-public class LenientCookieSpec extends DefaultCookieSpec {
-
- public static String KARATE = "karate";
-
- public LenientCookieSpec() {
- super(new String[]{"EEE, dd-MMM-yy HH:mm:ss z", "EEE, dd MMM yyyy HH:mm:ss Z"}, false);
- }
-
- @Override
- public boolean match(Cookie cookie, CookieOrigin origin) {
- return true;
- }
-
- @Override
- public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException {
- // do nothing
- }
-
- public static Registry registry() {
- CookieSpecProvider specProvider = (HttpContext hc) -> new LenientCookieSpec();
- return RegistryBuilder.create()
- .register(KARATE, specProvider).build();
- }
-
-}
diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/LoggingUtils.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/LoggingUtils.java
deleted file mode 100644
index 7b6af608a..000000000
--- a/karate-apache/src/main/java/com/intuit/karate/http/apache/LoggingUtils.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2017 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.http.apache;
-
-import com.intuit.karate.http.HttpLogModifier;
-import com.intuit.karate.http.HttpRequest;
-import com.intuit.karate.http.HttpUtils;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-
-/**
- *
- * @author pthomas3
- */
-public class LoggingUtils {
-
- private LoggingUtils() {
- // only static methods
- }
-
- private static Collection sortKeys(Header[] headers) {
- Set keys = new TreeSet<>();
- for (Header header : headers) {
- keys.add(header.getName());
- }
- return keys;
- }
-
- private static void logHeaderLine(HttpLogModifier logModifier, StringBuilder sb, int id, char prefix, String key, Header[] headers) {
- sb.append(id).append(' ').append(prefix).append(' ').append(key).append(": ");
- if (headers.length == 1) {
- if (logModifier == null) {
- sb.append(headers[0].getValue());
- } else {
- sb.append(logModifier.header(key, headers[0].getValue()));
- }
- } else {
- List list = new ArrayList(headers.length);
- for (Header header : headers) {
- if (logModifier == null) {
- list.add(header.getValue());
- } else {
- list.add(logModifier.header(key, header.getValue()));
- }
- }
- sb.append(list);
- }
- sb.append('\n');
- }
-
- public static void logHeaders(HttpLogModifier logModifier, StringBuilder sb, int id, char prefix, org.apache.http.HttpRequest request, HttpRequest actual) {
- for (String key : sortKeys(request.getAllHeaders())) {
- Header[] headers = request.getHeaders(key);
- logHeaderLine(logModifier, sb, id, prefix, key, headers);
- for (Header header : headers) {
- actual.addHeader(header.getName(), header.getValue());
- }
- }
- }
-
- public static void logHeaders(HttpLogModifier logModifier, StringBuilder sb, int id, char prefix, HttpResponse response) {
- for (String key : sortKeys(response.getAllHeaders())) {
- Header[] headers = response.getHeaders(key);
- logHeaderLine(logModifier, sb, id, prefix, key, headers);
- }
- }
-
- public static boolean isPrintable(HttpEntity entity) {
- if (entity == null) {
- return false;
- }
- return entity.getContentType() != null
- && HttpUtils.isPrintable(entity.getContentType().getValue());
- }
-
-}
diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/RequestLoggingInterceptor.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/RequestLoggingInterceptor.java
deleted file mode 100644
index 5a2aa63e4..000000000
--- a/karate-apache/src/main/java/com/intuit/karate/http/apache/RequestLoggingInterceptor.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2017 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.http.apache;
-
-import com.intuit.karate.FileUtils;
-import com.intuit.karate.core.ScenarioContext;
-import com.intuit.karate.http.HttpLogModifier;
-import com.intuit.karate.http.HttpRequest;
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.protocol.HttpContext;
-
-/**
- *
- * @author pthomas3
- */
-public class RequestLoggingInterceptor implements HttpRequestInterceptor {
-
- private final ScenarioContext context;
- private final HttpLogModifier logModifier;
- private final AtomicInteger counter = new AtomicInteger();
-
- public RequestLoggingInterceptor(ScenarioContext context) {
- this.context = context;
- logModifier = context.getConfig().getLogModifier();
- }
-
- public AtomicInteger getCounter() {
- return counter;
- }
-
- @Override
- public void process(org.apache.http.HttpRequest request, HttpContext httpContext) throws HttpException, IOException {
- HttpRequest actual = new HttpRequest();
- int id = counter.incrementAndGet();
- String uri = (String) httpContext.getAttribute(ApacheHttpClient.URI_CONTEXT_KEY);
- String method = request.getRequestLine().getMethod();
- actual.setUri(uri);
- actual.setMethod(method);
- context.setPrevRequest(actual);
- HttpLogModifier requestModifier = logModifier == null ? null : logModifier.enableForUri(uri) ? logModifier : null;
- String maskedUri = requestModifier == null ? uri : requestModifier.uri(uri);
- boolean showLog = !context.isReportDisabled() && context.getConfig().isShowLog();
- if (showLog) {
- StringBuilder sb = new StringBuilder();
- sb.append("request:\n").append(id).append(" > ").append(method).append(' ').append(maskedUri).append('\n');
- LoggingUtils.logHeaders(requestModifier, sb, id, '>', request, actual);
- if (request instanceof HttpEntityEnclosingRequest) {
- HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) request;
- HttpEntity entity = entityRequest.getEntity();
- if (LoggingUtils.isPrintable(entity)) {
- LoggingEntityWrapper wrapper = new LoggingEntityWrapper(entity); // todo optimize, preserve if stream
- String buffer = FileUtils.toString(wrapper.getContent());
- if (context.getConfig().isLogPrettyRequest()) {
- buffer = FileUtils.toPrettyString(buffer);
- }
- if (requestModifier != null) {
- buffer = requestModifier.request(uri, buffer);
- }
- sb.append(buffer).append('\n');
- actual.setBody(wrapper.getBytes());
- entityRequest.setEntity(wrapper);
- }
- }
- context.logger.debug(sb.toString());
- }
- // make sure this does not include the toString / logging time
- actual.startTimer();
- }
-
-}
diff --git a/karate-apache/src/main/java/com/intuit/karate/http/apache/ResponseLoggingInterceptor.java b/karate-apache/src/main/java/com/intuit/karate/http/apache/ResponseLoggingInterceptor.java
deleted file mode 100644
index b6fa9025f..000000000
--- a/karate-apache/src/main/java/com/intuit/karate/http/apache/ResponseLoggingInterceptor.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2017 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.http.apache;
-
-import com.intuit.karate.FileUtils;
-import com.intuit.karate.core.ScenarioContext;
-import com.intuit.karate.http.HttpLogModifier;
-import com.intuit.karate.http.HttpRequest;
-import java.io.IOException;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpResponseInterceptor;
-import org.apache.http.protocol.HttpContext;
-
-/**
- *
- * @author pthomas3
- */
-public class ResponseLoggingInterceptor implements HttpResponseInterceptor {
-
- private final ScenarioContext context;
- private final HttpLogModifier logModifier;
- private final RequestLoggingInterceptor requestInterceptor;
-
- public ResponseLoggingInterceptor(RequestLoggingInterceptor requestInterceptor, ScenarioContext context) {
- this.requestInterceptor = requestInterceptor;
- this.context = context;
- logModifier = context.getConfig().getLogModifier();
- }
-
- @Override
- public void process(HttpResponse response, HttpContext httpContext) throws HttpException, IOException {
- HttpRequest actual = context.getPrevRequest();
- actual.stopTimer();
- boolean showLog = !context.isReportDisabled() && context.getConfig().isShowLog();
- if (!showLog) {
- return;
- }
- int id = requestInterceptor.getCounter().get();
- StringBuilder sb = new StringBuilder();
- sb.append("response time in milliseconds: ").append(actual.getResponseTimeFormatted()).append('\n');
- sb.append(id).append(" < ").append(response.getStatusLine().getStatusCode()).append('\n');
- HttpLogModifier responseModifier = logModifier == null ? null : logModifier.enableForUri(actual.getUri()) ? logModifier : null;
- LoggingUtils.logHeaders(responseModifier, sb, id, '<', response);
- HttpEntity entity = response.getEntity();
- if (LoggingUtils.isPrintable(entity)) {
- LoggingEntityWrapper wrapper = new LoggingEntityWrapper(entity);
- String buffer = FileUtils.toString(wrapper.getContent());
- if (context.getConfig().isLogPrettyResponse()) {
- buffer = FileUtils.toPrettyString(buffer);
- }
- if (responseModifier != null) {
- buffer = responseModifier.response(actual.getUri(), buffer);
- }
- sb.append(buffer).append('\n');
- response.setEntity(wrapper);
- }
- context.logger.debug(sb.toString());
- }
-
-}
diff --git a/karate-apache/src/main/resources/karate-http.properties b/karate-apache/src/main/resources/karate-http.properties
deleted file mode 100644
index e4f7cfd31..000000000
--- a/karate-apache/src/main/resources/karate-http.properties
+++ /dev/null
@@ -1 +0,0 @@
-client.class=com.intuit.karate.http.apache.ApacheHttpClient
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
deleted file mode 100644
index 1fc56ac3d..000000000
--- a/karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpClientTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-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/java/com/intuit/karate/http/apache/ApacheHttpUtilsTest.java b/karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpUtilsTest.java
deleted file mode 100644
index 85bacb03f..000000000
--- a/karate-apache/src/test/java/com/intuit/karate/http/apache/ApacheHttpUtilsTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.intuit.karate.http.apache;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import java.nio.charset.StandardCharsets;
-
-import org.apache.http.HttpEntity;
-import org.junit.Test;
-
-/** @author nsehgal */
-public class ApacheHttpUtilsTest {
-
- @Test
- public void testContentTypeWithQuotes() {
- final String originalContentType =
- "multipart/related; charset=UTF-8; boundary=\"----=_Part_19_1913847857.1592612068756\"; type=\"application/xop+xml\"; start-info=\"text/xml\"";
-
- HttpEntity httpEntity =
- ApacheHttpUtils.getEntity(
- "content is not important", originalContentType, StandardCharsets.UTF_8);
-
- assertEquals(originalContentType, httpEntity.getContentType().getValue());
- }
-
- @Test
- public void testContentTypeWithoutQuotes() {
- final String originalContentType =
- "multipart/related; charset=UTF-8; boundary=----=_Part_19_1913847857.1592612068756; type=application/xop+xml; start-info=text/xml";
-
- final String expectedContentType =
- "multipart/related; charset=UTF-8; boundary=\"----=_Part_19_1913847857.1592612068756\"; type=\"application/xop+xml\"; start-info=\"text/xml\"";
-
- HttpEntity httpEntity =
- ApacheHttpUtils.getEntity(
- "content is not important", originalContentType, StandardCharsets.UTF_8);
-
- assertNotEquals(originalContentType, httpEntity.getContentType().getValue());
- assertEquals(expectedContentType, httpEntity.getContentType().getValue());
- }
-
- @Test
- public void testContentTypeWithoutQuotesCharsetInLast() {
- final String originalContentType =
- "multipart/related; boundary=----=_Part_19_1913847857.1592612068756; type=application/xop+xml; start-info=text/xml; charset=UTF-8";
-
- final String expectedContentType =
- "multipart/related; boundary=\"----=_Part_19_1913847857.1592612068756\"; type=\"application/xop+xml\"; start-info=\"text/xml\"; charset=UTF-8";
-
- HttpEntity httpEntity =
- ApacheHttpUtils.getEntity(
- "content is not important", originalContentType, StandardCharsets.UTF_8);
-
- assertNotEquals(originalContentType, httpEntity.getContentType().getValue());
- assertEquals(expectedContentType, httpEntity.getContentType().getValue());
- }
-
- @Test
- public void testContentTypeWithCustomCharset() {
- final String originalContentType =
- "multipart/related; boundary=----=_Part_19_1913847857.1592612068756; type=application/xop+xml; start-info=text/xml";
-
- final String expectedContentType =
- "multipart/related; boundary=\"----=_Part_19_1913847857.1592612068756\"; type=\"application/xop+xml\"; start-info=\"text/xml\"; charset=UTF-8";
-
- HttpEntity httpEntity =
- ApacheHttpUtils.getEntity(
- "content is not important", originalContentType, StandardCharsets.UTF_8);
-
- assertNotEquals(originalContentType, httpEntity.getContentType().getValue());
- assertEquals(expectedContentType, httpEntity.getContentType().getValue());
- }
-}
diff --git a/karate-apache/src/test/resources/karate-config.js b/karate-apache/src/test/resources/karate-config.js
deleted file mode 100755
index dea6405ed..000000000
--- a/karate-apache/src/test/resources/karate-config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644
index cd3832389..000000000
--- a/karate-apache/src/test/resources/karate-http.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-client.class=com.intuit.karate.http.apache.ApacheHttpClient
-
diff --git a/karate-archetype/src/main/resources/archetype-resources/pom.xml b/karate-archetype/src/main/resources/archetype-resources/pom.xml
index 887d2eb5f..755de4084 100755
--- a/karate-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/karate-archetype/src/main/resources/archetype-resources/pom.xml
@@ -14,13 +14,7 @@
0.9.6
-
-
- com.intuit.karate
- karate-apache
- ${karate.version}
- test
-
+
com.intuit.karate
karate-junit5
diff --git a/karate-core/pom.xml b/karate-core/pom.xml
index fb37c9f9e..6ef17c53d 100644
--- a/karate-core/pom.xml
+++ b/karate-core/pom.xml
@@ -12,21 +12,58 @@
4.7.1
- 4.1.50.Final
- 2.30
+ 20.3.0
- io.netty
- netty-handler
- ${netty.version}
-
+ org.graalvm.js
+ js-scriptengine
+ ${graal.version}
+
+
+ org.graalvm.js
+ js
+ ${graal.version}
+ runtime
+
+
+ org.thymeleaf
+ thymeleaf
+ 3.0.11.RELEASE
+
+
+ com.linecorp.armeria
+ armeria
+ 1.3.0
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+
+
+ commons-logging
+ commons-logging
+
+
+ commons-codec
+ commons-codec
+
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+
- io.netty
- netty-codec-http
- ${netty.version}
-
+ org.slf4j
+ jcl-over-slf4j
+
+ 1.7.25
+ runtime
+
org.antlr
antlr4-runtime
@@ -59,29 +96,29 @@
org.yaml
snakeyaml
- 1.26
+ 1.27
de.siegmar
fastcsv
- 1.0.3
+ 1.0.4
info.picocli
picocli
- 4.0.3
+ 4.5.2
- org.glassfish.jersey.core
- jersey-common
- ${jersey.version}
-
+ io.github.classgraph
+ classgraph
+ 4.8.93
+
- junit
- junit
- ${junit.version}
+ org.junit.jupiter
+ junit-jupiter
+ ${junit5.version}
test
-
+
@@ -133,6 +170,24 @@
pre-release
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.2
+
+
+ unpack-dependencies
+ validate
+
+ unpack-dependencies
+
+
+ /META-INF/native/*
+ target/shade
+
+
+
+
org.apache.maven.plugins
maven-shade-plugin
@@ -146,32 +201,144 @@
+ com.linecorp.armeria:*
+ io.micrometer:*
+ org.reactivestreams:*
io.netty:*
+ io.netty.incubator:*
+ org.apache.httpcomponents:*
org.antlr:*
- org.glassfish.jersey.core:*
-
+
+
+ com.linecorp
+ karate.com.linecorp
+
io.netty
- io.netty.karate
+ karate.io.netty
- org.antlr.v4
- org.antlr.karate
-
+ org.apache.http
+ karate.org.apache.http
+
- org.glassfish.jersey
- org.glassfish.jersey.karate
-
+ org.antlr.v4
+ karate.org.antlr.v4
+
+
+
+ io.netty.incubator:netty-incubator-transport-native-io_uring
+
+ META-INF/native/libnetty_transport_native_io_uring_x86_64.so
+
+
+
+ io.netty:netty-transport-native-epoll
+
+ META-INF/native/libnetty_transport_native_epoll_x86_64.so
+
+
+
+ io.netty:netty-tcnative-boringssl-static
+
+ META-INF/native/libnetty_tcnative_linux_x86_64.so
+ META-INF/native/libnetty_tcnative_linux_aarch64.so
+ META-INF/native/libnetty_tcnative_osx_x86_64.jnilib
+ META-INF/native/netty_tcnative_windows_x86_64.dll
+
+
+
+
+
+ com.intuit.karate.Main
+
+
+ META-INF/native/libkarate_netty_transport_native_io_uring_x86_64.so
+ target/shade/META-INF/native/libnetty_transport_native_io_uring_x86_64.so
+
+
+ META-INF/native/libkarate_netty_transport_native_epoll_x86_64.so
+ target/shade/META-INF/native/libnetty_transport_native_epoll_x86_64.so
+
+
+ META-INF/native/libkarate_netty_tcnative_linux_x86_64.so
+ target/shade/META-INF/native/libnetty_tcnative_linux_x86_64.so
+
+
+ META-INF/native/libkarate_netty_tcnative_linux_aarch64.so
+ target/shade/META-INF/native/libnetty_tcnative_linux_aarch64.so
+
+
+ META-INF/native/libkarate_netty_tcnative_osx_x86_64.jnilib
+ target/shade/META-INF/native/libnetty_tcnative_osx_x86_64.jnilib
+
+
+ META-INF/native/karate_netty_tcnative_windows_x86_64.dll
+ target/shade/META-INF/native/netty_tcnative_windows_x86_64.dll
+
+
-
+
+
+ fatjar
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ ${maven.shade.version}
+
+
+ package
+
+ shade
+
+
+ karate-${project.version}
+
+
+ *:*
+
+
+
+
+ com.intuit.karate.Main
+
+
+
+
+
+
+
+ maven-assembly-plugin
+ 3.3.0
+
+
+ src/assembly/bin.xml
+
+ karate-${project.version}
+ false
+
+
+
+ package
+
+ single
+
+
+
+
+
+
+
diff --git a/karate-netty/src/assembly/bin.xml b/karate-core/src/assembly/bin.xml
similarity index 100%
rename from karate-netty/src/assembly/bin.xml
rename to karate-core/src/assembly/bin.xml
diff --git a/karate-core/src/main/java/com/intuit/karate/Actions.java b/karate-core/src/main/java/com/intuit/karate/Actions.java
index 2f4af6507..d56743427 100644
--- a/karate-core/src/main/java/com/intuit/karate/Actions.java
+++ b/karate-core/src/main/java/com/intuit/karate/Actions.java
@@ -32,23 +32,29 @@
*/
public interface Actions {
- void assertTrue(String expression);
+ boolean isFailed();
+
+ Throwable getFailedReason();
+
+ boolean isAborted();
+
+ void assertTrue(String exp);
void call(String line);
void callonce(String line);
-
- void csv(String name, String expression);
- void json(String name, String expression);
+ void csv(String name, String exp);
+
+ void json(String name, String exp);
- void string(String name, String expression);
+ void string(String name, String exp);
- void xml(String name, String expression);
+ void xml(String name, String exp);
- void xmlstring(String name, String expression);
-
- void bytes(String name, String expression);
+ void xmlstring(String name, String exp);
+
+ void bytes(String name, String exp);
void configure(String key, String exp);
@@ -56,53 +62,55 @@ public interface Actions {
void cookie(String name, String value);
- void cookies(String expr);
+ void cookies(String exp);
- void copy(String name, String expression);
+ void copy(String name, String exp);
- void def(String name, String expression);
+ void def(String name, String exp);
- void defDocstring(String name, String expression);
+ void defDocstring(String name, String exp);
void eval(String exp);
void evalDocstring(String exp);
-
- void eval(String name, String dotOrParen, String expression);
-
- void evalIf(String expression);
-
- void formField(String name, List values);
- void formFields(String expr);
+ void eval(String name, String dotOrParen, String exp);
+
+ void evalIf(String exp);
+
+ void formField(String name, String exp);
+
+ void formFields(String exp);
- void header(String name, List values);
+ void header(String name, String exp);
- void headers(String expr);
+ void headers(String exp);
- void match(String expression, String op1, String op2, String rhs);
+ void listen(String exp);
+
+ void match(String exp, String op1, String op2, String rhs);
void method(String method);
-
+
void retry(String until);
void multipartEntity(String value);
- void multipartFiles(String expr);
+ void multipartFiles(String exp);
void multipartField(String name, String value);
- void multipartFields(String expr);
+ void multipartFields(String exp);
void multipartFile(String name, String value);
- void param(String name, List values);
+ void param(String name, String exp);
- void params(String expr);
+ void params(String exp);
- void path(List paths);
+ void path(String exp);
- void print(List exps);
+ void print(String exp);
void remove(String name, String path);
@@ -126,16 +134,20 @@ public interface Actions {
void table(String name, List