diff --git a/.travis.yml b/.travis.yml index bf56b25..eb29729 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: node_js node_js: - "0.10" - - "0.8" services: - mongodb - redis diff --git a/api/Melted.js b/api/Melted.js index 50d7b1f..4f4c00d 100644 --- a/api/Melted.js +++ b/api/Melted.js @@ -1,7 +1,6 @@ var spawn = require('child_process').spawn; var exec = require('child_process').exec; var net = require('net'); -var semaphore = require('semaphore')(1); var mbc = require('mbc-common'); var conf = mbc.config.Mosto.Melted; var melted_bin_path = conf.root + '/melted/BUILD/bin/melted'; @@ -176,6 +175,7 @@ exports.push = function(conn, commands, command_callback, close_callback) { var s = 0; conn.on('connect', function() { conn.on('data', function(data) { + logger.debug('[push] got data: "%s"', data); if (command_callback) command_callback(data); if (s < commands.length && data.indexOf("\n") > -1) { conn.write(commands[s]+"\n"); @@ -208,20 +208,3 @@ exports.setup = function(root, output, callback) { }) }; -/** - * take - * - * Take melted and not leave execution to other melted taked. - * - * @callback: callback function to process while take melted. - * - */ -exports.take = semaphore.take; - -/** - * leave - * - * Leave execution to other melted taked. - * - */ -exports.leave = semaphore.leave; diff --git a/drivers/playlists/mongo-driver.js b/drivers/playlists/mongo-driver.js index bb9562d..4d22112 100644 --- a/drivers/playlists/mongo-driver.js +++ b/drivers/playlists/mongo-driver.js @@ -1,5 +1,4 @@ var mbc = require('mbc-common') -, config = mbc.config.Mosto.Mongo , mubsub = require("mubsub") , moment = require("moment") , async = require('async') @@ -28,6 +27,7 @@ util.inherits (mongo_driver, events.EventEmitter); mongo_driver.prototype.start = function() { var self = this; + logger.info("Opening db connection", this.conf); var db = mbc.db(this.conf && this.conf.db); self.channel = mbc.pubsub(); @@ -144,8 +144,9 @@ mongo_driver.prototype.createPlaylist = function(sched, callback) { } logger.debug("LIST:" + list._id); - logger.info("Processing list:", {"id": list && list._id, "clips": list && list.pieces.length}); + logger.info("Processing list:", {"id": list && list._id, "clips": list && list.pieces}); self.pieces.findItems({_id:{"$in": list.pieces}}, function(err, pieces) { + logger.info('found', (pieces && pieces.length) || 0, 'pieces'); pieces = _.chain(pieces).map(function(block){ block._id = (block._id.toHexString && block._id.toHexString()) || block._id; return block; diff --git a/drivers/playlists/playlists-driver.js b/drivers/playlists/playlists-driver.js index 6468a3f..6a03a90 100644 --- a/drivers/playlists/playlists-driver.js +++ b/drivers/playlists/playlists-driver.js @@ -1,15 +1,18 @@ -var json_driver = require("./json-driver"), - mongo_driver = require("./mongo-driver"), - mbc = require("mbc-common"), - logger = mbc.logger().addLogger('PLAYLISTS-DRIVER'); +var mbc = require("mbc-common"), +logger = mbc.logger().addLogger('PLAYLISTS-DRIVER'), exports = module.exports = function(type, config) { logger.info("Creating playlists driver for type [" + type + "]"); if (type === 'json') { + var json_driver = require("./json-driver"); return new json_driver(config); } else if (type === 'mongo') { + var mongo_driver = require("./mongo-driver"); return new mongo_driver(config); + } else if (type === 'test') { + var test_driver = require("./test-driver"); + return new test_driver(config); } /****************************************************************** diff --git a/drivers/status/pubsub.js b/drivers/status/pubsub.js index 17b9735..43f1fbe 100644 --- a/drivers/status/pubsub.js +++ b/drivers/status/pubsub.js @@ -33,11 +33,11 @@ function MostoMessage(value, description, message) { this.message = message; } -function CaspaDriver() { +function CaspaDriver(conf) { events.EventEmitter.call(this); var self = this; this.status = _.clone(defaults); - this.db = mbc.db(); + this.db = mbc.db(conf && conf.db); this.publisher = mbc.pubsub(); } util.inherits(CaspaDriver, events.EventEmitter); @@ -194,8 +194,8 @@ CaspaDriver.prototype.dropMessage = function(message) { this.publisher.publish("mostoMessage.delete", { model: message }); }; -exports = module.exports = function() { - var driver = new CaspaDriver(); +exports = module.exports = function(conf) { + var driver = new CaspaDriver(conf); driver.setupAll(); return driver; diff --git a/models/Mosto.js b/models/Mosto.js index 71c73bc..d9459a0 100644 --- a/models/Mosto.js +++ b/models/Mosto.js @@ -553,12 +553,12 @@ Mosto.LoadedPlaylists = Backbone.Model.extend({ this.get('melted_medias').on('all', bubbleEvents(this, 'melted_medias')); }, - save: function() { + save: function(options) { // set fires add, remove, change and sort var mm = this.get('melted_medias'); var pl = this.get('playlists'); mm.write.take(function() { - mm.set(pl.getMedias()); + mm.set(pl.getMedias(), options); }); }, diff --git a/mosto.js b/mosto.js index 81b74e9..26087e1 100644 --- a/mosto.js +++ b/mosto.js @@ -9,6 +9,7 @@ var fs = require('fs') , utils = require('./utils') , mbc = require('mbc-common') , config = mbc.config.Mosto.General +, mongoConfig = mbc.config.Mosto.Mongo , _ = require('underscore') , heartbeats = require('./heartbeats') , models = require('./models/Mosto') @@ -16,10 +17,11 @@ var fs = require('fs') ; //TODO: Chequear window, se esta construyendo de formas distintas //INCLUSO EN EL DRIVER MISMO SE USA DE FORMAS DISTINTAS!!! -function mosto(customConfig) { +function mosto(customConfig, customMongoConfig) { /** CONFIGURATION */ this.config = customConfig || config; + this.mongoConfig = customMongoConfig || mongoConfig; this.server = undefined; this.pl_driver = undefined; this.status_driver = undefined; @@ -224,8 +226,9 @@ mosto.prototype.init = function(melted, callback) { * linkear heartbeat con status driver */ function startall() { - self.pl_driver = new playlists_driver(self.config.playlist_server); - self.status_driver = new status_driver(); + logger.info("Starting modules..."); + self.pl_driver = new playlists_driver(self.config.playlist_server, self.mongoConfig); + self.status_driver = new status_driver(self.mongoConfig); self.playlists = models.Playlists(); self.heartbeats = new heartbeats(); @@ -243,23 +246,24 @@ mosto.prototype.init = function(melted, callback) { self.checkMelted(startall); }; - if (melted !== undefined) { + if (melted !== undefined) Melted = melted; - check_and_start(); - } - else - Melted.take(check_and_start); + + check_and_start(); }; mosto.prototype.scheduleMeltedCheck = function() { - this.meltedInterval = setTimeout(this.checkMelted.bind(this, this.scheduleMeltedCheck.bind(this), true), 100); + this.meltedInterval = setTimeout(this.checkMelted.bind(this, this.scheduleMeltedCheck.bind(this), true), 500); + logger.debug("Melted Timeout id:", this.meltedInterval); }; mosto.prototype.checkMelted = function(callback, forceLoad) { + logger.debug("Checking melted..."); var self = this; Melted.is_running(function(running) { if (!running) { + logger.error("Melted was not running!"); Melted.start(function(pid) { Melted.setup(undefined, undefined, function(result) { if (forceLoad) @@ -278,24 +282,33 @@ mosto.prototype.checkMelted = function(callback, forceLoad) { mosto.prototype.finish = function(callback) { var self = this; logger.info("mbc-mosto: [INFO] Finish mbc-mosto... "); - if (self.restartMelted) + if (self.restartMelted) { + logger.debug("Clearing Melted Timeout id:", self.meltedInterval); clearTimeout(self.meltedInterval); + } this.stopDriver(); this.playlists.get("melted_medias").write.take(function() { - self.playlists.get("melted_medias").stopMvcpServer().fin(self.stopHeartbeats).fin(function() { + logger.debug("[finish] stop melted_medias mvcp server"); + self.playlists.get("melted_medias").stopMvcpServer().fin(function() { + logger.debug("[finish] stop heartbeats"); + return self.stopHeartbeats(); + }).fin(function() { + logger.debug("[finish] leave melted_medias write lock") self.playlists.get("melted_medias").write.leave(); + logger.debug("[finish] stop Melted"); Melted.stop(function(pid) { + logger.debug("[finish] melted stopped"); setTimeout( function() { - Melted.leave(); + logger.debug("[finish] calling callback"); if (callback) callback(); - }, 1000 ); + }, 7000 ); }); }); }); }; -exports = module.exports = function(customConfig) { - var mosto_server = new mosto(customConfig); +exports = module.exports = function(customConfig, customMongoConfig) { + var mosto_server = new mosto(customConfig, customMongoConfig); return mosto_server; }; /* diff --git a/package.json b/package.json index 7173795..f4f2a8d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Juan Martin Runge ", "contributors": [ "Niv Sardi ", "hatcsh"], "scripts": { - "test": "make coverage" + "test": "make LOG_LEVEL=info coverage" }, "main": "mosto", "repository": { diff --git a/test/general-functional-test.js b/test/general-functional-test.js index 92bb27b..0a49afb 100644 --- a/test/general-functional-test.js +++ b/test/general-functional-test.js @@ -6,14 +6,16 @@ var melted = require('melted-node'); var _ = require('underscore'); var seed = require('seed-random'); var mbc = require('mbc-common'); +var melted_log = mbc.logger().addLogger('MELTED-NODE'); var Media = require('mbc-common/models/Media'); var Q = require('q'); var moment = require('moment'); var helper = require('./media_helpers.js'); +var test = require('./test_helper.js'); var uuid = require('node-uuid'); var mosto_config = require('mbc-common').config.Mosto.General; -describe.skip("Mosto functional test", function() { +describe("Mosto functional test", function() { /* * arrancar sin playlists ** ver negro @@ -26,12 +28,14 @@ describe.skip("Mosto functional test", function() { self.create_playlist = function(medias) { medias = medias || []; - var mediamodels = []; - medias.forEach(function(media) { - mediamodels.push( new Media.Piece(media.toJSON()) ); - }); - return new Media.List({ - models: mediamodels + console.log('create playlist with', medias.length, 'pieces'); + return new Media.Playlist({ + _id: uuid.v1(), + pieces: _.map(medias, function(m) { + var piece = m.toJSON(); + piece._id = uuid.v1(); + return new Media.Piece(piece); + }), }); }; @@ -50,15 +54,18 @@ describe.skip("Mosto functional test", function() { }); var occcol = self.db.collection('scheds'); var listcol = self.db.collection('lists'); + var piececol = self.db.collection('pieces'); var log = []; for( var i = 0 ; i < self.playlists.length ; i++ ) { var playlist = self.playlists[i]; - var occurrence = { - start: timewalk.unix() - }; + var occurrence = new Media.Occurrence({ + playlist: playlist, + start: timewalk.valueOf(), + _id: uuid.v1(), + }); log.push(i+':'); - log.push('occurrence.start: ' + occurrence.start); - var medias = playlist.get('collection'); + log.push('occurrence.start: ' + occurrence.get('start')); + var medias = playlist.get('pieces'); for( var j = 0 ; j < medias.length ; j++ ) { var media = medias.at(j); media.start_time = timewalk.valueOf(); @@ -69,32 +76,35 @@ describe.skip("Mosto functional test", function() { media.end_time = timewalk.valueOf(); log.push('media ' + j + ' end : ' + media.end_time); } - occurrence.end = timewalk.unix(); - log.push('occurrence.end : ' + occurrence.end); - var playlist_json = _.omit(playlist.toJSON(), 'collection'); - playlist_json.models = _.invoke(playlist_json.models, 'toJSON'); - playlist_json._id = uuid.v4(); + occurrence.set('end', timewalk.valueOf()); + log.push('occurrence.end : ' + occurrence.get('end')); log.forEach(function(l) { console.log('[setup_playlists]:', l) ; }); - console.log('[setup_playlists] final:', playlist_json); + console.log('[setup_playlists] final:', playlist.toJSON()); // I need to wrap this in order to keep the `playlist` variable (function(pl, oc) { - listcol.insert(playlist_json, function(err, obj) { + console.log('saving occurrence', oc.id); + console.log('inserting', pl.get('pieces').length, 'pieces'); + Q.ninvoke(piececol, 'insert', pl.get('pieces').toJSON(), {safe:true}).then(function(obj) { + console.log(obj.length, 'pieces inserted'); + console.log('inserting playlist', pl.id); + return Q.ninvoke(listcol, 'insert', pl.toJSON(), {safe:true}) + }).then(function(obj) { obj = obj[0]; + console.log('inserted playlist', obj._id); // update self.playlists - _.extend(pl, obj); - occurrence = new Media.Occurrence({ - list: obj._id, - start: oc.start, - end: oc.end, - _id: oc.start.toString(), - }); - occcol.insert(occurrence.toJSON(), function(err, obj) { - var obj = obj[0]; - self.occurrences.push(obj); - done(); - }); + pl.set(obj); + console.log('inserting occurrence', oc.id); + return Q.ninvoke(occcol, 'insert', oc.toJSON(), {safe:true}); + }).then(function(obj) { + var obj = obj[0]; + console.log('inserted occurrence', obj._id); + self.occurrences.push(obj); + done(); + }).fail(function(err) { + console.log('ERROR ERROR', err); + throw new Error(err); }); })(playlist, occurrence); } @@ -147,7 +157,7 @@ describe.skip("Mosto functional test", function() { self.get_occurrence = function(time) { time = time || moment(); return _.find(self.occurrences, function(pl) { - return pl.start <= time.unix() && pl.end >= time.unix(); + return pl.start <= time.valueOf() && pl.end >= time.valueOf(); }); }; @@ -155,7 +165,7 @@ describe.skip("Mosto functional test", function() { time = time || moment(); var occurrence = self.get_occurrence(time); return _.find(self.playlists, function(pl) { - return pl._id === occurrence.list; + return pl.id === occurrence.playlist; }); }; @@ -163,22 +173,25 @@ describe.skip("Mosto functional test", function() { time = time || moment(); var playlist = self.get_playlist(time); - return _.find(playlist.get('models'), function(me) { + return playlist.get('pieces').find(function(me) { return me.start_time <= time && me.end_time >= time; }); }; self.publisher = mbc.pubsub(); self.listener = mbc.pubsub(); - self.db = mbc.db({ - dbName: 'mediatestdb', - dbHost: 'localhost', - dbPort: 27017 - }); + self.mongoConf = { + db: { + dbName: 'mediatestdb', + dbHost: 'localhost', + dbPort: 27017 + } + }; + self.db = mbc.db(self.mongoConf.db); /* generic tests */ - self.is_synced = function(done) { - var result = self.melted.sendPromisedCommand('USTA U0', '202 OK').then(function(val) { + self.is_synced = function(time) { + var result = self.melted.sendCommand('USTA U0').then(function(val) { var time = moment(); var expected_media = self.get_media(time); console.log('[is_synced] time:', time.valueOf()); @@ -192,22 +205,30 @@ describe.skip("Mosto functional test", function() { var elapsed = helper.framesToMilliseconds(frame, fps); var expected = (time - expected_media.start_time).valueOf(); console.log('[is_synced] got', lines[1], 'at', frame, ':', elapsed, 'expected', expected); - elapsed.should.be.approximately(expected, 1000); - done(); + elapsed.should.be.approximately(expected, time); }); return result; }; - before(function() { - self.melted = melted(); + before(function(done) { + test.take(function() { + test.init(function() { + self.melted = melted(undefined, undefined, melted_log); + done(); + }); + }); }); - after(function() { - delete self.melted; + after(function(done) { + test.finish(function() { + delete self.melted; + test.leave(); + done(); + }); }); describe('start without playlists', function() { before(function(done) { self.db.dropDatabase(function(err, success) { - self.mosto = new mosto(); + self.mosto = new mosto(undefined, self.mongoConf); self.mosto.once('playing', function() { done(); }); @@ -223,11 +244,11 @@ describe.skip("Mosto functional test", function() { }); }); it('should show black', function(done) { - var promise = self.melted.sendPromisedCommand('USTA U0', '202 OK'); + var promise = self.melted.sendCommand('USTA U0'); promise.then(function(result) { result = result.split('\r\n')[1].split(' '); var file = result[2]; - file.should.include('black_id'); + file.should.include('BLANK'); }).then(done).done(); }); }); @@ -259,10 +280,12 @@ describe.skip("Mosto functional test", function() { var setup = self.setup_playlists(moment( moment() + _.randint(0, -30000))); setup.then(function() { - self.mosto = new mosto(); + self.mosto = new mosto(undefined, self.mongoConf); self.mosto.once('playing', function() { // send pubsub messages with new playlists - self.melted.connect().then(done); + self.melted.connect().then(function(){ + done(); + }).done(); }); self.mosto.init(); }); @@ -279,7 +302,7 @@ describe.skip("Mosto functional test", function() { var expected_occurrence = self.get_occurrence(time); var expected_media = self.get_media(time); - var result = self.melted.sendPromisedCommand('USTA U0', '202 OK'); + var result = self.melted.sendCommand('USTA U0'); result.then(function(val) { var lines = val.split("\r\n"); lines[0].should.eql('202 OK'); @@ -300,20 +323,24 @@ describe.skip("Mosto functional test", function() { before(function(done) { var occurrence = self.get_occurrence(); self.delete_occurrence(occurrence).then(function() { - setTimeout(function() { - self.mosto.once('status', function(status) { - done(); - }); - }, mosto_config.timer_interval); + self.listener.on('JSONmessage', function(chan, msg) { + if(chan == 'mostoStatus') { + if (msg.piece.current._id.indexOf('BLANK') > -1) { + self.listener.unsubscribe('mostoStatus'); + done(); + } + } + }); + self.listener.subscribe('mostoStatus'); }).done(); }); it('should not break'); it('should be playing blank clip', function(done) { - var promise = self.melted.sendPromisedCommand('USTA U0', '202 OK'); + var promise = self.melted.sendCommand('USTA U0'); promise.then(function(result) { result = result.split('\r\n')[1].split(' '); var file = result[2]; - file.should.include('black_id'); + file.should.include('BLANK'); }).then(done).done(); }); }); @@ -339,7 +366,7 @@ describe.skip("Mosto functional test", function() { var setup = self.setup_playlists(moment( moment() - 5 * 60 * 1000)); setup.then(function() { - self.mosto = new mosto(); + self.mosto = new mosto(undefined, self.mongoConf); self.mosto.once('playing', function() { // send pubsub messages with new playlists done(); diff --git a/test/heartbeats-test.js b/test/heartbeats-test.js index aea0fe4..86a0739 100644 --- a/test/heartbeats-test.js +++ b/test/heartbeats-test.js @@ -1,6 +1,6 @@ var assert = require("assert"), - melted = require('../api/Melted'), helpers = require('./media_helpers'), + test = require('./test_helper.js'); Mosto = require('../models/Mosto'), _ = require('underscore'), moment = require('moment'), @@ -10,18 +10,14 @@ var assert = require("assert"), describe('Mosto Heartbeats Test', function() { before(function(done) { - melted.take(function() { - melted.stop(function(){ - melted.start(function(pid) { - melted.setup(undefined, undefined, function(has_err) { - Mosto.Playlists().get('playlists').reset(); - Mosto.Playlists().save(); - Mosto.Playlists().get('melted_medias').initMvcpServer().then(function() { - Mosto.Playlists().get('melted_medias').write.take(function() { - Mosto.Playlists().get('melted_medias').write.leave(); - done(); - }); - }); + test.take(function() { + test.init(function() { + Mosto.Playlists().get('playlists').reset(); + Mosto.Playlists().save(); + Mosto.Playlists().get('melted_medias').initMvcpServer().then(function() { + Mosto.Playlists().get('melted_medias').write.take(function() { + Mosto.Playlists().get('melted_medias').write.leave(); + done(); }); }); }); @@ -136,9 +132,9 @@ describe('Mosto Heartbeats Test', function() { after(function(done) { this.timeout(15000); self.hb.stop().then(function() { - Mosto.Playlists().get('melted_medias').stopMvcpServer().then(function() { +// Mosto.Playlists().get('melted_medias').stopMvcpServer().then(function() { done(); - }); +// }); }); }); }); @@ -216,12 +212,12 @@ describe('Mosto Heartbeats Test', function() { playlists().addPlaylist(pl); - Mosto.Playlists().get('melted_medias').initMvcpServer().then(function() { - Mosto.Playlists().get('melted_medias').write.take(function() { - Mosto.Playlists().get('melted_medias').write.leave(); +// Mosto.Playlists().get('melted_medias').initMvcpServer().then(function() { +// Mosto.Playlists().get('melted_medias').write.take(function() { +// Mosto.Playlists().get('melted_medias').write.leave(); done(); - }); - }); +// }); +// }); }); describe('-- Starting playback and wait 3 seconds', function() { @@ -387,12 +383,10 @@ describe('Mosto Heartbeats Test', function() { }); }); - describe('#leave melted', function() { - it('-- leave melted', function(done) { - melted.stop(function(pid) { - melted.leave(); - done(); - }); + after(function(done) { + test.finish(function() { + test.leave(); + done(); }); }); diff --git a/test/media_helpers.js b/test/media_helpers.js index 5f06e4d..36e7b95 100644 --- a/test/media_helpers.js +++ b/test/media_helpers.js @@ -90,6 +90,32 @@ exports.getMBCMedia = function(path) { }; +/* + * getJSONMedia(path) + * - path: optional path + * + * Scans given path (or default) getting media files and returns JSON objects array + */ +exports.getJSONMedia = function(path) { + if (path === undefined) { + path = "test/videos/"; // TODO FIXME XXX: ugly hardcoded -> should be in config? + } + + var parsed = parseXMLs(path); + var medias = parsed.map(function(elem) { + var params = {}; + params.name = elem.filename; + params._id = crypto.createHash('md5').update(params.name).digest('hex'); + params.file = process.cwd() + '/' + path + elem.filename; + params.fps = parseInt(elem.data.mlt.profile[0]["$"].frame_rate_num, 10); + var frames = parseInt(elem.data.mlt.producer[0]["$"].out, 10); + var duration = moment("0:0:0.0", "HH:mm:ss.SSS").add(exports.framesToMilliseconds(frames, params.fps)); + params.durationraw = duration.format("HH:mm:ss.SSS"); + return params; + }); + return medias; +}; + /* * getTotalMediaLength(media_array) * - media_array: an array of Media objects diff --git a/test/models-test.js b/test/models-test.js index 1e693dd..0bab4a0 100644 --- a/test/models-test.js +++ b/test/models-test.js @@ -1,13 +1,13 @@ var Mosto = require('../models/Mosto') , should = require('should') , mvcp = require('../drivers/mvcp/mvcp-driver') -, melted = require('../api/Melted') , helpers = require('./media_helpers') +, test = require('./test_helper.js') , _ = require('underscore') , moment = require('moment') ; -describe.skip('models.Mosto', function() { +describe('models.Mosto', function() { var self = this; self.playlists = Mosto.Playlists; self.medias = helpers.getMedia(); @@ -15,7 +15,7 @@ describe.skip('models.Mosto', function() { self.server = new mvcp('melted'); self.createPlaylist = function(medias, start) { - var duration = _.reduce(medias, function(acc, m) { + var duration = _.reduce(medias, function(acc, m) { return acc + m.get('length') * m.get('fps'); }, 0); start = start || moment(); @@ -31,24 +31,19 @@ describe.skip('models.Mosto', function() { describe('MeltedCollection', function(){ before(function(done) { - // restart melted - melted.take(function() { - melted.stop(function() { - melted.start(function() { - melted.setup(undefined, undefined, function() { - self.server.initServer().fin(function() { - done(); - }); - }); + test.take(function() { + test.init(function() { + self.server.initServer().fin(function() { + done(); }); }); }); }); after(function(done) { - self.playlists().get('melted_medias').stopMvcpServer().fin(self.server.stopServer).fin(function() { - melted.stop(function() { - melted.leave(); + self.server.stopServer().fin(function() { + test.finish(function() { + test.leave(); done(); }); }); @@ -58,8 +53,8 @@ describe.skip('models.Mosto', function() { before(function(done) { self.mlt_media = self.playlists().get('melted_medias'); self.pls = self.playlists().get('playlists'); - self.mediamodels = _.map(self.medias, function(media, ix) { - return new Mosto.Media(_.extend(media, {playlist_order: ix})); + self.mediamodels = _.map(self.medias, function(media, ix) { + return new Mosto.Media(_.extend(media, {playlist_order: ix})); }); done(); }); @@ -107,7 +102,7 @@ describe.skip('models.Mosto', function() { self.playlists().save(); self.mlt_media.write.take(function() { self.mlt_media.write.leave(); - done(); + done(); }); }); afterEach(function(done) { diff --git a/test/mosto-status-test.js b/test/mosto-status-test.js index 8f7efc4..8e33bcd 100644 --- a/test/mosto-status-test.js +++ b/test/mosto-status-test.js @@ -1,26 +1,24 @@ var assert = require("assert"), - mosto = require('../mosto'), - melted = require('../api/Melted'); +mosto = require('../mosto'), +test = require('./test_helper.js'); //TODO: This test should be rewritten after @fabriciocosta merges his part with more usefull data! -describe.skip('Mosto status', function() { +describe('Mosto status', function() { var mosto_server = undefined; var rec = -1; before(function(done) { - melted.take(function() { - console.error("MELTED 1"); - melted.stop(function(){ - console.error("MELTED 2"); - melted.start(function() { - console.error("MELTED 3"); - melted.setup(undefined, undefined, function() { - console.error("MELTED READY"); -// melted.leave(); - done(); - }); - }); + test.take(function() { + test.init(done); + }); + }); + + after(function(done) { + mosto_server.finish(function() { + test.finish(function() { + test.leave(); + done(); }); }); }); @@ -33,7 +31,7 @@ describe.skip('Mosto status', function() { rec++; done(); }); - mosto_server.init(melted); + mosto_server.init(); }); it('--should have received 1 status', function() { assert.equal(rec, 0); @@ -57,11 +55,4 @@ describe.skip('Mosto status', function() { }); }); }); - - - after(function(done) { - mosto_server.finish(done); - }); - - }); diff --git a/test/mvcp-driver-test.js b/test/mvcp-driver-test.js index 0746de0..6d651d7 100644 --- a/test/mvcp-driver-test.js +++ b/test/mvcp-driver-test.js @@ -4,6 +4,8 @@ var _ = require('underscore'); var mvcp_server = require('../drivers/mvcp/mvcp-driver'); var melted = require('../api/Melted'); var helpers = require('./media_helpers'); +var test = require('./test_helper.js'); + function getMedia(id, orig_order, playlist_id, name, type, file, length, fps) { var media = {}; @@ -25,18 +27,16 @@ describe('start mvcp-driver test', function(done) { this.timeout(15000); before(function(done) { - // Make sure we start with a fresh melted - melted.take(function() { - melted.stop(function(){ + test.take(function() { + test.init(function(){ done(); }); }); }); after(function(done) { - // and leave it "clean" after we leave - melted.stop(function() { - melted.leave(); - done() + test.finish(function() { + test.leave(); + done(); }); }); diff --git a/test/playlist-mongo-driver.js b/test/playlist-mongo-driver.js index 35c29c4..518acc5 100644 --- a/test/playlist-mongo-driver.js +++ b/test/playlist-mongo-driver.js @@ -3,8 +3,8 @@ var mongo_driver = require('../drivers/playlists/mongo-driver'); var should = require('should'); var mbc = require('mbc-common'); var _ = require('underscore'); -var melted = require('../api/Melted'); var helpers = require('./media_helpers'); +var test = require('./test_helper.js') var Media = require('mbc-common/models/Media'); var uuid = require('node-uuid'); @@ -12,8 +12,8 @@ describe('PlaylistMongoDriver', function(){ var self = this; before(function(done) { - melted.take(function() { - melted.stop(function(pid){ + test.take(function() { + test.init(function(pid){ // setup mongo driver var conf = { @@ -26,69 +26,75 @@ describe('PlaylistMongoDriver', function(){ self.driver = new mongo_driver(conf); self.db = mbc.db(conf.db); - self.driver.start(); - self.from = moment(); - self.span = 120; - self.to = moment((self.from.unix() + self.span * 60) * 1000); // add 2hs - - self.collections = { - lists: self.db.collection('lists'), - scheds: self.db.collection('scheds'), - pieces: self.db.collection('pieces'), - }; + self.db.dropDatabase(function(err, success) { + self.driver.start(); + self.from = moment(); + self.span = 120; + self.to = moment((self.from.unix() + self.span * 60) * 1000); // add 2hs + + self.collections = { + lists: self.db.collection('lists'), + scheds: self.db.collection('scheds'), + pieces: self.db.collection('pieces'), + }; - var medias = helpers.getMBCMedia(); - // let's create a playlist at least 1 hour long - var playlist = new Media.Playlist({_id: uuid.v1()}); - playlist.set('title', 'TestPlaylist'); - while(playlist.get('duration') < 3600000) { - var media = _.randelem(medias); - var piece = new Media.Piece(media.toJSON()); - piece.set('_id', uuid.v1()); - playlist.get('pieces').add(piece); - playlist.update_duration_nowait(playlist.get('pieces')); - } - self.pieces = playlist.get('pieces'); - self.lists = [playlist]; - // program at least 4hs of schedules - self.scheds = []; - for(var i = 0 ; i < 5 ; i++) { - var schedule = { - _id: uuid.v1(), - playlist: playlist, - title: playlist.get('title') + i, + var medias = helpers.getJSONMedia(); + // let's create a playlist at least 1 hour long + var playlist = new Media.Playlist({_id: uuid.v1(), title: 'Name'}); + while(playlist.get('duration') < 3600000) { + var m = _.randelem(medias); + var piece = new Media.Piece(); + piece.set('_id', uuid.v1()); + piece.set('name', m.name); + piece.set('file', m.file); + piece.set('fps', m.fps); + piece.set('durationraw', m.durationraw); + playlist.get('pieces').add(piece); + playlist.update_duration_nowait(playlist.get('pieces')); + } + self.pieces = playlist.get('pieces'); + self.lists = [playlist]; + // program at least 4hs of schedules + self.scheds = []; + for(var i = 0 ; i < 5 ; i++) { + var schedule = { + _id: uuid.v1(), + playlist: playlist, + title: playlist.get('title') + i, + }; + var hsix = i - 3; + var now = self.from; + // schedules are from 1hs before now + var schtime = moment(now + (hsix * 30 * 60 * 1000)).valueOf(); + var length = moment.duration(playlist.get('duration')); + schedule.start = schtime; + schedule.end = schtime + length; + var occurrence = new Media.Occurrence(schedule); + self.scheds.push(occurrence); }; - var hsix = i - 3; - var now = self.from; - // schedules are from 1hs before now - var schtime = moment(now + (hsix * 30 * 60 * 1000)); - var length = moment.duration(playlist.get('duration')); - schedule.start = schtime.valueOf(); - schedule.end = schtime + length; - var occurrence = new Media.Occurrence(schedule); - self.scheds.push(occurrence); - }; - var ready = _.after( - self.lists.length + self.pieces.length + self.scheds.length, - function(){ done() }); + var ready = _.after( + self.lists.length + self.pieces.length + self.scheds.length, + function(){ done() }); - self.pieces.forEach(function(piece) { - self.collections.pieces.save(piece.toJSON(), {safe:true}, function(err, list) { - ready(); + self.pieces.forEach(function(piece) { + self.collections.pieces.save(piece.toJSON(), {safe:true}, function(err, list) { + ready(); + }); }); - }); - self.lists.forEach(function(playlist) { - self.collections.lists.save(playlist.toJSON(), {safe:true}, function(err, list) { - ready(); + self.lists.forEach(function(playlist) { + self.collections.lists.save(playlist.toJSON(), {safe:true}, function(err, list) { + ready(); + }); }); - }); - self.scheds.forEach(function(occurrence) { - self.collections.scheds.save(occurrence.toJSON(), {safe:true}, function(err, sched){ - ready(); + self.scheds.forEach(function(occurrence) { + self.collections.scheds.save(occurrence.toJSON(), {safe:true}, function(err, sched){ + ready(); + }); }); + }); }); }); @@ -102,52 +108,9 @@ describe('PlaylistMongoDriver', function(){ self.collections[col].drop(); } } - melted.leave(); - done(); - }); - - describe.skip('#getWindow()', function() { - beforeEach(function(){ - self.driver.window = undefined; - }); - it('should exist', function() { - self.driver.should.have.property('getWindow'); - self.driver.getWindow.should.be.a('function'); - }); - it('should accept two parameters and save them in window = {from, to}', function() { - var window = self.driver.getWindow(self.from, self.to); - window.from.valueOf().should.equal(self.from.valueOf()); - window.to.valueOf().should.equal(self.to.valueOf()); - }); - it('should accept an object with {from, to}', function() { - var window = self.driver.getWindow({from: self.from, to: self.to}); - window.from.valueOf().should.equal(self.from.valueOf()); - window.to.valueOf().should.equal(self.to.valueOf()); - }); - it('should accept an object with {from, timeSpan}', function() { - var window = self.driver.getWindow({from: self.from, timeSpan: self.span}); - window.from.valueOf().should.equal(self.from.valueOf()); - var to = moment(self.from.valueOf()); - to.add(self.span * 60 * 1000); - console.log('popop', window.to.valueOf(), to.valueOf()) - window.to.valueOf().should.equal(to.valueOf()); - }); - it('should accept only a "to" object and assume "from" is now', function() { - var window = self.driver.getWindow({to: self.to}); - window.should.have.property('from'); - window.from.valueOf().should.approximately((new moment()).valueOf(), 10); - }); - it('should accept no parameters, and use the config file from defaults', function(){ - var window = self.driver.getWindow(); - var config = require('mbc-common').config.Mosto.Mongo; - window.timeSpan.should.equal(config.load_time * 60 * 1000); - window.from.valueOf().should.approximately(moment().valueOf(), 10); - window.to.diff(window.from).valueOf().should.equal(window.timeSpan.valueOf()); - }); - it('should accept dates and transform them to moments', function() { - var window = self.driver.getWindow(new Date(), new Date()); - moment.isMoment(window.from).should.be.ok; - moment.isMoment(window.to).should.be.ok; + test.finish(function() { + test.leave(); + done(); }); }); @@ -158,7 +121,7 @@ describe('PlaylistMongoDriver', function(){ var list = sched.get('playlist'); var model = sched.toJSON(); model.start = moment().valueOf() - model.end = moment().add(list.get('duration')); + model.end = moment().add(list.get('duration')).valueOf(); self.message = { backend: 'schedbackend', model: model, @@ -171,10 +134,10 @@ describe('PlaylistMongoDriver', function(){ var message = self.message; message.method = 'create'; self.driver.on('create', function(playlist) { - console.log("create received! - " + playlist.name ); - playlist.get('id').should.be.eql(message.model._id); + playlist.id.should.be.eql(message.model._id); playlist.get('name').should.be.eql(message.model.title); - playlist.get('start').should.eql(message.model.start); + moment(playlist.get('start')).valueOf().should.eql(message.model.start); + self.driver.removeAllListeners('create'); done(); }); self.pubsub.publishJSON(message.channel(), message); @@ -183,6 +146,7 @@ describe('PlaylistMongoDriver', function(){ var message = self.message; message.method = 'update'; self.driver.on('update', function(playlist) { + self.driver.removeAllListeners('update'); done(); }); self.pubsub.publishJSON(message.channel(), message); @@ -192,6 +156,7 @@ describe('PlaylistMongoDriver', function(){ message.method = 'delete'; self.driver.on('delete', function(id) { id.should.be.eql(message.model._id); + self.driver.removeAllListeners('delete'); done(); }); self.pubsub.publishJSON(message.channel(), message); @@ -201,13 +166,15 @@ describe('PlaylistMongoDriver', function(){ it('should return playlists', function(done) { self.driver.getPlaylists({from: self.from, to: self.to}, function(playlists) { playlists.length.should.not.be.eql(0); - playlists.forEach(function(playlist) { - playlist.get('id').should.be.ok; - playlist.get('name').should.be.ok; - playlist.get('start').should.be.ok; - playlist.get('medias').should.be.ok; - playlist.get('end').should.be.ok; - playlist.get('loaded').should.not.be.ok; + playlists.forEach(function(pl) { + var playlist = pl.toJSON(); + playlist.should.have.property('id'); + playlist.should.have.property('name'); + playlist.should.have.property('start'); + playlist.should.have.property('medias'); + playlist.should.have.property('end'); + playlist.should.have.property('loaded'); + playlist.should.have.property('mode'); }); done(); }); @@ -215,18 +182,15 @@ describe('PlaylistMongoDriver', function(){ it('should return only playlists within timeframe', function(done) { var inside = function(sched) { - return (sched.get('start') <= self.to.valueOf() && - sched.get('end') >= self.from.valueOf()); - }; - var sched_id = function(sched) { - return sched.get('_id'); + return (sched.get('start') <= self.to && + sched.get('end') >= self.from); }; - var in_scheds = _.chain(self.scheds).filter(inside).map(sched_id).value(); - var out_scheds = _.chain(self.scheds).reject(inside).map(sched_id).value(); + var in_scheds = _.chain(self.scheds).filter(inside).pluck('id').value(); + var out_scheds = _.chain(self.scheds).reject(inside).pluck('id').value(); self.driver.getPlaylists({from: self.from, to: self.to}, function(playlists) { - var pl_ids = _.chain(playlists).map(function(pl) { return pl.get('id') }).value(); + var pl_ids = _.chain(playlists).pluck('id').value(); pl_ids.forEach(function(playlist, ix) { playlist.should.eql(in_scheds[ix]); diff --git a/test/test_helper.js b/test/test_helper.js new file mode 100644 index 0000000..ef7e423 --- /dev/null +++ b/test/test_helper.js @@ -0,0 +1,27 @@ +var semaphore = require('semaphore')(1) +, melted = require('../api/Melted') +, Mosto = require('../models/Mosto') +; + + +exports.take = function() { + return semaphore.take.apply(this, arguments); +}; + +exports.leave = function() { + return semaphore.leave.apply(this, arguments); +}; + +exports.init = function(callback) { + melted.stop(function(){ + melted.start(function(pid) { + melted.setup(undefined, undefined, function(has_err) { + callback(); + }); + }); + }); +}; + +exports.finish = function(callback) { + melted.stop(callback); +}; \ No newline at end of file diff --git a/utils.js b/utils.js index 9ebbe58..84aa984 100644 --- a/utils.js +++ b/utils.js @@ -22,68 +22,11 @@ exports = module.exports = { return filename; }, - getTimeLengthFromFrames: function(frames, fps) { - var seconds = parseFloat(frames) / parseFloat(fps); - var minutes = 0; - if (seconds > 60) { - minutes = parseInt(seconds / 60); - seconds = parseInt (seconds - (minutes * 60)); - } - var hours = 0; - if (minutes > 60) { - hours = parseInt(hours / 60); - minutes = parseInt(minutes - (hours * 60)); - } - return "." + hours + ":" + minutes + ":" + seconds; - }, - getCurrentPosFromClip: function(actualFrame, totalFrames) { return parseFloat(actualFrame / totalFrames); }, - getFramePositionFromClock: function( clock_position, clip_start, frames_length, fps ) { - var millis = moment.duration( clock_position - clip_start ).asMilliseconds(); - var frame_position = Math.max( (millis / 1000.0 ) * fps, frames_length - 1); - return frame_position; - }, - convertFramesToSeconds: function ( frames, fps ) { return frames/fps; }, - - convertLengthToMilliseconds: function ( frames ) { - var m = moment( frames, "HH:mm:ss.SS"); - return m.hours()*60*60*1000 + m.minutes()*60*1000 + m.seconds()*1000 + m.milliseconds(); - }, - - convertFramesToMilliseconds: function ( frames, fps ) { - if ( isNaN(frames) || fps+""=="NaN" || fps==undefined || fps===false || fps==0) { - var m = moment( frames, "HH:mm:ss.SS"); - if (m) return m.hours()*60*60*1000 + m.minutes()*60*1000 + m.seconds()*1000 + m.milliseconds(); - } - fps = parseFloat(fps); - var millis = frames * 1000.0 / (1.0 * fps); - if (millis!==undefined) return millis; - }, - - convertDurationToString: function( moment_duration ) { - return moment_duration.hours()+":"+moment_duration.minutes()+":"+moment_duration.seconds()+"."+moment_duration.milliseconds(); - }, - - convertUnixToDate: function ( unix_timestamp ) { - //var date = new Date(unix_timestamp*1000); - var date = new moment(unix_timestamp); - return date.format("hh:mm:ss"); - }, - - convertDateToUnix: function ( date_timestamp ) { - var date = new moment(date_timestamp); - return date.unix(); - }, - - convertTimeToFrames: function(time, fps) { - var mTime = moment(time, "HH:mm:ss"); - var seconds = mTime.seconds() + (mTime.minutes() * 60) + (mTime.hours() * 60 * 60); - return seconds * fps; - } };