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