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