Skip to content

Resolves #699 Intermittent failure was due to Thread.sleep in the code #802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions balking/src/main/java/com/iluwatar/balking/DelayProvider.java
Original file line number Diff line number Diff line change
@@ -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);
}
33 changes: 25 additions & 8 deletions balking/src/main/java/com/iluwatar/balking/WashingMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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);
}

/**
Expand Down
44 changes: 24 additions & 20 deletions balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
}
}