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