/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.script.execution.testutils;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import de.rcenvironment.components.script.common.ScriptComponentHistoryDataItem;
import de.rcenvironment.components.script.common.registry.ScriptExecutor;
import de.rcenvironment.core.component.api.ComponentException;
import de.rcenvironment.core.component.datamanagement.api.ComponentDataManagementService;
import de.rcenvironment.core.component.execution.api.ComponentContext;
import de.rcenvironment.core.component.execution.api.ConsoleRow.Type;
import de.rcenvironment.core.component.scripting.WorkflowConsoleForwardingWriter;
import de.rcenvironment.core.component.testutils.ComponentContextMock;
import de.rcenvironment.core.configuration.ConfigurationService;
import de.rcenvironment.core.datamodel.api.DataType;
import de.rcenvironment.core.datamodel.api.TypedDatumFactory;
import de.rcenvironment.core.datamodel.api.TypedDatumService;
import de.rcenvironment.core.datamodel.types.api.BooleanTD;
import de.rcenvironment.core.datamodel.types.api.DirectoryReferenceTD;
import de.rcenvironment.core.datamodel.types.api.FileReferenceTD;
import de.rcenvironment.core.datamodel.types.api.FloatTD;
import de.rcenvironment.core.datamodel.types.api.IntegerTD;
import de.rcenvironment.core.datamodel.types.api.MatrixTD;
import de.rcenvironment.core.datamodel.types.api.ShortTextTD;
import de.rcenvironment.core.datamodel.types.api.VectorTD;
import de.rcenvironment.core.scripting.ScriptingService;
import de.rcenvironment.core.scripting.ScriptingUtils;
import de.rcenvironment.core.scripting.python.PythonComponentConstants;
import de.rcenvironment.core.scripting.python.PythonOutputWriter;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
import de.rcenvironment.core.utils.scripting.ScriptLanguage;
import junit.framework.Assert;
/**
* Abstract class for testing the implementations of {@link ScriptExecutor} since all should have the same results with the same
* configurations.
*
* @author Sascha Zur
*/
public abstract class ScriptExecutorTest {
private static final String PRINT_TEST = "print test";
private static Object[][] dataInputs = new Object[][] {
{ "float", DataType.Float, 1d },
{ "shorttext", DataType.ShortText, "testWert" },
{ "boolean", DataType.Boolean, true },
{ "integer", DataType.Integer, 1L },
{ "file", DataType.FileReference, "test.txt" },
{ "dir", DataType.DirectoryReference, "" },
{ "vec", DataType.Vector, null },
{ "mat", DataType.Matrix, null }
};
protected ComponentContextMock context;
protected ScriptExecutor executor;
/**
* Test preparing the executor and a new run.
*
* @throws ComponentException e
* @throws ScriptException e
* @throws IOException if writer cannot be closed
*/
@Test
public void testExecutorLifecycle() throws ComponentException, ScriptException, IOException {
ScriptEngine scriptEngine = getScriptingEngine();
WorkflowConsoleForwardingWriter stdOutWriter = new WorkflowConsoleForwardingWriter(new Object(), context.getLog(), Type.TOOL_OUT);
WorkflowConsoleForwardingWriter stdErrWriter = new WorkflowConsoleForwardingWriter(new Object(), context.getLog(), Type.TOOL_ERROR);
ScriptContext cont = EasyMock.createNiceMock(ScriptContext.class);
EasyMock.expect(cont.getWriter()).andReturn(stdOutWriter).anyTimes();
EasyMock.expect(cont.getErrorWriter()).andReturn(stdErrWriter).anyTimes();
EasyMock.replay(cont);
EasyMock.expect(scriptEngine.getContext()).andReturn(cont).anyTimes();
List<Capture<String>> captures = new LinkedList<>();
for (int i = 0; i < 5; i++) {
Capture<String> evalCapture = new Capture<>();
EasyMock.expect(scriptEngine.eval(EasyMock.capture(evalCapture))).andReturn(0);
captures.add(evalCapture);
}
EasyMock.replay(scriptEngine);
executor.setScriptEngine(scriptEngine);
ScriptingService scriptingService = EasyMock.createNiceMock(ScriptingService.class);
EasyMock.expect(scriptingService.createScriptEngine(getScriptLanguage())).andReturn(scriptEngine).anyTimes();
EasyMock.replay(scriptingService);
context.addService(ScriptingService.class, scriptingService);
context.setConfigurationValue(PythonComponentConstants.PYTHON_INSTALLATION, "hell�");
testPrepareHook();
executor.prepareExecutor(context);
executor.prepareNewRun(getScriptLanguage(), PRINT_TEST, null);
executor.setComponentContext(context);
try {
stdOutWriter.write(PythonOutputWriter.CONSOLE_END);
stdErrWriter.write(PythonOutputWriter.CONSOLE_END);
stdOutWriter.flush();
stdErrWriter.flush();
} catch (IOException e) {
Logger.getGlobal().log(Level.ALL, e.getMessage());
} finally {
stdOutWriter.close();
stdErrWriter.close();
}
executor.runScript();
boolean hasTestScript = false;
for (int i = 0; i < 5; i++) {
if (captures.get(i).hasCaptured() && captures.get(i).getValue().contains(PRINT_TEST)) {
hasTestScript = true;
}
}
Assert.assertEquals(true, hasTestScript);
}
/**
* Set up tests.
*/
@Before
public void setup() {
TempFileServiceAccess.setupUnitTestEnvironment();
}
/**
* Common tear down.
*/
@After
public void tearDown() {
executor = null;
context = null;
}
protected abstract ScriptEngine getScriptingEngine();
protected abstract ScriptLanguage getScriptLanguage();
protected abstract void testPrepareHook();
/**
* Test post run method.
*
* @throws IOException .
*
* @throws ComponentException .
*/
@Test
public void testPostRun() throws ComponentException, IOException {
ScriptEngine scriptEngine = getScriptingEngine();
File testfile = null;
try {
testfile = TempFileServiceAccess.getInstance().createTempFileWithFixedFilename("test.txt");
dataInputs[4][2] = testfile.getAbsolutePath();
} catch (IOException e) {
Assert.fail("Could not create test file. " + e.getMessage());
return;
}
addOutputsToEngine(scriptEngine, testfile);
prepareScriptingUtilsAndContext();
executor.setComponentContext(context);
executor.setHistoryDataItem(new ScriptComponentHistoryDataItem());
executor.setScriptEngine(scriptEngine);
executor.setStateMap(new HashMap<String, Object>());
executor.setWorkingPath(testfile.getParent());
executor.setStdoutWriter(EasyMock.createNiceMock(Writer.class));
executor.setStderrWriter(EasyMock.createNiceMock(Writer.class));
executor.postRun();
for (Object[] dataInput : dataInputs) {
Assert.assertEquals(context.getCapturedOutput((String) dataInput[0]).size(), 1);
}
TempFileServiceAccess.getInstance().disposeManagedTempDirOrFile(testfile);
}
@SuppressWarnings("rawtypes")
private void addOutputsToEngine(ScriptEngine scriptEngine, File testfile) {
Map<String, ArrayList<Object>> outputChannelMap = new HashMap<>();
List list = EasyMock.createNiceMock(List.class);
Iterator it = EasyMock.createNiceMock(Iterator.class);
EasyMock.expect(it.next()).andReturn(new Integer(1));
EasyMock.expect(it);
EasyMock.expect(list.iterator()).andReturn(it);
EasyMock.expect(list.size()).andReturn(1).anyTimes();
EasyMock.replay(list);
List<List> matrixList = new LinkedList<>();
List<Integer> valueList = new LinkedList<>();
valueList.add(1);
valueList.add(1);
valueList.add(1);
matrixList.add(valueList);
matrixList.add(valueList);
dataInputs[6][2] = list;
dataInputs[7][2] = matrixList;
for (Object[] dataInput : dataInputs) {
context.addSimulatedOutput((String) dataInput[0], "default", (DataType) dataInput[1], true,
new HashMap<String, String>());
List<Object> outputValues = new ArrayList<>();
if (((DataType) dataInput[1]) == DataType.FileReference) {
outputValues.add(testfile.getAbsolutePath());
} else {
outputValues.add(dataInput[2]);
}
outputChannelMap.put((String) dataInput[0], (ArrayList<Object>) outputValues);
List<Object> linkedList = new LinkedList<>();
linkedList.add(dataInput[2]);
EasyMock.expect(scriptEngine.get((String) dataInput[0])).andReturn(linkedList).anyTimes();
}
EasyMock.expect(scriptEngine.get("RCE_Dict_OutputChannels")).andReturn(outputChannelMap);
EasyMock.expect(scriptEngine.get("RCE_STATE_VARIABLES")).andReturn(new HashMap<String, Object>());
EasyMock.expect(scriptEngine.get("RCE_CloseOutputChannelsList")).andReturn(new LinkedList<String>());
EasyMock.replay(scriptEngine);
}
private void prepareScriptingUtilsAndContext() throws IOException {
ScriptingUtils su = new ScriptingUtils();
TypedDatumService tds = EasyMock.createMock(TypedDatumService.class);
TypedDatumFactory tdf = EasyMock.createMock(TypedDatumFactory.class);
EasyMock.expect(tds.getFactory()).andReturn(tdf);
EasyMock.replay(tds);
addMocksToFactory(tdf);
EasyMock.replay(tdf);
su.bindTypedDatumService(tds);
ComponentDataManagementService cdms = EasyMock.createNiceMock(ComponentDataManagementService.class);
DirectoryReferenceTD directoryMock = EasyMock.createNiceMock(DirectoryReferenceTD.class);
EasyMock.expect(directoryMock.getDataType()).andReturn(DataType.DirectoryReference).anyTimes();
EasyMock.replay(directoryMock);
EasyMock.expect(
cdms.createDirectoryReferenceTDFromLocalDirectory(EasyMock.anyObject(ComponentContext.class), EasyMock.anyObject(File.class),
EasyMock.anyObject(String.class)))
.andReturn(directoryMock);
FileReferenceTD fileMock = EasyMock.createNiceMock(FileReferenceTD.class);
EasyMock.expect(fileMock.getDataType()).andReturn(DataType.FileReference).anyTimes();
EasyMock.replay(fileMock);
EasyMock.expect(
cdms.createFileReferenceTDFromLocalFile(EasyMock.anyObject(ComponentContext.class), EasyMock.anyObject(File.class),
EasyMock.anyObject(String.class)))
.andReturn(fileMock);
EasyMock.replay(cdms);
context.addService(ComponentDataManagementService.class, cdms);
su.bindComponentDataManagementService(cdms);
ConfigurationService configs = EasyMock.createNiceMock(ConfigurationService.class);
EasyMock.expect(configs.getParentTempDirectoryRoot()).andReturn(new File("")).anyTimes();
EasyMock.replay(configs);
context.addService(ConfigurationService.class, configs);
}
private void addMocksToFactory(TypedDatumFactory tdf) {
BooleanTD booleanMock = EasyMock.createMock(BooleanTD.class);
EasyMock.expect(booleanMock.getDataType()).andReturn(DataType.Boolean);
EasyMock.replay(booleanMock);
EasyMock.expect(tdf.createBoolean(EasyMock.anyBoolean())).andReturn(booleanMock);
FloatTD floatMock = EasyMock.createMock(FloatTD.class);
EasyMock.expect(floatMock.getDataType()).andReturn(DataType.Float);
EasyMock.replay(floatMock);
EasyMock.expect(tdf.createFloat(EasyMock.anyDouble())).andReturn(floatMock).anyTimes();
IntegerTD intMock = EasyMock.createNiceMock(IntegerTD.class);
EasyMock.expect(intMock.getDataType()).andReturn(DataType.Integer);
EasyMock.expect(intMock.getIntValue()).andReturn(new Long(1)).anyTimes();
EasyMock.replay(intMock);
EasyMock.expect(tdf.createInteger(EasyMock.anyLong())).andReturn(intMock).anyTimes();
ShortTextTD textMock = EasyMock.createMock(ShortTextTD.class);
EasyMock.expect(textMock.getDataType()).andReturn(DataType.ShortText);
EasyMock.replay(textMock);
EasyMock.expect(tdf.createShortText(EasyMock.anyObject(String.class))).andReturn(textMock);
VectorTD vectorMock = EasyMock.createMock(VectorTD.class);
EasyMock.expect(vectorMock.getDataType()).andReturn(DataType.Vector);
EasyMock.replay(vectorMock);
EasyMock.expect(tdf.createVector(EasyMock.anyInt())).andReturn(vectorMock);
MatrixTD matrixMock = EasyMock.createNiceMock(MatrixTD.class);
EasyMock.expect(matrixMock.getDataType()).andReturn(DataType.Matrix);
EasyMock.replay(matrixMock);
EasyMock.expect(tdf.createMatrix(EasyMock.anyInt(), EasyMock.anyInt())).andReturn(matrixMock);
}
}