1 /*
2  * Copyright (C) 2014 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.internal;
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.ArgumentMatchers.nullable;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.verifyNoMoreInteractions;
25 import static org.mockito.Mockito.when;
26 
27 import com.google.common.util.concurrent.Futures;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import com.google.common.util.concurrent.MoreExecutors;
30 import com.google.common.util.concurrent.SettableFuture;
31 import dagger.internal.Provider;
32 import dagger.producers.Producer;
33 import dagger.producers.monitoring.ProducerMonitor;
34 import dagger.producers.monitoring.ProducerToken;
35 import dagger.producers.monitoring.ProductionComponentMonitor;
36 import java.util.concurrent.ExecutionException;
37 import java.util.concurrent.Executor;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.junit.runners.JUnit4;
42 import org.mockito.Mock;
43 import org.mockito.Mockito;
44 import org.mockito.MockitoAnnotations;
45 
46 /**
47  * Tests {@link AbstractProducer}.
48  */
49 @RunWith(JUnit4.class)
50 public class AbstractProducesMethodProducerTest {
51   @Mock private ProductionComponentMonitor componentMonitor;
52   private ProducerMonitor monitor;
53   private Provider<ProductionComponentMonitor> componentMonitorProvider;
54 
55   @Before
initMocks()56   public void initMocks() {
57     MockitoAnnotations.initMocks(this);
58     monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
59     when(componentMonitor.producerMonitorFor(nullable(ProducerToken.class))).thenReturn(monitor);
60     componentMonitorProvider =
61         new Provider<ProductionComponentMonitor>() {
62           @Override
63           public ProductionComponentMonitor get() {
64             return componentMonitor;
65           }
66         };
67   }
68 
69   @Test
monitor_success()70   public void monitor_success() throws Exception {
71     SettableFuture<Integer> delegateFuture = SettableFuture.create();
72     Producer<Integer> producer = new DelegateProducer<>(componentMonitorProvider, delegateFuture);
73 
74     ListenableFuture<Integer> future = producer.get();
75     assertThat(future.isDone()).isFalse();
76     verify(monitor).ready();
77     verify(monitor).requested();
78     verify(monitor).addCallbackTo(anyListenableFuture());
79     verify(monitor).methodStarting();
80     verify(monitor).methodFinished();
81     delegateFuture.set(-42);
82     assertThat(future.get()).isEqualTo(-42);
83     verify(monitor).succeeded(-42);
84     verifyNoMoreInteractions(monitor);
85   }
86 
87   @Test
monitor_failure()88   public void monitor_failure() throws Exception {
89     SettableFuture<Integer> delegateFuture = SettableFuture.create();
90     Producer<Integer> producer = new DelegateProducer<>(componentMonitorProvider, delegateFuture);
91 
92     ListenableFuture<Integer> future = producer.get();
93     assertThat(future.isDone()).isFalse();
94     verify(monitor).ready();
95     verify(monitor).requested();
96     verify(monitor).addCallbackTo(anyListenableFuture());
97     verify(monitor).methodStarting();
98     verify(monitor).methodFinished();
99     Throwable t = new RuntimeException("monkey");
100     delegateFuture.setException(t);
101     try {
102       future.get();
103       fail();
104     } catch (ExecutionException e) {
105       assertThat(e).hasCauseThat().isSameInstanceAs(t);
106     }
107     verify(monitor).failed(t);
108     verifyNoMoreInteractions(monitor);
109   }
110 
anyListenableFuture()111   private ListenableFuture<?> anyListenableFuture() {
112     return any(ListenableFuture.class);
113   }
114 
115   @Test(expected = NullPointerException.class)
monitor_null()116   public void monitor_null() throws Exception {
117     new DelegateProducer<>(null, Futures.immediateFuture(42));
118   }
119 
120   static final class DelegateProducer<T> extends AbstractProducesMethodProducer<Void, T> {
121     private final ListenableFuture<T> delegate;
122 
DelegateProducer( Provider<ProductionComponentMonitor> componentMonitorProvider, ListenableFuture<T> delegate)123     DelegateProducer(
124         Provider<ProductionComponentMonitor> componentMonitorProvider,
125         ListenableFuture<T> delegate) {
126       super(
127           componentMonitorProvider,
128           null, // token
129           new Provider<Executor>() {
130             @Override
131             public Executor get() {
132               return MoreExecutors.directExecutor();
133             }
134           });
135       this.delegate = delegate;
136     }
137 
138     @Override
collectDependencies()139     protected ListenableFuture<Void> collectDependencies() {
140       return Futures.immediateFuture(null);
141     }
142 
143     @Override
callProducesMethod(Void asyncDependencies)144     protected ListenableFuture<T> callProducesMethod(Void asyncDependencies) {
145       return delegate;
146     }
147   }
148 }
149