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.functional.producers;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.fail;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Mockito.inOrder;
23 import static org.mockito.Mockito.when;
24 
25 import com.google.common.util.concurrent.ListenableFuture;
26 import com.google.common.util.concurrent.MoreExecutors;
27 import com.google.common.util.concurrent.SettableFuture;
28 import dagger.producers.Producer;
29 import dagger.producers.internal.AbstractProducer;
30 import dagger.producers.internal.CancellableProducer;
31 import dagger.producers.monitoring.ProducerMonitor;
32 import dagger.producers.monitoring.ProducerToken;
33 import dagger.producers.monitoring.ProductionComponentMonitor;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.Executor;
36 import javax.inject.Provider;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.junit.runners.JUnit4;
41 import org.mockito.InOrder;
42 import org.mockito.Mock;
43 import org.mockito.Mockito;
44 import org.mockito.MockitoAnnotations;
45 
46 @RunWith(JUnit4.class)
47 public class ProducerFactoryTest {
48   @Mock private ProductionComponentMonitor componentMonitor;
49   private ProducerMonitor monitor;
50   private Provider<Executor> executorProvider;
51   private Provider<ProductionComponentMonitor> componentMonitorProvider;
52 
53   @Before
setUpMocks()54   public void setUpMocks() {
55     MockitoAnnotations.initMocks(this);
56     monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
57     when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
58     // TODO(beder): Use Providers.of when available.
59     executorProvider =
60         new Provider<Executor>() {
61           @Override
62           public Executor get() {
63             return MoreExecutors.directExecutor();
64           }
65         };
66     componentMonitorProvider =
67         new Provider<ProductionComponentMonitor>() {
68           @Override
69           public ProductionComponentMonitor get() {
70             return componentMonitor;
71           }
72         };
73   }
74 
75   @Test
noArgMethod()76   public void noArgMethod() throws Exception {
77     ProducerToken token = ProducerToken.create(SimpleProducerModule_StrFactory.class);
78     Producer<String> producer =
79         SimpleProducerModule_StrFactory.create(executorProvider, componentMonitorProvider);
80     assertThat(producer.get().get()).isEqualTo("str");
81     InOrder order = inOrder(componentMonitor, monitor);
82     order.verify(componentMonitor).producerMonitorFor(token);
83     order.verify(monitor).methodStarting();
84     order.verify(monitor).methodFinished();
85     order.verify(monitor).succeeded("str");
86     order.verifyNoMoreInteractions();
87   }
88 
89   @Test
singleArgMethod()90   public void singleArgMethod() throws Exception {
91     SettableFuture<Integer> intFuture = SettableFuture.create();
92     CancellableProducer<Integer> intProducer = producerOfFuture(intFuture);
93     Producer<String> producer =
94         SimpleProducerModule_StrWithArgFactory.create(
95             executorProvider, componentMonitorProvider, intProducer);
96     assertThat(producer.get().isDone()).isFalse();
97     intFuture.set(42);
98     assertThat(producer.get().get()).isEqualTo("str with arg");
99   }
100 
101   @Test
successMonitor()102   public void successMonitor() throws Exception {
103     ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
104 
105     SettableFuture<String> strFuture = SettableFuture.create();
106     @SuppressWarnings("FutureReturnValueIgnored")
107     SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
108     CancellableProducer<SettableFuture<String>> strFutureProducer =
109         producerOfFuture(strFutureFuture);
110     Producer<String> producer =
111         SimpleProducerModule_SettableFutureStrFactory.create(
112             executorProvider, componentMonitorProvider, strFutureProducer);
113     assertThat(producer.get().isDone()).isFalse();
114 
115     InOrder order = inOrder(componentMonitor, monitor);
116     order.verify(componentMonitor).producerMonitorFor(token);
117 
118     strFutureFuture.set(strFuture);
119     order.verify(monitor).methodStarting();
120     order.verify(monitor).methodFinished();
121     assertThat(producer.get().isDone()).isFalse();
122 
123     strFuture.set("monkey");
124     assertThat(producer.get().get()).isEqualTo("monkey");
125     order.verify(monitor).succeeded("monkey");
126 
127     order.verifyNoMoreInteractions();
128   }
129 
130   @Test
failureMonitor()131   public void failureMonitor() throws Exception {
132     ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
133 
134     SettableFuture<String> strFuture = SettableFuture.create();
135     @SuppressWarnings("FutureReturnValueIgnored")
136     SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
137     CancellableProducer<SettableFuture<String>> strFutureProducer =
138         producerOfFuture(strFutureFuture);
139     Producer<String> producer =
140         SimpleProducerModule_SettableFutureStrFactory.create(
141             executorProvider, componentMonitorProvider, strFutureProducer);
142     assertThat(producer.get().isDone()).isFalse();
143 
144     InOrder order = inOrder(componentMonitor, monitor);
145     order.verify(componentMonitor).producerMonitorFor(token);
146 
147     strFutureFuture.set(strFuture);
148     order.verify(monitor).methodStarting();
149     order.verify(monitor).methodFinished();
150     assertThat(producer.get().isDone()).isFalse();
151 
152     Throwable t = new RuntimeException("monkey");
153     strFuture.setException(t);
154     try {
155       producer.get().get();
156       fail();
157     } catch (ExecutionException e) {
158       assertThat(e).hasCauseThat().isSameInstanceAs(t);
159       order.verify(monitor).failed(t);
160     }
161 
162     order.verifyNoMoreInteractions();
163   }
164 
165   @Test
failureMonitorDueToThrowingProducer()166   public void failureMonitorDueToThrowingProducer() throws Exception {
167     ProducerToken token = ProducerToken.create(SimpleProducerModule_ThrowingProducerFactory.class);
168 
169     Producer<String> producer =
170         SimpleProducerModule_ThrowingProducerFactory.create(
171             executorProvider, componentMonitorProvider);
172     assertThat(producer.get().isDone()).isTrue();
173 
174     InOrder order = inOrder(componentMonitor, monitor);
175     order.verify(componentMonitor).producerMonitorFor(token);
176 
177     order.verify(monitor).methodStarting();
178     order.verify(monitor).methodFinished();
179 
180     try {
181       producer.get().get();
182       fail();
183     } catch (ExecutionException e) {
184       order.verify(monitor).failed(e.getCause());
185     }
186 
187     order.verifyNoMoreInteractions();
188   }
189 
190   @Test(expected = NullPointerException.class)
nullComponentMonitorProvider()191   public void nullComponentMonitorProvider() throws Exception {
192     SimpleProducerModule_StrFactory.create(executorProvider, null);
193   }
194 
producerOfFuture(final ListenableFuture<T> future)195   private static <T> CancellableProducer<T> producerOfFuture(final ListenableFuture<T> future) {
196     return new AbstractProducer<T>() {
197       @Override
198       public ListenableFuture<T> compute() {
199         return future;
200       }
201     };
202   }
203 }
204