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