blob: a38a88d97b76fbc90e428a924b4d282f6e3b27d7 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.marmotta.ldclient.test.helper;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
import org.apache.marmotta.ldclient.api.ldclient.LDClientService;
import org.apache.marmotta.ldclient.api.provider.DataProvider;
import org.apache.marmotta.ldclient.exception.DataRetrievalException;
import org.apache.marmotta.ldclient.model.ClientConfiguration;
import org.apache.marmotta.ldclient.model.ClientResponse;
import org.junit.Assume;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a simple wrapper to use in UnitTests, which handles typical
* Exceptions when contacting remote resources.
*
* All methods except {@link #retrieveResource(String)} are relayed to the
* delegate. {@link #retrieveResource(String)} checks for common retrieval
* errors such as "IOException: Connection refused" and deactivates any ongoing
* Unit-Test using {@link Assume}.
*
*/
public class TestLDClient implements LDClientService {
private static final Logger log = LoggerFactory.getLogger(TestLDClient.class);
/**
* The default checks were shamelessly taken from Apache Stanbol.
* @see <a href="http://svn.apache.org/repos/asf/stanbol/trunk/enhancer/generic/test/src/main/java/org/apache/stanbol/enhancer/test/helper/RemoteServiceHelper.java">http://svn.apache.org/repos/asf/stanbol/trunk/enhancer/generic/test/src/main/java/org/apache/stanbol/enhancer/test/helper/RemoteServiceHelper.java</a>
*/
public static final List<Check> DEFAULT_CHECKS;
static {
LinkedList<Check> dc = new LinkedList<Check>();
dc.add(new Check(UnknownHostException.class));
dc.add(new Check(SocketTimeoutException.class));
dc.add(new Check(IOException.class, "Connection refused"));
dc.add(new Check(IOException.class, "Server returned HTTP response code: 50"));
dc.add(new Check(ConnectException.class, "unreachable"));
DEFAULT_CHECKS = Collections.unmodifiableList(dc);
}
private final LDClientService delegate;
private final List<Check> extraCheck;
private boolean defaultChecks = true;
public TestLDClient(LDClientService delegate) {
this(delegate, new LinkedList<Check>());
}
public TestLDClient(LDClientService delegate, LinkedList<Check> extraChecks) {
this(delegate, extraChecks, true);
}
public TestLDClient(LDClientService delegate, LinkedList<Check> extraChecks, boolean defaultChecks) {
this.delegate = delegate;
this.extraCheck = extraChecks;
this.defaultChecks = defaultChecks;
}
@Override
public boolean ping(String resource) {
return delegate.ping(resource);
}
@Override
public ClientResponse retrieveResource(String resource)
throws DataRetrievalException {
try {
return delegate.retrieveResource(resource);
} catch (final DataRetrievalException e) {
if (defaultChecks) {
for (Check exCheck : DEFAULT_CHECKS) {
exCheck.matches(e);
}
}
for (Check exCheck : extraCheck) {
exCheck.matches(e);
}
throw e;
}
}
@Override
public CloseableHttpClient getClient() {
return delegate.getClient();
}
@Override
public ClientConfiguration getClientConfiguration() {
return delegate.getClientConfiguration();
}
@Override
public Endpoint getEndpoint(String resource) {
return delegate.getEndpoint(resource);
}
@Override
public boolean hasEndpoint(String urlPattern) {
return delegate.hasEndpoint(urlPattern);
}
@Override
public void shutdown() {
delegate.shutdown();
}
/**
* Return a collection of all available data providers (i.e. registered through the service loader).
*
* @return
*/
@Override
public Set<DataProvider> getDataProviders() {
return delegate.getDataProviders();
}
public void addCheck(Check check) {
extraCheck.add(check);
}
public void addChecks(Collection<Check> checks) {
extraCheck.addAll(checks);
}
public boolean isDefaultChecks() {
return defaultChecks;
}
public void setDefaultChecks(boolean defaultChecks) {
this.defaultChecks = defaultChecks;
}
public static class Check {
private final Class<? extends Throwable> throwable;
private final Pattern messagePattern;
private boolean checkStack = true;
private String infoMessage;
public Check(Class<? extends Throwable> throwable) {
this(throwable, (Pattern) null);
}
public Check(Class<? extends Throwable> throwable, String message) {
this(throwable, Pattern.compile(Pattern.quote(message), Pattern.CASE_INSENSITIVE));
this.infoMessage = String.format("Ignoring because of %s(\"%s\")", throwable.getSimpleName(), message);
}
public Check(Class<? extends Throwable> throwable, Pattern mPattern) {
this.throwable = throwable;
this.messagePattern = mPattern;
this.infoMessage = String.format("Ignoring because of %s", throwable.getSimpleName());
}
public Check setCheckStack(boolean checkStack) {
this.checkStack = checkStack;
return this;
}
/**
* Check if the provided parameter matches this check.
* If so, the current JUnit test is ignored ({@link Assume}) and the parameter exception is re-thrown.
* @param t the {@link Throwable} to check.
*/
public <T extends Throwable> void matches(T t) throws T {
matches(t, t);
}
private <T extends Throwable> void matches(T t, Throwable toCheck) throws T {
if (toCheck == null) return;
if (throwable.isAssignableFrom(toCheck.getClass())
&& (messagePattern == null
|| (toCheck.getMessage() != null && messagePattern.matcher(toCheck.getMessage()).find()))) {
log.info("Ignoring test because '{}' ({})", getMessage(), t.getMessage());
Assume.assumeNoException(getMessage(), t);
throw t;
}
if (checkStack)
matches(t, toCheck.getCause());
}
public String getMessage() {
return infoMessage;
}
public Check setMessage(String infoMessage) {
this.infoMessage = infoMessage;
return this;
}
}
}