Compare commits
1 Commits
Ambassador
...
Issue#699
Author | SHA1 | Date | |
---|---|---|---|
829df031c3 |
@ -22,7 +22,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.ambassador;
|
package com.iluwatar.ambassador;
|
||||||
|
|
||||||
import com.iluwatar.ambassador.util.RandomProvider;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -32,10 +31,9 @@ import static java.lang.Thread.sleep;
|
|||||||
* A remote legacy application represented by a Singleton implementation.
|
* A remote legacy application represented by a Singleton implementation.
|
||||||
*/
|
*/
|
||||||
public class RemoteService implements RemoteServiceInterface {
|
public class RemoteService implements RemoteServiceInterface {
|
||||||
static final int THRESHOLD = 200;
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
|
||||||
private static RemoteService service = null;
|
private static RemoteService service = null;
|
||||||
private final RandomProvider randomProvider;
|
|
||||||
|
|
||||||
static synchronized RemoteService getRemoteService() {
|
static synchronized RemoteService getRemoteService() {
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
@ -44,33 +42,24 @@ public class RemoteService implements RemoteServiceInterface {
|
|||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RemoteService() {
|
private RemoteService() {}
|
||||||
this(Math::random);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This constuctor is used for testing purposes only.
|
|
||||||
*/
|
|
||||||
RemoteService(RandomProvider randomProvider) {
|
|
||||||
this.randomProvider = randomProvider;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Remote function takes a value and multiplies it by 10 taking a random amount of time.
|
* Remote function takes a value and multiplies it by 10 taking a random amount of time.
|
||||||
* Will sometimes return -1. This imitates connectivity issues a client might have to account for.
|
* Will sometimes return -1. This imitates connectivity issues a client might have to account for.
|
||||||
* @param value integer value to be multiplied.
|
* @param value integer value to be multiplied.
|
||||||
* @return if waitTime is less than {@link RemoteService#THRESHOLD}, it returns value * 10,
|
* @return if waitTime is more than 200ms, it returns value * 10, otherwise -1.
|
||||||
* otherwise {@link RemoteServiceInterface#FAILURE}.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long doRemoteFunction(int value) {
|
public long doRemoteFunction(int value) {
|
||||||
|
|
||||||
long waitTime = (long) Math.floor(randomProvider.random() * 1000);
|
long waitTime = (long) Math.floor(Math.random() * 1000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sleep(waitTime);
|
sleep(waitTime);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOGGER.error("Thread sleep state interrupted", e);
|
LOGGER.error("Thread sleep state interrupted", e);
|
||||||
}
|
}
|
||||||
return waitTime <= THRESHOLD ? value * 10 : FAILURE;
|
return waitTime >= 200 ? value * 10 : -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ package com.iluwatar.ambassador;
|
|||||||
* Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}).
|
* Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}).
|
||||||
*/
|
*/
|
||||||
interface RemoteServiceInterface {
|
interface RemoteServiceInterface {
|
||||||
int FAILURE = -1;
|
|
||||||
|
|
||||||
long doRemoteFunction(int value) throws Exception;
|
long doRemoteFunction(int value) throws Exception;
|
||||||
}
|
}
|
||||||
|
@ -59,15 +59,15 @@ public class ServiceAmbassador implements RemoteServiceInterface {
|
|||||||
private long safeCall(int value) {
|
private long safeCall(int value) {
|
||||||
|
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
long result = FAILURE;
|
long result = -1;
|
||||||
|
|
||||||
for (int i = 0; i < RETRIES; i++) {
|
for (int i = 0; i < RETRIES; i++) {
|
||||||
|
|
||||||
if (retries >= RETRIES) {
|
if (retries >= RETRIES) {
|
||||||
return FAILURE;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result = checkLatency(value)) == FAILURE) {
|
if ((result = checkLatency(value)) == -1) {
|
||||||
LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
|
LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
|
||||||
retries++;
|
retries++;
|
||||||
try {
|
try {
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
package com.iluwatar.ambassador.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for randomness. Useful for testing purposes.
|
|
||||||
*/
|
|
||||||
public interface RandomProvider {
|
|
||||||
double random();
|
|
||||||
}
|
|
@ -24,8 +24,6 @@ package com.iluwatar.ambassador;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link Client}
|
* Test for {@link Client}
|
||||||
*/
|
*/
|
||||||
@ -37,6 +35,6 @@ public class ClientTest {
|
|||||||
Client client = new Client();
|
Client client = new Client();
|
||||||
long result = client.useService(10);
|
long result = client.useService(10);
|
||||||
|
|
||||||
assertTrue(result == 100 || result == RemoteService.FAILURE);
|
assert result == 100 || result == -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,43 +22,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.ambassador;
|
package com.iluwatar.ambassador;
|
||||||
|
|
||||||
import com.iluwatar.ambassador.util.RandomProvider;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link RemoteService}
|
* Test for {@link RemoteService}
|
||||||
*/
|
*/
|
||||||
public class RemoteServiceTest {
|
public class RemoteServiceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFailedCall() {
|
public void test() {
|
||||||
RemoteService remoteService = new RemoteService(
|
long result = RemoteService.getRemoteService().doRemoteFunction(10);
|
||||||
new StaticRandomProvider(0.21));
|
assert result == 100 || result == -1;
|
||||||
long result = remoteService.doRemoteFunction(10);
|
|
||||||
assertEquals(RemoteServiceInterface.FAILURE, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSuccessfulCall() {
|
|
||||||
RemoteService remoteService = new RemoteService(
|
|
||||||
new StaticRandomProvider(0.2));
|
|
||||||
long result = remoteService.doRemoteFunction(10);
|
|
||||||
assertEquals(100, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class StaticRandomProvider implements RandomProvider {
|
|
||||||
private double value;
|
|
||||||
|
|
||||||
StaticRandomProvider(double value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double random() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,6 @@ package com.iluwatar.ambassador;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link ServiceAmbassador}
|
* Test for {@link ServiceAmbassador}
|
||||||
*/
|
*/
|
||||||
@ -34,6 +32,6 @@ public class ServiceAmbassadorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
long result = new ServiceAmbassador().doRemoteFunction(10);
|
long result = new ServiceAmbassador().doRemoteFunction(10);
|
||||||
assertTrue(result == 100 || result == RemoteServiceInterface.FAILURE);
|
assert result == 100 || result == -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -25,17 +25,38 @@ package com.iluwatar.balking;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Washing machine class
|
* Washing machine class
|
||||||
*/
|
*/
|
||||||
public class WashingMachine {
|
public class WashingMachine {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
|
||||||
|
private final DelayProvider delayProvider;
|
||||||
private WashingMachineState washingMachineState;
|
private WashingMachineState washingMachineState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of WashingMachine
|
||||||
|
*/
|
||||||
public 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() {
|
public WashingMachineState getWashingMachineState() {
|
||||||
@ -56,12 +77,8 @@ public class WashingMachine {
|
|||||||
washingMachineState = WashingMachineState.WASHING;
|
washingMachineState = WashingMachineState.WASHING;
|
||||||
}
|
}
|
||||||
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
|
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
|
||||||
try {
|
|
||||||
Thread.sleep(50);
|
this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
ie.printStackTrace();
|
|
||||||
}
|
|
||||||
endOfWashing();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,11 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
@ -36,32 +33,39 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
*/
|
*/
|
||||||
public class WashingMachineTest {
|
public class WashingMachineTest {
|
||||||
|
|
||||||
private volatile WashingMachineState machineStateGlobal;
|
private FakeDelayProvider fakeDelayProvider = new FakeDelayProvider();
|
||||||
|
|
||||||
@Disabled
|
|
||||||
@Test
|
@Test
|
||||||
public void wash() throws Exception {
|
public void wash() {
|
||||||
WashingMachine washingMachine = new WashingMachine();
|
WashingMachine washingMachine = new WashingMachine(fakeDelayProvider);
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(2);
|
|
||||||
executorService.execute(washingMachine::wash);
|
washingMachine.wash();
|
||||||
executorService.execute(() -> {
|
washingMachine.wash();
|
||||||
washingMachine.wash();
|
|
||||||
machineStateGlobal = washingMachine.getWashingMachineState();
|
WashingMachineState machineStateGlobal = washingMachine.getWashingMachineState();
|
||||||
});
|
|
||||||
executorService.shutdown();
|
fakeDelayProvider.task.run();
|
||||||
try {
|
|
||||||
executorService.awaitTermination(10, TimeUnit.SECONDS);
|
// washing machine remains in washing state
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
ie.printStackTrace();
|
|
||||||
}
|
|
||||||
assertEquals(WashingMachineState.WASHING, machineStateGlobal);
|
assertEquals(WashingMachineState.WASHING, machineStateGlobal);
|
||||||
|
|
||||||
|
// washing machine goes back to enabled state
|
||||||
|
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void endOfWashing() throws Exception {
|
public void endOfWashing() {
|
||||||
WashingMachine washingMachine = new WashingMachine();
|
WashingMachine washingMachine = new WashingMachine();
|
||||||
washingMachine.wash();
|
washingMachine.wash();
|
||||||
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user