mirror of https://github.com/thumbsup/thumbsup
test(exiftool): add tests for batch exiftool streaming
parent
79dd36f77b
commit
00dac76983
@ -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…
Reference in New Issue