test(exiftool): add tests for batch exiftool streaming

pull/118/head
Romain 6 years ago
parent 79dd36f77b
commit 00dac76983

42
package-lock.json generated

@ -314,6 +314,24 @@
}
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": {
"core-js": "2.5.7",
"regenerator-runtime": "0.11.1"
},
"dependencies": {
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
"dev": true
}
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -3275,6 +3293,15 @@
"integrity": "sha512-qqudNfOX7ZmX9vm1WIAU+gWlmxVNAnwY6UG3RkFutNywmRCUGP83tujP6IxX2DS1TmcaEZBOhYwDuYEmJYE+3w==",
"dev": true
},
"mock-spawn": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/mock-spawn/-/mock-spawn-0.2.6.tgz",
"integrity": "sha1-s5wVocBnUEMQFEFR8sHeNE0Dk38=",
"dev": true,
"requires": {
"through": "2.3.8"
}
},
"moment": {
"version": "2.22.2",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
@ -3968,6 +3995,12 @@
"glob-to-regexp": "0.4.0"
}
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
"dev": true
},
"regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@ -4646,6 +4679,15 @@
"duplexer": "0.1.1"
}
},
"stream-mock": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/stream-mock/-/stream-mock-1.2.0.tgz",
"integrity": "sha1-9otVI8Dhz+YZ6gnX0QlykPQFuWo=",
"dev": true,
"requires": {
"babel-runtime": "6.26.0"
}
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",

@ -61,11 +61,13 @@
"markdown-toc": "^1.1.0",
"mocha": "^5.1.1",
"mock-fs": "^4.5.0",
"mock-spawn": "^0.2.6",
"require-all": "^2.2.0",
"require-lint": "^1.3.0",
"should": "^13.2.1",
"sinon": "^6.0.0",
"standard": "^11.0.1",
"stream-mock": "^1.2.0",
"tmp": "0.0.33"
},
"standard": {

@ -0,0 +1,76 @@
const should = require('should/as-function')
const sinon = require('sinon')
const streamMock = require('stream-mock')
const exifStream = require('../../../src/components/exiftool/stream')
const parallel = require('../../../src/components/exiftool/parallel')
describe('exiftool parallel', function () {
beforeEach(() => {
sinon.stub(exifStream, 'parse').callsFake(mockExifStream)
})
afterEach(() => {
exifStream.parse.restore()
})
it('creates 1 stream if no concurrency', (done) => {
// test data
const files = numberedFiles(3)
const concurrency = 1
// create the streams
const stream = parallel.parse('input', files, concurrency)
reduceStream(stream, emittedData => {
const emittedPaths = emittedData.map(e => e.SourceFile)
should(emittedPaths).eql([
'input/IMG_0001.jpg',
'input/IMG_0002.jpg',
'input/IMG_0003.jpg'
])
done()
})
})
it('creates concurrent streams to split files evenly', (done) => {
// test data
const files = numberedFiles(5)
const concurrency = 2
// create the streams
const stream = parallel.parse('input', files, concurrency)
reduceStream(stream, emittedData => {
// should have created 2 streams, with 2 or 3 files each
sinon.assert.callCount(exifStream.parse, 2)
should(exifStream.parse.args[0]).eql(['input', ['IMG_0001.jpg', 'IMG_0002.jpg', 'IMG_0003.jpg']])
should(exifStream.parse.args[1]).eql(['input', ['IMG_0004.jpg', 'IMG_0005.jpg']])
// should have 5 files in the merged output
const emittedPaths = emittedData.map(e => e.SourceFile)
should(emittedPaths).eql([
'input/IMG_0001.jpg',
'input/IMG_0002.jpg',
'input/IMG_0003.jpg',
'input/IMG_0004.jpg',
'input/IMG_0005.jpg'
])
done()
})
})
})
function numberedFiles (count) {
return Array(count).join(' ').split(' ').map((a, i) => `IMG_000${i + 1}.jpg`)
}
function mockExifStream (root, filenames) {
const input = filenames.map(name => {
return { SourceFile: `${root}/${name}`, Directory: root }
})
return new streamMock.ReadableMock(input, {objectMode: true})
}
function reduceStream (stream, done) {
const emittedData = []
stream.on('data', entry => {
emittedData.push(entry)
}).on('end', () => {
done(emittedData)
})
}

@ -0,0 +1,78 @@
const childProcess = require('child_process')
const debug = require('debug')
const mockSpawn = require('mock-spawn')
const should = require('should/as-function')
const sinon = require('sinon')
const exifStream = require('../../../src/components/exiftool/stream')
describe('exiftool stream', function () {
beforeEach(() => {
sinon.stub(childProcess, 'spawn')
debug.reset()
})
afterEach(() => {
childProcess.spawn.restore()
})
it('parses exiftool JSON output into an array', (done) => {
// setup a mock that returns exiftool-like JSON data
const errorSpawn = mockSpawn()
childProcess.spawn.callsFake(errorSpawn)
errorSpawn.setDefault(function (cb) {
setTimeout(() => {
this.stdout.write(`[{
"SourceFile": "IMG_0001.jpg",
"MIMEType": "image/jpeg"
},`)
}, 10)
setTimeout(() => {
this.stdout.write(`{
"SourceFile": "IMG_0002.jpg",
"MIMEType": "image/jpeg"
}]`)
}, 20)
setTimeout(() => cb(), 30)
})
// check the data returned
const stream = exifStream.parse('input', ['IMG_0001.jpg', 'IMG_0002.jpg'])
reduceStream(stream, emittedData => {
should(emittedData).eql([{
SourceFile: 'IMG_0001.jpg',
MIMEType: 'image/jpeg'
},
{
SourceFile: 'IMG_0002.jpg',
MIMEType: 'image/jpeg'
}])
done()
})
})
it('returns an empty array and prints an error if exiftool is not available', (done) => {
// setup a mock that always fails
const errorSpawn = mockSpawn()
childProcess.spawn.callsFake(errorSpawn)
errorSpawn.setDefault(function (cb) {
this.emit('error', new Error('spawn ENOENT'))
setTimeout(() => cb(), 10)
})
// check the data returned
const stream = exifStream.parse('input', ['IMG_0001.jpg'])
reduceStream(stream, emittedData => {
should(emittedData).eql([])
debug.assertContains('installed on your system')
debug.assertContains('spawn ENOENT')
done()
})
})
})
function reduceStream (stream, done) {
const emittedData = []
stream.on('data', entry => {
emittedData.push(entry)
}).on('end', () => {
done(emittedData)
})
}
Loading…
Cancel
Save