// Copyright 2011 Google Inc. // // 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.connector.pusher; import com.google.enterprise.connector.pusher.ExceptionalPusher; import com.google.enterprise.connector.pusher.ExceptionalPusher.Where; import com.google.enterprise.connector.pusher.Pusher.PusherStatus; import com.google.enterprise.connector.spi.Document; import com.google.enterprise.connector.spi.DocumentAcceptor; import com.google.enterprise.connector.spi.DocumentAcceptorException; import com.google.enterprise.connector.spi.RepositoryException; import com.google.enterprise.connector.test.ConnectorTestUtils; import com.google.enterprise.connector.traversal.MockLister; import com.google.enterprise.connector.util.SystemClock; import junit.framework.TestCase; import java.util.logging.Logger; /** * Tests for DocumentAcceptorImpl. */ public class DocumentAcceptorTest extends TestCase { private static final Logger LOGGER = Logger.getLogger(DocumentAcceptorTest.class.getName()); /** Test feeding a limited number of docs. */ public void testFeedDocs() throws Exception { String connectorName = getName(); MockPusher pusher = new MockPusher(); DocumentAcceptorImpl documentAcceptor = new DocumentAcceptorImpl(connectorName, pusher); MockLister lister = new MockLister(10, 0); lister.setDocumentAcceptor(documentAcceptor); // With no inter-document delay, MockLister feeds all documents // from its start() method, then returns when done. lister.start(); assertEquals(10, pusher.getTotalDocs()); } /** Test feeding more docs after a flush. */ public void testFeedAfterFlush() throws Exception { String connectorName = getName(); MockPusher pusher = new MockPusher(); DocumentAcceptorImpl documentAcceptor = new DocumentAcceptorImpl(connectorName, pusher); // Feed a couple of documents. assertEquals(0, pusher.getTotalDocs()); documentAcceptor.take(ConnectorTestUtils.createSimpleDocument("foo")); documentAcceptor.take(ConnectorTestUtils.createSimpleDocument("bar")); // Flush the feed. This shuts down the Pusher. assertEquals(PusherStatus.OK, pusher.getPusherStatus()); documentAcceptor.flush(); assertEquals(2, pusher.getTotalDocs()); assertEquals(PusherStatus.DISABLED, pusher.getPusherStatus()); // Feed another document. Should get a new Pusher. documentAcceptor.take(ConnectorTestUtils.createSimpleDocument("baz")); assertEquals(1, pusher.getTotalDocs()); assertEquals(PusherStatus.OK, pusher.getPusherStatus()); // Cancel that feed, without flushing. documentAcceptor.cancel(); assertEquals(0, pusher.getTotalDocs()); assertEquals(PusherStatus.DISABLED, pusher.getPusherStatus()); } /** * Test that if Pusher appears to be backlogged transmitting feeds, * (feeds backed up on this end of the FeedConnection), the DocumentAcceptor * waits a short period of time for the backlog to clear. */ public void testProximalFeedBacklog() throws Exception { testPusherStatus(PusherStatus.LOCAL_FEED_BACKLOG, 500L, 2000L, 1, 500L); testPusherStatus(PusherStatus.LOCAL_FEED_BACKLOG, 500L, 2000L, 2, 2 * 500L); } /** * Test that if GSA appears to be backlogged processing feeds, the * DocumentAcceptor waits a longer period of time for the backlog to clear. */ public void testDistalFeedBacklog() throws Exception { testPusherStatus(PusherStatus.GSA_FEED_BACKLOG, 250L, 750L, 1, 750L); testPusherStatus(PusherStatus.GSA_FEED_BACKLOG, 250L, 750L, 2, 2 * 750L); } /** * Test that if runtime environment seems to be running low on memory, the * DocumentAcceptor waits a short period of time for the low memory condition * to clear. */ public void testLowMemory() throws Exception { testPusherStatus(PusherStatus.LOW_MEMORY, 500L, 2000L, 1, 500L); testPusherStatus(PusherStatus.LOW_MEMORY, 500L, 2000L, 2, 2 * 500L); } private void testPusherStatus(PusherStatus status, long shortSleep, long longSleep, int retries, long expectedDelay) throws Exception { SystemClock clock = new SystemClock(); String connectorName = getName(); Document document = ConnectorTestUtils.createSimpleDocument("foo"); MockPusher pusher = new MockPusher(); DocumentAcceptorImpl documentAcceptor = new DocumentAcceptorImpl(connectorName, pusher); documentAcceptor.setSleepIntervals(shortSleep, longSleep, retries); // Initial document feed should go unimpeded. long startTime = clock.getTimeMillis(); documentAcceptor.take(document); long stopTime = clock.getTimeMillis(); assertEquals(1, pusher.getTotalDocs()); assertEquals(PusherStatus.OK, pusher.getPusherStatus()); assertTrue("Delay too long " + (stopTime - startTime), shortSleep > (stopTime - startTime)); // If pusher returns not-ready status, documentAcceptor should sleep. pusher.setPusherStatus(status); startTime = clock.getTimeMillis(); documentAcceptor.take(document); stopTime = clock.getTimeMillis(); assertEquals(2, pusher.getTotalDocs()); assertTrue("Delay " + (stopTime - startTime), expectedDelay <= (stopTime - startTime)); // Once the Pusher is OK, there should be no delays. pusher.setPusherStatus(PusherStatus.OK); startTime = clock.getTimeMillis(); documentAcceptor.take(document); stopTime = clock.getTimeMillis(); assertEquals(3, pusher.getTotalDocs()); assertTrue("Delay " + (stopTime - startTime), shortSleep > (stopTime - startTime)); } /** Test PushException in take(). */ public void testTakePushException() throws Exception { checkExceptionHandling(new PushException("TestPushException"), Where.TAKE); } /** Test FeedException in take(). */ public void testTakeFeedException() throws Exception { checkExceptionHandling(new FeedException("TestFeedException"), Where.TAKE); } /** Test RepositoryException in take(). */ public void testTakeRepositoryException() throws Exception { checkExceptionHandling(new RepositoryException("TestRepositoryException"), Where.TAKE); } /** Test RuntimeException in take(). */ public void testTakeRuntimeException() throws Exception { checkExceptionHandling(new RuntimeException("TestRuntimeException"), Where.TAKE); } /** Test PushException in flush(). */ public void testFlushPushException() throws Exception { checkExceptionHandling(new PushException("TestPushException"), Where.FLUSH); } /** Test FeedException in flush(). */ public void testFlushFeedException() throws Exception { checkExceptionHandling(new FeedException("TestFeedException"), Where.FLUSH); } /** Test RepositoryException in flush(). */ public void testFlushRepositoryException() throws Exception { checkExceptionHandling(new RepositoryException("TestRepositoryException"), Where.FLUSH); } /** Test RuntimeException in flush(). */ public void testFlushRuntimeException() throws Exception { checkExceptionHandling(new RuntimeException("TestRuntimeException"), Where.FLUSH); } /** Test PushException in cancel(). */ public void testCancelPushException() throws Exception { checkExceptionHandling(new PushException("TestPushException"), Where.CANCEL); } /** Test FeedException in cancel(). */ public void testCancelFeedException() throws Exception { checkExceptionHandling(new FeedException("TestFeedException"), Where.CANCEL); } /** Test RepositoryException in cancel(). */ public void testCancelRepositoryException() throws Exception { checkExceptionHandling(new RepositoryException("TestRepositoryException"), Where.CANCEL); } /** Test RuntimeException in cancel(). */ public void testCancelRuntimeException() throws Exception { checkExceptionHandling(new RuntimeException("TestRuntimeException"), Where.CANCEL); } private void checkExceptionHandling(Exception exception, Where where) throws Exception { ExceptionalPusher pusher = new ExceptionalPusher(exception, where); String connectorName = getName(); DocumentAcceptorImpl documentAcceptor = new DocumentAcceptorImpl(connectorName, pusher); // Test take(). try { documentAcceptor.take(ConnectorTestUtils.createSimpleDocument("testDoc")); assertFalse("Expected Exception", (where == Where.TAKE)); } catch (Exception e) { assertTrue("Unexpected Exception", (where == Where.TAKE)); if (exception instanceof PushException) { assertEquals(DocumentAcceptorException.class, e.getClass()); assertEquals(PushException.class, e.getCause().getClass()); } else if (exception instanceof FeedException) { assertEquals(DocumentAcceptorException.class, e.getClass()); assertEquals(FeedException.class, e.getCause().getClass()); } else if (exception instanceof RuntimeException) { assertEquals(RuntimeException.class, e.getClass()); } else { assertEquals(RepositoryException.class, e.getClass()); } } // Test flush(). try { documentAcceptor.flush(); assertFalse("Expected Exception", (where == Where.FLUSH)); } catch (Exception e) { assertTrue("Unexpected Exception", (where == Where.FLUSH)); if (exception instanceof PushException) { assertEquals(DocumentAcceptorException.class, e.getClass()); assertEquals(PushException.class, e.getCause().getClass()); } else if (exception instanceof FeedException) { assertEquals(DocumentAcceptorException.class, e.getClass()); assertEquals(FeedException.class, e.getCause().getClass()); } else if (exception instanceof RuntimeException) { assertEquals(RuntimeException.class, e.getClass()); } else { assertEquals(RepositoryException.class, e.getClass()); } } // Test take() again after flush(). try { documentAcceptor.take(ConnectorTestUtils.createSimpleDocument("testDoc")); assertFalse("Expected Exception", (where == Where.TAKE)); } catch (Exception e) { assertTrue("Unexpected Exception", (where == Where.TAKE)); if (exception instanceof PushException) { assertEquals(DocumentAcceptorException.class, e.getClass()); assertEquals(PushException.class, e.getCause().getClass()); } else if (exception instanceof FeedException) { assertEquals(DocumentAcceptorException.class, e.getClass()); assertEquals(FeedException.class, e.getCause().getClass()); } else if (exception instanceof RuntimeException) { assertEquals(RuntimeException.class, e.getClass()); } else { assertEquals(RepositoryException.class, e.getClass()); } } // Test cancel(). try { documentAcceptor.cancel(); assertFalse("Expected Exception", (where == Where.CANCEL)); } catch (Exception e) { assertTrue("Unexpected Exception", (where == Where.CANCEL)); assertEquals(RuntimeException.class, e.getClass()); } } }