| // Copyright 2013 Google Inc. 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. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.enterprise.adaptor; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.ExpectedException; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.concurrent.TimeUnit; |
| import java.util.logging.Logger; |
| |
| /** Tests for {@link Application}. */ |
| public class ApplicationTest { |
| private Config config; |
| private NullAdaptor adaptor = new NullAdaptor(); |
| private MockFile configFile = new MockFile("non-existent-file"); |
| private Application app; |
| private static final Logger log |
| = Logger.getLogger(ApplicationTest.class.getName()); |
| |
| @Rule |
| public ExpectedException thrown = ExpectedException.none(); |
| |
| @Before |
| public void setup() { |
| config = new ModifiedConfig(); |
| config.setValue("gsa.hostname", "localhost"); |
| // Let the OS choose the port |
| config.setValue("server.port", "0"); |
| config.setValue("server.dashboardPort", "0"); |
| config.setValue("gsa.version", "7.2.0-6"); |
| app = new Application(adaptor, config); |
| } |
| |
| @After |
| public void teardown() { |
| // No need to block. |
| new Thread(new Runnable() { |
| @Override |
| public void run() { |
| app.stop(0, TimeUnit.SECONDS); |
| } |
| }).start(); |
| } |
| |
| @Test |
| public void testCommandLine() { |
| config = new ModifiedConfig(); |
| configFile.setExists(false); |
| Application.autoConfig(config, new String[] {"-Dgsa.hostname=notreal"}, |
| configFile); |
| assertEquals("notreal", config.getGsaHostname()); |
| } |
| |
| @Test |
| public void testConfigFile() { |
| config = new ModifiedConfig(); |
| configFile.setFileContents("gsa.hostname=notreal\n"); |
| Application.autoConfig(config, new String[0], configFile); |
| assertEquals("notreal", config.getGsaHostname()); |
| } |
| |
| @Test |
| public void testConfigFileOverrideArgumentParse() { |
| config = new ModifiedConfig(); |
| configFile.setFileContents("gsa.hostname=notreal\n"); |
| thrown.expect(InvalidConfigurationException.class); |
| // provide config file name and above config isn't read; validate fails |
| Application.autoConfig(config, new String[] {"-Dadaptor.configfile=NFE"}, |
| configFile); |
| } |
| |
| private static void addContent(File f, String content) throws IOException { |
| FileOutputStream fw = null; |
| try { |
| fw = new FileOutputStream(f); |
| fw.write(content.getBytes("UTF-8")); |
| fw.flush(); |
| } finally { |
| if (null != fw) { |
| fw.close(); |
| } |
| } |
| } |
| |
| @Test |
| public void testConfigOverrideFileContentIsUsed() throws IOException { |
| config = new Config(); |
| configFile.setFileContents("gsa.hostname=override-me\n"); |
| File override = null; |
| try { |
| override = File.createTempFile("adaptor-test-config", ".cfg"); |
| addContent(override, "gsa.hostname=flavourful\n"); |
| String n = override.getAbsolutePath(); |
| log.info("made real file to override configuration: " + n); |
| Application.autoConfig(config, new String[] {"-Dadaptor.configfile=" + n}, |
| configFile); |
| // getting hostname from the override file passed by -D argument |
| assertEquals("flavourful", config.getGsaHostname()); |
| } finally { |
| if (null != override) { |
| String n = override.getAbsolutePath(); |
| boolean deleted = override.delete(); |
| if (deleted) { |
| log.info("deleted real file that overrode configuration: " + n); |
| } else { |
| log.info("didn't delete real file that overrode configuration: " + n); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testConfigReload() throws Exception { |
| app.start(); |
| assertTrue(adaptor.inited); |
| assertFalse(adaptor.hasBeenShutdownAtSomePoint); |
| configFile.setFileContents("server.hostname=127.0.0.10\n"); |
| config.load(configFile); |
| assertTrue(adaptor.inited); |
| assertTrue(adaptor.hasBeenShutdownAtSomePoint); |
| } |
| |
| @Test |
| public void testConfigReloadNoRestart() throws Exception { |
| app.start(); |
| assertTrue(adaptor.inited); |
| assertFalse(adaptor.hasBeenShutdownAtSomePoint); |
| configFile.setFileContents("adaptor.fullListingSchedule=1 1 1 1 1\n"); |
| config.load(configFile); |
| assertTrue(adaptor.inited); |
| assertFalse(adaptor.hasBeenShutdownAtSomePoint); |
| } |
| |
| @Test |
| public void testFastShutdownWhenStarting() throws Exception { |
| class FailAlwaysAdaptor extends NullAdaptor { |
| @Override |
| public void init(AdaptorContext context) { |
| throw new RuntimeException(); |
| } |
| } |
| app = new Application(new FailAlwaysAdaptor(), config); |
| new Thread(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| // Wait a bit for the handler to start. |
| Thread.sleep(50); |
| } catch (InterruptedException ex) { |
| throw new RuntimeException(ex); |
| } |
| app.stop(0, TimeUnit.SECONDS); |
| } |
| }).start(); |
| long startTime = System.nanoTime(); |
| app.start(); |
| long duration = System.nanoTime() - startTime; |
| final long nanosInAMilli = 1000 * 1000; |
| if (duration > 1000 * nanosInAMilli) { |
| fail("Starting took a long time to stop after being aborted: " |
| + duration); |
| } |
| } |
| |
| @Test |
| public void testFastShutdown() throws Exception { |
| app.start(); |
| long startTime = System.nanoTime(); |
| app.stop(10, TimeUnit.SECONDS); |
| long duration = System.nanoTime() - startTime; |
| final long nanosInAMilli = 1000 * 1000; |
| if (duration > 1000 * nanosInAMilli) { |
| fail("Stopping took a long time: " + duration); |
| } |
| } |
| |
| @Test |
| public void testBasicListen() throws Exception { |
| app.start(); |
| assertTrue(adaptor.inited); |
| URL url = new URL("http", "localhost", config.getServerPort(), "/"); |
| URLConnection conn = url.openConnection(); |
| try { |
| thrown.expect(java.io.FileNotFoundException.class); |
| conn.getContent(); |
| } finally { |
| app.stop(0, TimeUnit.SECONDS); |
| assertFalse(adaptor.inited); |
| } |
| } |
| |
| @Test |
| public void testBasicHttpsListen() throws Exception { |
| config.setValue("server.secure", "true"); |
| app.start(); |
| assertTrue(adaptor.inited); |
| URL url = new URL("https", "localhost", config.getServerPort(), "/"); |
| URLConnection conn = url.openConnection(); |
| thrown.expect(java.io.FileNotFoundException.class); |
| conn.getContent(); |
| } |
| |
| @Test |
| public void testFailWithStartupException() throws Exception { |
| class FailStartupAdaptor extends NullAdaptor { |
| @Override |
| public void init(AdaptorContext context) throws Exception { |
| throw new StartupException("Unrecoverable error."); |
| } |
| } |
| FailStartupAdaptor adaptor = new FailStartupAdaptor(); |
| app = new Application(adaptor, config); |
| |
| // Make sure StartupException bypasses the retry after wait logic. |
| long startTime = System.nanoTime(); |
| try { |
| app.start(); |
| fail("Expected a StartupException, but got none."); |
| } catch (StartupException expected) { |
| long duration = System.nanoTime() - startTime; |
| final long nanosInAMilli = 1000 * 1000; |
| if (duration > 1000 * nanosInAMilli) { |
| fail("StartupException took a long time: " + duration); |
| } |
| } |
| } |
| |
| @Test |
| public void testFailOnceInitAdaptor() throws Exception { |
| class FailFirstAdaptor extends NullAdaptor { |
| private int count = 0; |
| public boolean started = false; |
| |
| @Override |
| public void init(AdaptorContext context) { |
| if (count == 0) { |
| count++; |
| throw new RuntimeException(); |
| } |
| started = true; |
| } |
| } |
| FailFirstAdaptor adaptor = new FailFirstAdaptor(); |
| app = new Application(adaptor, config); |
| app.start(); |
| assertTrue(adaptor.started); |
| } |
| |
| @Test |
| public void testRestart() throws Exception { |
| app.start(); |
| assertTrue(adaptor.inited); |
| app.stop(0, TimeUnit.SECONDS); |
| assertFalse(adaptor.inited); |
| app.start(); |
| assertTrue(adaptor.inited); |
| } |
| |
| private static class NullAdaptor extends AbstractAdaptor { |
| private boolean inited; |
| private boolean hasBeenShutdownAtSomePoint; |
| |
| @Override |
| public void init(AdaptorContext context) throws Exception { |
| inited = true; |
| } |
| |
| @Override |
| public void destroy() { |
| inited = false; |
| hasBeenShutdownAtSomePoint = true; |
| } |
| |
| @Override |
| public void getDocIds(DocIdPusher pusher) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void getDocContent(Request req, Response resp) throws IOException { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| |
| private static class ModifiedConfig extends Config { |
| @Override |
| Reader createReader(File file) throws IOException { |
| return ((MockFile) file).createReader(); |
| } |
| } |
| } |