1 /*
2  * Copyright (C) 2015 The Dagger Authors.
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 
17 package dagger.producers.monitoring;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.ArgumentMatchers.anyLong;
22 import static org.mockito.ArgumentMatchers.nullable;
23 import static org.mockito.Mockito.doThrow;
24 import static org.mockito.Mockito.inOrder;
25 import static org.mockito.Mockito.verifyNoMoreInteractions;
26 import static org.mockito.Mockito.when;
27 
28 import com.google.common.collect.ImmutableList;
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 @RunWith(JUnit4.class)
38 public final class TimingRecordersTest {
39   @Mock
40   private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactory;
41 
42   @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorder;
43   @Mock private ProducerTimingRecorder mockProducerTimingRecorder;
44 
45   @Mock
46   private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactoryA;
47 
48   @Mock
49   private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactoryB;
50 
51   @Mock
52   private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactoryC;
53 
54   @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorderA;
55   @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorderB;
56   @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorderC;
57   @Mock private ProducerTimingRecorder mockProducerTimingRecorderA;
58   @Mock private ProducerTimingRecorder mockProducerTimingRecorderB;
59   @Mock private ProducerTimingRecorder mockProducerTimingRecorderC;
60 
61   @Before
initMocks()62   public void initMocks() {
63     MockitoAnnotations.initMocks(this);
64   }
65 
66   @Test
zeroRecordersReturnsNoOp()67   public void zeroRecordersReturnsNoOp() {
68     ProductionComponentTimingRecorder.Factory factory =
69         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
70             ImmutableList.<ProductionComponentTimingRecorder.Factory>of());
71     assertThat(factory)
72         .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorderFactory());
73   }
74 
75   @Test
singleRecorder_nullProductionComponentTimingRecorder()76   public void singleRecorder_nullProductionComponentTimingRecorder() {
77     when(mockProductionComponentTimingRecorderFactory.create(any(Object.class))).thenReturn(null);
78     ProductionComponentTimingRecorder.Factory factory =
79         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
80             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
81     assertThat(factory.create(new Object()))
82         .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
83   }
84 
85   @Test
singleRecorder_throwingProductionComponentTimingRecorderFactory()86   public void singleRecorder_throwingProductionComponentTimingRecorderFactory() {
87     when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
88         .thenThrow(new RuntimeException("monkey"));
89     ProductionComponentTimingRecorder.Factory factory =
90         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
91             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
92     assertThat(factory.create(new Object()))
93         .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
94   }
95 
96   @Test
singleRecorder_nullProducerTimingRecorder()97   public void singleRecorder_nullProducerTimingRecorder() {
98     when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
99         .thenReturn(mockProductionComponentTimingRecorder);
100     when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(
101             nullable(ProducerToken.class)))
102         .thenReturn(null);
103     ProductionComponentTimingRecorder.Factory factory =
104         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
105             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
106     ProductionComponentTimingRecorder recorder = factory.create(new Object());
107     assertThat(recorder.producerTimingRecorderFor(ProducerToken.create(Object.class)))
108         .isSameInstanceAs(ProducerTimingRecorder.noOp());
109   }
110 
111   @Test
singleRecorder_throwingProductionComponentTimingRecorder()112   public void singleRecorder_throwingProductionComponentTimingRecorder() {
113     when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
114         .thenReturn(mockProductionComponentTimingRecorder);
115     when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(
116             nullable(ProducerToken.class)))
117         .thenThrow(new RuntimeException("monkey"));
118     ProductionComponentTimingRecorder.Factory factory =
119         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
120             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
121     ProductionComponentTimingRecorder recorder = factory.create(new Object());
122     assertThat(recorder.producerTimingRecorderFor(ProducerToken.create(Object.class)))
123         .isSameInstanceAs(ProducerTimingRecorder.noOp());
124   }
125 
126   @Test
singleRecorder_normalProducerTimingRecorderSuccess()127   public void singleRecorder_normalProducerTimingRecorderSuccess() {
128     setUpNormalSingleRecorder();
129     ProductionComponentTimingRecorder.Factory factory =
130         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
131             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
132     ProductionComponentTimingRecorder recorder = factory.create(new Object());
133     ProducerTimingRecorder producerTimingRecorder =
134         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
135     producerTimingRecorder.recordMethod(15, 42);
136     producerTimingRecorder.recordSuccess(100);
137 
138     InOrder order = inOrder(mockProducerTimingRecorder);
139     order.verify(mockProducerTimingRecorder).recordMethod(15, 42);
140     order.verify(mockProducerTimingRecorder).recordSuccess(100);
141     verifyNoMoreInteractions(mockProducerTimingRecorder);
142   }
143 
144   @Test
singleRecorder_normalProducerTimingRecorderFailure()145   public void singleRecorder_normalProducerTimingRecorderFailure() {
146     setUpNormalSingleRecorder();
147     ProductionComponentTimingRecorder.Factory factory =
148         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
149             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
150     ProductionComponentTimingRecorder recorder = factory.create(new Object());
151     ProducerTimingRecorder producerTimingRecorder =
152         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
153     Throwable t = new RuntimeException("monkey");
154     producerTimingRecorder.recordMethod(15, 42);
155     producerTimingRecorder.recordFailure(t, 100);
156 
157     InOrder order = inOrder(mockProducerTimingRecorder);
158     order.verify(mockProducerTimingRecorder).recordMethod(15, 42);
159     order.verify(mockProducerTimingRecorder).recordFailure(t, 100);
160     verifyNoMoreInteractions(mockProducerTimingRecorder);
161   }
162 
163   @Test
singleRecorder_throwingProducerTimingRecorderSuccess()164   public void singleRecorder_throwingProducerTimingRecorderSuccess() {
165     setUpNormalSingleRecorder();
166     doThrow(new RuntimeException("monkey"))
167         .when(mockProducerTimingRecorder)
168         .recordMethod(anyLong(), anyLong());
169     doThrow(new RuntimeException("monkey"))
170         .when(mockProducerTimingRecorder)
171         .recordSuccess(anyLong());
172     ProductionComponentTimingRecorder.Factory factory =
173         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
174             ImmutableList.of(mockProductionComponentTimingRecorderFactory));
175     ProductionComponentTimingRecorder recorder = factory.create(new Object());
176     ProducerTimingRecorder producerTimingRecorder =
177         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
178     producerTimingRecorder.recordMethod(15, 42);
179     producerTimingRecorder.recordSuccess(100);
180 
181     InOrder order = inOrder(mockProducerTimingRecorder);
182     order.verify(mockProducerTimingRecorder).recordMethod(15, 42);
183     order.verify(mockProducerTimingRecorder).recordSuccess(100);
184     verifyNoMoreInteractions(mockProducerTimingRecorder);
185   }
186 
187   @Test
multipleRecorders_nullProductionComponentTimingRecorders()188   public void multipleRecorders_nullProductionComponentTimingRecorders() {
189     when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class))).thenReturn(null);
190     when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class))).thenReturn(null);
191     when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class))).thenReturn(null);
192     ProductionComponentTimingRecorder.Factory factory =
193         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
194             ImmutableList.of(
195                 mockProductionComponentTimingRecorderFactoryA,
196                 mockProductionComponentTimingRecorderFactoryB,
197                 mockProductionComponentTimingRecorderFactoryC));
198     assertThat(factory.create(new Object()))
199         .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
200   }
201 
202   @Test
multipleRecorders_throwingProductionComponentTimingRecorderFactories()203   public void multipleRecorders_throwingProductionComponentTimingRecorderFactories() {
204     when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
205         .thenThrow(new RuntimeException("monkey"));
206     when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class)))
207         .thenThrow(new RuntimeException("monkey"));
208     when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
209         .thenThrow(new RuntimeException("monkey"));
210     ProductionComponentTimingRecorder.Factory factory =
211         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
212             ImmutableList.of(
213                 mockProductionComponentTimingRecorderFactoryA,
214                 mockProductionComponentTimingRecorderFactoryB,
215                 mockProductionComponentTimingRecorderFactoryC));
216     assertThat(factory.create(new Object()))
217         .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
218   }
219 
220   @Test
multipleRecorders_someNullProductionComponentTimingRecorders()221   public void multipleRecorders_someNullProductionComponentTimingRecorders() {
222     when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
223         .thenReturn(mockProductionComponentTimingRecorderA);
224     when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class))).thenReturn(null);
225     when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class))).thenReturn(null);
226     when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(
227             nullable(ProducerToken.class)))
228         .thenReturn(mockProducerTimingRecorderA);
229     ProductionComponentTimingRecorder.Factory factory =
230         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
231             ImmutableList.of(
232                 mockProductionComponentTimingRecorderFactoryA,
233                 mockProductionComponentTimingRecorderFactoryB,
234                 mockProductionComponentTimingRecorderFactoryC));
235     ProductionComponentTimingRecorder recorder = factory.create(new Object());
236     ProducerTimingRecorder producerTimingRecorder =
237         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
238 
239     producerTimingRecorder.recordMethod(15, 42);
240     producerTimingRecorder.recordSuccess(100);
241 
242     InOrder order = inOrder(mockProducerTimingRecorderA);
243     order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
244     order.verify(mockProducerTimingRecorderA).recordSuccess(100);
245     verifyNoMoreInteractions(mockProducerTimingRecorderA);
246   }
247 
248   @Test
multipleRecorders_someThrowingProductionComponentTimingRecorderFactories()249   public void multipleRecorders_someThrowingProductionComponentTimingRecorderFactories() {
250     when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
251         .thenReturn(mockProductionComponentTimingRecorderA);
252     when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class)))
253         .thenThrow(new RuntimeException("monkey"));
254     when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
255         .thenThrow(new RuntimeException("monkey"));
256     when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(
257             nullable(ProducerToken.class)))
258         .thenReturn(mockProducerTimingRecorderA);
259     ProductionComponentTimingRecorder.Factory factory =
260         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
261             ImmutableList.of(
262                 mockProductionComponentTimingRecorderFactoryA,
263                 mockProductionComponentTimingRecorderFactoryB,
264                 mockProductionComponentTimingRecorderFactoryC));
265     ProductionComponentTimingRecorder recorder = factory.create(new Object());
266     ProducerTimingRecorder producerTimingRecorder =
267         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
268 
269     producerTimingRecorder.recordMethod(15, 42);
270     producerTimingRecorder.recordSuccess(100);
271 
272     InOrder order = inOrder(mockProducerTimingRecorderA);
273     order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
274     order.verify(mockProducerTimingRecorderA).recordSuccess(100);
275     verifyNoMoreInteractions(mockProducerTimingRecorderA);
276   }
277 
278   @Test
multipleRecorders_normalProductionComponentTimingRecorderSuccess()279   public void multipleRecorders_normalProductionComponentTimingRecorderSuccess() {
280     setUpNormalMultipleRecorders();
281     ProductionComponentTimingRecorder.Factory factory =
282         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
283             ImmutableList.of(
284                 mockProductionComponentTimingRecorderFactoryA,
285                 mockProductionComponentTimingRecorderFactoryB,
286                 mockProductionComponentTimingRecorderFactoryC));
287     ProductionComponentTimingRecorder recorder = factory.create(new Object());
288     ProducerTimingRecorder producerTimingRecorder =
289         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
290 
291     producerTimingRecorder.recordMethod(15, 42);
292     producerTimingRecorder.recordSuccess(100);
293 
294     InOrder order =
295         inOrder(
296             mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
297     order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
298     order.verify(mockProducerTimingRecorderB).recordMethod(15, 42);
299     order.verify(mockProducerTimingRecorderC).recordMethod(15, 42);
300     order.verify(mockProducerTimingRecorderA).recordSuccess(100);
301     order.verify(mockProducerTimingRecorderB).recordSuccess(100);
302     order.verify(mockProducerTimingRecorderC).recordSuccess(100);
303     verifyNoMoreInteractions(
304         mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
305   }
306 
307   @Test
multipleRecorders_someThrowingProducerTimingRecordersSuccess()308   public void multipleRecorders_someThrowingProducerTimingRecordersSuccess() {
309     setUpNormalMultipleRecorders();
310     doThrow(new RuntimeException("monkey"))
311         .when(mockProducerTimingRecorderA)
312         .recordMethod(anyLong(), anyLong());
313     doThrow(new RuntimeException("monkey"))
314         .when(mockProducerTimingRecorderB)
315         .recordSuccess(anyLong());
316     doThrow(new RuntimeException("monkey"))
317         .when(mockProducerTimingRecorderC)
318         .recordMethod(anyLong(), anyLong());
319     ProductionComponentTimingRecorder.Factory factory =
320         TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
321             ImmutableList.of(
322                 mockProductionComponentTimingRecorderFactoryA,
323                 mockProductionComponentTimingRecorderFactoryB,
324                 mockProductionComponentTimingRecorderFactoryC));
325     ProductionComponentTimingRecorder recorder = factory.create(new Object());
326     ProducerTimingRecorder producerTimingRecorder =
327         recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
328 
329     producerTimingRecorder.recordMethod(15, 42);
330     producerTimingRecorder.recordSuccess(100);
331 
332     InOrder order =
333         inOrder(
334             mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
335     order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
336     order.verify(mockProducerTimingRecorderB).recordMethod(15, 42);
337     order.verify(mockProducerTimingRecorderC).recordMethod(15, 42);
338     order.verify(mockProducerTimingRecorderA).recordSuccess(100);
339     order.verify(mockProducerTimingRecorderB).recordSuccess(100);
340     order.verify(mockProducerTimingRecorderC).recordSuccess(100);
341     verifyNoMoreInteractions(
342         mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
343   }
344 
setUpNormalSingleRecorder()345   private void setUpNormalSingleRecorder() {
346     when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
347         .thenReturn(mockProductionComponentTimingRecorder);
348     when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(
349             nullable(ProducerToken.class)))
350         .thenReturn(mockProducerTimingRecorder);
351   }
352 
setUpNormalMultipleRecorders()353   private void setUpNormalMultipleRecorders() {
354     when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
355         .thenReturn(mockProductionComponentTimingRecorderA);
356     when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class)))
357         .thenReturn(mockProductionComponentTimingRecorderB);
358     when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
359         .thenReturn(mockProductionComponentTimingRecorderC);
360     when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(
361             nullable(ProducerToken.class)))
362         .thenReturn(mockProducerTimingRecorderA);
363     when(mockProductionComponentTimingRecorderB.producerTimingRecorderFor(
364             nullable(ProducerToken.class)))
365         .thenReturn(mockProducerTimingRecorderB);
366     when(mockProductionComponentTimingRecorderC.producerTimingRecorderFor(
367             nullable(ProducerToken.class)))
368         .thenReturn(mockProducerTimingRecorderC);
369   }
370 }
371