/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.test;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import junit.framework.TestCase;
/**
* Test support for test cases which require an "online" resource, such as an
* external server or database.
* <p>
* Online tests work off of a "fixture". A fixture is a properties file which
* defines connection parameters for some remote service. Each online test case
* must define the id of the fixture is uses with {@link #getFixtureId()}.
* </p>
* <p>
* Fixtures are stored under the users home directory, under the "{@code .geotools}"
* directory. In the event that a fixture does not exist, the test case is
* aborted.
* </p>
* <p>
* Online tests connect to remote / online resources. Test cases should do all
* connection / disconnection in the {@link #connect} and {@link #disconnect()}
* methods.
* </p>
*
* <p>
* The default behaviour of this class is that if {@link #connect()} throws an exception, the test
* suite is disabled, causing each test to pass without being run. In addition, exceptions thrown by
* {@link #disconnect()} are ignored. This behaviour allows tests to be robust against transient
* outages of online resources, but also means that local software failures in {@link #connect()} or
* {@link #disconnect()} will be silent.
* </p>
*
* <p>
* To have exceptions thrown by {@link #connect()} and {@link #disconnect()} cause tests to fail,
* set <code>skip.on.failure=false</code> in the fixture property file. This restores the
* traditional behaviour of unit tests, that is, that exceptions cause unit tests to fail.
* </p>
*
* @since 2.4
* @source $URL$
* @version $Id$
* @author Justin Deoliveira, The Open Planning Project
*/
public abstract class OnlineTestCase extends TestCase {
/**
* The key in the test fixture property file used to set the behaviour of the online test if
* {@link #connect()} fails.
*/
public static final String SKIP_ON_FAILURE_KEY = "skip.on.failure";
/**
* The default value used for {@link #SKIP_ON_FAILURE_KEY} if it is not present.
*/
public static final String SKIP_ON_FAILURE_DEFAULT = "true";
/**
* The test fixture, {@code null} if the fixture is not available.
*/
protected Properties fixture;
/**
* Flag that determines effect of exceptions in connect/disconnect. If true (the default),
* exceptions in connect cause the the test to be disabled, and exceptions in disconnect to be
* ignored. If false, exceptions will be rethrown, and cause the test to fail.
*/
protected boolean skipOnFailure = true;
/**
* Loads the test fixture for the test case.
* <p>
* The fixture id is obtained via {@link #getFixtureId()}.
* </p>
*/
@Override
protected void setUp() throws Exception {
super.setUp();
// load the fixture
File base = new File(System.getProperty("user.home") + File.separator + ".geotools");
String fixtureId = getFixtureId();
if (fixtureId == null) {
fixture = null; // not available (turn test off)
return;
}
File fixtureFile = new File(base, fixtureId.replace('.',
File.separatorChar).concat(".properties"));
if (fixtureFile.exists()) {
InputStream input = new BufferedInputStream(new FileInputStream(fixtureFile));
try {
fixture = new Properties();
fixture.load(input);
} finally {
input.close();
}
skipOnFailure = Boolean.parseBoolean(fixture.getProperty(SKIP_ON_FAILURE_KEY,
SKIP_ON_FAILURE_DEFAULT));
// call the setUp template method
try {
connect();
} catch (Exception e) {
if (skipOnFailure) {
// disable the test
fixture = null;
// leave some trace of the swallowed exception
e.printStackTrace();
} else {
// do not swallow the exception
throw e;
}
}
}
}
/**
* Tear down method for test, calls through to {@link #disconnect()} if the
* test is active.
*/
@Override
protected void tearDown() throws Exception {
if (fixture != null) {
try {
disconnect();
} catch (Exception e) {
if (skipOnFailure) {
// do nothing
} else {
throw e;
}
}
}
}
/**
* Connection method, called from {@link #setUp()}.
* <p>
* Subclasses should do all initialization / connection here. In the event
* of a connection not being available, this method should throw an
* exception to abort the test case.
* </p>
*
* @throws Exception if the connection failed.
*/
protected void connect() throws Exception {
}
/**
* Disconnection method, called from {@link #tearDown()}.
* <p>
* Subclasses should do all cleanup here.
* </p>
*
* @throws Exception if the disconnection failed.
*/
protected void disconnect() throws Exception {
}
/**
* Override which checks if the fixture is available. If not the test is not
* executed.
*/
@Override
protected void runTest() throws Throwable {
// if the fixture was loaded, run
if (fixture != null) {
super.runTest();
}
// otherwise do nothing
}
/**
* The fixture id for the test case.
* <p>
* This name is hierarchical, similar to a java package name. Example:
* {@code "postgis.demo_bc"}.
* </p>
*
* @return The fixture id.
*/
protected abstract String getFixtureId();
}