/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* 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.kie.server.integrationtests.optaplanner;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.junit.BeforeClass;
import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.server.api.model.ReleaseId;
import org.kie.server.api.model.instance.ScoreWrapper;
import org.kie.server.api.model.instance.SolverInstance;
import org.kie.server.integrationtests.shared.KieServerAssert;
import org.kie.server.integrationtests.shared.KieServerDeployer;
import org.kie.server.api.exception.KieServicesException;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import static org.junit.Assert.*;
public class OptaplannerIntegrationTest
extends OptaplannerKieServerBaseIntegrationTest {
private static final ReleaseId kjar1 = new ReleaseId(
"org.kie.server.testing",
"cloudbalance",
"1.0.0.Final");
private static final String NOT_EXISTING_CONTAINER_ID = "no_container";
private static final String CONTAINER_1_ID = "cloudbalance";
private static final String SOLVER_1_ID = "cloudsolver";
private static final String SOLVER_1_CONFIG = "META-INF/cloudbalance-solver.xml";
private static final String CLASS_CLOUD_BALANCE = "org.kie.server.testing.CloudBalance";
private static final String CLASS_CLOUD_COMPUTER = "org.kie.server.testing.CloudComputer";
private static final String CLASS_CLOUD_PROCESS = "org.kie.server.testing.CloudProcess";
private static final String CLASS_CLOUD_GENERATOR = "org.kie.server.testing.CloudBalancingGenerator";
@BeforeClass
public static void deployArtifacts() {
KieServerDeployer.buildAndDeployCommonMavenParent();
KieServerDeployer.buildAndDeployMavenProject(ClassLoader.class.getResource("/kjars-sources/cloudbalance").getFile());
kieContainer = KieServices.Factory.get().newKieContainer(kjar1);
createContainer(CONTAINER_1_ID,
kjar1);
}
@Override
protected void addExtraCustomClasses(Map<String, Class<?>> extraClasses)
throws Exception {
extraClasses.put(CLASS_CLOUD_BALANCE,
Class.forName(CLASS_CLOUD_BALANCE,
true,
kieContainer.getClassLoader()));
extraClasses.put(CLASS_CLOUD_COMPUTER,
Class.forName(CLASS_CLOUD_COMPUTER,
true,
kieContainer.getClassLoader()));
extraClasses.put(CLASS_CLOUD_PROCESS,
Class.forName(CLASS_CLOUD_PROCESS,
true,
kieContainer.getClassLoader()));
}
@Test
public void testCreateDisposeSolver()
throws Exception {
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
solverClient.disposeSolver(CONTAINER_1_ID,
SOLVER_1_ID);
}
@Test
public void testCreateSolverFromNotExistingContainer() {
try {
solverClient.createSolver(NOT_EXISTING_CONTAINER_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Failed to create solver. Container does not exist: .*");
}
}
@Test(expected = IllegalArgumentException.class)
public void testCreateSolverWithoutSolverInstance() throws Exception {
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
null);
}
@Test
public void testCreateSolverWrongSolverInstanceConfigPath() throws Exception {
try {
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
"NonExistingPath");
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*The solverConfigResource \\(.*\\) does not exist as a classpath resource in the classLoader \\(.*\\)*");
}
}
@Test(expected = IllegalArgumentException.class)
public void testCreateSolverNullContainer() throws Exception {
solverClient.createSolver(null,
SOLVER_1_ID,
null);
}
@Test
public void testCreateDuplicitSolver() throws Exception {
SolverInstance solverInstance = solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
assertNotNull(solverInstance);
try {
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Failed to create solver. Solver .* already exists for container .*");
}
}
@Test
public void testDisposeNotExistingSolver() throws Exception {
try {
solverClient.disposeSolver(CONTAINER_1_ID,
SOLVER_1_ID);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Solver.*from container.*not found.*");
}
}
@Test
public void testGetSolverState() throws Exception {
SolverInstance solverInstance = solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
assertNotNull(solverInstance);
solverInstance = solverClient.getSolver(CONTAINER_1_ID,
SOLVER_1_ID);
assertNotNull(solverInstance);
assertEquals(CONTAINER_1_ID,
solverInstance.getContainerId());
assertEquals(SOLVER_1_CONFIG,
solverInstance.getSolverConfigFile());
assertEquals(SOLVER_1_ID,
solverInstance.getSolverId());
assertEquals(SolverInstance.getSolverInstanceKey(CONTAINER_1_ID,
SOLVER_1_ID),
solverInstance.getSolverInstanceKey());
assertEquals(SolverInstance.SolverStatus.NOT_SOLVING,
solverInstance.getStatus());
assertNotNull(solverInstance.getScoreWrapper());
assertNull(solverInstance.getScoreWrapper().toScore());
}
@Test
public void testGetNotExistingSolverState() throws Exception {
try {
solverClient.getSolver(CONTAINER_1_ID,
SOLVER_1_ID);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Solver.*not found in container.*");
}
}
@Test
public void testGetSolvers() throws Exception {
List<SolverInstance> solverInstanceList = solverClient.getSolvers(CONTAINER_1_ID);
assertNotNull(solverInstanceList);
assertEquals(0,
solverInstanceList.size());
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
solverInstanceList = solverClient.getSolvers(CONTAINER_1_ID);
assertNotNull(solverInstanceList);
assertEquals(1,
solverInstanceList.size());
SolverInstance returnedInstance = solverInstanceList.get(0);
assertEquals(CONTAINER_1_ID,
returnedInstance.getContainerId());
assertEquals(SOLVER_1_CONFIG,
returnedInstance.getSolverConfigFile());
assertEquals(SOLVER_1_ID,
returnedInstance.getSolverId());
assertEquals(SolverInstance.getSolverInstanceKey(CONTAINER_1_ID,
SOLVER_1_ID),
returnedInstance.getSolverInstanceKey());
assertEquals(SolverInstance.SolverStatus.NOT_SOLVING,
returnedInstance.getStatus());
assertNotNull(returnedInstance.getScoreWrapper());
assertNull(returnedInstance.getScoreWrapper().toScore());
}
@Test
public void testExecuteSolver() throws Exception {
SolverInstance solverInstance = solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
assertNotNull(solverInstance);
assertEquals(SolverInstance.SolverStatus.NOT_SOLVING,
solverInstance.getStatus());
// the following status starts the solver
Object planningProblem = loadPlanningProblem(5,
15);
solverClient.solvePlanningProblem(CONTAINER_1_ID,
SOLVER_1_ID,
planningProblem);
solverInstance = solverClient.getSolver(CONTAINER_1_ID,
SOLVER_1_ID);
// solver should finish in 5 seconds, but we wait up to 15s before timing out
for (int i = 0; i < 5 && solverInstance.getStatus() == SolverInstance.SolverStatus.SOLVING; i++) {
Thread.sleep(3000);
solverInstance = solverClient.getSolver(CONTAINER_1_ID,
SOLVER_1_ID);
assertNotNull(solverInstance);
}
assertEquals(SolverInstance.SolverStatus.NOT_SOLVING,
solverInstance.getStatus());
solverClient.disposeSolver(CONTAINER_1_ID,
SOLVER_1_ID);
}
@Test
public void testExecuteRunningSolver() throws Exception {
SolverInstance solverInstance = solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
assertNotNull(solverInstance);
assertEquals(SolverInstance.SolverStatus.NOT_SOLVING,
solverInstance.getStatus());
// start solver
Object planningProblem = loadPlanningProblem(5,
15);
solverClient.solvePlanningProblem(CONTAINER_1_ID,
SOLVER_1_ID,
planningProblem);
// start solver again
try {
solverClient.solvePlanningProblem(CONTAINER_1_ID,
SOLVER_1_ID,
planningProblem);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Solver .* on container .* is already executing.*");
}
solverClient.disposeSolver(CONTAINER_1_ID,
SOLVER_1_ID);
}
@Test(timeout = 60000)
public void testGetBestSolution() throws Exception {
SolverInstance solverInstance = solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
// Start the solver
Object planningProblem = loadPlanningProblem(10,
30);
solverClient.solvePlanningProblem(CONTAINER_1_ID,
SOLVER_1_ID,
planningProblem);
Object solution = null;
HardSoftScore score = null;
// It can take a while for the Construction Heuristic to initialize the solution
// The test timeout will interrupt this thread if it takes too long
while (!Thread.currentThread().isInterrupted()) {
solverInstance = solverClient.getSolverWithBestSolution(CONTAINER_1_ID,
SOLVER_1_ID);
assertNotNull(solverInstance);
solution = solverInstance.getBestSolution();
ScoreWrapper scoreWrapper = solverInstance.getScoreWrapper();
assertNotNull(scoreWrapper);
if (scoreWrapper.toScore() != null) {
assertEquals(HardSoftScore.class,
scoreWrapper.getScoreClass());
score = (HardSoftScore) scoreWrapper.toScore();
}
// Wait until the solver finished initializing the solution
if (solution != null && score != null && score.isSolutionInitialized()) {
break;
}
Thread.sleep(1000);
}
assertNotNull(score);
assertTrue(score.isSolutionInitialized());
assertTrue(score.getHardScore() <= 0);
// A soft score of 0 is impossible because we'll always need at least 1 computer
assertTrue(score.getSoftScore() < 0);
List<?> computerList = (List<?>) valueOf(solution,
"computerList");
assertEquals(10,
computerList.size());
List<?> processList = (List<?>) valueOf(solution,
"processList");
assertEquals(30,
processList.size());
for (Object process : processList) {
Object computer = valueOf(process,
"computer");
assertNotNull(computer);
// TODO: Change to identity comparation after @XmlID is implemented
assertTrue(computerList.contains(computer));
}
solverClient.disposeSolver(CONTAINER_1_ID,
SOLVER_1_ID);
}
@Test
public void testGetBestSolutionNotExistingSolver() throws Exception {
try {
solverClient.getSolverWithBestSolution(CONTAINER_1_ID,
SOLVER_1_ID);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Solver.*not found in container.*");
}
}
@Test
public void testTerminateEarlyNotExistingSolver() throws Exception {
try {
solverClient.terminateSolverEarly(CONTAINER_1_ID,
SOLVER_1_ID);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Solver.*not found in container.*");
}
}
@Test
public void testTerminateEarlyStoppedSolver() throws Exception {
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
try {
solverClient.terminateSolverEarly(CONTAINER_1_ID,
SOLVER_1_ID);
fail("A KieServicesException should have been thrown by now.");
} catch (KieServicesException e) {
KieServerAssert.assertResultContainsStringRegex(e.getMessage(),
".*Solver.*from container.*is not executing.*");
}
}
@Test
public void testTerminateEarly() throws Exception {
solverClient.createSolver(CONTAINER_1_ID,
SOLVER_1_ID,
SOLVER_1_CONFIG);
// start solver
solverClient.solvePlanningProblem(CONTAINER_1_ID,
SOLVER_1_ID,
loadPlanningProblem(50,
150));
SolverInstance instance = solverClient.getSolver(CONTAINER_1_ID,
SOLVER_1_ID);
assertEquals(SolverInstance.SolverStatus.SOLVING,
instance.getStatus());
// and then terminate it
solverClient.terminateSolverEarly(CONTAINER_1_ID,
SOLVER_1_ID);
instance = solverClient.getSolver(CONTAINER_1_ID,
SOLVER_1_ID);
assertTrue(instance.getStatus() == SolverInstance.SolverStatus.TERMINATING_EARLY
|| instance.getStatus() == SolverInstance.SolverStatus.NOT_SOLVING);
solverClient.disposeSolver(CONTAINER_1_ID,
SOLVER_1_ID);
}
public Object loadPlanningProblem(int computerListSize,
int processListSize) {
Object problem = null;
try {
Class<?> cbgc = kieContainer.getClassLoader().loadClass(CLASS_CLOUD_GENERATOR);
Object cbgi = cbgc.newInstance();
Method method = cbgc.getMethod("createCloudBalance",
int.class,
int.class);
problem = method.invoke(cbgi,
computerListSize,
processListSize);
} catch (Exception e) {
e.printStackTrace();
fail("Exception trying to create cloud balance unsolved problem.");
}
return problem;
}
}