1 /*
2  * Copyright (C) 2009 The Guava 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 com.google.common.util.concurrent;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
21 
22 import com.google.common.collect.Lists;
23 import java.util.List;
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.TimeUnit;
26 import java.util.concurrent.TimeoutException;
27 import junit.framework.TestCase;
28 
29 /**
30  * Tests for {@link AbstractIdleService}.
31  *
32  * @author Chris Nokleberg
33  * @author Ben Yu
34  */
35 public class AbstractIdleServiceTest extends TestCase {
36 
37   // Functional tests using real thread. We only verify publicly visible state.
38   // Interaction assertions are done by the single-threaded unit tests.
39 
40   public static class FunctionalTest extends TestCase {
41 
42     private static class DefaultService extends AbstractIdleService {
43       @Override
startUp()44       protected void startUp() throws Exception {}
45 
46       @Override
shutDown()47       protected void shutDown() throws Exception {}
48     }
49 
testServiceStartStop()50     public void testServiceStartStop() throws Exception {
51       AbstractIdleService service = new DefaultService();
52       service.startAsync().awaitRunning();
53       assertEquals(Service.State.RUNNING, service.state());
54       service.stopAsync().awaitTerminated();
55       assertEquals(Service.State.TERMINATED, service.state());
56     }
57 
testStart_failed()58     public void testStart_failed() throws Exception {
59       final Exception exception = new Exception("deliberate");
60       AbstractIdleService service =
61           new DefaultService() {
62             @Override
63             protected void startUp() throws Exception {
64               throw exception;
65             }
66           };
67       try {
68         service.startAsync().awaitRunning();
69         fail();
70       } catch (RuntimeException e) {
71         assertThat(e).hasCauseThat().isSameInstanceAs(exception);
72       }
73       assertEquals(Service.State.FAILED, service.state());
74     }
75 
testStop_failed()76     public void testStop_failed() throws Exception {
77       final Exception exception = new Exception("deliberate");
78       AbstractIdleService service =
79           new DefaultService() {
80             @Override
81             protected void shutDown() throws Exception {
82               throw exception;
83             }
84           };
85       service.startAsync().awaitRunning();
86       try {
87         service.stopAsync().awaitTerminated();
88         fail();
89       } catch (RuntimeException e) {
90         assertThat(e).hasCauseThat().isSameInstanceAs(exception);
91       }
92       assertEquals(Service.State.FAILED, service.state());
93     }
94   }
95 
testStart()96   public void testStart() {
97     TestService service = new TestService();
98     assertEquals(0, service.startUpCalled);
99     service.startAsync().awaitRunning();
100     assertEquals(1, service.startUpCalled);
101     assertEquals(Service.State.RUNNING, service.state());
102     assertThat(service.transitionStates).containsExactly(Service.State.STARTING);
103   }
104 
testStart_failed()105   public void testStart_failed() {
106     final Exception exception = new Exception("deliberate");
107     TestService service =
108         new TestService() {
109           @Override
110           protected void startUp() throws Exception {
111             super.startUp();
112             throw exception;
113           }
114         };
115     assertEquals(0, service.startUpCalled);
116     try {
117       service.startAsync().awaitRunning();
118       fail();
119     } catch (RuntimeException e) {
120       assertThat(e).hasCauseThat().isSameInstanceAs(exception);
121     }
122     assertEquals(1, service.startUpCalled);
123     assertEquals(Service.State.FAILED, service.state());
124     assertThat(service.transitionStates).containsExactly(Service.State.STARTING);
125   }
126 
testStop_withoutStart()127   public void testStop_withoutStart() {
128     TestService service = new TestService();
129     service.stopAsync().awaitTerminated();
130     assertEquals(0, service.startUpCalled);
131     assertEquals(0, service.shutDownCalled);
132     assertEquals(Service.State.TERMINATED, service.state());
133     assertThat(service.transitionStates).isEmpty();
134   }
135 
testStop_afterStart()136   public void testStop_afterStart() {
137     TestService service = new TestService();
138     service.startAsync().awaitRunning();
139     assertEquals(1, service.startUpCalled);
140     assertEquals(0, service.shutDownCalled);
141     service.stopAsync().awaitTerminated();
142     assertEquals(1, service.startUpCalled);
143     assertEquals(1, service.shutDownCalled);
144     assertEquals(Service.State.TERMINATED, service.state());
145     assertThat(service.transitionStates)
146         .containsExactly(Service.State.STARTING, Service.State.STOPPING)
147         .inOrder();
148   }
149 
testStop_failed()150   public void testStop_failed() {
151     final Exception exception = new Exception("deliberate");
152     TestService service =
153         new TestService() {
154           @Override
155           protected void shutDown() throws Exception {
156             super.shutDown();
157             throw exception;
158           }
159         };
160     service.startAsync().awaitRunning();
161     assertEquals(1, service.startUpCalled);
162     assertEquals(0, service.shutDownCalled);
163     try {
164       service.stopAsync().awaitTerminated();
165       fail();
166     } catch (RuntimeException e) {
167       assertThat(e).hasCauseThat().isSameInstanceAs(exception);
168     }
169     assertEquals(1, service.startUpCalled);
170     assertEquals(1, service.shutDownCalled);
171     assertEquals(Service.State.FAILED, service.state());
172     assertThat(service.transitionStates)
173         .containsExactly(Service.State.STARTING, Service.State.STOPPING)
174         .inOrder();
175   }
176 
testServiceToString()177   public void testServiceToString() {
178     AbstractIdleService service = new TestService();
179     assertEquals("TestService [NEW]", service.toString());
180     service.startAsync().awaitRunning();
181     assertEquals("TestService [RUNNING]", service.toString());
182     service.stopAsync().awaitTerminated();
183     assertEquals("TestService [TERMINATED]", service.toString());
184   }
185 
testTimeout()186   public void testTimeout() throws Exception {
187     // Create a service whose executor will never run its commands
188     Service service =
189         new TestService() {
190           @Override
191           protected Executor executor() {
192             return new Executor() {
193               @Override
194               public void execute(Runnable command) {}
195             };
196           }
197 
198           @Override
199           protected String serviceName() {
200             return "Foo";
201           }
202         };
203     try {
204       service.startAsync().awaitRunning(1, TimeUnit.MILLISECONDS);
205       fail("Expected timeout");
206     } catch (TimeoutException e) {
207       assertThat(e)
208           .hasMessageThat()
209           .isEqualTo("Timed out waiting for Foo [STARTING] to reach the RUNNING state.");
210     }
211   }
212 
213   private static class TestService extends AbstractIdleService {
214     int startUpCalled = 0;
215     int shutDownCalled = 0;
216     final List<State> transitionStates = Lists.newArrayList();
217 
218     @Override
startUp()219     protected void startUp() throws Exception {
220       assertEquals(0, startUpCalled);
221       assertEquals(0, shutDownCalled);
222       startUpCalled++;
223       assertEquals(State.STARTING, state());
224     }
225 
226     @Override
shutDown()227     protected void shutDown() throws Exception {
228       assertEquals(1, startUpCalled);
229       assertEquals(0, shutDownCalled);
230       shutDownCalled++;
231       assertEquals(State.STOPPING, state());
232     }
233 
234     @Override
executor()235     protected Executor executor() {
236       transitionStates.add(state());
237       return directExecutor();
238     }
239   }
240 }
241