Repository: iluwatar/java-design-patterns
Issue: Intermittent failure in Balking pattern
Labels: type: bug
epic: build issue

See Travis log https://api.travis-ci.org/v3/job/329176022/log.txt

Issue comments:
Ping @Rzeposlaw, care to investigate?
Why this is messy when I open the Travis log?
@iluwatar I would like to work on it :)
Ok @sharmin03 
Flaky test disabled in https://github.com/iluwatar/java-design-patterns/commit/17ea0b17f68e6d20917dfd2937db28de83d9bf27. Still needs to be fixed.

Pull request review comments:

Patch that resolved the issue:
diff --git a/balking/src/main/java/com/iluwatar/balking/DelayProvider.java b/balking/src/main/java/com/iluwatar/balking/DelayProvider.java
new file mode 100644
index 000000000000..26b4f8936127
--- /dev/null
+++ b/balking/src/main/java/com/iluwatar/balking/DelayProvider.java
@@ -0,0 +1,10 @@
+package com.iluwatar.balking;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An interface to simulate delay while executing some work.
+ */
+public interface DelayProvider {
+  void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
+}
diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java
index e4f1259add25..5aa39c66ca89 100644
--- a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java
+++ b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java
@@ -25,17 +25,38 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Washing machine class
  */
 public class WashingMachine {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
-
+  private final DelayProvider delayProvider;
   private WashingMachineState washingMachineState;
 
+  /**
+   * Creates a new instance of WashingMachine
+   */
   public WashingMachine() {
-    washingMachineState = WashingMachineState.ENABLED;
+    this((interval, timeUnit, task) -> {
+      try {
+        Thread.sleep(timeUnit.toMillis(interval));
+      } catch (InterruptedException ie) {
+        ie.printStackTrace();
+      }
+      task.run();
+    });
+  }
+
+  /**
+   * Creates a new instance of WashingMachine using provided delayProvider. This constructor is used only for
+   * unit testing purposes.
+   */
+  public WashingMachine(DelayProvider delayProvider) {
+    this.delayProvider = delayProvider;
+    this.washingMachineState = WashingMachineState.ENABLED;
   }
 
   public WashingMachineState getWashingMachineState() {
@@ -56,12 +77,8 @@ public void wash() {
       washingMachineState = WashingMachineState.WASHING;
     }
     LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
-    try {
-      Thread.sleep(50);
-    } catch (InterruptedException ie) {
-      ie.printStackTrace();
-    }
-    endOfWashing();
+
+    this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
   }
 
   /**


Test patch:
diff --git a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
index 9a13b8b2dcf4..100bf61a6341 100644
--- a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
+++ b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
@@ -22,11 +22,8 @@
  */
 package com.iluwatar.balking;
 
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -36,32 +33,39 @@
  */
 public class WashingMachineTest {
 
-  private volatile WashingMachineState machineStateGlobal;
+  private FakeDelayProvider fakeDelayProvider = new FakeDelayProvider();
 
-  @Disabled
   @Test
-  public void wash() throws Exception {
-    WashingMachine washingMachine = new WashingMachine();
-    ExecutorService executorService = Executors.newFixedThreadPool(2);
-    executorService.execute(washingMachine::wash);
-    executorService.execute(() -> {
-      washingMachine.wash();
-      machineStateGlobal = washingMachine.getWashingMachineState();
-    });
-    executorService.shutdown();
-    try {
-      executorService.awaitTermination(10, TimeUnit.SECONDS);
-    } catch (InterruptedException ie) {
-      ie.printStackTrace();
-    }
+  public void wash() {
+    WashingMachine washingMachine = new WashingMachine(fakeDelayProvider);
+
+    washingMachine.wash();
+    washingMachine.wash();
+
+    WashingMachineState machineStateGlobal = washingMachine.getWashingMachineState();
+
+    fakeDelayProvider.task.run();
+
+    // washing machine remains in washing state
     assertEquals(WashingMachineState.WASHING, machineStateGlobal);
+
+    // washing machine goes back to enabled state
+    assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
   }
 
   @Test
-  public void endOfWashing() throws Exception {
+  public void endOfWashing() {
     WashingMachine washingMachine = new WashingMachine();
     washingMachine.wash();
     assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
   }
 
+  private class FakeDelayProvider implements DelayProvider {
+    private Runnable task;
+
+    @Override
+    public void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task) {
+      this.task = task;
+    }
+  }
 }
\ No newline at end of file