All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.specto.hoverfly.junit.Hoverfly Maven / Gradle / Ivy
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2016-2016 SpectoLabs Ltd.
*/
package io.specto.hoverfly.junit;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.StartedProcess;
import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import static io.specto.hoverfly.junit.HoverflyMode.CAPTURE;
import static io.specto.hoverfly.junit.HoverflyRuleUtils.*;
import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
import static java.util.Arrays.asList;
class Hoverfly {
private static final Logger LOGGER = LoggerFactory.getLogger(Hoverfly.class);
private static final int BOOT_TIMEOUT_SECONDS = 10;
private static final String HEALTH_CHECK_URL = "http://localhost:%s/api/stats";
private static final String SIMULATION_URL = "http://localhost:%s/api/v2/simulation";
private static final String BINARY_VERSION = "0.9.1";
private static final String BINARY_PATH = "hoverfly_v%s_%s_%s";
private final HoverflyConfig hoverflyConfig;
private final HoverflyMode hoverflyMode;
private final Integer proxyPort;
private final Integer adminPort;
private StartedProcess startedProcess;
private Path binaryPath;
Hoverfly(HoverflyConfig hoverflyConfig, HoverflyMode hoverflyMode) {
this.hoverflyConfig = hoverflyConfig;
this.hoverflyMode = hoverflyMode;
proxyPort = hoverflyConfig.getProxyPort() == 0 ? findUnusedPort() : hoverflyConfig.getProxyPort();
adminPort = hoverflyConfig.getAdminPort() == 0 ? findUnusedPort() : hoverflyConfig.getAdminPort();
}
void start() throws IOException, URISyntaxException {
setTrustStore();
setProxySystemProperties();
final String binaryName = String.format(BINARY_PATH, BINARY_VERSION, getOs(), getArchitectureType()) + (SystemUtils.IS_OS_WINDOWS ? ".exe" : "");
LOGGER.info("Selecting the following binary based on the current operating system: {}", binaryName);
binaryPath = extractBinary(binaryName);
LOGGER.info("Executing binary at {}", binaryPath);
final List commands = new ArrayList<>();
commands.add(binaryPath.toString());
commands.add("-db");
commands.add("memory");
commands.add("-pp");
commands.add(proxyPort.toString());
commands.add("-ap");
commands.add(adminPort.toString());
if (hoverflyMode == CAPTURE) {
commands.add("-capture");
}
startedProcess = new ProcessExecutor()
.command(commands)
.redirectOutput(Slf4jStream.of(LOGGER).asInfo())
.directory(binaryPath.getParent().toFile())
.start();
waitForHoverflyToStart();
}
void stop() {
LOGGER.info("Destroying hoverfly process");
startedProcess.getProcess().destroy();
try {
Files.deleteIfExists(binaryPath);
} catch (IOException e) {
throw new RuntimeException("Failed to delete hoverfly binary", e);
}
}
boolean isHealthy(int adminPort) {
boolean isHealthy = false;
try {
HttpURLConnection con = (HttpURLConnection) new URL(String.format(HEALTH_CHECK_URL, adminPort)).openConnection();
con.setRequestMethod("GET");
LOGGER.debug("Hoverfly health check status code is: {}", con.getResponseCode());
isHealthy = con.getResponseCode() == 200;
} catch (IOException e) {
LOGGER.debug("Exception curling health check", e);
}
return isHealthy;
}
void importSimulation(URI serviceDataURI) throws IOException {
HttpURLConnection con = (HttpURLConnection) new URL(String.format(SIMULATION_URL, adminPort)).openConnection();
con.setRequestMethod("PUT");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
if (serviceDataURI.getScheme().startsWith("http")) {
IOUtils.copy(serviceDataURI.toURL().openStream(), os);
} else {
Files.copy(Paths.get(serviceDataURI), os);
}
os.flush();
}
con.connect();
int responseCode = con.getResponseCode();
if (responseCode < 200 || responseCode > 299) {
String result = new BufferedReader(new InputStreamReader(con.getErrorStream()))
.lines().collect(Collectors.joining("\n"));
throw new RuntimeException("Submit simulation data failed with error: " + result);
}
}
void exportSimulation(URI serviceDataURI) {
LOGGER.info("Storing captured data");
try {
HttpURLConnection con = (HttpURLConnection) new URL(String.format(SIMULATION_URL, adminPort)).openConnection();
con.setRequestMethod("GET");
final Path path = Paths.get(serviceDataURI);
Files.deleteIfExists(path);
Files.copy(con.getInputStream(), path);
} catch (IOException e) {
throw new RuntimeException("Unable to persist captured data", e);
}
}
private void setProxySystemProperties() {
LOGGER.info("Setting proxy host to {}", "localhost");
System.setProperty("http.proxyHost", "localhost");
System.setProperty("https.proxyHost", "localhost");
if (hoverflyConfig.isProxyLocalHost()) {
System.setProperty("http.nonProxyHosts", "");
} else {
System.setProperty("http.nonProxyHosts", "local|*.local|169.254/16|*.169.254/16");
}
LOGGER.info("Setting proxy proxyPort to {}", hoverflyConfig.getProxyPort());
System.setProperty("http.proxyPort", proxyPort.toString());
System.setProperty("https.proxyPort", proxyPort.toString());
}
private void waitForHoverflyToStart() {
final Instant now = Instant.now();
while (Duration.between(now, Instant.now()).getSeconds() < BOOT_TIMEOUT_SECONDS) {
if (isHealthy(adminPort)) return;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
throw new IllegalStateException("Hoverfly has not become healthy in " + BOOT_TIMEOUT_SECONDS + " seconds");
}
private Path extractBinary(final String binaryName) throws IOException {
final URI sourceHoverflyUrl = findResourceOnClasspath(binaryName);
final Path temporaryHoverflyPath = Files.createTempFile(binaryName, "");
LOGGER.info("Storing binary in temporary directory {}", temporaryHoverflyPath);
final File temporaryHoverflyFile = temporaryHoverflyPath.toFile();
FileUtils.copyURLToFile(sourceHoverflyUrl.toURL(), temporaryHoverflyFile);
if (SystemUtils.IS_OS_WINDOWS) {
temporaryHoverflyFile.setExecutable(true);
temporaryHoverflyFile.setReadable(true);
temporaryHoverflyFile.setWritable(true);
} else {
Files.setPosixFilePermissions(temporaryHoverflyPath, new HashSet<>(asList(OWNER_EXECUTE, OWNER_READ)));
}
return temporaryHoverflyPath;
}
private void setTrustStore() {
try {
// load your key store as a stream and initialize a KeyStore
InputStream trustStream = findResourceOnClasspath("hoverfly.jks").toURL().openStream();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// load the stream to your store
trustStore.load(trustStream, "hoverfly".toCharArray());
// initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
// get the trust managers from the factory
TrustManager[] trustManagers = trustFactory.getTrustManagers();
// initialize an ssl context to use these managers and set as default
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
SSLContext.setDefault(sslContext);
} catch (Exception e) {
throw new RuntimeException("Unable to set hoverfly trust store", e);
}
}
public Integer getProxyPort() {
return proxyPort;
}
}