Drop the entire sails-memory database? - sails.js

I'm using 'sails-memory' as the database for my Sails unit tests and ideally would like to clear the entire database after individual tests. Is there a way I can drop the entire database?

I found another method which seems to work. This emits an event which tells the orm hook to reload before each test. If using the memory db, or the disk db with the 'drop' migrate option, it accomplishes the desired.
beforeEach((done) => {
"use strict";
// Drops database between each test. This works because we use
// the memory database
sails.once('hook:orm:reloaded', done);
sails.emit('hook:orm:reload');
});

You could lift your sails app before each test, rebuilding your database (migrate: 'drop'). Here is an example:
Sails = require('sails/lib/app');
app = Sails();
var testConfig = {
environment: 'test',
port: 1337,
log: {
level: 'error'
},
connections: {
testDB: {
adapter: 'sails-memory'
}
},
connection: 'testDB',
//wipe/drop ALL my data and rebuild models every time
migrate: 'drop'
};
beforeEach(function (done) {
// start sails app for tests
app.lift(testConfig, function (err, sails) {
done(err);
});
});
//tests...

Related

mocha test for sails hook that depends on a sails app

I'm trying to write a mocha test for a sails installable hook (myhook) that is dependent on a particular sails app (myapp). I'd like the bootstrap.test.js to lift myapp with myhook. Thus, I have myapp a devDependency in myhook project.
My bootstrap.test.js has something like this:
var myapp = require('myapp');
// put it in global (special case) for npm test only
global.thehook = require('../api/hooks/myhook/index');
before(function(done) {
this.timeout(10000);
console.log("Bootstrap lifting sails...");
myapp.lift({
hooks: {
"myhook": global.thehook,
"grunt": false
},
log: {level: "error"},
}, function(err) {
if (err) return done(err);
// here you can load fixtures, etc.
done(err, sails);
});
});
after(function(done) {
myapp.lower(done);
});
Thinking .lift() and .lower would apply to the sails app. But, that doesn't seem to be the case.
How do I make this work?
You will need to use the sails dependency in place of myapp.
var sails = require('sails');
before(function(done) {
sails.lift({
// test configuration
}, function (error) {
// ...
done();
});
});
after(function(done) {
sails.lower(function (error) {
//...
done();
});
})
The sails dependency starts in the root of the project directory and will lift the application, so there's no need to require app.js for lifting the app.

running background job on a specific action in sails js

i am trying to make a service that runs in background when specific event happens. As an example when user verifies email i want my service of deleting possible unverified duplicate emails form database. i tried using kue to save my purpose but i think its more like the services will run once the sails lift fires?
so how to run a service when specific event happens? any help would be much appreciated.
thanks
You can indeed use Kue for this purpose.
Create a config file kue.js for Kue
var kue = require('kue');
var kue_engine = kue.createQueue({
prefix: 'kue',
redis: {
port: '6379',
host: 'localhost'
}
});
process.once('SIGTERM', function (sig) {
kue_engine.shutdown( 5000, function(err) {
console.log( 'Kue shutdown: ', err||'' );
process.exit( 0 );
});
});
module.exports.kue = kue_engine;
Add the job to Kue in relevant controller action.
var kue_engine = sails.config.kue;
kue_engine.create('delete_verified_email', {email: '123#456.com'})
.priority('medium')
.attempts(3)
.save();
Create a worker.js in project root to consume kue jobs.
var kue = require('kue');
require('sails').load({
hooks: {
blueprints: false,
cors: false,
csrf: false,
grunt: false,
http: false,
i18n: false,
logger: false,
policies: false,
pubsub: false,
request: false,
responses: false,
session: false,
sockets: false,
views: false
}
}, function (err, app) {
sails.log.info('Starting kue');
var kue_engine = sails.config.kue;
//register kue.
kue_engine.on('job complete', function (id) {
sails.log.info('Removing completed job: ' + id);
kue.Job.get(id, function (err, job) {
job.remove();
});
});
kue_engine.process('delete_verified_email', 20, function (job, done) {
// you can access the data passed while creating job at job.data
// all the sails models, services are available here
console.log(job.data.email)
done && done();
});
Run the worker.js to consume the kue jobs created by your sails app.
Maybe Sails.js lifecycle hooks could help you. We are using them for instance to update statistics, e.g. persisting number of users per type after a user update call.
Also we are using Node Agenda (Sails.js hook) to create jobs to be executed either one time to a defined time in the future or like a cron job. Maybe you will want to collect the invalid/ expired email address verification entries to be purged and delete them in a hourly batch.

How to seed dev database in Sails.js in a reproducible way

I'm looking for a best way to seed my development database in sails js.
In rails I would just use the seeds.rb file but even without that I could use a rake task.
With sails I am unsure of how I could do this outside of manually doing it with sails console.
Please note that solutions which add logic to config/models and the models themselves for production seeding are not what I am looking for. I don't want these records to exist in production.
You can seed your database in the config/bootstrap.js file.
To seed it for a particular environment, what I usually do is:
// config/bootstrap.js
module.exports.bootstrap = function (cb) {
if(process.env.NODE_ENV !== 'development')
return cb();
// Do whatever you want
// And don't forget to...
return cb();
};
And to drop the database each time during the Sails lifting:
// config/env/development.js
module.exports = {
models: {
migrate: 'drop'
}
};
You can use test framework, like Mocha. At your development mode, switch your table name to development table. Here is step by step:
Install mocha with npm install mocha --save-dev
Create test/boostrap.test.js and fill with (configure as your needs), look at my configured connections, it'll override default connections at config.
var Sails = require('sails'),
sails;
before(function (done) {
Sails.lift({
log : {
level: 'error'
},
connections: {
mongodbServer: {
database: 'table_test'
}
},
models : {
migrate: 'drop'
}
}, function (err, server) {
sails = server;
done(err, sails);
});
});
after(function (done) {
// here you can clear fixtures, etc.
sails.lower(done);
});
Create another file for seeding your data, for example create test/inject/seed.js and fill with something like.
describe('data seeding', function(){
it('should seed data', function(done){
sails.models.someModel
.create({
name: 'Some Name'
})
.then(function(result){
done();
})
.catch(done);
});
});
Add this at your package.json under "scripts" key.
"test": "_mocha test/bootstrap.test.js test/inject/**/*.inject.js --no-timeouts"
Run it with npm test to seed your data.
If you need to use it at development mode, when you run sails lift, edit your config/env/development.js and add something like this.
module.exports = {
connections: {
mongodbServer: {
database: 'table_test'
}
}
};
Now your sails lift will use table_test instead of production table, so your production table will be clean.

How to set up unit tests in sailsjs

I cannot run sailsjs unit tests. It seems sails cannot be lifted,
my test (/test/unit/test.js):
var Sails = require('sails');
var app;
before(function() {
console.log('before');
Sails.lift({
log: {
level: 'error'
}
}, function(err, server) {
console.log('lifted');
app = server;
done(err, app);
});
});
// Global after hook
after(function(done) {
app.lower(done);
});
describe('mailer service', function() {
it('should connect to gmail', function() {
console.log(app);
});
});
In my app folder I run: mocha test/unit/test.js
The "app" variable is undefined, console.log('lifted') is not being triggered. What am I doing wrong?
First of all.
You need to call before with a done parameter :
before(function(done){...})
Does your app lift succesfully when you run it with ?
sails lift

Node.js connect-mongo database connection problem

This is a very weird problem with "connect-mongo"
In my server, I have two scripts.
1) create the express server with session with Mongo DataStore: It has no problem for connection or creating the session.
MongoStore = require('connect-mongo'),
app = require('express').createServer(
express.session({ secret: cfg.wiki_session_secret,
store:new MongoStore({
db: 'mydatabase',
host: '10.10.10.10',
port: 27017
})
})
);
2) just create the store without express:
var MongoStore = require('connect-mongo');
var options = {db: 'mydatabase'};
var store = new MongoStore(options, function() {
var db = new mongo.Db(options.db, new mongo.Server('10.10.10.10', 27017, {}));
db.open(function(err) {
db.collection('sessions', function(err, collection) {
callback(store, db, collection);
});
});
});
That will throw the connection problem:
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Error connecting to database
at /home/eauser/node_modules/connect-mongo/lib/connect-mongo.js:106:13
at /home/eauser/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/db.js:79:30
at [object Object].<anonymous> (/home/eauser/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/connections/server.js:113:12)
at [object Object].emit (events.js:64:17)
at Array.<anonymous> (/home/eauser/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/connection.js:166:14)
at EventEmitter._tickCallback (node.js:126:26)
I just don't know why..
connect-mongo is a middleware for the connect framework, which express is based on.
So, you must use the middleware with the express framework or the connect framework, otherwise it won't work. It's not written to be a standalone session library.
You can go for mongoose to connect. Install using npm command
npm install mongoose
Install mongoose globally
npm install -g mongoose
app.js
var mongoose = require("mongoose");
This module has callback in the constructor which is called when the database is connected, and the collection is initialized so it won't work as you expect.
I've the same problem than you and I wanted the same interface that you aim here. So I wrote another module called YAMS - Yet Another Mongo Store. This is an example with YAMS:
var MongoClient = require("mongodb").MongoClient;
var Yams = require('yams');
var store = new Yams(function (done) {
//this will be called once, you must return the collection sessions.
MongoClient.connect('mongo://localhost/myapp', function (err, db) {
if (err) return done(err);
var sessionsCollection = db.collection('sessions')
//use TTL in mongodb, the document will be automatically expired when the session ends.
sessionsCollection.ensureIndex({expires:1}, {expireAfterSeconds: 0}, function(){});
done(null, sessionsCollection);
});
});
app.usage(express.session({
secret: 'black whisky boycott tango 2013',
store: store
}));
This is in my opinion more flexible than the connect-mongo middleware.