1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hbase; 19 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertTrue; 24 25 import java.util.concurrent.TimeUnit; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.commons.logging.LogFactory; 29 import org.apache.hadoop.hbase.TestChoreService.ScheduledChoreSamples.CountingChore; 30 import org.apache.hadoop.hbase.TestChoreService.ScheduledChoreSamples.DoNothingChore; 31 import org.apache.hadoop.hbase.TestChoreService.ScheduledChoreSamples.FailInitialChore; 32 import org.apache.hadoop.hbase.TestChoreService.ScheduledChoreSamples.SampleStopper; 33 import org.apache.hadoop.hbase.TestChoreService.ScheduledChoreSamples.SleepingChore; 34 import org.apache.hadoop.hbase.TestChoreService.ScheduledChoreSamples.SlowChore; 35 import org.apache.hadoop.hbase.testclassification.SmallTests; 36 import org.junit.Test; 37 import org.junit.experimental.categories.Category; 38 39 @Category(SmallTests.class) 40 public class TestChoreService { 41 /** 42 * A few ScheduledChore samples that are useful for testing with ChoreService 43 */ 44 public static class ScheduledChoreSamples { 45 /** 46 * Straight forward stopper implementation that is used by default when one is not provided 47 */ 48 public static class SampleStopper implements Stoppable { 49 private boolean stopped = false; 50 51 @Override stop(String why)52 public void stop(String why) { 53 stopped = true; 54 } 55 56 @Override isStopped()57 public boolean isStopped() { 58 return stopped; 59 } 60 } 61 62 /** 63 * Sleeps for longer than the scheduled period. This chore always misses its scheduled periodic 64 * executions 65 */ 66 public static class SlowChore extends ScheduledChore { SlowChore(String name, int period)67 public SlowChore(String name, int period) { 68 this(name, new SampleStopper(), period); 69 } 70 SlowChore(String name, Stoppable stopper, int period)71 public SlowChore(String name, Stoppable stopper, int period) { 72 super(name, stopper, period); 73 } 74 75 @Override initialChore()76 protected boolean initialChore() { 77 try { 78 Thread.sleep(getPeriod() * 2); 79 } catch (InterruptedException e) { 80 e.printStackTrace(); 81 } 82 return true; 83 } 84 85 @Override chore()86 protected void chore() { 87 try { 88 Thread.sleep(getPeriod() * 2); 89 } catch (InterruptedException e) { 90 //e.printStackTrace(); 91 } 92 } 93 } 94 95 /** 96 * Lightweight ScheduledChore used primarily to fill the scheduling queue in tests 97 */ 98 public static class DoNothingChore extends ScheduledChore { DoNothingChore(String name, int period)99 public DoNothingChore(String name, int period) { 100 super(name, new SampleStopper(), period); 101 } 102 DoNothingChore(String name, Stoppable stopper, int period)103 public DoNothingChore(String name, Stoppable stopper, int period) { 104 super(name, stopper, period); 105 } 106 107 @Override chore()108 protected void chore() { 109 // DO NOTHING 110 } 111 112 } 113 114 public static class SleepingChore extends ScheduledChore { 115 private int sleepTime; 116 SleepingChore(String name, int chorePeriod, int sleepTime)117 public SleepingChore(String name, int chorePeriod, int sleepTime) { 118 this(name, new SampleStopper(), chorePeriod, sleepTime); 119 } 120 SleepingChore(String name, Stoppable stopper, int period, int sleepTime)121 public SleepingChore(String name, Stoppable stopper, int period, int sleepTime) { 122 super(name, stopper, period); 123 this.sleepTime = sleepTime; 124 } 125 126 @Override initialChore()127 protected boolean initialChore() { 128 try { 129 Thread.sleep(sleepTime); 130 } catch (InterruptedException e) { 131 e.printStackTrace(); 132 } 133 return true; 134 } 135 136 @Override chore()137 protected void chore() { 138 try { 139 Thread.sleep(sleepTime); 140 } catch (Exception e) { 141 System.err.println(e.getStackTrace()); 142 } 143 } 144 } 145 146 public static class CountingChore extends ScheduledChore { 147 private int countOfChoreCalls; 148 private boolean outputOnTicks = false; 149 CountingChore(String name, int period)150 public CountingChore(String name, int period) { 151 this(name, new SampleStopper(), period); 152 } 153 CountingChore(String name, Stoppable stopper, int period)154 public CountingChore(String name, Stoppable stopper, int period) { 155 this(name, stopper, period, false); 156 } 157 CountingChore(String name, Stoppable stopper, int period, final boolean outputOnTicks)158 public CountingChore(String name, Stoppable stopper, int period, 159 final boolean outputOnTicks) { 160 super(name, stopper, period); 161 this.countOfChoreCalls = 0; 162 this.outputOnTicks = outputOnTicks; 163 } 164 165 @Override initialChore()166 protected boolean initialChore() { 167 countOfChoreCalls++; 168 if (outputOnTicks) outputTickCount(); 169 return true; 170 } 171 172 @Override chore()173 protected void chore() { 174 countOfChoreCalls++; 175 if (outputOnTicks) outputTickCount(); 176 } 177 outputTickCount()178 private void outputTickCount() { 179 System.out.println("Chore: " + getName() + ". Count of chore calls: " + countOfChoreCalls); 180 } 181 getCountOfChoreCalls()182 public int getCountOfChoreCalls() { 183 return countOfChoreCalls; 184 } 185 isOutputtingOnTicks()186 public boolean isOutputtingOnTicks() { 187 return outputOnTicks; 188 } 189 setOutputOnTicks(boolean o)190 public void setOutputOnTicks(boolean o) { 191 outputOnTicks = o; 192 } 193 } 194 195 /** 196 * A Chore that will try to execute the initial chore a few times before succeeding. Once the 197 * initial chore is complete the chore cancels itself 198 */ 199 public static class FailInitialChore extends ScheduledChore { 200 private int numberOfFailures; 201 private int failureThreshold; 202 203 /** 204 * @param failThreshold Number of times the Chore fails when trying to execute initialChore 205 * before succeeding. 206 */ FailInitialChore(String name, int period, int failThreshold)207 public FailInitialChore(String name, int period, int failThreshold) { 208 this(name, new SampleStopper(), period, failThreshold); 209 } 210 FailInitialChore(String name, Stoppable stopper, int period, int failThreshold)211 public FailInitialChore(String name, Stoppable stopper, int period, int failThreshold) { 212 super(name, stopper, period); 213 numberOfFailures = 0; 214 failureThreshold = failThreshold; 215 } 216 217 @Override initialChore()218 protected boolean initialChore() { 219 if (numberOfFailures < failureThreshold) { 220 numberOfFailures++; 221 return false; 222 } else { 223 return true; 224 } 225 } 226 227 @Override chore()228 protected void chore() { 229 assertTrue(numberOfFailures == failureThreshold); 230 cancel(false); 231 } 232 233 } 234 } 235 236 @Test (timeout=20000) testInitialChorePrecedence()237 public void testInitialChorePrecedence() throws InterruptedException { 238 ChoreService service = ChoreService.getInstance("testInitialChorePrecedence"); 239 240 final int period = 100; 241 final int failureThreshold = 5; 242 243 try { 244 ScheduledChore chore = new FailInitialChore("chore", period, failureThreshold); 245 service.scheduleChore(chore); 246 247 int loopCount = 0; 248 boolean brokeOutOfLoop = false; 249 250 while (!chore.isInitialChoreComplete() && chore.isScheduled()) { 251 Thread.sleep(failureThreshold * period); 252 loopCount++; 253 if (loopCount > 3) { 254 brokeOutOfLoop = true; 255 break; 256 } 257 } 258 259 assertFalse(brokeOutOfLoop); 260 } finally { 261 shutdownService(service); 262 } 263 } 264 265 @Test (timeout=20000) testCancelChore()266 public void testCancelChore() throws InterruptedException { 267 final int period = 100; 268 ScheduledChore chore1 = new DoNothingChore("chore1", period); 269 ChoreService service = ChoreService.getInstance("testCancelChore"); 270 try { 271 service.scheduleChore(chore1); 272 assertTrue(chore1.isScheduled()); 273 274 chore1.cancel(true); 275 assertFalse(chore1.isScheduled()); 276 assertTrue(service.getNumberOfScheduledChores() == 0); 277 } finally { 278 shutdownService(service); 279 } 280 } 281 282 @Test (timeout=20000) testScheduledChoreConstruction()283 public void testScheduledChoreConstruction() { 284 final String NAME = "chore"; 285 final int PERIOD = 100; 286 final long VALID_DELAY = 0; 287 final long INVALID_DELAY = -100; 288 final TimeUnit UNIT = TimeUnit.NANOSECONDS; 289 290 ScheduledChore chore1 = 291 new ScheduledChore(NAME, new SampleStopper(), PERIOD, VALID_DELAY, UNIT) { 292 @Override 293 protected void chore() { 294 // DO NOTHING 295 } 296 }; 297 298 assertEquals("Name construction failed", chore1.getName(), NAME); 299 assertEquals("Period construction failed", chore1.getPeriod(), PERIOD); 300 assertEquals("Initial Delay construction failed", chore1.getInitialDelay(), VALID_DELAY); 301 assertEquals("TimeUnit construction failed", chore1.getTimeUnit(), UNIT); 302 303 ScheduledChore invalidDelayChore = 304 new ScheduledChore(NAME, new SampleStopper(), PERIOD, INVALID_DELAY, UNIT) { 305 @Override 306 protected void chore() { 307 // DO NOTHING 308 } 309 }; 310 311 assertEquals("Initial Delay should be set to 0 when invalid", 0, 312 invalidDelayChore.getInitialDelay()); 313 } 314 315 @Test (timeout=20000) testChoreServiceConstruction()316 public void testChoreServiceConstruction() throws InterruptedException { 317 final int corePoolSize = 10; 318 final int defaultCorePoolSize = ChoreService.MIN_CORE_POOL_SIZE; 319 320 ChoreService customInit = new ChoreService("testChoreServiceConstruction_custom", corePoolSize, false); 321 try { 322 assertEquals(corePoolSize, customInit.getCorePoolSize()); 323 } finally { 324 shutdownService(customInit); 325 } 326 327 ChoreService defaultInit = new ChoreService("testChoreServiceConstruction_default"); 328 try { 329 assertEquals(defaultCorePoolSize, defaultInit.getCorePoolSize()); 330 } finally { 331 shutdownService(defaultInit); 332 } 333 334 ChoreService invalidInit = new ChoreService("testChoreServiceConstruction_invalid", -10, false); 335 try { 336 assertEquals(defaultCorePoolSize, invalidInit.getCorePoolSize()); 337 } finally { 338 shutdownService(invalidInit); 339 } 340 } 341 342 @Test (timeout=20000) testFrequencyOfChores()343 public void testFrequencyOfChores() throws InterruptedException { 344 final int period = 100; 345 // Small delta that acts as time buffer (allowing chores to complete if running slowly) 346 final int delta = 5; 347 ChoreService service = ChoreService.getInstance("testFrequencyOfChores"); 348 CountingChore chore = new CountingChore("countingChore", period); 349 try { 350 service.scheduleChore(chore); 351 352 Thread.sleep(10 * period + delta); 353 assertTrue(chore.getCountOfChoreCalls() == 11); 354 355 Thread.sleep(10 * period); 356 assertTrue(chore.getCountOfChoreCalls() == 21); 357 } finally { 358 shutdownService(service); 359 } 360 } 361 shutdownService(ChoreService service)362 public void shutdownService(ChoreService service) throws InterruptedException { 363 service.shutdown(); 364 while (!service.isTerminated()) { 365 Thread.sleep(100); 366 } 367 } 368 369 @Test (timeout=20000) testForceTrigger()370 public void testForceTrigger() throws InterruptedException { 371 final int period = 100; 372 final int delta = 5; 373 ChoreService service = ChoreService.getInstance("testForceTrigger"); 374 final CountingChore chore = new CountingChore("countingChore", period); 375 try { 376 service.scheduleChore(chore); 377 Thread.sleep(10 * period + delta); 378 379 assertTrue(chore.getCountOfChoreCalls() == 11); 380 381 // Force five runs of the chore to occur, sleeping between triggers to ensure the 382 // chore has time to run 383 chore.triggerNow(); 384 Thread.sleep(delta); 385 chore.triggerNow(); 386 Thread.sleep(delta); 387 chore.triggerNow(); 388 Thread.sleep(delta); 389 chore.triggerNow(); 390 Thread.sleep(delta); 391 chore.triggerNow(); 392 Thread.sleep(delta); 393 394 assertTrue("" + chore.getCountOfChoreCalls(), chore.getCountOfChoreCalls() == 16); 395 396 Thread.sleep(10 * period + delta); 397 398 // Be loosey-goosey. It used to be '26' but it was a big flakey relying on timing. 399 assertTrue("" + chore.getCountOfChoreCalls(), chore.getCountOfChoreCalls() > 16); 400 } finally { 401 shutdownService(service); 402 } 403 } 404 405 @Test (timeout=20000) testCorePoolIncrease()406 public void testCorePoolIncrease() throws InterruptedException { 407 final int initialCorePoolSize = 3; 408 ChoreService service = new ChoreService("testCorePoolIncrease", initialCorePoolSize, false); 409 410 try { 411 assertEquals("Should have a core pool of size: " + initialCorePoolSize, initialCorePoolSize, 412 service.getCorePoolSize()); 413 414 final int slowChorePeriod = 100; 415 SlowChore slowChore1 = new SlowChore("slowChore1", slowChorePeriod); 416 SlowChore slowChore2 = new SlowChore("slowChore2", slowChorePeriod); 417 SlowChore slowChore3 = new SlowChore("slowChore3", slowChorePeriod); 418 419 service.scheduleChore(slowChore1); 420 service.scheduleChore(slowChore2); 421 service.scheduleChore(slowChore3); 422 423 Thread.sleep(slowChorePeriod * 10); 424 assertEquals("Should not create more pools than scheduled chores", 3, 425 service.getCorePoolSize()); 426 427 SlowChore slowChore4 = new SlowChore("slowChore4", slowChorePeriod); 428 service.scheduleChore(slowChore4); 429 430 Thread.sleep(slowChorePeriod * 10); 431 assertEquals("Chores are missing their start time. Should expand core pool size", 4, 432 service.getCorePoolSize()); 433 434 SlowChore slowChore5 = new SlowChore("slowChore5", slowChorePeriod); 435 service.scheduleChore(slowChore5); 436 437 Thread.sleep(slowChorePeriod * 10); 438 assertEquals("Chores are missing their start time. Should expand core pool size", 5, 439 service.getCorePoolSize()); 440 } finally { 441 shutdownService(service); 442 } 443 } 444 445 @Test(timeout = 30000) testCorePoolDecrease()446 public void testCorePoolDecrease() throws InterruptedException { 447 final int initialCorePoolSize = 3; 448 ChoreService service = new ChoreService("testCorePoolDecrease", initialCorePoolSize, false); 449 final int chorePeriod = 100; 450 try { 451 // Slow chores always miss their start time and thus the core pool size should be at least as 452 // large as the number of running slow chores 453 SlowChore slowChore1 = new SlowChore("slowChore1", chorePeriod); 454 SlowChore slowChore2 = new SlowChore("slowChore2", chorePeriod); 455 SlowChore slowChore3 = new SlowChore("slowChore3", chorePeriod); 456 457 service.scheduleChore(slowChore1); 458 service.scheduleChore(slowChore2); 459 service.scheduleChore(slowChore3); 460 461 Thread.sleep(chorePeriod * 10); 462 assertEquals("Should not create more pools than scheduled chores", 463 service.getNumberOfScheduledChores(), service.getCorePoolSize()); 464 465 SlowChore slowChore4 = new SlowChore("slowChore4", chorePeriod); 466 service.scheduleChore(slowChore4); 467 Thread.sleep(chorePeriod * 10); 468 assertEquals("Chores are missing their start time. Should expand core pool size", 469 service.getNumberOfScheduledChores(), service.getCorePoolSize()); 470 471 SlowChore slowChore5 = new SlowChore("slowChore5", chorePeriod); 472 service.scheduleChore(slowChore5); 473 Thread.sleep(chorePeriod * 10); 474 assertEquals("Chores are missing their start time. Should expand core pool size", 475 service.getNumberOfScheduledChores(), service.getCorePoolSize()); 476 assertEquals(service.getNumberOfChoresMissingStartTime(), 5); 477 478 // Now we begin to cancel the chores that caused an increase in the core thread pool of the 479 // ChoreService. These cancellations should cause a decrease in the core thread pool. 480 slowChore5.cancel(); 481 Thread.sleep(chorePeriod * 10); 482 assertEquals(Math.max(ChoreService.MIN_CORE_POOL_SIZE, service.getNumberOfScheduledChores()), 483 service.getCorePoolSize()); 484 assertEquals(service.getNumberOfChoresMissingStartTime(), 4); 485 486 slowChore4.cancel(); 487 Thread.sleep(chorePeriod * 10); 488 assertEquals(Math.max(ChoreService.MIN_CORE_POOL_SIZE, service.getNumberOfScheduledChores()), 489 service.getCorePoolSize()); 490 assertEquals(service.getNumberOfChoresMissingStartTime(), 3); 491 492 slowChore3.cancel(); 493 Thread.sleep(chorePeriod * 10); 494 assertEquals(Math.max(ChoreService.MIN_CORE_POOL_SIZE, service.getNumberOfScheduledChores()), 495 service.getCorePoolSize()); 496 assertEquals(service.getNumberOfChoresMissingStartTime(), 2); 497 498 slowChore2.cancel(); 499 Thread.sleep(chorePeriod * 10); 500 assertEquals(Math.max(ChoreService.MIN_CORE_POOL_SIZE, service.getNumberOfScheduledChores()), 501 service.getCorePoolSize()); 502 assertEquals(service.getNumberOfChoresMissingStartTime(), 1); 503 504 slowChore1.cancel(); 505 Thread.sleep(chorePeriod * 10); 506 assertEquals(Math.max(ChoreService.MIN_CORE_POOL_SIZE, service.getNumberOfScheduledChores()), 507 service.getCorePoolSize()); 508 assertEquals(service.getNumberOfChoresMissingStartTime(), 0); 509 } finally { 510 shutdownService(service); 511 } 512 } 513 514 @Test (timeout=20000) testNumberOfRunningChores()515 public void testNumberOfRunningChores() throws InterruptedException { 516 ChoreService service = new ChoreService("testNumberOfRunningChores"); 517 518 final int period = 100; 519 final int sleepTime = 5; 520 521 try { 522 DoNothingChore dn1 = new DoNothingChore("dn1", period); 523 DoNothingChore dn2 = new DoNothingChore("dn2", period); 524 DoNothingChore dn3 = new DoNothingChore("dn3", period); 525 DoNothingChore dn4 = new DoNothingChore("dn4", period); 526 DoNothingChore dn5 = new DoNothingChore("dn5", period); 527 528 service.scheduleChore(dn1); 529 service.scheduleChore(dn2); 530 service.scheduleChore(dn3); 531 service.scheduleChore(dn4); 532 service.scheduleChore(dn5); 533 534 Thread.sleep(sleepTime); 535 assertEquals("Scheduled chore mismatch", 5, service.getNumberOfScheduledChores()); 536 537 dn1.cancel(); 538 Thread.sleep(sleepTime); 539 assertEquals("Scheduled chore mismatch", 4, service.getNumberOfScheduledChores()); 540 541 dn2.cancel(); 542 dn3.cancel(); 543 dn4.cancel(); 544 Thread.sleep(sleepTime); 545 assertEquals("Scheduled chore mismatch", 1, service.getNumberOfScheduledChores()); 546 547 dn5.cancel(); 548 Thread.sleep(sleepTime); 549 assertEquals("Scheduled chore mismatch", 0, service.getNumberOfScheduledChores()); 550 } finally { 551 shutdownService(service); 552 } 553 } 554 555 @Test (timeout=20000) testNumberOfChoresMissingStartTime()556 public void testNumberOfChoresMissingStartTime() throws InterruptedException { 557 ChoreService service = new ChoreService("testNumberOfChoresMissingStartTime"); 558 559 final int period = 100; 560 final int sleepTime = 5 * period; 561 562 try { 563 // Slow chores sleep for a length of time LONGER than their period. Thus, SlowChores 564 // ALWAYS miss their start time since their execution takes longer than their period 565 SlowChore sc1 = new SlowChore("sc1", period); 566 SlowChore sc2 = new SlowChore("sc2", period); 567 SlowChore sc3 = new SlowChore("sc3", period); 568 SlowChore sc4 = new SlowChore("sc4", period); 569 SlowChore sc5 = new SlowChore("sc5", period); 570 571 service.scheduleChore(sc1); 572 service.scheduleChore(sc2); 573 service.scheduleChore(sc3); 574 service.scheduleChore(sc4); 575 service.scheduleChore(sc5); 576 577 Thread.sleep(sleepTime); 578 assertEquals(5, service.getNumberOfChoresMissingStartTime()); 579 580 sc1.cancel(); 581 Thread.sleep(sleepTime); 582 assertEquals(4, service.getNumberOfChoresMissingStartTime()); 583 584 sc2.cancel(); 585 sc3.cancel(); 586 sc4.cancel(); 587 Thread.sleep(sleepTime); 588 assertEquals(1, service.getNumberOfChoresMissingStartTime()); 589 590 sc5.cancel(); 591 Thread.sleep(sleepTime); 592 assertEquals(0, service.getNumberOfChoresMissingStartTime()); 593 } finally { 594 shutdownService(service); 595 } 596 } 597 598 /** 599 * ChoreServices should never have a core pool size that exceeds the number of chores that have 600 * been scheduled with the service. For example, if 4 ScheduledChores are scheduled with a 601 * ChoreService, the number of threads in the ChoreService's core pool should never exceed 4 602 */ 603 @Test (timeout=20000) testMaximumChoreServiceThreads()604 public void testMaximumChoreServiceThreads() throws InterruptedException { 605 ChoreService service = new ChoreService("testMaximumChoreServiceThreads"); 606 607 final int period = 100; 608 final int sleepTime = 5 * period; 609 610 try { 611 // Slow chores sleep for a length of time LONGER than their period. Thus, SlowChores 612 // ALWAYS miss their start time since their execution takes longer than their period. 613 // Chores that miss their start time will trigger the onChoreMissedStartTime callback 614 // in the ChoreService. This callback will try to increase the number of core pool 615 // threads. 616 SlowChore sc1 = new SlowChore("sc1", period); 617 SlowChore sc2 = new SlowChore("sc2", period); 618 SlowChore sc3 = new SlowChore("sc3", period); 619 SlowChore sc4 = new SlowChore("sc4", period); 620 SlowChore sc5 = new SlowChore("sc5", period); 621 622 service.scheduleChore(sc1); 623 service.scheduleChore(sc2); 624 service.scheduleChore(sc3); 625 service.scheduleChore(sc4); 626 service.scheduleChore(sc5); 627 628 Thread.sleep(sleepTime); 629 assertTrue(service.getCorePoolSize() <= service.getNumberOfScheduledChores()); 630 631 SlowChore sc6 = new SlowChore("sc6", period); 632 SlowChore sc7 = new SlowChore("sc7", period); 633 SlowChore sc8 = new SlowChore("sc8", period); 634 SlowChore sc9 = new SlowChore("sc9", period); 635 SlowChore sc10 = new SlowChore("sc10", period); 636 637 service.scheduleChore(sc6); 638 service.scheduleChore(sc7); 639 service.scheduleChore(sc8); 640 service.scheduleChore(sc9); 641 service.scheduleChore(sc10); 642 643 Thread.sleep(sleepTime); 644 assertTrue(service.getCorePoolSize() <= service.getNumberOfScheduledChores()); 645 } finally { 646 shutdownService(service); 647 } 648 } 649 650 @Test (timeout=20000) testChangingChoreServices()651 public void testChangingChoreServices() throws InterruptedException { 652 final int period = 100; 653 final int sleepTime = 10; 654 ChoreService service1 = new ChoreService("testChangingChoreServices_1"); 655 ChoreService service2 = new ChoreService("testChangingChoreServices_2"); 656 ScheduledChore chore = new DoNothingChore("sample", period); 657 658 try { 659 assertFalse(chore.isScheduled()); 660 assertFalse(service1.isChoreScheduled(chore)); 661 assertFalse(service2.isChoreScheduled(chore)); 662 assertTrue(chore.getChoreServicer() == null); 663 664 service1.scheduleChore(chore); 665 Thread.sleep(sleepTime); 666 assertTrue(chore.isScheduled()); 667 assertTrue(service1.isChoreScheduled(chore)); 668 assertFalse(service2.isChoreScheduled(chore)); 669 assertFalse(chore.getChoreServicer() == null); 670 671 service2.scheduleChore(chore); 672 Thread.sleep(sleepTime); 673 assertTrue(chore.isScheduled()); 674 assertFalse(service1.isChoreScheduled(chore)); 675 assertTrue(service2.isChoreScheduled(chore)); 676 assertFalse(chore.getChoreServicer() == null); 677 678 chore.cancel(); 679 assertFalse(chore.isScheduled()); 680 assertFalse(service1.isChoreScheduled(chore)); 681 assertFalse(service2.isChoreScheduled(chore)); 682 assertTrue(chore.getChoreServicer() == null); 683 } finally { 684 shutdownService(service1); 685 shutdownService(service2); 686 } 687 } 688 689 @Test (timeout=20000) testTriggerNowFailsWhenNotScheduled()690 public void testTriggerNowFailsWhenNotScheduled() throws InterruptedException { 691 final int period = 100; 692 // Small sleep time buffer to allow CountingChore to complete 693 final int sleep = 5; 694 ChoreService service = new ChoreService("testTriggerNowFailsWhenNotScheduled"); 695 CountingChore chore = new CountingChore("dn", period); 696 697 try { 698 assertFalse(chore.triggerNow()); 699 assertTrue(chore.getCountOfChoreCalls() == 0); 700 701 service.scheduleChore(chore); 702 Thread.sleep(sleep); 703 assertEquals(1, chore.getCountOfChoreCalls()); 704 Thread.sleep(period); 705 assertEquals(2, chore.getCountOfChoreCalls()); 706 assertTrue(chore.triggerNow()); 707 Thread.sleep(sleep); 708 assertTrue(chore.triggerNow()); 709 Thread.sleep(sleep); 710 assertTrue(chore.triggerNow()); 711 Thread.sleep(sleep); 712 assertEquals(5, chore.getCountOfChoreCalls()); 713 } finally { 714 shutdownService(service); 715 } 716 } 717 718 @Test (timeout=20000) testStopperForScheduledChores()719 public void testStopperForScheduledChores() throws InterruptedException { 720 ChoreService service = ChoreService.getInstance("testStopperForScheduledChores"); 721 Stoppable stopperForGroup1 = new SampleStopper(); 722 Stoppable stopperForGroup2 = new SampleStopper(); 723 final int period = 100; 724 final int delta = 10; 725 726 try { 727 ScheduledChore chore1_group1 = new DoNothingChore("c1g1", stopperForGroup1, period); 728 ScheduledChore chore2_group1 = new DoNothingChore("c2g1", stopperForGroup1, period); 729 ScheduledChore chore3_group1 = new DoNothingChore("c3g1", stopperForGroup1, period); 730 731 ScheduledChore chore1_group2 = new DoNothingChore("c1g2", stopperForGroup2, period); 732 ScheduledChore chore2_group2 = new DoNothingChore("c2g2", stopperForGroup2, period); 733 ScheduledChore chore3_group2 = new DoNothingChore("c3g2", stopperForGroup2, period); 734 735 service.scheduleChore(chore1_group1); 736 service.scheduleChore(chore2_group1); 737 service.scheduleChore(chore3_group1); 738 service.scheduleChore(chore1_group2); 739 service.scheduleChore(chore2_group2); 740 service.scheduleChore(chore3_group2); 741 742 Thread.sleep(delta); 743 Thread.sleep(10 * period); 744 assertTrue(chore1_group1.isScheduled()); 745 assertTrue(chore2_group1.isScheduled()); 746 assertTrue(chore3_group1.isScheduled()); 747 assertTrue(chore1_group2.isScheduled()); 748 assertTrue(chore2_group2.isScheduled()); 749 assertTrue(chore3_group2.isScheduled()); 750 751 stopperForGroup1.stop("test stopping group 1"); 752 Thread.sleep(period); 753 assertFalse(chore1_group1.isScheduled()); 754 assertFalse(chore2_group1.isScheduled()); 755 assertFalse(chore3_group1.isScheduled()); 756 assertTrue(chore1_group2.isScheduled()); 757 assertTrue(chore2_group2.isScheduled()); 758 assertTrue(chore3_group2.isScheduled()); 759 760 stopperForGroup2.stop("test stopping group 2"); 761 Thread.sleep(period); 762 assertFalse(chore1_group1.isScheduled()); 763 assertFalse(chore2_group1.isScheduled()); 764 assertFalse(chore3_group1.isScheduled()); 765 assertFalse(chore1_group2.isScheduled()); 766 assertFalse(chore2_group2.isScheduled()); 767 assertFalse(chore3_group2.isScheduled()); 768 } finally { 769 shutdownService(service); 770 } 771 } 772 773 @Test (timeout=20000) testShutdownCancelsScheduledChores()774 public void testShutdownCancelsScheduledChores() throws InterruptedException { 775 final int period = 100; 776 ChoreService service = new ChoreService("testShutdownCancelsScheduledChores"); 777 ScheduledChore successChore1 = new DoNothingChore("sc1", period); 778 ScheduledChore successChore2 = new DoNothingChore("sc2", period); 779 ScheduledChore successChore3 = new DoNothingChore("sc3", period); 780 781 try { 782 assertTrue(service.scheduleChore(successChore1)); 783 assertTrue(successChore1.isScheduled()); 784 assertTrue(service.scheduleChore(successChore2)); 785 assertTrue(successChore2.isScheduled()); 786 assertTrue(service.scheduleChore(successChore3)); 787 assertTrue(successChore3.isScheduled()); 788 } finally { 789 shutdownService(service); 790 } 791 792 assertFalse(successChore1.isScheduled()); 793 assertFalse(successChore2.isScheduled()); 794 assertFalse(successChore3.isScheduled()); 795 } 796 797 @Test (timeout=20000) testShutdownWorksWhileChoresAreExecuting()798 public void testShutdownWorksWhileChoresAreExecuting() throws InterruptedException { 799 final int period = 100; 800 final int sleep = 5 * period; 801 ChoreService service = new ChoreService("testShutdownWorksWhileChoresAreExecuting"); 802 ScheduledChore slowChore1 = new SleepingChore("sc1", period, sleep); 803 ScheduledChore slowChore2 = new SleepingChore("sc2", period, sleep); 804 ScheduledChore slowChore3 = new SleepingChore("sc3", period, sleep); 805 try { 806 assertTrue(service.scheduleChore(slowChore1)); 807 assertTrue(service.scheduleChore(slowChore2)); 808 assertTrue(service.scheduleChore(slowChore3)); 809 810 Thread.sleep(sleep / 2); 811 shutdownService(service); 812 813 assertFalse(slowChore1.isScheduled()); 814 assertFalse(slowChore2.isScheduled()); 815 assertFalse(slowChore3.isScheduled()); 816 assertTrue(service.isShutdown()); 817 818 Thread.sleep(5); 819 assertTrue(service.isTerminated()); 820 } finally { 821 shutdownService(service); 822 } 823 } 824 825 @Test (timeout=20000) testShutdownRejectsNewSchedules()826 public void testShutdownRejectsNewSchedules() throws InterruptedException { 827 final int period = 100; 828 ChoreService service = new ChoreService("testShutdownRejectsNewSchedules"); 829 ScheduledChore successChore1 = new DoNothingChore("sc1", period); 830 ScheduledChore successChore2 = new DoNothingChore("sc2", period); 831 ScheduledChore successChore3 = new DoNothingChore("sc3", period); 832 ScheduledChore failChore1 = new DoNothingChore("fc1", period); 833 ScheduledChore failChore2 = new DoNothingChore("fc2", period); 834 ScheduledChore failChore3 = new DoNothingChore("fc3", period); 835 836 try { 837 assertTrue(service.scheduleChore(successChore1)); 838 assertTrue(successChore1.isScheduled()); 839 assertTrue(service.scheduleChore(successChore2)); 840 assertTrue(successChore2.isScheduled()); 841 assertTrue(service.scheduleChore(successChore3)); 842 assertTrue(successChore3.isScheduled()); 843 } finally { 844 shutdownService(service); 845 } 846 847 assertFalse(service.scheduleChore(failChore1)); 848 assertFalse(failChore1.isScheduled()); 849 assertFalse(service.scheduleChore(failChore2)); 850 assertFalse(failChore2.isScheduled()); 851 assertFalse(service.scheduleChore(failChore3)); 852 assertFalse(failChore3.isScheduled()); 853 } 854 } 855