Repository: nifi
Updated Branches:
  refs/heads/master fa5fed9bb -> 36796b544


NIFI-3078: Test InvokeScriptedProcessor with JS.

This closes #1255.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/36796b54
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/36796b54
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/36796b54

Branch: refs/heads/master
Commit: 36796b544007c7dc6f114be10718a7a8ce87bef5
Parents: fa5fed9
Author: Koji Kawamura <[email protected]>
Authored: Tue Nov 22 12:31:38 2016 +0900
Committer: Pierre Villard <[email protected]>
Committed: Tue Nov 22 21:42:36 2016 +0100

----------------------------------------------------------------------
 .../processors/script/TestInvokeJavascript.java | 179 +++++++++++++++++++
 .../testInvokeScriptCausesException.js          |  58 ++++++
 .../javascript/testScriptRoutesToFailure.js     |  79 ++++++++
 .../test/resources/javascript/test_reader.js    | 108 +++++++++++
 4 files changed, 424 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/36796b54/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/processors/script/TestInvokeJavascript.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/processors/script/TestInvokeJavascript.java
 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/processors/script/TestInvokeJavascript.java
new file mode 100644
index 0000000..4c39b11
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/processors/script/TestInvokeJavascript.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.script;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.util.MockFlowFile;
+import org.apache.nifi.util.MockProcessContext;
+import org.apache.nifi.util.MockProcessorInitializationContext;
+import org.apache.nifi.util.MockValidationContext;
+import org.apache.nifi.util.TestRunner;
+import org.apache.nifi.util.TestRunners;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class TestInvokeJavascript extends BaseScriptTest {
+
+    @Before
+    public void setup() throws Exception {
+        super.setupInvokeScriptProcessor();
+    }
+
+    /**
+     * Tests a scripted processor written in Javascript that reads the first 
line of text from the flowfiles content
+     * and stores the value in an attribute of the outgoing flowfile.
+     * Confirms that the scripted processor transfers the incoming flowfile 
with an attribute added.
+     *
+     * @throws Exception Any error encountered while testing
+     */
+    @Test
+    public void testReadFlowFileContentAndStoreInFlowFileAttribute() throws 
Exception {
+        runner.setValidateExpressionUsage(false);
+        runner.setProperty(InvokeScriptedProcessor.SCRIPT_ENGINE, 
"ECMAScript");
+        runner.setProperty(InvokeScriptedProcessor.SCRIPT_FILE, 
"target/test/resources/javascript/test_reader.js");
+        runner.setProperty(InvokeScriptedProcessor.MODULES, 
"target/test/resources/javascript");
+
+        runner.assertValid();
+        runner.enqueue("test content".getBytes(StandardCharsets.UTF_8));
+        runner.run();
+
+        runner.assertAllFlowFilesTransferred("test", 1);
+        final List<MockFlowFile> result = 
runner.getFlowFilesForRelationship("test");
+        result.get(0).assertAttributeEquals("from-content", "test content");
+    }
+
+    /**
+     * Tests a scripted processor written in Javascript that reads the first 
line of text from the flowfiles content and
+     * stores the value in an attribute of the outgoing flowfile.
+     * Confirms that the scripted processor can return property descriptors 
defined in it.
+     *
+     * @throws Exception Any error encountered while testing
+     */
+    @Test
+    public void testScriptDefinedAttribute() throws Exception {
+        InvokeScriptedProcessor processor = new InvokeScriptedProcessor();
+        MockProcessContext context = new MockProcessContext(processor);
+        MockProcessorInitializationContext initContext = new 
MockProcessorInitializationContext(processor, context);
+
+        processor.initialize(initContext);
+
+        context.setProperty(InvokeScriptedProcessor.SCRIPT_ENGINE, 
"ECMAScript");
+        context.setProperty(InvokeScriptedProcessor.SCRIPT_FILE, 
"target/test/resources/javascript/test_reader.js");
+        context.setProperty(InvokeScriptedProcessor.MODULES, 
"target/test/resources/javascript");
+        // State Manger is unused, and a null reference is specified
+        processor.customValidate(new MockValidationContext(context));
+        processor.setup(context);
+
+        List<PropertyDescriptor> descriptors = 
processor.getSupportedPropertyDescriptors();
+        assertNotNull(descriptors);
+        assertTrue(descriptors.size() > 0);
+        boolean found = false;
+        for (PropertyDescriptor descriptor : descriptors) {
+            if (descriptor.getName().equals("test-attribute")) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue(found);
+    }
+
+    /**
+     * Tests a scripted processor written in Javascript reads the first line 
of text from the flowfiles content and
+     * stores the value in an attribute of the outgoing flowfile.
+     * Confirms that the scripted processor can return relationships defined 
in it.
+     *
+     * @throws Exception Any error encountered while testing
+     */
+    @Test
+    public void testScriptDefinedRelationship() throws Exception {
+        InvokeScriptedProcessor processor = new InvokeScriptedProcessor();
+        MockProcessContext context = new MockProcessContext(processor);
+        MockProcessorInitializationContext initContext = new 
MockProcessorInitializationContext(processor, context);
+
+        processor.initialize(initContext);
+
+        context.setProperty(InvokeScriptedProcessor.SCRIPT_ENGINE, 
"ECMAScript");
+        context.setProperty(InvokeScriptedProcessor.SCRIPT_FILE, 
"target/test/resources/javascript/test_reader.js");
+        context.setProperty(InvokeScriptedProcessor.MODULES, 
"target/test/resources/javascript");
+
+        // State Manger is unused, and a null reference is specified
+        processor.customValidate(new MockValidationContext(context));
+        processor.setup(context);
+
+        Set<Relationship> relationships = processor.getRelationships();
+        assertNotNull(relationships);
+        assertTrue(relationships.size() > 0);
+        boolean found = false;
+        for (Relationship relationship : relationships) {
+            if (relationship.getName().equals("test")) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue(found);
+    }
+
+    /**
+     * Tests a script that throws a ProcessException within.
+     * The expected result is that the exception will be propagated.
+     *
+     * @throws Exception Any error encountered while testing
+     */
+    @Test(expected = AssertionError.class)
+    public void testInvokeScriptCausesException() throws Exception {
+        final TestRunner runner = TestRunners.newTestRunner(new 
InvokeScriptedProcessor());
+        runner.setValidateExpressionUsage(false);
+        runner.setProperty(InvokeScriptedProcessor.SCRIPT_ENGINE, 
"ECMAScript");
+        runner.setProperty(ExecuteScript.SCRIPT_BODY, getFileContentsAsString(
+                TEST_RESOURCE_LOCATION + 
"javascript/testInvokeScriptCausesException.js")
+        );
+        runner.assertValid();
+        runner.enqueue("test content".getBytes(StandardCharsets.UTF_8));
+        runner.run();
+
+    }
+
+    /**
+     * Tests a script that routes the FlowFile to failure.
+     *
+     * @throws Exception Any error encountered while testing
+     */
+    @Test
+    public void testScriptRoutesToFailure() throws Exception {
+        runner.setValidateExpressionUsage(false);
+        runner.setProperty(InvokeScriptedProcessor.SCRIPT_ENGINE, 
"ECMAScript");
+        runner.setProperty(ExecuteScript.SCRIPT_BODY, getFileContentsAsString(
+                TEST_RESOURCE_LOCATION + 
"javascript/testScriptRoutesToFailure.js")
+        );
+        runner.assertValid();
+        runner.enqueue("test content".getBytes(StandardCharsets.UTF_8));
+        runner.run();
+
+        runner.assertAllFlowFilesTransferred("FAILURE", 1);
+        final List<MockFlowFile> result = 
runner.getFlowFilesForRelationship("FAILURE");
+        assertFalse(result.isEmpty());
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/36796b54/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testInvokeScriptCausesException.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testInvokeScriptCausesException.js
 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testInvokeScriptCausesException.js
new file mode 100644
index 0000000..7cc17a1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testInvokeScriptCausesException.js
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+var Set = Java.type("java.util.HashSet");
+
+var processor = new Object() {
+    logger: null,
+
+    // Processor
+    initialize: function(context) {
+    },
+
+    getRelationships: function() {
+        return new Set();
+    },
+
+    onTrigger: function(context, sessionFactory) {
+        throw new Error("Failed!");
+    },
+
+    // ConfigurableComponent
+    validate: function(context) {
+        return [];
+    },
+
+    getPropertyDescriptor: function(name) {
+        return null;
+    },
+
+    onPropertyModified: function(descriptor, oldValue, newValue) {
+    },
+
+    getPropertyDescriptors: function() {
+        return [];
+    },
+
+    getIdentifier: function() {
+        return null;
+    },
+
+    setLogger: function(logger) {
+        this.logger = logger;
+    }
+};

http://git-wip-us.apache.org/repos/asf/nifi/blob/36796b54/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testScriptRoutesToFailure.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testScriptRoutesToFailure.js
 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testScriptRoutesToFailure.js
new file mode 100644
index 0000000..939278f
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/testScriptRoutesToFailure.js
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+var processor = new org.apache.nifi.processor.Processor() {
+This will cause following error:
+'ScriptValidation' validated against 
'target/test/resources/javascript/test_reader.js' is invalid because Unable to 
load script due to getInterface cannot be called on non-script object
+*/
+
+var Set = Java.type("java.util.HashSet");
+var Relationship = Java.type("org.apache.nifi.processor.Relationship");
+
+var REL_FAILURE = new Relationship.Builder()
+        .name("FAILURE")
+        .description("A FAILURE relationship")
+        .build();
+
+var processor = new Object() {
+    logger: null,
+
+    // Processor
+    initialize: function(context) {
+    },
+
+    getRelationships: function() {
+        var relationships = new Set();
+        relationships.addAll([REL_FAILURE]);
+        return relationships;
+    },
+
+    onTrigger: function(context, sessionFactory) {
+        var session = sessionFactory.createSession()
+        var flowFile = session.get();
+        if (flowFile == null) {
+            return;
+        }
+        // transfer
+        session.transfer(flowFile, REL_FAILURE)
+        session.commit()
+    },
+
+    // ConfigurableComponent
+    validate: function(context) {
+        return [];
+    },
+
+    getPropertyDescriptor: function(name) {
+        return null;
+    },
+
+    onPropertyModified: function(descriptor, oldValue, newValue) {
+    },
+
+    getPropertyDescriptors: function() {
+        return [];
+    },
+
+    getIdentifier: function() {
+        return null;
+    },
+
+    setLogger: function(logger) {
+        this.logger = logger;
+    }
+};

http://git-wip-us.apache.org/repos/asf/nifi/blob/36796b54/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/test_reader.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/test_reader.js
 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/test_reader.js
new file mode 100644
index 0000000..8c590f2
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/javascript/test_reader.js
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+var processor = new org.apache.nifi.processor.Processor() {
+This will cause following error:
+'ScriptValidation' validated against 
'target/test/resources/javascript/test_reader.js' is invalid because Unable to 
load script due to getInterface cannot be called on non-script object
+*/
+
+var String = Java.type("java.lang.String");
+var Set = Java.type("java.util.HashSet");
+var Relationship = Java.type("org.apache.nifi.processor.Relationship");
+var PropertyDescriptor = 
Java.type("org.apache.nifi.components.PropertyDescriptor");
+var StandardValidators = 
Java.type("org.apache.nifi.processor.util.StandardValidators");
+var StreamUtils = Java.type("org.apache.nifi.stream.io.StreamUtils");
+
+var REL_TEST = new Relationship.Builder()
+        .name("test")
+        .description("A test relationship")
+        .build();
+
+var PROP_TEST_ATTRIBUTE = new PropertyDescriptor.Builder()
+        
.name("test-attribute").addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build()
+
+var propertyDescriptors = [PROP_TEST_ATTRIBUTE];
+
+var processor = new Object() {
+    logger: null,
+
+    // Processor
+    initialize: function(context) {
+    },
+
+    getRelationships: function() {
+        var relationships = new Set();
+        relationships.addAll([REL_TEST]);
+        return relationships;
+    },
+
+    onTrigger: function(context, sessionFactory) {
+        var session = sessionFactory.createSession()
+        var flowFile = session.get();
+        if (flowFile == null) {
+            return;
+        }
+
+        // Set local logger variable so that read callback can use it.
+        var logger = this.logger;
+
+        // Read content from flowFile using Java classes.
+        var content;
+        session.read(flowFile, function (inputStream) {
+            var buffer = Java.to(new Array(flowFile.getSize()), "byte[]");
+            logger.info("Reading from inputStream, size={}, {}", 
[flowFile.getSize(), inputStream]);
+            StreamUtils.fillBuffer(inputStream, buffer, false);
+            content = new String(buffer, "UTF-8");
+        })
+
+        this.logger.info("Read content={}", [content]);
+
+        flowFile = session.putAttribute(flowFile, "from-content", content)
+        // transfer
+        session.transfer(flowFile, REL_TEST)
+        session.commit()
+    },
+
+    // ConfigurableComponent
+    validate: function(context) {
+        return [];
+    },
+
+    getPropertyDescriptor: function(name) {
+        for (var i = 0; i < propertyDescriptors.length; i++) {
+            if (name === p.getName) return p;
+        }
+        return null;
+    },
+
+    onPropertyModified: function(descriptor, oldValue, newValue) {
+    },
+
+    getPropertyDescriptors: function() {
+        return propertyDescriptors;
+    },
+
+    getIdentifier: function() {
+        return null;
+    },
+
+    setLogger: function(logger) {
+        this.logger = logger;
+        this.logger.info("logger is set! logger={}", [logger]);
+    }
+};

Reply via email to