/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation: version 3 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package functionaltests.rm;
import static functionaltests.utils.SchedulerTHelper.log;
import static org.junit.Assert.*;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.junit.*;
import org.objectweb.proactive.api.PAFuture;
import org.ow2.proactive.authentication.crypto.CredData;
import org.ow2.proactive.authentication.crypto.Credentials;
import org.ow2.proactive.resourcemanager.common.event.RMEventType;
import org.ow2.proactive.resourcemanager.frontend.ResourceManager;
import org.ow2.proactive.scheduler.core.properties.PASchedulerProperties;
import org.ow2.proactive.scheduler.core.rmproxies.PerUserConnectionRMProxiesManager;
import org.ow2.proactive.scheduler.core.rmproxies.RMProxiesManager;
import org.ow2.proactive.scheduler.core.rmproxies.RMProxy;
import org.ow2.proactive.scheduler.core.rmproxies.SingleConnectionRMProxiesManager;
import org.ow2.proactive.topology.descriptor.TopologyDescriptor;
import org.ow2.proactive.utils.Criteria;
import org.ow2.proactive.utils.NodeSet;
import org.ow2.tests.ProActiveTest;
import functionaltests.utils.RMTHelper;
import functionaltests.utils.SchedulerTHelper;
import functionaltests.utils.TestScheduler;
public class TestRMProxy extends ProActiveTest {
static final int NODES_NUMBER = 3;
private static Credentials user1Credentials;
private static Credentials user2Credentials;
private RMProxiesManager proxiesManager;
static String nsName = "test";
private static RMTHelper rmHelper;
@BeforeClass
public static void setUp() throws Exception {
if (TestScheduler.isStarted()) {
SchedulerTHelper.log("Killing previous scheduler.");
TestScheduler.kill();
}
rmHelper = new RMTHelper();
rmHelper.getResourceManager();
user1Credentials = Credentials.createCredentials(new CredData("admin", "admin"),
rmHelper.getRMAuth().getPublicKey());
user2Credentials = Credentials.createCredentials(new CredData("demo", "demo"),
rmHelper.getRMAuth().getPublicKey());
rmHelper.createNodeSource(nsName, NODES_NUMBER);
}
@Test
public void testProxiesManagerPerUser() throws Exception {
log("\n Test with per-user connection \n");
testRMProxies(false);
}
@Test
public void testProxiesManagerSingle() throws Exception {
log("\n Test with single connection \n");
testRMProxies(true);
}
@After
public void terminateProxies() {
log("Terminate all proxies");
if (proxiesManager != null) {
try {
proxiesManager.terminateAllProxies();
} catch (Exception ignored) {
}
}
}
@AfterClass
public static void deleteNS() throws Exception {
try {
rmHelper.removeNodeSource(nsName);
rmHelper.waitForNodeSourceEvent(RMEventType.NODESOURCE_REMOVED, nsName);
} catch (Exception ignored) {
}
rmHelper.shutdownRM();
}
private void testRMProxies(boolean singleUserConnection) throws Exception {
ResourceManager rm = rmHelper.getResourceManager();
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
URI rmUri = new URI(RMTHelper.getLocalUrl());
Credentials schedulerProxyCredentials = Credentials.getCredentials(PASchedulerProperties.getAbsolutePath(PASchedulerProperties.RESOURCE_MANAGER_CREDS.getValueAsString()));
if (singleUserConnection) {
proxiesManager = new SingleConnectionRMProxiesManager(rmUri, schedulerProxyCredentials);
} else {
proxiesManager = new PerUserConnectionRMProxiesManager(rmUri, schedulerProxyCredentials);
}
RMProxy user1RMProxy = proxiesManager.getUserRMProxy("admin", user1Credentials);
assertSame("Proxy manager should return cached proxy instance",
user1RMProxy,
proxiesManager.getUserRMProxy("admin", user1Credentials));
RMProxy user2RMProxy = proxiesManager.getUserRMProxy("demo", user2Credentials);
assertSame("Proxy manager should return cached proxy instance",
user2RMProxy,
proxiesManager.getUserRMProxy("demo", user2Credentials));
requestReleaseOneNode(user1RMProxy, rm);
testSplitNodeSet(user1RMProxy, rm);
checkSchedulerProxy(proxiesManager);
requestWithExtraNodes(user1RMProxy, rm);
requestTooManyNodes(user1RMProxy, rm);
requestReleaseAllNodes(user1RMProxy, rm);
checkSchedulerProxy(proxiesManager);
requestReleaseOneNode(user2RMProxy, rm);
requestReleaseAllNodes(user2RMProxy, rm);
requestWithTwoUsers(user1RMProxy, user2RMProxy, rm);
checkSchedulerProxy(proxiesManager);
log("Terminate user proxy1");
proxiesManager.terminateRMProxy("admin");
user1RMProxy = proxiesManager.getUserRMProxy("admin", user1Credentials);
requestReleaseAllNodes(user1RMProxy, rm);
log("Terminate user proxy2");
proxiesManager.terminateRMProxy("demo");
user2RMProxy = proxiesManager.getUserRMProxy("demo", user2Credentials);
requestReleaseAllNodes(user2RMProxy, rm);
}
private void requestWithTwoUsers(RMProxy proxy1, RMProxy proxy2, ResourceManager rm) throws Exception {
log("Request nodes for two users");
NodeSet nodeSet1 = proxy1.getNodes(new Criteria(1));
NodeSet nodeSet2 = proxy2.getNodes(new Criteria(2));
waitWhenNodeSetAcquired(nodeSet1, 1);
waitWhenNodeSetAcquired(nodeSet2, 2);
assertEquals(NODES_NUMBER - 3, rm.getState().getFreeNodesNumber());
proxy1.releaseNodes(nodeSet1);
proxy2.releaseNodes(nodeSet2);
waitWhenNodesAreReleased(3);
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
}
private void checkSchedulerProxy(RMProxiesManager proxiesManager) {
log("Check scheduler proxy");
RMProxy proxy = proxiesManager.getRmProxy();
assertEquals(proxy.getState().getFreeNodesNumber(), NODES_NUMBER);
assertTrue(proxy.isActive().getBooleanValue());
}
private void requestTooManyNodes(RMProxy proxy, ResourceManager rm) throws Exception {
log("Request more nodes than RM has");
Criteria criteria = new Criteria(NODES_NUMBER + 1);
criteria.setBestEffort(false);
NodeSet nodeSet = proxy.getNodes(criteria);
PAFuture.waitFor(nodeSet);
assertEquals(0, nodeSet.size());
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
}
private void requestWithExtraNodes(RMProxy proxy, ResourceManager rm) throws Exception {
log("Request NodeSet with extra nodes");
TopologyDescriptor topology = TopologyDescriptor.SINGLE_HOST_EXCLUSIVE;
Criteria criteria = new Criteria(1);
criteria.setTopology(topology);
NodeSet nodeSet = proxy.getNodes(criteria);
PAFuture.waitFor(nodeSet);
assertEquals(1, nodeSet.size());
Assert.assertNotNull("Extra nodes are expected", nodeSet.getExtraNodes());
assertEquals(NODES_NUMBER - 1, nodeSet.getExtraNodes().size());
assertEquals(0, rm.getState().getFreeNodesNumber());
proxy.releaseNodes(nodeSet);
waitWhenNodesAreReleased(NODES_NUMBER);
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
}
private void requestReleaseAllNodes(RMProxy proxy, ResourceManager rm) throws Exception {
log("Request and release all nodes");
List<NodeSet> nodeSets = new ArrayList<>();
for (int i = 0; i < NODES_NUMBER; i++) {
nodeSets.add(proxy.getNodes(new Criteria(1)));
}
for (NodeSet nodeSet : nodeSets) {
waitWhenNodeSetAcquired(nodeSet, 1);
proxy.releaseNodes(nodeSet);
}
waitWhenNodesAreReleased(NODES_NUMBER);
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
}
private void requestReleaseOneNode(RMProxy proxy, ResourceManager rm) throws Exception {
log("Request and release single node");
NodeSet nodeSet = proxy.getNodes(new Criteria(1));
waitWhenNodeSetAcquired(nodeSet, 1);
proxy.releaseNodes(nodeSet);
waitWhenNodesAreReleased(1);
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
}
private void testSplitNodeSet(RMProxy proxy, ResourceManager rm) throws Exception {
log("Request as single NodeSet, release it as two NodeSets");
NodeSet nodeSet = proxy.getNodes(new Criteria(3));
waitWhenNodeSetAcquired(nodeSet, 3);
assertEquals(NODES_NUMBER - 3, rm.getState().getFreeNodesNumber());
NodeSet nodeSet1 = new NodeSet();
nodeSet1.add(nodeSet.remove(0));
NodeSet nodeSet2 = new NodeSet();
nodeSet2.add(nodeSet.remove(0));
nodeSet2.add(nodeSet.remove(0));
proxy.releaseNodes(nodeSet1);
waitWhenNodesAreReleased(1);
assertEquals(NODES_NUMBER - 2, rm.getState().getFreeNodesNumber());
proxy.releaseNodes(nodeSet2);
waitWhenNodesAreReleased(2);
assertEquals(NODES_NUMBER, rm.getState().getFreeNodesNumber());
}
private void waitWhenNodesAreReleased(int nodesNumber) throws Exception {
for (int i = 0; i < nodesNumber; i++) {
rmHelper.waitForAnyNodeEvent(RMEventType.NODE_STATE_CHANGED);
}
}
private void waitWhenNodeSetAcquired(NodeSet nodeSet, int expectedNodesNumber) throws Exception {
PAFuture.waitFor(nodeSet);
assertEquals("Unexpected nodes number in NodeSet", expectedNodesNumber, nodeSet.size());
for (int i = 0; i < expectedNodesNumber; i++) {
rmHelper.waitForAnyNodeEvent(RMEventType.NODE_STATE_CHANGED);
}
}
}