| /* |
| * Copyright (c) 2012, the Dart project authors. |
| * |
| * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html |
| * |
| * 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.dart.engine.internal.index.operation; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Lists; |
| import com.google.dart.engine.AnalysisEngine; |
| import com.google.dart.engine.EngineTestCase; |
| import com.google.dart.engine.source.Source; |
| import com.google.dart.engine.utilities.logging.Logger; |
| |
| import org.mockito.invocation.InvocationOnMock; |
| import org.mockito.stubbing.Answer; |
| |
| import static org.mockito.Matchers.anyInt; |
| import static org.mockito.Matchers.anyString; |
| import static org.mockito.Matchers.same; |
| import static org.mockito.Mockito.doAnswer; |
| import static org.mockito.Mockito.doThrow; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.Set; |
| import java.util.concurrent.CountDownLatch; |
| |
| public class OperationProcessorTest extends EngineTestCase { |
| |
| /** |
| * Runs given {@link OperationProcessor} in thread. |
| */ |
| private static Source[] runOperationProcessor(IndexOperation beforeStopOperations[], |
| boolean waitStop, IndexOperation afterStopOperations[]) throws Exception { |
| final CountDownLatch stopLatch = new CountDownLatch(1); |
| // prepare operations |
| final LinkedList<IndexOperation> operations; |
| { |
| operations = Lists.newLinkedList(); |
| Collections.addAll(operations, beforeStopOperations); |
| // |
| IndexOperation stopOperation = mock(IndexOperation.class); |
| doAnswer(new Answer<Void>() { |
| @Override |
| public Void answer(InvocationOnMock invocation) throws Throwable { |
| stopLatch.countDown(); |
| return null; |
| } |
| }).when(stopOperation).performOperation(); |
| operations.add(stopOperation); |
| } |
| // prepare OperationQueue to return elements from "operations" |
| OperationQueue queue = mock(OperationQueue.class); |
| when(queue.dequeue(anyInt())).then(new Answer<IndexOperation>() { |
| @Override |
| public IndexOperation answer(InvocationOnMock invocation) throws Throwable { |
| if (!operations.isEmpty()) { |
| return operations.removeFirst(); |
| } |
| return null; |
| } |
| }); |
| when(queue.getOperations()).thenReturn(Arrays.asList(afterStopOperations)); |
| // run OperationProcessor |
| final OperationProcessor processor = new OperationProcessor(queue); |
| new Thread() { |
| @Override |
| public void run() { |
| processor.run(); |
| } |
| }.start(); |
| // wait for stop |
| stopLatch.await(); |
| return processor.stop(waitStop); |
| } |
| |
| public void test_performOperation() throws Exception { |
| IndexOperation operation = mock(IndexOperation.class); |
| runOperationProcessor(new IndexOperation[] {operation}, false, new IndexOperation[] {}); |
| verify(operation).performOperation(); |
| } |
| |
| public void test_performOperation_throwException() throws Exception { |
| Logger oldLogger = AnalysisEngine.getInstance().getLogger(); |
| try { |
| NullPointerException myException = new NullPointerException(); |
| IndexOperation operation = mock(IndexOperation.class); |
| doThrow(myException).when(operation).performOperation(); |
| // set mock Logger |
| Logger logger = mock(Logger.class); |
| AnalysisEngine.getInstance().setLogger(logger); |
| // run processor |
| runOperationProcessor(new IndexOperation[] {operation}, false, new IndexOperation[] {}); |
| // verify that "myException" was logged |
| verify(logger).logError(anyString(), same(myException)); |
| } finally { |
| AnalysisEngine.getInstance().setLogger(oldLogger); |
| } |
| } |
| |
| public void test_run_afterStop() throws Exception { |
| OperationQueue queue = mock(OperationQueue.class); |
| OperationProcessor processor = new OperationProcessor(queue); |
| processor.stop(false); |
| try { |
| processor.run(); |
| fail(); |
| } catch (IllegalStateException e) { |
| } |
| } |
| |
| public void test_run_InterruptedException() throws Exception { |
| final IndexOperation operation = mock(IndexOperation.class); |
| final OperationQueue queue = mock(OperationQueue.class); |
| final OperationProcessor processor = new OperationProcessor(queue); |
| when(queue.dequeue(anyInt())).then(new Answer<IndexOperation>() { |
| int num = 0; |
| |
| @Override |
| public IndexOperation answer(InvocationOnMock invocation) throws Throwable { |
| num++; |
| if (num == 1) { |
| throw new InterruptedException(); |
| } |
| if (num == 2) { |
| return operation; |
| } |
| processor.stop(false); |
| return null; |
| } |
| }); |
| // run processor |
| Thread thread = new Thread() { |
| @Override |
| public void run() { |
| processor.run(); |
| } |
| }; |
| thread.start(); |
| thread.join(); |
| // operation should be performed |
| verify(operation).performOperation(); |
| } |
| |
| public void test_stop_returnsNotIndexed_wasReady() throws Exception { |
| Source source = mock(Source.class); |
| IndexUnitOperation operation = mock(IndexUnitOperation.class); |
| OperationQueue queue = mock(OperationQueue.class); |
| when(operation.getSource()).thenReturn(source); |
| when(queue.getOperations()).thenReturn(ImmutableList.<IndexOperation> of(operation)); |
| // stop processor |
| OperationProcessor processor = new OperationProcessor(queue); |
| Source[] sources = processor.stop(false); |
| assertExactElementsInArray(sources, new Object[] {source}); |
| } |
| |
| public void test_stop_returnsNotIndexed_wasRunning() throws Exception { |
| Source source1 = mock(Source.class); |
| Source source2 = mock(Source.class); |
| IndexUnitOperation operation1 = mock(IndexUnitOperation.class); |
| IndexUnitOperation operation2 = mock(IndexUnitOperation.class); |
| when(operation1.getSource()).thenReturn(source1); |
| when(operation2.getSource()).thenReturn(source2); |
| // run processor |
| Source[] sources = runOperationProcessor(new IndexOperation[] {}, true, new IndexOperation[] { |
| operation1, operation2}); |
| Set<Source> sourceSet = ImmutableSet.copyOf(sources); |
| assertExactElementsInSet(sourceSet, new Object[] {source1, source2}); |
| } |
| |
| public void test_stop_returnsNotIndexed_wasStopped() throws Exception { |
| Source source = mock(Source.class); |
| IndexUnitOperation operation = mock(IndexUnitOperation.class); |
| OperationQueue queue = mock(OperationQueue.class); |
| when(operation.getSource()).thenReturn(source); |
| when(queue.getOperations()).thenReturn(ImmutableList.<IndexOperation> of(operation)); |
| // stop processor |
| OperationProcessor processor = new OperationProcessor(queue); |
| processor.stop(false); |
| Source[] sources = processor.stop(false); |
| assertExactElementsInArray(sources, new Object[] {source}); |
| } |
| |
| public void test_waitForRunning() throws Exception { |
| OperationQueue queue = mock(OperationQueue.class); |
| when(queue.getOperations()).thenReturn(ImmutableList.<IndexOperation> of()); |
| // start processor |
| final OperationProcessor processor = new OperationProcessor(queue); |
| new Thread() { |
| @Override |
| public void run() { |
| processor.run(); |
| } |
| }.start(); |
| assertEquals(true, processor.waitForRunning()); |
| // stop |
| processor.stop(true); |
| // cannot wait for "running" again |
| assertEquals(false, processor.waitForRunning()); |
| } |
| } |