/*
* (C) Copyright 2015-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Thierry Delprat <tdelprat@nuxeo.com>, Ronan DANIELLOU <rdaniellou@nuxeo.com>
*/
package org.nuxeo.automation.scripting.test;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.automation.scripting.AutomationScriptingFeature;
import org.nuxeo.common.utils.FileUtils;
import org.nuxeo.ecm.automation.AutomationService;
import org.nuxeo.ecm.automation.OperationContext;
import org.nuxeo.ecm.automation.OperationDocumentation.Param;
import org.nuxeo.ecm.automation.OperationException;
import org.nuxeo.ecm.automation.OperationType;
import org.nuxeo.ecm.automation.core.Constants;
import org.nuxeo.ecm.automation.core.scripting.MvelExpression;
import org.nuxeo.ecm.automation.core.trace.TracerFactory;
import org.nuxeo.ecm.automation.core.util.BlobList;
import org.nuxeo.ecm.automation.core.util.DataModelProperties;
import org.nuxeo.ecm.automation.core.util.DocumentHelper;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.Blobs;
import org.nuxeo.ecm.core.api.CoreInstance;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
/**
* @since 7.2
*/
@RunWith(FeaturesRunner.class)
@Features(AutomationScriptingFeature.class)
public class TestScriptRunnerInfrastructure {
protected static String[] attachments = { "att1", "att2", "att3" };
@Inject
CoreSession session;
@Inject
AutomationService automationService;
@Inject
AutomationScriptingFeature feature;
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private PrintStream outStream;
@Inject
TracerFactory factory;
@Before
public void setupContext() {
outStream = System.out;
System.setOut(new PrintStream(outContent));
}
@After
public void cleanUpStreams() throws IOException {
outContent.close();
System.setOut(outStream);
}
@Inject
AutomationScriptingFeature scripting;
@Test
public void shouldExecuteSimpleScript() throws Exception {
DocumentModelList docs = scripting.run("simpleAutomationScript.js", session, DocumentModelList.class);
assertEquals(10, docs.size());
}
@Test
public void simpleScriptingOperationShouldBeAvailable() throws Exception {
OperationType type = automationService.getOperation("Scripting" + ".HelloWorld");
assertNotNull(type);
Param[] paramDefs = type.getDocumentation().getParams();
assertEquals(1, paramDefs.length);
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> params = new HashMap<>();
params.put("lang", "en");
ctx.setInput("John");
Object result = automationService.run(ctx, "Scripting.HelloWorld", params);
assertEquals("Hello John", result.toString());
}
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> params = new HashMap<>();
params.put("lang", "fr");
ctx.setInput("John");
Object result = automationService.run(ctx, "Scripting.HelloWorld", params);
assertEquals("Bonjour John", result.toString());
}
}
@Test
public void runOperationOnSubTree() throws Exception {
DocumentModel root = session.getRootDocument();
for (int i = 0; i < 5; i++) {
DocumentModel doc = session.createDocumentModel("/", "new" + i, "File");
session.createDocument(doc);
}
session.save();
DocumentModelList res = session.query("select * from File where " + "ecm:mixinType = 'HiddenInNavigation'");
assertEquals(0, res.size());
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> params = new HashMap<>();
params.put("facet", "HiddenInNavigation");
params.put("type", "File");
ctx.setInput(root);
Object result = automationService.run(ctx, "Scripting.AddFacetInSubTree", params);
DocumentModelList docs = (DocumentModelList) result;
assertEquals(5, docs.size());
}
}
@Test
public void simpleScriptingOperationsInChain() throws Exception {
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> params = new HashMap<>();
ctx.setInput("John");
Object result = automationService.run(ctx, "Scripting.ChainedHello", params);
assertEquals("Hello Bonjour John", result.toString());
}
}
@Test
public void simpleCallToScriptingOperationsChain() throws Exception {
String message = scripting.run("simpleCallToChain.js", session, String.class);
assertEquals("Hello Bonjour John", message);
}
@Test
public void testOperationCtx() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> params = new HashMap<>();
ctx.put("test", "odd");
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestOperationCtx", params);
assertEquals("odd", result.getPropertyValue("dc:nature"));
assertEquals("modifiedValue", result.getPropertyValue("dc:description"));
assertEquals("newEntry", result.getPropertyValue("dc:title"));
assertEquals("Administrator", result.getPropertyValue("dc:creator"));
}
}
@Test
public void testOperationWithBlob() throws IOException, OperationException {
// upload file blob
File fieldAsJsonFile = FileUtils.getResourceFileFromContext("creationFields.json");
Blob fb = Blobs.createBlob(fieldAsJsonFile);
fb.setMimeType("image/jpeg");
try (OperationContext ctx = new OperationContext(session)) {
ctx.setInput(fb);
Map<String, Object> params = new HashMap<>();
params.put("document", "/newDoc");
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestBlob", params);
final Blob blob = (Blob) result.getPropertyValue("file:content");
assertEquals("New Title", result.getTitle());
assertEquals("creationFields.json", blob.getFilename());
}
}
@Test
public void testWithSetBlobOperation() throws IOException, OperationException {
// upload file blob
File fieldAsJsonFile = FileUtils.getResourceFileFromContext("creationFields.json");
Blob fb = Blobs.createBlob(fieldAsJsonFile);
fb.setMimeType("image/jpeg");
try (OperationContext ctx = new OperationContext(session)) {
ctx.setInput(fb);
Map<String, Object> params = new HashMap<>();
params.put("document", "/newDoc");
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestSetBlob", params);
assertEquals("creationFields.json", ((Blob) result.getPropertyValue("file:content")).getFilename());
}
}
@Test
public void testComplexProperties() throws IOException, OperationException {
// Fill the document properties
Map<String, Object> creationProps = new HashMap<>();
creationProps.put("ds:tableName", "MyTable");
creationProps.put("ds:attachments", attachments);
// send the fields representation as json
File fieldAsJsonFile = FileUtils.getResourceFileFromContext("creationFields.json");
assertNotNull(fieldAsJsonFile);
String fieldsDataAsJSon = org.apache.commons.io.FileUtils.readFileToString(fieldAsJsonFile);
fieldsDataAsJSon = fieldsDataAsJSon.replaceAll("\n", "");
fieldsDataAsJSon = fieldsDataAsJSon.replaceAll("\r", "");
creationProps.put("ds:fields", fieldsDataAsJSon);
creationProps.put("dc:title", "testDoc");
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> params = new HashMap<>();
params.put("properties", toString(creationProps));
params.put("type", "DataSet");
params.put("name", "testDoc");
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestComplexProperties",
params);
assertEquals("whatever",
((Map<?, ?>) ((List<?>) result.getPropertyValue("ds:fields")).get(0)).get("sqlTypeHint"));
}
}
@Test
public void testClassFilter() throws Exception {
try {
scripting.run("classFilterScript.js", session, Void.class);
} catch (RuntimeException cause) {
assertEquals(ClassNotFoundException.class, cause.getCause().getClass());
}
}
@Test
public void testFn() throws Exception {
// Test platform functions injection
String message = scripting.run("platformFunctions.js", session, String.class);
assertEquals("devnull@nuxeo.com", message);
}
public String toString(Map<String, Object> creationProps) {
StringBuilder buf = new StringBuilder();
for (Map.Entry<String, Object> entry : creationProps.entrySet()) {
Object v = entry.getValue();
if (v != null) {
if (v.getClass() == String.class) {
buf.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
}
} else {
buf.append(entry.getKey()).append("=").append("\n");
}
}
return buf.toString();
}
@Test
public void handleDocumentListAsInput() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModelList result = (DocumentModelList) automationService.run(ctx,
"Scripting.TestInputDocumentList");
assertNotNull(result);
}
}
@Test
public void handleWorkflowVariables() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
Map<String, Object> wfVars = new HashMap<>();
Map<String, Object> nodeVars = new HashMap<>();
wfVars.put("var", "workflow");
nodeVars.put("var", "node");
ctx.put(Constants.VAR_WORKFLOW, wfVars);
ctx.put(Constants.VAR_WORKFLOW_NODE, nodeVars);
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestOperationWF");
assertEquals("workflow", result.getPropertyValue("dc:title"));
assertEquals("node", result.getPropertyValue("dc:description"));
}
}
@Test
public void canUseChainWithDashes() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
ctx.setInput(root);
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestChainWithDashes");
assertNotNull(result);
}
}
@Test
public void canManageDocumentModelWrappers() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
root.setPropertyValue("dc:title", "New Title");
session.saveDocument(root);
ctx.setInput(root);
ctx.put("var", root);
Map<String, Object> params = new HashMap<>();
params.put("param", "root");
Object result = automationService.run(ctx, "Scripting.TestWrappers", params);
assertTrue(result instanceof DocumentModel);
Object doc = ctx.get("var");
assertNotNull(doc);
assertTrue(doc instanceof DocumentModel);
assertTrue((Boolean) ctx.get("entry"));
}
}
@Test
public void canHandleJavaListMap() throws OperationException {
DocumentModel doc = new DocumentModelImpl("/", "doc", "List");
List<String> attachments = new ArrayList<>();
attachments.add("att1");
attachments.add("att2");
attachments.add("att3");
doc.setPropertyValue("list:items", (Serializable) attachments);
Map<String, String> values = new HashMap<>();
values.put("name", "vlad");
values.put("description", "desc");
doc.setPropertyValue("list:complexItem", (Serializable) values);
try (OperationContext ctx = new OperationContext(session)) {
ctx.setInput(session.createDocument(doc));
DocumentModel result = (DocumentModel) automationService.run(ctx, "Scripting.TestList");
assertEquals("newValue", ((String[]) result.getPropertyValue("list:items"))[0]);
assertEquals("vlad", ((Map<?, ?>) result.getPropertyValue("list:complexItem")).get("name"));
}
}
@Test
public void canHandleLoginAsCtx() throws OperationException {
try (CoreSession session = CoreInstance.openCoreSession(this.session.getRepositoryName(), "jdoe")) {
try (OperationContext ctx = new OperationContext(session)) {
String username = (String) automationService.run(ctx, "my-chain-with-loginasctx");
assertEquals("Administrator", username);
}
}
}
@Test
public void canHandleLoginAsOp() throws OperationException {
try (CoreSession session = CoreInstance.openCoreSession(this.session.getRepositoryName(), "jdoe")) {
try (OperationContext ctx = new OperationContext(session)) {
String username = (String) automationService.run(ctx, "my-chain-with-loginasop");
assertEquals("Administrator", username);
}
}
}
@Test
public void canUnwrapContextDocListing() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
DocumentModelList docs = new DocumentModelListImpl();
docs.add(root);
docs.add(root);
ctx.put("docs", docs);
Object result = automationService.run(ctx, "Scripting.SimpleScript");
assertNotNull(result);
}
}
/*
* NXP-19012
*/
@Test
public void canUnwrapContextWithTrace() throws OperationException {
if (!factory.getRecordingState()) {
factory.toggleRecording();
}
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
DocumentModelList docs = new DocumentModelListImpl();
docs.add(root);
docs.add(root);
ctx.put("docs", docs);
ctx.setInput(root);
Map<String, Object> params = new HashMap<>();
Object result = automationService.run(ctx, "Scripting.ChainWithScripting", params);
assertNotNull(result);
// check if the context has been unwrapped correctly
assertTrue(
ctx.get("docs") instanceof DocumentModelList && ((DocumentModelList) ctx.get("docs")).size() == 2);
}
}
@Test
public void testMVELScriptResolver() throws Exception {
try (OperationContext ctx = new OperationContext(session)) {
Object mvelResult = automationService.run(ctx, "my-chain-with-mvelresolver");
assertEquals("Foo Bar", mvelResult);
}
}
/*
* NXP-19444
*/
@Test
public void testSet() throws Exception {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
ctx.setInput(root);
root = (DocumentModel) automationService.run(ctx, "Scripting.TestSet");
assertEquals("TitleFromTest", root.getProperty("dc:title").getValue());
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0L);
assertEquals(cal, root.getProperty("dc:created").getValue());
}
}
/*
* NXP-19444
*/
@Test
public void testSetPropertyValue() throws Exception {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
ctx.setInput(root);
root = (DocumentModel) automationService.run(ctx, "Scripting.TestSetPropertyValue");
assertEquals("TitleFromTest", root.getProperty("dc:title").getValue());
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0L);
assertEquals(cal, root.getProperty("dc:created").getValue());
}
}
/*
* NXP-19444
*/
@Test
public void testSetArray() throws Exception {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
ctx.setInput(root);
root = (DocumentModel) automationService.run(ctx, "Scripting.TestSetArray");
assertArrayEquals(new String[] { "sciences", "society" },
(Object[]) root.getProperty("dc:subjects").getValue());
}
}
/*
* NXP-19444
*/
@Test
public void testSetPropertyValueArray() throws Exception {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
ctx.setInput(root);
root = (DocumentModel) automationService.run(ctx, "Scripting.TestSetPropertyValueArray");
assertArrayEquals(new String[] { "sciences", "society" },
(Object[]) root.getProperty("dc:subjects").getValue());
}
}
/*
* NXP-19176
*/
@Test
public void handleBlobListAsInput() throws IOException, OperationException {
// Init parameters
File fieldAsJsonFile = FileUtils.getResourceFileFromContext("creationFields.json");
Blob fb = Blobs.createBlob(fieldAsJsonFile);
fb.setMimeType("image/jpeg");
DocumentModel doc = session.createDocumentModel("/", "docWithBlobs", "File");
doc = session.createDocument(doc);
DocumentHelper.addBlob(doc.getProperty("files:files"), fb);
DocumentHelper.addBlob(doc.getProperty("files:files"), fb);
session.saveDocument(doc);
try (OperationContext ctx = new OperationContext(session)) {
BlobList result = (BlobList) automationService.run(ctx, "Scripting.TestInputBlobList");
assertNotNull(result);
assertEquals(2, result.size());
// We added two blobs to context
BlobList blobs = (BlobList) ctx.pop(Constants.O_BLOBS);
assertNotNull(blobs);
assertEquals(2, blobs.size());
}
}
/*
* NXP-19176
*/
@Test
public void handleBlobArrayAsInput() throws IOException, OperationException {
// Init parameters
File fieldAsJsonFile = FileUtils.getResourceFileFromContext("creationFields.json");
Blob fb = Blobs.createBlob(fieldAsJsonFile);
fb.setMimeType("image/jpeg");
DocumentModel doc = session.createDocumentModel("/", "docWithBlobs", "File");
doc = session.createDocument(doc);
DocumentHelper.addBlob(doc.getProperty("files:files"), fb);
DocumentHelper.addBlob(doc.getProperty("files:files"), fb);
session.saveDocument(doc);
try (OperationContext ctx = new OperationContext(session)) {
BlobList result = (BlobList) automationService.run(ctx, "Scripting.TestInputBlobArray");
assertNotNull(result);
assertEquals(2, result.size());
// We added two blobs to context
BlobList blobs = (BlobList) ctx.pop(Constants.O_BLOBS);
assertNotNull(blobs);
assertEquals(2, blobs.size());
}
}
@Test
public void testArrayObjectParametersOperation() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
DocumentModel root = session.getRootDocument();
ctx.setInput(root);
root = (DocumentModel) automationService.run(ctx, "Scripting.TestArrayObjectProperties");
assertArrayEquals(new String[] { "sciences", "society" },
(Object[]) root.getProperty("dc:subjects").getValue());
}
}
@Test
public void testNotInlinedContext() throws OperationException {
try (OperationContext ctx = new OperationContext(session)) {
ctx.put("today", new MvelExpression("CurrentDate.date"));
ctx.put("tomorrow", new MvelExpression("CurrentDate.days(1).date"));
DataModelProperties props = (DataModelProperties)automationService.run(ctx, "Scripting.TestParams");
Assertions.assertThat(props.getMap()).containsOnlyKeys("today");
}
}
}