package org.mobicents.diameter.stack;
import static org.junit.Assert.fail;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import org.jdiameter.api.Answer;
import org.jdiameter.api.ApplicationId;
import org.jdiameter.api.Configuration;
import org.jdiameter.api.DisconnectCause;
import org.jdiameter.api.IllegalDiameterStateException;
import org.jdiameter.api.Mode;
import org.jdiameter.api.Network;
import org.jdiameter.api.NetworkReqListener;
import org.jdiameter.api.Request;
import org.jdiameter.client.api.StackState;
import org.jdiameter.server.impl.StackImpl;
import org.junit.Assert;
import org.junit.Test;
public class StackLifecycleTest {
// Stack Lifecycle
// +------+ +------------+ +---------+
// | Idle | = init => | Configured | = start => | Started |
// +------+ +------------+ +---------+
// /\ /\ || || /\
// || || || stop ||
// || ++==== destroy =====++ || ||
// || +---------+ <==============++ ||
// ++== destroy ==== | Stopped | ||
// +---------+ === start ==========++
@Test
public void testStartWithoutInit() {
StackImpl stack = new StackImpl();
try {
stack.start();
fail("Should have failed calling start() when stack is in state IDLE");
}
catch (IllegalDiameterStateException idse) {
// We are OK. This is what was expected.
}
catch (Exception e) {
e.printStackTrace();
fail("Expected different exception (IllegalDiameterStateException), got " + e.getClass().getName());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testDoubleInit() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
// We should fail here, it's already initialized
stack.init(config);
fail("Should have failed calling init() when stack is in state CONFIGURED");
}
catch (IllegalDiameterStateException idse) {
// We are OK. This is what was expected.
}
catch (Exception e) {
e.printStackTrace();
fail("Expected different exception (IllegalDiameterStateException), got " + e.getClass().getName());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testInitDestroyInit() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.destroy();
stack.init(config);
}
catch (Exception e) {
e.printStackTrace();
fail("Should have been successful switching states IDLE -> CONFIGURED -> IDLE -> CONFIGURED. Failed with: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testStopWithoutInit() {
StackImpl stack = new StackImpl();
try {
stack.stop(DisconnectCause.REBOOTING);
}
catch (Exception e) {
e.printStackTrace();
fail("Should have been successful calling stop(DisconnectCause.REBOOTING) with stack in IDLE state. Failed with: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testDestroyWithoutInit() {
StackImpl stack = new StackImpl();
try {
stack.destroy();
}
catch (Exception e) {
e.printStackTrace();
fail("Should have been successful calling destroy() with stack in IDLE state. Failed with: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testStopWithoutStart() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.stop(DisconnectCause.REBOOTING);
}
catch (Exception e) {
e.printStackTrace();
fail("Should have been successful calling stop(DisconnectCause.REBOOTING) with stack in CONFIGURED state. Failed with: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testDestroyWithoutStop() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.start();
stack.destroy();
}
catch (Exception e) {
e.printStackTrace();
fail("Should have been successful calling destroy() with stack in STARTED state. Failed with: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testInitAfterStart() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.start();
stack.init(config);
fail("Should have failed calling init() with stack in STARTED state.");
}
catch (IllegalDiameterStateException idse) {
// We are OK. This is what was expected.
}
catch (Exception e) {
e.printStackTrace();
fail("Expected different exception (IllegalDiameterStateException), got " + e.getClass().getName());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testDoubleStart() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.start();
// We should fail here, it's already started
stack.start();
fail("Should have failed calling start() when stack is in STARTED state.");
}
catch (IllegalDiameterStateException idse) {
// We are OK. This is what was expected.
}
catch (Exception e) {
e.printStackTrace();
fail("Expected different exception (IllegalDiameterStateException), got " + e.getClass().getName());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testInitWhenStopped() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.start();
stack.stop(DisconnectCause.REBOOTING);
// We should fail here, it's already configured, just stopped
stack.init(config);
fail("Should have failed calling init() when stack is in STOPPED state.");
}
catch (IllegalDiameterStateException idse) {
// We are OK. This is what was expected.
}
catch (Exception e) {
e.printStackTrace();
fail("Expected different exception (IllegalDiameterStateException), got " + e.getClass().getName());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testDoubleStop() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
stack.start();
stack.stop(DisconnectCause.REBOOTING);
// We should fail here, it's already configured, just stopped
stack.stop(DisconnectCause.REBOOTING);
}
catch (Exception e) {
e.printStackTrace();
fail("Should have been successful calling stop(DisconnectCause.REBOOTING) with stack in STOPPED state. Failed with: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
@Test
public void testStartStopStart() {
StackImpl stack = new StackImpl();
try {
InputStream is;
String configFile = "jdiameter-server-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Assert.assertNotNull("InputStream for configuration file should not be null", is);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
stack.init(config);
Network network = stack.unwrap(Network.class);
network.addNetworkReqListener(new NetworkReqListener() {
@Override
public Answer processRequest(Request request) {
//this wont be called.
return null;
}
}, ApplicationId.createByAuthAppId(193, 19302));
stack.start();
//System.err.println(" ///////////////////////////////////////////////////////////////////// ");
//System.err.println(" // 1. stack.start() called.");
//System.err.println(" ///////////////////////////////////////////////////////////////////// ");
/** can connect to the stack here **/
boolean canConnect = tryToConnect();
Assert.assertTrue("Should be able to connect to server after 1st 'start'.", canConnect);
stack.stop(DisconnectCause.REBOOTING);
//System.err.println(" ///////////////////////////////////////////////////////////////////// ");
//System.err.println(" // 2. stack.stop(DisconnectCause.REBOOTING) called.");
//System.err.println(" ///////////////////////////////////////////////////////////////////// ");
/** cannot connect to the stack here **/
canConnect = tryToConnect();
Assert.assertFalse("Should NOT be able to connect to server after 'stop'.", canConnect);
stack.start();
//System.err.println(" ///////////////////////////////////////////////////////////////////// ");
//System.err.println(" // 3. stack.start() called.");
//System.err.println(" ///////////////////////////////////////////////////////////////////// ");
/** should be able to connect to the stack here again **/
canConnect = tryToConnect();
Assert.assertTrue("Should be able to connect to server after 2nd 'start'.", canConnect);
stack.stop(DisconnectCause.REBOOTING);
stack.destroy();
}
catch (Exception e) {
e.printStackTrace();
fail("Failure while performing test: " + e.getMessage());
}
finally {
shutdownStack(stack);
}
}
/**
* Creates a client which tries to connect to stack under test.
*
* @return
*/
private boolean tryToConnect() {
org.jdiameter.server.impl.StackImpl clientStack = null;
try {
clientStack = new org.jdiameter.server.impl.StackImpl();
InputStream is;
String configFile = "jdiameter-client-two.xml";
is = StackLifecycleTest.class.getClassLoader().getResourceAsStream("configurations/" + configFile);
Configuration config;
config = new org.jdiameter.server.impl.helpers.XMLConfiguration(is);
clientStack.init(config);
Network network = clientStack.unwrap(Network.class);
network.addNetworkReqListener(new NetworkReqListener() {
@Override
public Answer processRequest(Request request) {
// this wont be called.
return null;
}
}, ApplicationId.createByAuthAppId(193, 19302));
clientStack.start(Mode.ALL_PEERS, 5000, TimeUnit.MILLISECONDS);
}
catch (Exception e) {
return false;
}
finally {
shutdownStack(clientStack);
}
return true;
}
private void shutdownStack(StackImpl stack) {
if (stack != null) {
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
// ignore
}
StackState curState = stack.getState();
if (curState == StackState.IDLE) {
// We are good. let's return
stack = null;
return;
}
else if (curState == StackState.CONFIGURED) {
// It's configured, just destroy it
try {
stack.destroy();
Thread.sleep(500);
}
catch (InterruptedException e) {
// ignore
}
finally {
stack = null;
}
}
else if (curState == StackState.STARTED) {
// It's started, stop and destroy it
try {
stack.stop(DisconnectCause.REBOOTING);
Thread.sleep(500);
}
catch (InterruptedException e) {
// ignore
}
finally {
try {
stack.destroy();
Thread.sleep(500);
}
catch (InterruptedException e) {
// ignore
}
finally {
stack = null;
}
}
}
else if (curState == StackState.STOPPED) {
// It's stopped, just destroy it
try {
stack.destroy();
Thread.sleep(500);
}
catch (InterruptedException e) {
// ignore
}
finally {
stack = null;
}
}
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
// ignore
}
}
}
}