/** * Copyright 2016 LinkedIn Corp. All rights reserved. * * Licensed 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. */ package com.github.ambry.rest; import com.github.ambry.clustermap.ClusterMap; import com.github.ambry.clustermap.MockClusterMap; import com.github.ambry.commons.LoggingNotificationSystem; import com.github.ambry.commons.SSLFactory; import com.github.ambry.config.VerifiableProperties; import com.github.ambry.notification.NotificationSystem; import com.github.ambry.router.InMemoryRouterFactory; import java.io.IOException; import java.util.Properties; import org.junit.Test; import static org.junit.Assert.*; /** * Test functionality of {@link RestServer}. */ public class RestServerTest { private static final SSLFactory SSL_FACTORY = RestTestUtils.getTestSSLFactory(); /** * Tests {@link RestServer#start()} and {@link RestServer#shutdown()}. * @throws Exception */ @Test public void startShutdownTest() throws Exception { Properties properties = new Properties(); VerifiableProperties verifiableProperties = getVProps(properties); ClusterMap clusterMap = new MockClusterMap(); NotificationSystem notificationSystem = new LoggingNotificationSystem(); RestServer server = new RestServer(verifiableProperties, clusterMap, notificationSystem, SSL_FACTORY); server.start(); server.shutdown(); server.awaitShutdown(); } /** * Tests for {@link RestServer#shutdown()} when {@link RestServer#start()} had not been called previously. This test * is for cases where {@link RestServer#start()} has failed and {@link RestServer#shutdown()} needs to be run. * @throws Exception */ @Test public void shutdownWithoutStartTest() throws Exception { Properties properties = new Properties(); VerifiableProperties verifiableProperties = getVProps(properties); ClusterMap clusterMap = new MockClusterMap(); NotificationSystem notificationSystem = new LoggingNotificationSystem(); RestServer server = new RestServer(verifiableProperties, clusterMap, notificationSystem, SSL_FACTORY); server.shutdown(); server.awaitShutdown(); } /** * Tests for correct exceptions thrown on {@link RestServer} instantiation/{@link RestServer#start()} with bad input. * @throws Exception * @throws IOException */ @Test public void serverCreationWithBadInputTest() throws Exception { badArgumentsTest(); badFactoriesTest(); } /** * Tests for correct exceptions thrown on {@link RestServer#start()}/{@link RestServer#shutdown()} with bad * components. * @throws Exception */ @Test public void startShutdownTestWithBadComponent() throws Exception { Properties properties = new Properties(); properties.setProperty("rest.server.nio.server.factory", MockNioServerFactory.class.getCanonicalName()); // makes MockNioServer throw exceptions. properties.setProperty(MockNioServerFactory.IS_FAULTY_KEY, "true"); VerifiableProperties verifiableProperties = getVProps(properties); ClusterMap clusterMap = new MockClusterMap(); NotificationSystem notificationSystem = new LoggingNotificationSystem(); RestServer server = new RestServer(verifiableProperties, clusterMap, notificationSystem, SSL_FACTORY); try { server.start(); fail("start() should not be successful. MockNioServer::start() would have thrown InstantiationException"); } catch (InstantiationException e) { // nothing to do. expected. } finally { try { server.shutdown(); fail("RestServer shutdown should have failed."); } catch (RuntimeException e) { // nothing to do. expected. } } } // helpers // general /** * Gets {@link VerifiableProperties} with some mandatory values set. * @param properties the {@link Properties} file to use to build the {@link VerifiableProperties}. * @return an instance of {@link VerifiableProperties}. */ private VerifiableProperties getVProps(Properties properties) { setMandatoryValues(properties); return new VerifiableProperties(properties); } /** * Set some mandatory values in the {@link Properties} passed in. * @param properties The {@link Properties} to set these values in. */ private void setMandatoryValues(Properties properties) { properties.setProperty("rest.server.router.factory", InMemoryRouterFactory.class.getCanonicalName()); properties.setProperty("rest.server.response.handler.factory", MockRestRequestResponseHandlerFactory.class.getCanonicalName()); properties.setProperty("rest.server.blob.storage.service.factory", MockBlobStorageServiceFactory.class.getCanonicalName()); properties.setProperty("rest.server.request.handler.factory", MockRestRequestResponseHandlerFactory.class.getCanonicalName()); properties.setProperty("rest.server.nio.server.factory", MockNioServerFactory.class.getCanonicalName()); } // serverCreationWithBadInputTest() helpers /** * Tests {@link RestServer} instantiation attempts with bad input. * @throws Exception * @throws IOException */ private void badArgumentsTest() throws Exception { // dud properties. server should pick up defaults Properties properties = new Properties(); VerifiableProperties verifiableProperties = new VerifiableProperties(properties); ClusterMap clusterMap = new MockClusterMap(); NotificationSystem notificationSystem = new LoggingNotificationSystem(); try { // no props. new RestServer(null, clusterMap, notificationSystem, SSL_FACTORY); fail("Properties missing, yet no exception was thrown"); } catch (IllegalArgumentException e) { // nothing to do. expected. } try { // no ClusterMap. new RestServer(verifiableProperties, null, notificationSystem, SSL_FACTORY); fail("ClusterMap missing, yet no exception was thrown"); } catch (IllegalArgumentException e) { // nothing to do. expected. } try { // no NotificationSystem. new RestServer(verifiableProperties, clusterMap, null, SSL_FACTORY); fail("NotificationSystem missing, yet no exception was thrown"); } catch (IllegalArgumentException e) { // nothing to do. expected. } } /** * Tests for bad factory class names in {@link RestServer}. * @throws Exception */ private void badFactoriesTest() throws Exception { doBadFactoryClassTest("rest.server.nio.server.factory"); doBadFactoryClassTest("rest.server.blob.storage.service.factory"); doBadFactoryClassTest("rest.server.router.factory"); doBadFactoryClassTest("rest.server.response.handler.factory"); doBadFactoryClassTest("rest.server.request.handler.factory"); } /** * Tests for bad factory class name for {@code configKey} in {@link RestServer}. * @param configKey the property whose value is the bad factory class * @throws Exception */ private void doBadFactoryClassTest(String configKey) throws Exception { Properties properties = new Properties(); setMandatoryValues(properties); // Non existent class. properties.setProperty(configKey, "non.existent.factory"); VerifiableProperties verifiableProperties = new VerifiableProperties(properties); try { new RestServer(verifiableProperties, new MockClusterMap(), new LoggingNotificationSystem(), SSL_FACTORY); fail("Properties file contained non existent " + configKey + ", yet no exception was thrown"); } catch (ClassNotFoundException e) { // nothing to do. expected. } // invalid factory class. properties.setProperty(configKey, RestServerTest.class.getCanonicalName()); verifiableProperties = new VerifiableProperties(properties); try { new RestServer(verifiableProperties, new MockClusterMap(), new LoggingNotificationSystem(), SSL_FACTORY); fail("Properties file contained invalid " + configKey + " class, yet no exception was thrown"); } catch (NullPointerException e) { // nothing to do. expected. } // faulty factory class properties.setProperty(configKey, FaultyFactory.class.getCanonicalName()); verifiableProperties = new VerifiableProperties(properties); try { RestServer restServer = new RestServer(verifiableProperties, new MockClusterMap(), new LoggingNotificationSystem(), SSL_FACTORY); restServer.start(); fail("Properties file contained faulty " + configKey + " class, yet no exception was thrown"); } catch (InstantiationException e) { // nothing to do. expected. } } }