package mil.nga.giat.geowave.test.service; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.ws.rs.core.Response.Status; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.EntityBuilder; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import mil.nga.giat.geowave.core.store.operations.remote.options.DataStorePluginOptions; import mil.nga.giat.geowave.service.client.GeoserverServiceClient; import mil.nga.giat.geowave.test.GeoWaveITRunner; import mil.nga.giat.geowave.test.TestUtils; import mil.nga.giat.geowave.test.annotation.Environments; import mil.nga.giat.geowave.test.annotation.Environments.Environment; import mil.nga.giat.geowave.test.annotation.GeoWaveTestStore; import mil.nga.giat.geowave.test.annotation.GeoWaveTestStore.GeoWaveStoreType; @RunWith(GeoWaveITRunner.class) @Environments({ Environment.SERVICES }) public class GeoServerIT { private static final Logger LOGGER = LoggerFactory.getLogger(GeoServerIT.class); private static final String WFS_URL_PREFIX = ServicesTestEnvironment.JETTY_BASE_URL + "/geoserver/wfs"; private static final String GEOSTUFF_LAYER_FILE = "src/test/resources/wfs-requests/geostuff_layer.xml"; private static final String INSERT_FILE = "src/test/resources/wfs-requests/insert.xml"; private static final String LOCK_FILE = "src/test/resources/wfs-requests/lock.xml"; private static final String QUERY_FILE = "src/test/resources/wfs-requests/query.xml"; private static final String UPDATE_FILE = "src/test/resources/wfs-requests/update.xml"; private GeoserverServiceClient geoserverServiceClient; private String geostuff_layer; private String insert; private String lock; private String query; private String update; @GeoWaveTestStore(value = { GeoWaveStoreType.ACCUMULO, GeoWaveStoreType.BIGTABLE, GeoWaveStoreType.HBASE }, options = { "disableServer=true", }) protected DataStorePluginOptions dataStoreOptions; private static long startMillis; @BeforeClass public static void startTimer() { startMillis = System.currentTimeMillis(); LOGGER.warn("-----------------------------------------"); LOGGER.warn("* *"); LOGGER.warn("* RUNNING GeoServerIT *"); LOGGER.warn("* *"); LOGGER.warn("-----------------------------------------"); } @AfterClass public static void reportTest() { LOGGER.warn("-----------------------------------------"); LOGGER.warn("* *"); LOGGER.warn("* FINISHED GeoServerIT *"); LOGGER .warn("* " + ((System.currentTimeMillis() - startMillis) / 1000) + "s elapsed. *"); LOGGER.warn("* *"); LOGGER.warn("-----------------------------------------"); } @Before public void initialize() throws ClientProtocolException, IOException { // setup the wfs-requests geostuff_layer = MessageFormat.format( IOUtils.toString(new FileInputStream( GEOSTUFF_LAYER_FILE)), ServicesTestEnvironment.TEST_WORKSPACE); insert = MessageFormat.format( IOUtils.toString(new FileInputStream( INSERT_FILE)), ServicesTestEnvironment.TEST_WORKSPACE); lock = MessageFormat.format( IOUtils.toString(new FileInputStream( LOCK_FILE)), ServicesTestEnvironment.TEST_WORKSPACE); query = MessageFormat.format( IOUtils.toString(new FileInputStream( QUERY_FILE)), ServicesTestEnvironment.TEST_WORKSPACE); geoserverServiceClient = new GeoserverServiceClient( ServicesTestEnvironment.GEOWAVE_BASE_URL, ServicesTestEnvironment.GEOSERVER_USER, ServicesTestEnvironment.GEOSERVER_PASS); // create the workspace boolean success = geoserverServiceClient.createWorkspace(ServicesTestEnvironment.TEST_WORKSPACE); // enable wfs & wms success &= enableWfs(); success &= enableWms(); final Map<String, String> configOptions = dataStoreOptions.getOptionsAsMap(); configOptions.put( "gwNamespace", TestUtils.TEST_NAMESPACE); // create the datastore success &= geoserverServiceClient.publishDatastore( dataStoreOptions.getType(), configOptions, TestUtils.TEST_NAMESPACE); // make sure the datastore exists success &= (null != geoserverServiceClient.getDatastore( TestUtils.TEST_NAMESPACE, ServicesTestEnvironment.TEST_WORKSPACE)); success &= createLayers(); if (!success) { LOGGER.error("Geoserver WFS setup failed."); } } @After public void cleanupWorkspace() { assertTrue(geoserverServiceClient.deleteWorkspace(ServicesTestEnvironment.TEST_WORKSPACE)); TestUtils.deleteAll(dataStoreOptions); } @Test public void test() throws Exception { assertTrue(createPoint()); final String lockID = lockPoint(); // setup the lock and update messages update = MessageFormat.format( IOUtils.toString(new FileInputStream( UPDATE_FILE)), ServicesTestEnvironment.TEST_WORKSPACE, lockID); assertNotNull(lockID); assertTrue(updatePoint(lockID)); assertTrue(queryPoint()); assertTrue(queryFindPointWithTime()); assertTrue(queryFindPointBeyondTime()); } public static boolean enableWfs() throws ClientProtocolException, IOException { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPut command = new HttpPut( ServicesTestEnvironment.GEOSERVER_REST_PATH + "/services/wfs/workspaces/" + ServicesTestEnvironment.TEST_WORKSPACE + "/settings"); command.setHeader( "Content-type", "text/xml"); command.setEntity(EntityBuilder.create().setFile( new File( "src/test/resources/wfs-requests/wfs.xml")).setContentType( ContentType.TEXT_XML).build()); final HttpResponse r = httpclient.execute( command, context); return r.getStatusLine().getStatusCode() == Status.OK.getStatusCode(); } finally { httpclient.close(); } } public static boolean enableWms() throws ClientProtocolException, IOException { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPut command = new HttpPut( ServicesTestEnvironment.GEOSERVER_REST_PATH + "/services/wms/workspaces/" + ServicesTestEnvironment.TEST_WORKSPACE + "/settings"); command.setHeader( "Content-type", "text/xml"); command.setEntity(EntityBuilder.create().setFile( new File( "src/test/resources/wfs-requests/wms.xml")).setContentType( ContentType.TEXT_XML).build()); final HttpResponse r = httpclient.execute( command, context); return r.getStatusLine().getStatusCode() == Status.OK.getStatusCode(); } finally { httpclient.close(); } } public boolean createLayers() throws ClientProtocolException, IOException { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPost command = new HttpPost( ServicesTestEnvironment.GEOSERVER_REST_PATH + "/workspaces/" + ServicesTestEnvironment.TEST_WORKSPACE + "/datastores/" + TestUtils.TEST_NAMESPACE + "/featuretypes"); command.setHeader( "Content-type", "text/xml"); command.setEntity(EntityBuilder.create().setText( geostuff_layer).setContentType( ContentType.TEXT_XML).build()); final HttpResponse r = httpclient.execute( command, context); return r.getStatusLine().getStatusCode() == Status.CREATED.getStatusCode(); } finally { httpclient.close(); } } static protected Pair<CloseableHttpClient, HttpClientContext> createClientAndContext() { final CredentialsProvider provider = new BasicCredentialsProvider(); provider.setCredentials( new AuthScope( "localhost", ServicesTestEnvironment.JETTY_PORT), new UsernamePasswordCredentials( ServicesTestEnvironment.GEOSERVER_USER, ServicesTestEnvironment.GEOSERVER_PASS)); final AuthCache authCache = new BasicAuthCache(); final HttpHost targetHost = new HttpHost( "localhost", ServicesTestEnvironment.JETTY_PORT, "http"); authCache.put( targetHost, new BasicScheme()); // Add AuthCache to the execution context final HttpClientContext context = HttpClientContext.create(); context.setCredentialsProvider(provider); context.setAuthCache(authCache); return ImmutablePair.of( HttpClientBuilder.create().setDefaultCredentialsProvider( provider).build(), context); } private HttpPost createWFSTransaction( final HttpClient httpclient, final String version, final BasicNameValuePair... paramTuples ) throws Exception { final HttpPost command = new HttpPost( WFS_URL_PREFIX + "/Transaction"); final ArrayList<BasicNameValuePair> postParameters = new ArrayList<BasicNameValuePair>(); postParameters.add(new BasicNameValuePair( "version", version)); postParameters.add(new BasicNameValuePair( "typename", ServicesTestEnvironment.TEST_WORKSPACE + ":geostuff")); Collections.addAll( postParameters, paramTuples); command.setEntity(new UrlEncodedFormEntity( postParameters)); command.setHeader( "Content-type", "text/xml"); command.setHeader( "Accept", "text/xml"); return command; } private HttpGet createWFSGetFeature( final String version, final BasicNameValuePair... paramTuples ) { final StringBuilder buf = new StringBuilder(); final List<BasicNameValuePair> localParams = new LinkedList<BasicNameValuePair>(); localParams.add(new BasicNameValuePair( "version", version)); localParams.add(new BasicNameValuePair( "request", "GetFeature")); localParams.add(new BasicNameValuePair( "typeNames", ServicesTestEnvironment.TEST_WORKSPACE + ":geostuff")); localParams.add(new BasicNameValuePair( "service", "WFS")); for (final BasicNameValuePair aParam : paramTuples) { if (buf.length() > 0) { buf.append('&'); } buf.append( aParam.getName()).append( '=').append( aParam.getValue()); } for (final BasicNameValuePair aParam : localParams) { if (buf.length() > 0) { buf.append('&'); } buf.append( aParam.getName()).append( '=').append( aParam.getValue()); } final HttpGet command = new HttpGet( WFS_URL_PREFIX + "?" + buf.toString()); return command; } public boolean createPoint() throws Exception { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPost command = createWFSTransaction( httpclient, "1.1.0"); command.setEntity(EntityBuilder.create().setText( insert).setContentType( ContentType.TEXT_XML).build()); final HttpResponse r = httpclient.execute( command, context); return r.getStatusLine().getStatusCode() == Status.OK.getStatusCode(); } finally { httpclient.close(); } } private String getContent( final HttpResponse r ) throws IOException { final InputStream is = r.getEntity().getContent(); final Header encoding = r.getEntity().getContentEncoding(); final String encodingName = encoding == null ? "UTF-8" : encoding.getName(); return IOUtils.toString( is, encodingName); } /* * @return lockID */ public String lockPoint() throws Exception { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPost command = createWFSTransaction( httpclient, "1.1.0"); command.setEntity(EntityBuilder.create().setText( lock).setContentType( ContentType.TEXT_XML).build()); final HttpResponse r = httpclient.execute( command, context); final boolean result = r.getStatusLine().getStatusCode() == Status.OK.getStatusCode(); if (result) { final String content = getContent(r); final String pattern = "lockId=\"([^\"]+)\""; // Create a Pattern object final Pattern compiledPattern = Pattern.compile(pattern); final Matcher matcher = compiledPattern.matcher(content); if (matcher.find()) { return matcher.group(1); } return content; } return null; } finally { httpclient.close(); } } /* * @return queryPOINT */ public boolean queryPoint() throws Exception { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPost command = createWFSTransaction( httpclient, "1.1.0"); command.setEntity(EntityBuilder.create().setText( query).setContentType( ContentType.TEXT_XML).build()); final HttpResponse r = httpclient.execute( command, context); final boolean result = r.getStatusLine().getStatusCode() == Status.OK.getStatusCode(); if (result) { final String content = getContent(r); System.out.println(content); final String patternX = "34.6815818"; final String patternY = "35.1828408"; // name space check as well return content.contains(patternX) && content.contains(patternY) && content.contains(ServicesTestEnvironment.TEST_WORKSPACE + ":geometry"); } return false; } finally { httpclient.close(); } } public boolean updatePoint( final String lockID ) throws Exception { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpPost command = createWFSTransaction( httpclient, "1.1.0"); command.setEntity(new StringEntity( update)); final LinkedList<HttpResponse> capturedResponse = new LinkedList<HttpResponse>(); run( new Runnable() { @Override public void run() { try { capturedResponse.add(httpclient.execute( command, context)); } catch (final Exception e) { throw new RuntimeException( "update point client failed", e); } } }, 500000); final HttpResponse r = capturedResponse.getFirst(); return r.getStatusLine().getStatusCode() == Status.OK.getStatusCode(); } finally { httpclient.close(); } } /* * @return lockID */ public boolean queryFindPointWithTime() throws ClientProtocolException, IOException { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpGet command = createWFSGetFeature( "1.1.0", new BasicNameValuePair( "cql_filter", URLEncoder .encode( "BBOX(geometry,34.68,35.18,34.7,35.19) and when during 2005-05-19T00:00:00Z/2005-05-19T21:32:56Z", "UTF8")), new BasicNameValuePair( "srsName", "EPSG:4326")); final HttpResponse r = httpclient.execute( command, context); final String content = getContent(r); System.out.println(content); return content.contains("numberOfFeatures=") && !content.contains("numberOfFeatures=\"0\""); } finally { httpclient.close(); } } public boolean queryFindPointBeyondTime() throws ClientProtocolException, IOException { final Pair<CloseableHttpClient, HttpClientContext> clientAndContext = createClientAndContext(); final CloseableHttpClient httpclient = clientAndContext.getLeft(); final HttpClientContext context = clientAndContext.getRight(); try { final HttpGet command = createWFSGetFeature( "1.1.0", new BasicNameValuePair( "cql_filter", URLEncoder .encode( "BBOX(geometry,34.68,35.18,34.7,35.19) and when during 2005-05-19T20:32:56Z/2005-05-19T21:32:56Z", "UTF8")), new BasicNameValuePair( "srsName", "EPSG:4326")); final HttpResponse r = httpclient.execute( command, context); final String content = getContent(r); return content.contains("numberOfFeatures=\"0\""); } finally { httpclient.close(); } } public static void run( final Runnable run, final long waitTime ) throws InterruptedException { final Thread thread = new Thread( run); thread.start(); thread.join(waitTime); } }