1 /* 2 * Copyright (C) 2015 Google, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package producerstest.monitoring; 17 18 import com.google.common.base.Throwables; 19 import com.google.common.collect.ImmutableList; 20 import com.google.common.util.concurrent.ListenableFuture; 21 import com.google.common.util.concurrent.MoreExecutors; 22 import com.google.common.util.concurrent.SettableFuture; 23 import dagger.producers.monitoring.ProducerMonitor; 24 import dagger.producers.monitoring.ProducerToken; 25 import dagger.producers.monitoring.ProductionComponentMonitor; 26 import java.util.LinkedHashMap; 27 import java.util.Map; 28 import java.util.concurrent.ExecutionException; 29 import org.junit.Before; 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 import org.junit.runners.JUnit4; 33 import org.mockito.InOrder; 34 import org.mockito.Mock; 35 import org.mockito.MockitoAnnotations; 36 37 import static com.google.common.truth.Truth.assertThat; 38 import static org.junit.Assert.fail; 39 import static org.mockito.Mockito.any; 40 import static org.mockito.Mockito.inOrder; 41 import static org.mockito.Mockito.mock; 42 import static org.mockito.Mockito.verifyNoMoreInteractions; 43 import static org.mockito.Mockito.when; 44 45 /** Tests for production components using monitoring. */ 46 @RunWith(JUnit4.class) 47 public final class MonitoringTest { 48 @Mock private ProductionComponentMonitor.Factory componentMonitorFactory; 49 @Mock private StringStub server1; 50 @Mock private StringStub server2; 51 private SettableFuture<String> server1Future; 52 private SettableFuture<String> server2Future; 53 private FakeProductionComponentMonitor componentMonitor; 54 55 @Before 56 public void setUp() { 57 MockitoAnnotations.initMocks(this); 58 componentMonitor = new FakeProductionComponentMonitor(); 59 when(componentMonitorFactory.create(any())).thenReturn(componentMonitor); 60 server1Future = SettableFuture.create(); 61 server2Future = SettableFuture.create(); 62 when(server1.run(any(String.class))).thenReturn(server1Future); 63 when(server2.run(any(String.class))).thenReturn(server2Future); 64 } 65 66 @Test 67 public void basicMonitoring() throws Exception { 68 MonitoredComponent component = 69 DaggerMonitoredComponent.builder() 70 .executor(MoreExecutors.directExecutor()) 71 .monitoringModule(new MonitoringModule(componentMonitorFactory)) 72 .stubModule(new StubModule(server1, server2)) 73 .build(); 74 ListenableFuture<String> output = component.output(); 75 assertThat(componentMonitor.monitors).hasSize(3); 76 ImmutableList<Map.Entry<ProducerToken, ProducerMonitor>> entries = 77 ImmutableList.copyOf(componentMonitor.monitors.entrySet()); 78 assertThat(entries.get(0).getKey().toString()).contains("CallServer2"); 79 assertThat(entries.get(1).getKey().toString()).contains("CallServer1"); 80 assertThat(entries.get(2).getKey().toString()).contains("RequestData"); 81 82 ProducerMonitor callServer2Monitor = entries.get(0).getValue(); 83 ProducerMonitor callServer1Monitor = entries.get(1).getValue(); 84 ProducerMonitor requestDataMonitor = entries.get(2).getValue(); 85 86 InOrder inOrder = inOrder(requestDataMonitor, callServer1Monitor, callServer2Monitor); 87 inOrder.verify(requestDataMonitor).methodStarting(); 88 inOrder.verify(requestDataMonitor).methodFinished(); 89 inOrder.verify(requestDataMonitor).succeeded("Hello, World!"); 90 inOrder.verify(callServer1Monitor).methodStarting(); 91 inOrder.verify(callServer1Monitor).methodFinished(); 92 verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); 93 94 server1Future.set("server 1 response"); 95 inOrder.verify(callServer1Monitor).succeeded("server 1 response"); 96 inOrder.verify(callServer2Monitor).methodStarting(); 97 inOrder.verify(callServer2Monitor).methodFinished(); 98 verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); 99 100 server2Future.set("server 2 response"); 101 inOrder.verify(callServer2Monitor).succeeded("server 2 response"); 102 verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); 103 assertThat(output.get()).isEqualTo("server 2 response"); 104 } 105 106 @Test 107 public void basicMonitoringWithFailure() throws Exception { 108 MonitoredComponent component = 109 DaggerMonitoredComponent.builder() 110 .executor(MoreExecutors.directExecutor()) 111 .monitoringModule(new MonitoringModule(componentMonitorFactory)) 112 .stubModule(new StubModule(server1, server2)) 113 .build(); 114 ListenableFuture<String> output = component.output(); 115 assertThat(componentMonitor.monitors).hasSize(3); 116 ImmutableList<Map.Entry<ProducerToken, ProducerMonitor>> entries = 117 ImmutableList.copyOf(componentMonitor.monitors.entrySet()); 118 assertThat(entries.get(0).getKey().toString()).contains("CallServer2"); 119 assertThat(entries.get(1).getKey().toString()).contains("CallServer1"); 120 assertThat(entries.get(2).getKey().toString()).contains("RequestData"); 121 122 ProducerMonitor callServer2Monitor = entries.get(0).getValue(); 123 ProducerMonitor callServer1Monitor = entries.get(1).getValue(); 124 ProducerMonitor requestDataMonitor = entries.get(2).getValue(); 125 126 InOrder inOrder = inOrder(requestDataMonitor, callServer1Monitor, callServer2Monitor); 127 inOrder.verify(requestDataMonitor).methodStarting(); 128 inOrder.verify(requestDataMonitor).methodFinished(); 129 inOrder.verify(requestDataMonitor).succeeded("Hello, World!"); 130 inOrder.verify(callServer1Monitor).methodStarting(); 131 inOrder.verify(callServer1Monitor).methodFinished(); 132 verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); 133 134 RuntimeException cause = new RuntimeException("monkey"); 135 server1Future.setException(cause); 136 inOrder.verify(callServer1Monitor).failed(cause); 137 inOrder.verify(callServer2Monitor).failed(any(Throwable.class)); 138 verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor); 139 try { 140 output.get(); 141 fail(); 142 } catch (ExecutionException e) { 143 assertThat(Throwables.getRootCause(e)).isSameAs(cause); 144 } 145 } 146 147 private static final class FakeProductionComponentMonitor implements ProductionComponentMonitor { 148 final Map<ProducerToken, ProducerMonitor> monitors = new LinkedHashMap<>(); 149 150 @Override 151 public ProducerMonitor producerMonitorFor(ProducerToken token) { 152 ProducerMonitor monitor = mock(ProducerMonitor.class); 153 monitors.put(token, monitor); 154 return monitor; 155 } 156 } 157 } 158