• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.cancellation;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static java.util.concurrent.TimeUnit.MILLISECONDS;
21 
22 import com.google.common.util.concurrent.ListenableFuture;
23 import com.google.common.util.concurrent.MoreExecutors;
24 import dagger.BindsInstance;
25 import dagger.producers.CancellationPolicy;
26 import dagger.producers.CancellationPolicy.Propagation;
27 import dagger.producers.ProducerModule;
28 import dagger.producers.Produces;
29 import dagger.producers.Production;
30 import dagger.producers.ProductionComponent;
31 import dagger.producers.ProductionSubcomponent;
32 import java.util.concurrent.Executor;
33 import javax.inject.Named;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.junit.runners.JUnit4;
37 
38 /**
39  * Tests for parent production components with a {@code CancellationPolicy} that allows subcomponent
40  * cancellation to propagate to them
41  */
42 @RunWith(JUnit4.class)
43 public final class CancellationPolicyTest {
44 
45   @ProducerModule(subcomponents = Child.class)
46   static class ParentModule {
47     private final ProducerTester tester;
48 
ParentModule(ProducerTester tester)49     ParentModule(ProducerTester tester) {
50       this.tester = tester;
51     }
52 
53     @Produces
54     @Named("a")
produceA()55     ListenableFuture<String> produceA() {
56       return tester.start("a");
57     }
58   }
59 
60   interface Parent {
61     @Named("a")
a()62     ListenableFuture<String> a();
63 
childBuilder()64     Child.Builder childBuilder();
65 
66     interface Builder<P extends Parent, B extends Builder<P, B>> {
module(ParentModule module)67       B module(ParentModule module);
68 
69       @BindsInstance
executor(@roduction Executor executor)70       B executor(@Production Executor executor);
71 
build()72       P build();
73     }
74   }
75 
76   @CancellationPolicy(fromSubcomponents = Propagation.PROPAGATE)
77   @ProductionComponent(modules = ParentModule.class)
78   interface PropagatingParent extends Parent {
79     @ProductionComponent.Builder
80     interface Builder extends Parent.Builder<PropagatingParent, Builder> {}
81   }
82 
83   @CancellationPolicy(fromSubcomponents = Propagation.IGNORE)
84   @ProductionComponent(modules = ParentModule.class)
85   interface NonPropagatingParent extends Parent {
86     @ProductionComponent.Builder
87     interface Builder extends Parent.Builder<NonPropagatingParent, Builder> {}
88   }
89 
90   @ProducerModule
91   static class ChildModule {
92     private final ProducerTester tester;
93 
ChildModule(ProducerTester tester)94     ChildModule(ProducerTester tester) {
95       this.tester = tester;
96     }
97 
98     @Produces
99     @Named("b")
b(@amed"a") String a)100     ListenableFuture<String> b(@Named("a") String a) {
101       return tester.start("b");
102     }
103   }
104 
105   @ProductionSubcomponent(modules = ChildModule.class)
106   interface Child {
107     @Named("b")
b()108     ListenableFuture<String> b();
109 
110     @ProductionSubcomponent.Builder
111     interface Builder {
module(ChildModule module)112       Builder module(ChildModule module);
113 
build()114       Child build();
115     }
116   }
117 
118   private final ProducerTester tester = new ProducerTester();
119 
120   @Test
propagatingParent_childCancellationPropagatesToParent()121   public void propagatingParent_childCancellationPropagatesToParent() {
122     PropagatingParent parent =
123         DaggerCancellationPolicyTest_PropagatingParent.builder()
124             .module(new ParentModule(tester))
125             .executor(MoreExecutors.directExecutor())
126             .build();
127     ListenableFuture<String> a = parent.a();
128 
129     Child child = parent.childBuilder().module(new ChildModule(tester)).build();
130 
131     ListenableFuture<String> b = child.b();
132 
133     tester.assertStarted("a").only();
134 
135     assertThat(a.isDone()).isFalse();
136     assertThat(b.isDone()).isFalse();
137 
138     assertThat(b.cancel(true)).isTrue();
139     assertThat(b.isCancelled()).isTrue();
140 
141     tester.assertCancelled("a");
142 
143     assertThat(a.isCancelled()).isTrue();
144   }
145 
146   @Test
nonPropagatingParent_childCancellationDoesNotPropagateToParent()147   public void nonPropagatingParent_childCancellationDoesNotPropagateToParent() throws Exception {
148     // This test is basically just checking that when the parent has fromSubcomponents = IGNORE, it
149     // behaves the same as having no @CancellationPolicy at all (as tested in
150     // ProducerSubcomponentCancellationTester)
151     NonPropagatingParent parent =
152         DaggerCancellationPolicyTest_NonPropagatingParent.builder()
153             .module(new ParentModule(tester))
154             .executor(MoreExecutors.directExecutor())
155             .build();
156     ListenableFuture<String> a = parent.a();
157 
158     Child child = parent.childBuilder().module(new ChildModule(tester)).build();
159 
160     ListenableFuture<String> b = child.b();
161 
162     tester.assertStarted("a").only();
163 
164     assertThat(a.isDone()).isFalse();
165     assertThat(b.isDone()).isFalse();
166 
167     assertThat(b.cancel(true)).isTrue();
168     assertThat(b.isCancelled()).isTrue();
169 
170     tester.assertNotCancelled("a");
171 
172     assertThat(a.isDone()).isFalse();
173 
174     tester.complete("a");
175     assertThat(a.isDone()).isTrue();
176     assertThat(a.get(1, MILLISECONDS)).isEqualTo("completed");
177 
178     tester.assertNotStarted("b");
179   }
180 }
181