/*
* Copyright to the original author or authors.
*
* 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 org.rioproject.test.monitor;
import net.jini.lookup.ServiceDiscoveryManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.RunWith;
import org.rioproject.cybernode.Cybernode;
import org.rioproject.monitor.ProvisionMonitor;
import org.rioproject.impl.opstring.OpString;
import org.rioproject.impl.opstring.OpStringLoader;
import org.rioproject.opstring.OperationalString;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.test.RioTestRunner;
import org.rioproject.test.ServiceMonitor;
import org.rioproject.test.SetTestManager;
import org.rioproject.test.TestManager;
import org.rioproject.test.simple.Simple;
import org.rioproject.test.utils.ArrayUtils;
import org.rioproject.test.utils.CybernodeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.rmi.RemoteException;
import java.text.MessageFormat;
import java.util.Arrays;
/**
* The class tests the <code>MaxPerMachine</code> capability.
*/
@RunWith (RioTestRunner.class)
public class MaxPerMachineTest {
static Logger logger = LoggerFactory.getLogger("org.rioproject.test.monitor");
@SetTestManager
static TestManager testManager;
static ServiceMonitor<Cybernode> cyberMon;
static ServiceMonitor<ProvisionMonitor> pmMon;
/**
* The service counts fetched before deploying a new OpString.
*/
int[] prevCounts;
@Before
public void setup() throws Exception {
if(cyberMon==null) {
//testManager.startReggie();
//testManager.startProvisionMonitor();
final int N = Math.max(testManager.getHostList().size(), 2);
for (int i = 0; i < N; i++) {
testManager.startCybernode(i);
}
ServiceDiscoveryManager sdm = testManager.getServiceDiscoveryManager();
pmMon = new ServiceMonitor<ProvisionMonitor>(sdm, ProvisionMonitor.class);
pmMon.waitFor(1);
cyberMon = new ServiceMonitor<Cybernode>(sdm, Cybernode.class);
cyberMon.waitFor(N);
}
}
/**
* Runs Scenario A, which tests different combinations of provision type,
* maintain, and max per machine values. Every attempt is preceded by
* full undeployment.
*
* @throws Exception If there are any problems
*/
@Test
public void scenarioA() throws Exception {
logBanner("Running Scenario A");
final Boolean[] trueFalse = ArrayUtils.asObjects(new boolean[] {false, true});
final Integer[] maintainValues = ArrayUtils.asObjects(new int[] {1, 5, 10, 20});
final Integer[] maxPerMachineValues = ArrayUtils.asObjects(new int[] {-1, 0, 1, 5, 10});
Object[][] combinations = ArrayUtils.combinations(new Object[][] {trueFalse, maintainValues, maxPerMachineValues});
ProvisionMonitor monitor = pmMon.getServices().get(0);
for (Object[] combination : combinations) {
boolean fixed = (Boolean) combination[0];
int maintain = (Integer) combination[1];
int maxPerMachine = (Integer) combination[2];
if (!fixed) {
maintain = maintain * 2;
}
testCombinationA(fixed, maintain, maxPerMachine, monitor);
}
testManager.undeployAll(monitor);
logBanner("Scenario A Complete");
}
/*
* Tests one combination of Scenario A.
*/
private void testCombinationA(boolean fixed, int maintain, int maxPerMachine, ProvisionMonitor monitor)
throws Exception {
logBanner("Test combination:, fixed="+fixed+ ", maintain="+maintain+", maxPerMachine="+maxPerMachine+"]");
testManager.undeployAll(monitor);
// Prepare OpString
OpStringLoader loader = new OpStringLoader();
OperationalString[] opstrings =
loader.parseOperationalString(new File("src/test/resources/opstring/simple_opstring.groovy"));
org.junit.Assert.assertEquals(1, opstrings.length);
OpString opstring = (OpString)opstrings[0];
org.junit.Assert.assertEquals(1, opstring.getServices().length);
ServiceElement service = opstring.getServices()[0];
service.setPlanned(maintain);
service.setMaxPerMachine(maxPerMachine);
service.setProvisionType(fixed? ServiceElement.ProvisionType.FIXED: ServiceElement.ProvisionType.DYNAMIC);
prevCounts = CybernodeUtils.calcServices(cyberMon.getServices(),Simple.class);
logger.info("**** Services found before deploying the OpString: {}",
Arrays.asList(ArrayUtils.asObjects(prevCounts)));
logger.debug("Service details: ["+service.getProvisionType()+"]");
if (maxPerMachine == -1) {
maxPerMachine = Integer.MAX_VALUE;
}
testManager.deploy(opstring, monitor);
checkStateA(fixed, maintain, maxPerMachine);
}
/*
* Checks that the current state of the system is as expected.
*/
private void checkStateA(final boolean fixed, final int maintain, final long maxPerMachine) throws Exception {
// Setup the condition to wait for
Condition condition = new Condition() {
public boolean test() {
int[] counts;
try {
counts = CybernodeUtils.calcServices(cyberMon.getServices(), Simple.class);
} catch (RemoteException e) {
logger.error("Error calculating services", e);
return false;
}
logger.info("Services found: {}", Arrays.asList(ArrayUtils.asObjects(counts)));
if (!fixed) { // dynamic
long max = maxPerMachine * cyberMon.getServices().size();
long expected = Math.min(max, maintain);
if (ArrayUtils.sum(counts) != expected) {
return false;
}
for (int count : counts) {
if (count > maxPerMachine) {
return false;
}
}
} else { // fixed
long expected = Math.min(maxPerMachine, maintain);
for (int count : counts) {
if (count != expected) {
return false;
}
}
}
return true;
}
public String toString() {
if (!fixed) { // dynamic
long max = maxPerMachine * cyberMon.getServices().size();
long expected = Math.min(max, maintain);
if (maxPerMachine < Integer.MAX_VALUE) {
return MessageFormat.format(
"# of services == {0} and # of services"
+ " on each Cybernode <= {1}",
expected,
maxPerMachine);
} else {
return MessageFormat.format(
"# of services == {0}",
expected);
}
} else { // fixed
long expected = Math.min(maxPerMachine, maintain);
return MessageFormat.format(
"# of services on each Cybernode == {0}",
expected);
}
}
};
Waiter waiter = new Waiter();
waiter.waitFor(condition);
}
/**
* Runs Scenario B, which tests what happens if the
* <code><MaxPerMachine></code> element varies without
* undeployment. The <code><Maintain></code> value is fixed.
*
* @throws Exception If there are any problems
*/
@Test
public void scenarioB() throws Exception {
logBanner("Running Scenario B");
ProvisionMonitor monitor = pmMon.getServices().get(0);
final boolean[] fixedValues = new boolean[] {false, true};
final int maintainValue = 6;
final int[] maxPerMachineValues = new int[] {
0, 1, 2, 5, 10, 0, 5, 2, 1, 0};
for (boolean fixedValue : fixedValues) {
testManager.undeployAll(monitor);
for (int maxPerMachineValue : maxPerMachineValues) {
int maintain = maintainValue;
if (!fixedValue) {
maintain = maintain * 2;
}
testCombinationB(fixedValue, maintain, maxPerMachineValue, monitor);
}
}
logBanner("Scenario B Complete");
}
/*
* Tests one combination of Scenario B.
*/
private void testCombinationB(boolean fixed,
int maintain,
int maxPerMachine,
ProvisionMonitor monitor) throws Exception {
logBanner("Test combination:"
+ " [fixed=" + fixed
+ ", maintain=" + maintain
+ ", maxPerMachine=" + maxPerMachine + "]");
testManager.undeployAll(monitor);
// Prepare OpString
OpStringLoader loader = new OpStringLoader();
OperationalString[] opstrings =
loader.parseOperationalString(
new File("src/test/resources/opstring/simple_opstring.groovy"));
org.junit.Assert.assertEquals(1, opstrings.length);
OpString opstring = (OpString)opstrings[0];
org.junit.Assert.assertEquals(1, opstring.getServices().length);
ServiceElement service = opstring.getServices()[0];
service.setPlanned(maintain);
service.setMaxPerMachine(maxPerMachine);
service.setProvisionType(fixed?
ServiceElement.ProvisionType.FIXED:
ServiceElement.ProvisionType.DYNAMIC);
prevCounts = CybernodeUtils.calcServices(cyberMon.getServices(),
Simple.class);
logger.info("**** Services found before deploying the OpString: {}",
Arrays.asList(ArrayUtils.asObjects(prevCounts)).toString());
testManager.deploy(opstring, monitor);
checkStateB(fixed, maintain, maxPerMachine);
}
/*
* Checks that the current state of the system is as expected.
*/
private void checkStateB(final boolean fixed, final int maintain,
final int maxPerMachine) throws Exception {
boolean expectPrevCount = false;
if (!fixed) { // dynamic
long max = maxPerMachine * cyberMon.getServices().size();
if (ArrayUtils.sum(prevCounts) > max) {
expectPrevCount = true;
}
} else { // fixed
if (prevCounts[0] > maxPerMachine) {
expectPrevCount = true;
}
}
// Setup the condition to wait for
Condition condition;
if (expectPrevCount) {
condition = new Condition() {
public boolean test() {
int[] counts;
try {
counts = CybernodeUtils.calcServices(
cyberMon.getServices(), Simple.class);
} catch (RemoteException e) {
logger.error("Error calculating services", e);
return false;
}
logger.info("Services found: {}", Arrays.asList(ArrayUtils.asObjects(counts)).toString());
for (int i = 0; i < counts.length; i++) {
if (counts[i] != prevCounts[i]) {
return false;
}
}
return true;
}
public String toString() {
return MessageFormat.format(
"exact counts == {0}",
Arrays.asList(ArrayUtils.asObjects(prevCounts)));
}
};
} else {
condition = new Condition() {
public boolean test() {
int[] counts;
try {
counts = CybernodeUtils.calcServices(
cyberMon.getServices(), Simple.class);
} catch (RemoteException e) {
logger.error("Error calculating services", e);
return false;
}
logger.info("Services found: {}", Arrays.asList(ArrayUtils.asObjects(counts)).toString());
if (!fixed) { // dynamic
long max = maxPerMachine * cyberMon.getServices().size();
long expected = Math.min(max, maintain);
if (ArrayUtils.sum(counts) != expected) {
return false;
}
for (int count : counts) {
if (count > maxPerMachine) {
return false;
}
}
} else { //fixed
long expected = Math.min(maxPerMachine, maintain);
for (int count : counts) {
if (count != expected) {
return false;
}
}
}
return true;
}
public String toString() {
if (!fixed) { // dynamic
long max = maxPerMachine * cyberMon.getServices().size();
long expected = Math.min(max, maintain);
if (maxPerMachine < Integer.MAX_VALUE) {
return MessageFormat.format(
"# of services == {0} and # of services"
+ " on each Cybernode <= {1}",
expected,
maxPerMachine);
} else {
return MessageFormat.format(
"# of services == {0}",
expected);
}
} else { // fixed
long expected = Math.min(maxPerMachine, maintain);
return MessageFormat.format(
"# of services on each Cybernode == {0}",
expected);
}
}
};
}
Waiter waiter = new Waiter();
waiter.waitFor(condition);
}
private void logBanner(String message) {
logger.info("\n" +
"------------------------------------------------\n"+
message+
"\n------------------------------------------------");
}
public static void main(String... args) {
JUnitCore.main(MaxPerMachineTest.class.getName());
}
}