| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| |
| package org.eclipse.jetty.gcloud.session; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.nio.channels.Channels; |
| import java.nio.channels.ReadableByteChannel; |
| import java.nio.file.Files; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Locale; |
| |
| import org.eclipse.jetty.util.IO; |
| import org.eclipse.jetty.util.resource.JarResource; |
| import org.eclipse.jetty.util.resource.Resource; |
| |
| import com.google.api.client.util.Strings; |
| import com.google.gcloud.datastore.Datastore; |
| import com.google.gcloud.datastore.DatastoreFactory; |
| import com.google.gcloud.datastore.Entity; |
| import com.google.gcloud.datastore.GqlQuery; |
| import com.google.gcloud.datastore.Key; |
| import com.google.gcloud.datastore.ProjectionEntity; |
| import com.google.gcloud.datastore.Query; |
| import com.google.gcloud.datastore.Query.ResultType; |
| import com.google.gcloud.datastore.QueryResults; |
| import com.google.gcloud.datastore.StructuredQuery; |
| import com.google.gcloud.datastore.StructuredQuery.Projection; |
| |
| /** |
| * GCloudSessionTestSupport |
| * |
| * |
| */ |
| public class GCloudSessionTestSupport |
| { |
| |
| private static class ProcessOutputReader implements Runnable |
| { |
| private InputStream _is; |
| private String _startupSentinel; |
| private BufferedReader _reader; |
| |
| public ProcessOutputReader (InputStream is, String startupSentinel) |
| throws Exception |
| { |
| _is = is; |
| _startupSentinel = startupSentinel; |
| _reader = new BufferedReader(new InputStreamReader(_is)); |
| if (!Strings.isNullOrEmpty(_startupSentinel)) |
| { |
| String line; |
| while ((line = _reader.readLine()) != (null) && !line.contains(_startupSentinel)) |
| { |
| //System.err.println(line); |
| } |
| } |
| } |
| |
| |
| public void run() |
| { |
| String line; |
| try |
| { |
| while ((line = _reader.readLine()) != (null)) |
| { |
| } |
| } |
| catch (IOException ignore) |
| { |
| /* ignore */ |
| } |
| finally |
| { |
| IO.close(_reader); |
| } |
| } |
| } |
| |
| |
| public static String DEFAULT_PROJECTID = "jetty9-work"; |
| public static String DEFAULT_PORT = "8088"; |
| public static String DEFAULT_HOST = "http://localhost:"+DEFAULT_PORT; |
| public static String DEFAULT_GCD_ZIP = "gcd-v1beta2-rev1-2.1.2b.zip"; |
| public static String DEFAULT_GCD_UNPACKED = "gcd-v1beta2-rev1-2.1.2b"; |
| public static String DEFAULT_DOWNLOAD_URL = "http://storage.googleapis.com/gcd/tools/"; |
| |
| |
| String _projectId; |
| String _testServerUrl; |
| String _testPort; |
| File _datastoreDir; |
| File _gcdInstallDir; |
| File _gcdUnpackedDir; |
| Datastore _ds; |
| |
| public GCloudSessionTestSupport (File gcdInstallDir) |
| { |
| _gcdInstallDir = gcdInstallDir; |
| if (_gcdInstallDir == null) |
| _gcdInstallDir = new File (System.getProperty("java.io.tmpdir")); |
| |
| _projectId = System.getProperty("DATASTORE_DATASET", System.getenv("DATASTORE_DATASET")); |
| if (_projectId == null) |
| { |
| _projectId = DEFAULT_PROJECTID; |
| System.setProperty("DATASTORE_DATASET", _projectId); |
| } |
| _testServerUrl = System.getProperty("DATASTORE_HOST", System.getenv("DATASTORE_HOST")); |
| if (_testServerUrl == null) |
| { |
| _testServerUrl = DEFAULT_HOST; |
| _testPort = DEFAULT_PORT; |
| System.setProperty("DATASTORE_HOST", _testServerUrl); |
| } |
| else |
| { |
| int i = _testServerUrl.lastIndexOf(':'); |
| _testPort = _testServerUrl.substring(i+1); |
| } |
| } |
| |
| public GCloudSessionTestSupport () |
| { |
| this(null); |
| } |
| |
| public GCloudConfiguration getConfiguration () |
| { |
| return new GCloudConfiguration(); |
| } |
| |
| |
| public void setUp() |
| throws Exception |
| { |
| downloadGCD(); |
| createDatastore(); |
| startDatastore(); |
| } |
| |
| |
| public void downloadGCD() |
| throws Exception |
| { |
| File zipFile = new File (_gcdInstallDir, DEFAULT_GCD_ZIP); |
| _gcdUnpackedDir = new File (_gcdInstallDir, DEFAULT_GCD_UNPACKED); |
| File gcdSh = new File (_gcdUnpackedDir, "gcd.sh"); |
| if (gcdSh.exists()) |
| return; |
| |
| |
| if (_gcdInstallDir.exists() && !zipFile.exists()) |
| { |
| //download it |
| ReadableByteChannel rbc = Channels.newChannel(new URL(DEFAULT_DOWNLOAD_URL+DEFAULT_GCD_ZIP).openStream()); |
| try (FileOutputStream fos = new FileOutputStream(zipFile)) |
| { |
| fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); |
| } |
| } |
| |
| if (zipFile.exists()) |
| { |
| //unpack it |
| Resource zipResource = JarResource.newJarResource(Resource.newResource(zipFile)); |
| zipResource.copyTo(_gcdInstallDir); |
| } |
| |
| System.err.println("GCD downloaded and unpacked"); |
| } |
| |
| |
| |
| public void createDatastore () |
| throws Exception |
| { |
| |
| _datastoreDir = Files.createTempDirectory("gcloud-sessions").toFile(); |
| _datastoreDir.deleteOnExit(); |
| |
| ProcessBuilder processBuilder = new ProcessBuilder(); |
| processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); |
| processBuilder.directory(_datastoreDir); |
| if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")) |
| { |
| processBuilder.command("cmd", "/C", new File(_gcdUnpackedDir, "gcd.cmd").getAbsolutePath(), "create", "-p", _projectId, _projectId); |
| processBuilder.redirectOutput(new File("NULL:")); |
| } |
| else |
| { |
| processBuilder.redirectOutput(new File("/tmp/run.out")); |
| processBuilder.command("bash", new File(_gcdUnpackedDir, "gcd.sh").getAbsolutePath(), "create", "-p",_projectId, _projectId); |
| } |
| |
| Process temp = processBuilder.start(); |
| System.err.println("Create outcome: "+temp.waitFor()); |
| } |
| |
| |
| public void startDatastore() |
| throws Exception |
| { |
| //start the datastore for the test |
| ProcessBuilder processBuilder = new ProcessBuilder(); |
| processBuilder.directory(_datastoreDir); |
| processBuilder.redirectErrorStream(true); |
| if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")) |
| { |
| processBuilder.command("cmd", "/C", new File(_gcdUnpackedDir, "gcd.cmd").getAbsolutePath(), "start", "--testing", "--allow_remote_shutdown","--port="+_testPort, _projectId); |
| } |
| else |
| { |
| processBuilder.command("bash", new File(_gcdUnpackedDir, "gcd.sh").getAbsolutePath(), "start", "--testing", "--allow_remote_shutdown", "--port="+_testPort, _projectId); |
| } |
| |
| System.err.println("Starting datastore"); |
| Process temp = processBuilder.start(); |
| ProcessOutputReader reader = new ProcessOutputReader(temp.getInputStream(), "Dev App Server is now running"); |
| Thread readerThread = new Thread(reader, "GCD reader"); |
| readerThread.setDaemon(true); |
| readerThread.start(); |
| } |
| |
| public void stopDatastore() |
| throws Exception |
| { |
| //Send request to terminate test datastore |
| URL url = new URL("http", "localhost", Integer.parseInt(_testPort.trim()), "/_ah/admin/quit"); |
| HttpURLConnection con = (HttpURLConnection) url.openConnection(); |
| con.setRequestMethod("POST"); |
| con.setDoOutput(true); |
| con.setDoInput(true); |
| OutputStream out = con.getOutputStream(); |
| out.write("".getBytes()); |
| out.flush(); |
| InputStream in = con.getInputStream(); |
| while (in.read() != -1) |
| { |
| // consume input |
| |
| } |
| |
| System.err.println("Stop issued"); |
| } |
| |
| |
| public void clearDatastore() |
| { |
| org.eclipse.jetty.util.IO.delete(_datastoreDir); |
| } |
| |
| public void tearDown() |
| throws Exception |
| { |
| stopDatastore(); |
| clearDatastore(); |
| } |
| |
| public void ensureDatastore() |
| throws Exception |
| { |
| if (_ds == null) |
| _ds = DatastoreFactory.instance().get(getConfiguration().getDatastoreOptions()); |
| } |
| public void listSessions () throws Exception |
| { |
| ensureDatastore(); |
| GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionDataStore.KIND); |
| |
| Query<Entity> query = builder.build(); |
| |
| QueryResults<Entity> results = _ds.run(query); |
| assertNotNull(results); |
| System.err.println("SESSIONS::::::::"); |
| while (results.hasNext()) |
| { |
| |
| Entity e = results.next(); |
| System.err.println(e.getString("clusterId")+" expires at "+e.getLong("expiry")); |
| } |
| System.err.println("END OF SESSIONS::::::::"); |
| } |
| |
| public void assertSessions(int count) throws Exception |
| { |
| ensureDatastore(); |
| StructuredQuery<ProjectionEntity> keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder() |
| .kind(GCloudSessionDataStore.KIND) |
| .projection(Projection.property("__key__")) |
| .limit(100) |
| .build(); |
| QueryResults<ProjectionEntity> results = _ds.run(keyOnlyProjectionQuery); |
| assertNotNull(results); |
| int actual = 0; |
| while (results.hasNext()) |
| { |
| results.next(); |
| ++actual; |
| } |
| assertEquals(count, actual); |
| } |
| |
| public void deleteSessions () throws Exception |
| { |
| ensureDatastore(); |
| StructuredQuery<ProjectionEntity> keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder() |
| .kind(GCloudSessionDataStore.KIND) |
| .projection(Projection.property("__key__")) |
| .limit(100) |
| .build(); |
| QueryResults<ProjectionEntity> results = _ds.run(keyOnlyProjectionQuery); |
| if (results != null) |
| { |
| List<Key> keys = new ArrayList<Key>(); |
| |
| while (results.hasNext()) |
| { |
| ProjectionEntity pe = results.next(); |
| keys.add(pe.key()); |
| } |
| |
| _ds.delete(keys.toArray(new Key[keys.size()])); |
| } |
| |
| assertSessions(0); |
| } |
| } |