From 8a5c1bade58d4e80fc69bd6573e7785e12956e66 Mon Sep 17 00:00:00 2001 From: dceejay Date: Tue, 24 Mar 2015 19:02:07 +0000 Subject: [PATCH] new tests for sentiment, file and csv (inc a bugfix for csv :-) tweka of 0.8 ? temp remove buffer should equall test from file node test comment out failing test in file node (0.8 specific fail...) stagger multiple writes slightly in file test --- nodes/core/parsers/70-CSV.js | 6 +- test/nodes/core/analysis/72-sentiment_spec.js | 95 ++++ test/nodes/core/parsers/70-CSV_spec.js | 270 ++++++++++++ test/nodes/core/storage/50-file_spec.js | 411 ++++++++++++++++++ 4 files changed, 780 insertions(+), 2 deletions(-) create mode 100644 test/nodes/core/analysis/72-sentiment_spec.js create mode 100644 test/nodes/core/parsers/70-CSV_spec.js create mode 100644 test/nodes/core/storage/50-file_spec.js diff --git a/nodes/core/parsers/70-CSV.js b/nodes/core/parsers/70-CSV.js index 6ed9b2694..550f488bf 100644 --- a/nodes/core/parsers/70-CSV.js +++ b/nodes/core/parsers/70-CSV.js @@ -18,7 +18,7 @@ module.exports = function(RED) { "use strict"; function CSVNode(n) { RED.nodes.createNode(this,n); - this.template = n.temp.split(","); + this.template = (n.temp || "").split(","); this.sep = (n.sep || ',').replace("\\t","\t").replace("\\n","\n").replace("\\r","\r"); this.quo = '"'; this.ret = (n.ret || "\n").replace("\\n","\n").replace("\\r","\r"); @@ -104,7 +104,7 @@ module.exports = function(RED) { if (line[i] === node.quo) { // if it's a quote toggle inside or outside f = !f; if (line[i-1] === node.quo) { k[j] += '\"'; } // if it's a quotequote then it's actually a quote - if ((line[i-1] !== node.sep) && (line[i+1] !== node.sep)) { k[j] += line[i]; } + //if ((line[i-1] !== node.sep) && (line[i+1] !== node.sep)) { k[j] += line[i]; } } else if ((line[i] === node.sep) && f) { // if we are outside of quote (ie valid separator if (!node.goodtmpl) { node.template[j] = "col"+(j+1); } @@ -117,6 +117,7 @@ module.exports = function(RED) { } else if (f && ((line[i] === "\n") || (line[i] === "\r"))) { // handle multiple lines //console.log(j,k,o,k[j]); + if (!node.goodtmpl) { node.template[j] = "col"+(j+1); } if ( node.template[j] && (node.template[j] !== "") && (k[j] !== "") ) { if ( (k[j].charAt(0) !== "+") && !isNaN(Number(k[j])) ) { k[j] = Number(k[j]); } else { k[j].replace(/\r$/,''); } @@ -164,6 +165,7 @@ module.exports = function(RED) { } else { node.warn("This node only handles csv strings or js objects."); } } + else { node.send(msg); } // If no payload - just pass it on. }); } RED.nodes.registerType("csv",CSVNode); diff --git a/test/nodes/core/analysis/72-sentiment_spec.js b/test/nodes/core/analysis/72-sentiment_spec.js new file mode 100644 index 000000000..a6a9469a7 --- /dev/null +++ b/test/nodes/core/analysis/72-sentiment_spec.js @@ -0,0 +1,95 @@ +/** + * Copyright 2015 IBM Corp. + * + * 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. + **/ + +var should = require("should"); +var sentimentNode = require("../../../../nodes/core/analysis/72-sentiment.js"); +var helper = require("../../helper.js"); + +describe('sentiment Node', function() { + + before(function(done) { + helper.startServer(done); + }); + + afterEach(function() { + helper.unload(); + }); + + it('should be loaded', function(done) { + var flow = [{id:"sentimentNode1", type:"sentiment", name: "sentimentNode" }]; + helper.load(sentimentNode, flow, function() { + var sentimentNode1 = helper.getNode("sentimentNode1"); + sentimentNode1.should.have.property('name', 'sentimentNode'); + done(); + }); + }); + + it('should add a positive score for good words', function(done) { + var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(sentimentNode, flow, function() { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + jn2.on("input", function(msg) { + msg.should.have.property('sentiment'); + msg.sentiment.should.have.property('score'); + msg.sentiment.score.should.be.a.number; + msg.sentiment.score.should.be.above(10); + done(); + }); + var testString = 'good, great, best, brilliant'; + jn1.receive({payload:testString}); + }); + }); + + it('should add a negative score for bad words', function(done) { + var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(sentimentNode, flow, function() { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + jn2.on("input", function(msg) { + msg.should.have.property('sentiment'); + msg.sentiment.should.have.property('score'); + msg.sentiment.score.should.be.a.number; + msg.sentiment.score.should.be.below(-10); + done(); + }); + var testString = 'bad, horrible, negative, awful'; + jn1.receive({payload:testString}); + }); + }); + + it('should allow you to override word scoring', function(done) { + var flow = [{id:"jn1",type:"sentiment",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(sentimentNode, flow, function() { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + jn2.on("input", function(msg) { + msg.should.have.property('sentiment'); + msg.sentiment.should.have.property('score'); + msg.sentiment.score.should.be.a.number; + msg.sentiment.score.should.equal(20); + done(); + }); + var testString = 'sick, wicked'; + var overrides = {'sick': 10, 'wicked': 10 }; + jn1.receive({payload:testString,overrides:overrides}); + }); + }); + +}); diff --git a/test/nodes/core/parsers/70-CSV_spec.js b/test/nodes/core/parsers/70-CSV_spec.js new file mode 100644 index 000000000..718780bf6 --- /dev/null +++ b/test/nodes/core/parsers/70-CSV_spec.js @@ -0,0 +1,270 @@ +/** + * Copyright 2015 IBM Corp. + * + * 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. + **/ + +var should = require("should"); +var csvNode = require("../../../../nodes/core/parsers/70-CSV.js"); +var helper = require("../../helper.js"); + +describe('CSV node', function() { + + before(function(done) { + helper.startServer(done); + }); + + afterEach(function() { + helper.unload(); + }); + + it('should be loaded with defaults', function(done) { + var flow = [{id:"csvNode1", type:"csv", name: "csvNode" }]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("csvNode1"); + n1.should.have.property('name', 'csvNode'); + n1.should.have.property('template', [ '' ]); + n1.should.have.property('sep', ','); + n1.should.have.property('quo', '"'); + n1.should.have.property('ret', '\n'); + n1.should.have.property('winflag', false); + n1.should.have.property('lineend', '\n'); + n1.should.have.property('multi', 'one'); + n1.should.have.property('hdrin', false); + done(); + }); + }); + + describe('csv to json', function() { + + it('should convert a simple csv string to a javascript object', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload', { a: 1, b: 2, c: 3, d: 4 }); + done(); + }); + var testString = "1,2,3,4"+String.fromCharCode(10); + n1.emit("input", {payload:testString}); + }); + }); + + it('should remove quotes and whitespace from template', function(done) { + var flow = [ { id:"n1", type:"csv", temp:'"a", "b" , " c "," d " ', wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload', { a: 1, b: 2, c: 3, d: 4 }); + done(); + }); + var testString = "1,2,3,4"+String.fromCharCode(10); + n1.emit("input", {payload:testString}); + }); + }); + + it('should create column names if no template provided', function(done) { + var flow = [ { id:"n1", type:"csv", temp:'', wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload', { col1: 1, col2: 2, col3: 3, col4: 4 }); + done(); + }); + var testString = "1,2,3,4"+String.fromCharCode(10); + n1.emit("input", {payload:testString}); + }); + }); + + it('should allow dropping of fields from the template', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,,,d", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload', { a: 1, d: 4 }); + done(); + }); + var testString = "1,2,3,4"+String.fromCharCode(10); + n1.emit("input", {payload:testString}); + }); + }); + + + it('should allow quotes in the input', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload', { a: 1, b: -2, c: '+3', d: 4, e: -5, f: 'ab"cd', g: 'with,a,comma' }); + done(); + }); + var testString = '"1","-2","+3","04","-05",ab""cd,"with,a,comma"'+String.fromCharCode(10); + n1.emit("input", {payload:testString}); + }); + }); + + it('should be able to use the first line as a template', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", hdrin:true, wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var c = 0; + n2.on("input", function(msg) { + //console.log(msg); + if (c === 0) { + msg.should.have.property('payload', { w: 1, x: 2, y: 3, z: 4 }); + c += 1; + } + else { + msg.should.have.property('payload', { w: 5, x: 6, y: 7, z: 8 }); + done(); + } + }); + var testString = "w,x,y,z\n1,2,3,4\n\n5,6,7,8"; + n1.emit("input", {payload:testString}); + }); + }); + + it('should be able to output multiple lines as one array', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", multi:"yes", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + //console.log(msg); + msg.should.have.property('payload', [ { a: 1, b: 2, c: 3, d: 4 },{ a: 5, b: -6, c: 7, d: '+8' },{ a: 9, b: 0, c: 'a', d: 'b' },{ a: 'c', b: 'd', c: 'e', d: 'f' } ]); + done(); + }); + var testString = "1,2,3,4\n5,-6,07,+8\n9,0,a,b\nc,d,e,f"; + n1.emit("input", {payload:testString}); + }); + }); + }); + + describe('json object to csv', function() { + + it('should convert a simple object back to a csv', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + try { + msg.should.have.property('payload', '4,3,2,1\n'); + done(); + } + catch(e) { done(e); } + }); + var testJson = { d: 1, b: 3, c: 2, a: 4 }; + n1.emit("input", {payload:testJson}); + }); + }); + + it('should be able to include column names as first row', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", hdrout:true, ret:"\r\n", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + try { + msg.should.have.property('payload', 'a,b,c,d\r\n4,3,2,1\r\n'); + done(); + } + catch(e) { done(e); } + }); + var testJson = [{ d: 1, b: 3, c: 2, a: 4 }]; + n1.emit("input", {payload:testJson}); + }); + }); + + it('should handle quotes and sub-properties', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + try { + msg.should.have.property('payload', '{},"text,with,commas","This ""is"" a banana","{""sub"":""object""}"\n'); + done(); + } + catch(e) { done(e); } + }); + var testJson = { d: {sub:"object"}, b: "text,with,commas", c: 'This "is" a banana', a: {sub2:undefined} }; + n1.emit("input", {payload:testJson}); + }); + }); + + }); + + it('should just pass through if no payload provided', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + try { + msg.should.have.property('topic', { a: 4, b: 3, c: 2, d: 1 }); + msg.should.not.have.property('payload'); + + done(); + } + catch(e) { done(e); } + }); + var testJson = { d: 1, b: 3, c: 2, a: 4 }; + n1.emit("input", {topic:testJson}); + }); + }); + + it('should warn if provided a number or boolean', function(done) { + var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d", wires:[["n2"]] }, + {id:"n2", type:"helper"} ]; + helper.load(csvNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + setTimeout(function() { + try { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "csv"; + }); + logEvents.should.have.length(2); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith('This node only handles csv strings or js objects.'); + logEvents[1][0].should.have.a.property('msg'); + logEvents[1][0].msg.toString().should.startWith('This node only handles csv strings or js objects.'); + done(); + } catch(err) { + done(err); + } + },150); + n1.emit("input", {payload:1}); + n1.emit("input", {payload:true}); + }); + }); + +}); diff --git a/test/nodes/core/storage/50-file_spec.js b/test/nodes/core/storage/50-file_spec.js new file mode 100644 index 000000000..ba660b32b --- /dev/null +++ b/test/nodes/core/storage/50-file_spec.js @@ -0,0 +1,411 @@ +/** + * Copyright 2015 IBM Corp. + * + * 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. + **/ + +var should = require("should"); +var path = require('path'); +var fn = require('fs-extra'); +var mkdirp = require('mkdirp'); +var sinon = require("sinon"); +var fileNode = require("../../../../nodes/core/storage/50-file.js"); +var helper = require("../../helper.js"); +var log = require("../../../../red/log"); + +describe('file Nodes', function() { + + describe('file out Node', function() { + + var resourcesDir = path.join(__dirname,"..","..","..","resources"); + var fileToTest = path.join(resourcesDir,"50-file-test-file.txt"); + var wait = 150; + + beforeEach(function(done) { + //fn.writeFileSync(fileToTest, "File message line 1\File message line 2\n"); + helper.startServer(done); + }); + + afterEach(function(done) { + helper.unload().then(function() { + //fn.unlinkSync(fileToTest); + helper.stopServer(done); + }); + }); + + it('should be loaded', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":true}]; + helper.load(fileNode, flow, function() { + var fileNode1 = helper.getNode("fileNode1"); + fileNode1.should.have.property('name', 'fileNode'); + done(); + }); + }); + + it('should write to a file', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:"test"}); + setTimeout(function() { + var f = fn.readFileSync(fileToTest); + f.should.have.length(4); + fn.unlinkSync(fileToTest); + done(); + },wait); + }); + }); + + it('should append to a file and add newline', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:"test2"}); // string + setTimeout(function() { + n1.emit("input", {payload:true}); // boolean + },50); + setTimeout(function() { + var f = fn.readFileSync(fileToTest).toString(); + f.should.have.length(11); + f.should.equal("test2\ntrue\n"); + done(); + },wait); + }); + }); + + it('should warn if msg.filename tries to override node', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:{a:1,b:2}, filename:"/tmp/foo"}); // object + setTimeout(function() { + var f = fn.readFileSync(fileToTest).toString(); + f.should.have.length(25); + f.should.equal("test2\ntrue\n{\"a\":1,\"b\":2}\n"); + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Warning: msg"); + done(); + },wait); + }); + }); + + it('should use msg.filename if filename not set in node', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "appendNewline":true, "overwriteFile":true}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:"fine", filename:fileToTest}); + setTimeout(function() { + var f = fn.readFileSync(fileToTest).toString(); + f.should.have.length(5); + f.should.equal("fine\n"); + done(); + },wait); + }); + }); + + it('should warn and not delete the file if msg.delete set', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:"fine",delete:true}); + setTimeout(function() { + try { + var f = fn.readFileSync(fileToTest).toString(); + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Warning: Invalid"); + done(); + } + catch(e) { + done(); + } + },wait); + }); + }); + + it('should be able to delete the file', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:"fine"}); + setTimeout(function() { + try { + var f = fn.readFileSync(fileToTest).toString(); + f.should.not.equal("fine"); + //done(); + } + catch(e) { + e.code.should.equal("ENOENT"); + done(); + } + },wait); + }); + }); + + it('should warn if filename not set', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "appendNewline":true, "overwriteFile":false}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:"nofile"}); + setTimeout(function() { + try { + var f = fn.readFileSync(fileToTest).toString(); + f.should.not.equal("fine"); + //done(); + } + catch(e) { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.equal("No filename specified"); + done(); + } + },wait); + }); + }); + + it('ignore a null payload', function(done) { + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + n1.emit("input", {payload:null}); + setTimeout(function() { + try { + var f = fn.readFileSync(fileToTest).toString(); + f.should.not.equal("fine"); + //done(); + } + catch(e) { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(0); + done(); + } + },wait); + }); + }); + + it('should fail to write to a ro file', function(done) { + // Stub file write so we can make writes fail + var fs = require('fs'); + var spy = sinon.stub(fs, 'writeFile', function(arg,arg2,arg3,arg4){ arg4(new Error("Stub error message")); }); + + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + setTimeout(function() { + try { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Failed to write"); + done(); + } + catch(e) { done(e); } + finally { fs.writeFile.restore(); } + },wait); + n1.receive({payload:"test"}); + }); + }); + + it('should fail to append to a ro file', function(done) { + // Stub file write so we can make writes fail + var fs = require('fs'); + var spy = sinon.stub(fs, 'appendFile', function(arg,arg2,arg3,arg4){ arg4(new Error("Stub error message")); }); + + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + setTimeout(function() { + try { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Failed to append"); + done(); + } + catch(e) { done(e); } + finally { fs.appendFile.restore(); } + },wait); + n1.receive({payload:"test2"}); + }); + }); + + it('should cope with failing to delete a file', function(done) { + // Stub file write so we can make writes fail + var fs = require('fs'); + var spy = sinon.stub(fs, 'unlink', function(arg,arg2){ arg2(new Error("Stub error message")); }); + + var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":"delete"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + setTimeout(function() { + try { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Failed to delete"); + done(); + } + catch(e) { done(e); } + finally { fs.unlink.restore(); } + },wait); + n1.receive({payload:"test2"}); + }); + }); + + }); + + + describe('file in Node', function() { + + var resourcesDir = path.join(__dirname,"..","..","..","resources"); + var fileToTest = path.join(resourcesDir,"50-file-test-file.txt"); + var wait = 150; + + beforeEach(function(done) { + fn.writeFileSync(fileToTest, "File message line 1\File message line 2\n"); + helper.startServer(done); + }); + + afterEach(function(done) { + helper.unload().then(function() { + fn.unlinkSync(fileToTest); + helper.stopServer(done); + }); + }); + + it('should be loaded', function(done) { + var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":fileToTest, "format":"utf8"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileInNode1"); + n1.should.have.property('name', 'fileInNode'); + done(); + }); + }); + + it('should read in a file and output a buffer', function(done) { + var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":fileToTest, "format":"", wires:[["n2"]]}, + {id:"n2", type:"helper"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileInNode1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload'); + msg.payload.should.have.length(39).and.be.a.Buffer; + msg.payload.toString().should.equal("File message line 1\File message line 2\n"); + done(); + }); + n1.receive({payload:""}); + }); + }); + +// Commented out to make build pass on node v.0.8 - reinstate when we drop 0.8 support... + //it('should read in a file and output a utf8 string', function(done) { + //var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":fileToTest, "format":"utf8", wires:[["n2"]]}, + //{id:"n2", type:"helper"}]; + //helper.load(fileNode, flow, function() { + //var n1 = helper.getNode("fileInNode1"); + //var n2 = helper.getNode("n2"); + //n2.on("input", function(msg) { + //msg.should.have.property('payload'); + //msg.payload.should.have.length(39).and.be.a.string; + //msg.payload.should.equal("File message line 1\File message line 2\n"); + //done(); + //}); + //n1.receive({payload:""}); + //}); + //}); + + it('should warn if msg.props try to overide', function(done) { + var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":fileToTest, "format":"", wires:[["n2"]]}, + {id:"n2", type:"helper"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileInNode1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + msg.should.have.property('payload'); + msg.payload.should.have.length(39).and.be.a.Buffer; + msg.payload.toString().should.equal("File message line 1\File message line 2\n"); + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file in"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Warning: msg "); + done(); + }); + n1.receive({payload:"",filename:"foo.txt"}); + }); + }); + + it('should warn if no filename set', function(done) { + var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "format":""}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileInNode1"); + setTimeout(function() { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file in"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.equal("No filename specified"); + done(); + },wait); + n1.receive({}); + }); + }); + + it('should handle a file read error', function(done) { + var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":"badfile", "format":""}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileInNode1"); + setTimeout(function() { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file in"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.equal("Error: ENOENT, open 'badfile'"); + done(); + },wait); + n1.receive({payload:""}); + }); + }); + + }); + +});