/*
* Copyright 2009 Programming Mastery Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
package com.example.circuitbreaker.test;
import static org.junit.Assert.assertEquals;
import java.lang.management.ManagementFactory;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.example.circuitbreaker.CircuitBreakerMXBean;
import com.example.circuitbreaker.CircuitBreakerOpenException;
import com.example.circuitbreaker.CircuitBreakerStatus;
import com.example.circuitbreaker.test.localservice.ILocalService;
import com.example.circuitbreaker.test.localservice.LocalServiceWithCallback;
import com.example.circuitbreaker.test.remotesystem.RemoteSystem;
import com.example.circuitbreaker.test.remotesystem.RemoteSystemException;
public class CircuitBreakerTest {
protected CircuitBreakerMXBean circuitBreaker;
protected RemoteSystem remote;
protected ILocalService service;
protected final int maxFailuresBeforeOpen = 2;
protected final long resetTimeInMilliSeconds = 1000;
private void delayTillBreakerReset() throws InterruptedException
{
Thread.sleep(this.resetTimeInMilliSeconds+100);
}
private void callAndFailWithRemoteException()
{
try {
service.foo();
} catch( RemoteSystemException e)
{
}
}
private void callAndFailWithCircuitBreakerOpenException()
{
try {
service.foo();
} catch( CircuitBreakerOpenException e){
}
}
@Before
public void setupTest() throws Exception {
this.remote = new RemoteSystem();
this.service = new LocalServiceWithCallback(remote);
this.setupLocalService();
}
public void setupLocalService() throws Exception
{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=CircuitBreaker,name=RemoteSystem");
this.circuitBreaker = JMX.newMXBeanProxy(mbs, name, CircuitBreakerMXBean.class);
circuitBreaker.setMaxFailuresBeforeOpening(this.maxFailuresBeforeOpen);
circuitBreaker.setResetTimeInMilliSeconds(this.resetTimeInMilliSeconds);
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(0, circuitBreaker.getCumulativeFailureCount());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
}
@After
public void teardownTest() throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=CircuitBreaker,name=RemoteSystem");
mbs.unregisterMBean(name);
this.remote = null;
this.service = null;
}
@Test
public void testWhenRemoteSystemUp() throws Exception
{
this.remote.setFailOnNextCall(false);
this.service.foo();
this.service.foo();
this.service.foo();
this.service.foo();
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(0,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
}
@Test
public void testWhenRemoteSystemDown() throws Exception
{
this.remote.setFailOnNextCall(true);
// first call
this.callAndFailWithRemoteException();
assertEquals(1,circuitBreaker.getCurrentFailureCount());
assertEquals(1,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// second call
this.callAndFailWithRemoteException();
assertEquals(2,circuitBreaker.getCurrentFailureCount());
assertEquals(2,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// third call
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fourth call
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(1,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fifth call
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(2,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// sixth call
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
}
@Test
public void testWhenRemoteSystemUpThenDown() throws Exception
{
// remote system up
this.remote.setFailOnNextCall(false);
// first call
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(0,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// second call
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(0,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// remote system down
this.remote.setFailOnNextCall(true);
// third,fourth,fifth call breaker opens
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// sixth, seventh, call breaker is dropping calls to remote system
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
}
@Test
public void testWhenRemoteSystemDownThenUp() throws Exception
{
// remote system down
this.remote.setFailOnNextCall(true);
// first, second, third call trigger opening of breaker
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fourth, fifth, sixth, call breaker is dropping calls to remote system
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// remote system is up
this.remote.setFailOnNextCall(false);
// wait for the breaker to reset
this.delayTillBreakerReset();
// make a few calls when the system is up
this.service.foo();
this.service.foo();
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
}
@Test
public void testWhenRemoteSystemDownThenUpThenDownThenUp() throws Exception
{
// remote system down
this.remote.setFailOnNextCall(true);
// first, second, third call trigger opening of breaker
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fourth, fifth, sixth, call breaker is dropping calls to remote system
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// remote system is up
this.remote.setFailOnNextCall(false);
// wait for the breaker to reset
this.delayTillBreakerReset();
// make a few calls when the system is up
this.service.foo();
this.service.foo();
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// remote system down
this.remote.setFailOnNextCall(true);
// make a few calls to trigger the breaker to open
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(6,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fourth, fifth, sixth, call breaker is dropping calls to remote system
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(6,circuitBreaker.getCumulativeFailureCount());
assertEquals(5,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// remote system is up
this.remote.setFailOnNextCall(false);
// wait for the breaker to reset
this.delayTillBreakerReset();
// make a few calls when the system is up
this.service.foo();
this.service.foo();
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(6,circuitBreaker.getCumulativeFailureCount());
assertEquals(5,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
}
@Test
public void testWhenRemoteSystemUpThenDownThenUpThenDown() throws InterruptedException
{
// system is up
this.remote.setFailOnNextCall(false);
this.service.foo();
this.service.foo();
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(0,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// remote system down
this.remote.setFailOnNextCall(true);
// first, second, third call trigger opening of breaker
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(0,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fourth, fifth, sixth, call breaker is dropping calls to remote system
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// remote system is up
this.remote.setFailOnNextCall(false);
// wait for the breaker to reset
this.delayTillBreakerReset();
// make a few calls when the system is up
this.service.foo();
this.service.foo();
this.service.foo();
assertEquals(0,circuitBreaker.getCurrentFailureCount());
assertEquals(3,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.closed,circuitBreaker.getStatus());
// remote system down
this.remote.setFailOnNextCall(true);
// first, second, third call trigger opening of breaker
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
this.callAndFailWithRemoteException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(6,circuitBreaker.getCumulativeFailureCount());
assertEquals(3,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
// fourth, fifth, sixth, call breaker is dropping calls to remote system
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
this.callAndFailWithCircuitBreakerOpenException();
assertEquals(3,circuitBreaker.getCurrentFailureCount());
assertEquals(6,circuitBreaker.getCumulativeFailureCount());
assertEquals(6,circuitBreaker.getCumultaviteCallsWhenOpen());
assertEquals(CircuitBreakerStatus.open,circuitBreaker.getStatus());
}
}