/* * Copyright (c) 2011-2014 The original author or authors * ------------------------------------------------------ * 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 io.vertx.test.core; import io.vertx.core.AbstractVerticle; import io.vertx.core.AsyncResult; import io.vertx.core.Context; import io.vertx.core.DeploymentOptions; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.core.net.JksOptions; import io.vertx.core.net.PemKeyCertOptions; import io.vertx.core.net.KeyCertOptions; import io.vertx.core.net.PfxOptions; import io.vertx.core.net.TCPSSLOptions; import io.vertx.core.spi.cluster.ClusterManager; import io.vertx.test.fakecluster.FakeClusterManager; import org.junit.Rule; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * @author <a href="http://tfox.org">Tim Fox</a> */ public class VertxTestBase extends AsyncTestBase { private static final Logger log = LoggerFactory.getLogger(VertxTestBase.class); @Rule public RepeatRule repeatRule = new RepeatRule(); protected Vertx vertx; protected Vertx[] vertices; private List<Vertx> created; protected void vinit() { vertx = null; vertices = null; created = null; } public void setUp() throws Exception { super.setUp(); vinit(); vertx = Vertx.vertx(getOptions()); } protected VertxOptions getOptions() { return new VertxOptions(); } protected void tearDown() throws Exception { if (vertx != null) { CountDownLatch latch = new CountDownLatch(1); vertx.close(ar -> { latch.countDown(); }); awaitLatch(latch); } if (created != null) { CountDownLatch latch = new CountDownLatch(created.size()); for (Vertx v : created) { v.close(ar -> { if (ar.failed()) { log.error("Failed to shutdown vert.x", ar.cause()); } latch.countDown(); }); } assertTrue(latch.await(180, TimeUnit.SECONDS)); } FakeClusterManager.reset(); // Bit ugly super.tearDown(); } /** * @return create a blank new Vert.x instance with no options closed when tear down executes. */ protected Vertx vertx() { if (created == null) { created = new ArrayList<>(); } Vertx vertx = Vertx.vertx(); created.add(vertx); return vertx; } /** * @return create a blank new Vert.x instance with @{@code options} closed when tear down executes. */ protected Vertx vertx(VertxOptions options) { if (created == null) { created = new ArrayList<>(); } Vertx vertx = Vertx.vertx(options); created.add(vertx); return vertx; } /** * Create a blank new clustered Vert.x instance with @{@code options} closed when tear down executes. */ protected void clusteredVertx(VertxOptions options, Handler<AsyncResult<Vertx>> ar) { if (created == null) { created = Collections.synchronizedList(new ArrayList<>()); } Vertx.clusteredVertx(options, event -> { if (event.succeeded()) { created.add(event.result()); } ar.handle(event); }); } protected ClusterManager getClusterManager() { return null; } protected void startNodes(int numNodes) { startNodes(numNodes, getOptions()); } protected void startNodes(int numNodes, VertxOptions options) { CountDownLatch latch = new CountDownLatch(numNodes); vertices = new Vertx[numNodes]; for (int i = 0; i < numNodes; i++) { int index = i; clusteredVertx(options.setClusterHost("localhost").setClusterPort(0).setClustered(true) .setClusterManager(getClusterManager()), ar -> { try { if (ar.failed()) { ar.cause().printStackTrace(); } assertTrue("Failed to start node", ar.succeeded()); vertices[index] = ar.result(); } finally { latch.countDown(); } }); } try { assertTrue(latch.await(2, TimeUnit.MINUTES)); } catch (InterruptedException e) { fail(e.getMessage()); } } protected static void setOptions(TCPSSLOptions sslOptions, KeyCertOptions options) { if (options instanceof JksOptions) { sslOptions.setKeyStoreOptions((JksOptions) options); } else if (options instanceof PfxOptions) { sslOptions.setPfxKeyCertOptions((PfxOptions) options); } else { sslOptions.setPemKeyCertOptions((PemKeyCertOptions) options); } } protected static final String[] ENABLED_CIPHER_SUITES = new String[] { "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_SHA", "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "TLS_ECDH_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_RC4_128_MD5", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "TLS_DH_anon_WITH_AES_128_GCM_SHA256", "TLS_DH_anon_WITH_AES_128_CBC_SHA256", "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "TLS_DH_anon_WITH_AES_128_CBC_SHA", "TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_DH_anon_WITH_RC4_128_MD5", "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_NULL_SHA256", "TLS_ECDHE_ECDSA_WITH_NULL_SHA", "TLS_ECDHE_RSA_WITH_NULL_SHA", "SSL_RSA_WITH_NULL_SHA", "TLS_ECDH_ECDSA_WITH_NULL_SHA", "TLS_ECDH_RSA_WITH_NULL_SHA", "TLS_ECDH_anon_WITH_NULL_SHA", "SSL_RSA_WITH_NULL_MD5", "SSL_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_DES_CBC_SHA", "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "TLS_KRB5_WITH_RC4_128_SHA", "TLS_KRB5_WITH_RC4_128_MD5", "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", "TLS_KRB5_WITH_DES_CBC_SHA", "TLS_KRB5_WITH_DES_CBC_MD5", "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5" }; /** * Create a worker verticle for the current Vert.x and return its context. * * @return the context * @throws Exception anything preventing the creation of the worker */ protected Context createWorker() throws Exception { CompletableFuture<Context> fut = new CompletableFuture<>(); vertx.deployVerticle(new AbstractVerticle() { @Override public void start() throws Exception { fut.complete(context); } }, new DeploymentOptions().setWorker(true), ar -> { if (ar.failed()) { fut.completeExceptionally(ar.cause()); } }); return fut.get(); } /** * Create worker verticles for the current Vert.x and returns the list of their contexts. * * @param num the number of verticles to create * @return the contexts * @throws Exception anything preventing the creation of the workers */ protected List<Context> createWorkers(int num) throws Exception { List<Context> contexts = new ArrayList<>(); for (int i = 0;i < num;i++) { contexts.add(createWorker()); } return contexts; } }