I'm creating a unit test to test Passport, and the first step is to create a user. Creating the user times out and the test is unable to progress.
Test (login.js):
'use strict';
var app = require('../index'),
kraken = require('kraken-js'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
should = require('chai').should(),
Q = require('q'),
agent = require('supertest'),
cookie,
pUser = {
firstName: 'pasport-test',
lastName: 'user',
userName: 'passport-user',
email: 'passport-user#here.com',
password: 'h#rdP#ssw0rd'
}
describe('#create user and log them in with passport', function () {
this.timeout(10000);
var mock;
beforeEach(function (done) {
kraken.create(app).listen(function (err, server) {
mock = server;
done(err);
});
});
afterEach(function (done) {
mock.close(done);
});
describe('#login the user', function () {
it('should create a user', function (done) {
var user = new User({
firstName: pUser.firstName,
lastName: pUser.lastName,
userName: pUser.userName,
email: pUser.email,
password: pUser.password
});
user.save(function(err, data) {
if(err) {
done(err);
} else {
done();
}
});
//it should then login that user with passport
});
});
If I connect o to mongoose directly:
mongoose.connect("mongodb://localhost/testing");
and require User this way:
User = require('../models/user');
It works.
I'd like to use the server and connection that the beforeEach sets up with kraken, so that inserts happen in the configured database...
Question is why does the mongoose insert never come back in the test?
You need to call mongoose.connect in your test code. mongoose queues all pending operations until a first db connection is made, which is why your save callback never gets called.
As noted by #Peter Lyons, I needed to perform the connect to the database.
I wrote a small helper to do this (that I can use across my test files).
db.js:
'use strict';
var nconf = require('nconf'),
mongoose = require('mongoose'),
env = process.env.NODE_ENV || 'testing';
//get the db config stuff for mongoose from the application config file
nconf.use('file', {
file: process.cwd() + '/config/app.json',
format: nconf.formats.json
});
var dbConf = nconf.get('databaseConfig')[env];
var db = function() {
return {
connect: function() {
if(!mongoose.connection.db) {
mongoose.connect("mongodb://" + dbConf.host + '/' + dbConf.database);
}
}
};
};
module.exports = db();
Then in my tests:
var db = require('./db');
db.connect();
And the model classes perform as expected.
Related
I am inserting dummy data into my application's database with a single script. I am new to node.js and suspect I might be blowing stack memory...however:
I am getting a process exit code 3, which according to the documentation:
3 Internal JavaScript Parse Error - The JavaScript source code internal in Node's bootstrapping process caused a parse error. This is extremely rare, and generally can only happen during development of Node itself.
I am using 3 loops, and it's all nested callback code. Since I am new to JavaScript back-end programming, I am not sure if the stack could be the problem, but the exit code doesn't make it sound like it is a stack problem.
Here's the code:
var mongoose = require('mongoose');
var UserModel = require('../models/UserModel');
UserModel.registerSchema(mongoose);
var TeamModel = require('../models/TeamModel');
TeamModel.registerSchema(mongoose);
var PlayerModel = require('../models/PlayerModel');
PlayerModel.registerSchema(mongoose);
var fs = require('fs');
var parsedJSON = JSON.parse(fs.readFileSync('../dummy_data/dummy_player_data', 'utf8'));
var system_db = mongoose.connect('mongodb://localhost:27017/local_dev_db');
var userz = UserModel.getNewUser(system_db).find({}, function (err, users) {
users.forEach(function (user, userIndex) {
var user_id = user._id.toString();
var teamz = TeamModel.getNewTeam(system_db, user_id).find({}, function (err, teams) {
teams.forEach(function (team, teamIndex) {
parsedJSON.forEach(function (player, playerIndex) {
var Player = PlayerModel.getNewPlayer(system_db, user_id);
var newPlayer = new Player({
team_id: team._id,
firstName: player.firstName,
lastName: player.lastName,
hidden: player.hidden,
email: player.email,
phone: player.phone,
gender: player.gender,
age: player.age,
shirtNumber: player.shirtNumber
});
newPlayer.save(function (err, result) {
if (err) {
console.log("error in player save method:", err);
}
if (result) {
//console.log('Added!', result);
}
});
});
});
});
});
});
I am only getting the error code when I am using lots of data, so that's what makes me think it's a stack problem. I am using Mongoose for MongoDB. Any ideas on what could be happening?
inside getNewUser, getNewTeam, getNewPlayer I have:
exports.getNewUser = function (system_db) {
return system_db.model('users', userSchema);;
};
exports.getNewTeam = function (system_db,user_id) {
return system_db.model('teams_'.concat(user_id.toString()), teamSchema);
};
exports.getNewPlayer = function (system_db,user_id) {
return system_db.model('players_'.concat(user_id.toString()), playerSchema);
};
these functions are returning the mongoose model for each of user, team and player.
I want to use mocha to add to my program feature by feature, test by test.
var assert = require('assert');
var mongoskin = require('mongoskin');
describe('basic database tests', function(){
before(function(){
});
it('should have 3 users', function(done){
var db = mongoskin.db('mongodb://localhost:27017/stuffTest', {safe:true});
db.collection('users').find().toArray(function (err,result){
console.log(result.length);
assert.equal(result.length,3);
});
});
});
It doesn't work. I get an error no matter where I put stuff in the test. With this arrangement I get Error: timeout of 2000ms exceeded
This is the code to set up the database. My old way of development was to litter my code with console.logs and such. This code uses console.logs to let me know if the collection is empty and then if so was it filled with 3 records.
var mongoskin = require('mongoskin')
var db = mongoskin.db('mongodb://localhost:27017/stuffTest', {safe:true})
db.collection('users').find().toArray(function (err,result){
console.log(result.length)
})
db.collection('users', {strict:true}, function(err, collection) {
if (err) {
console.log("The 'users' collection doesn't exist. Creating it with sample data...");
populateDB(users);
}
});
var populateDB = function(huh) {
console.log("Populating database...");
var name= huh.name;
var coll= huh.items;
db.collection(name, function(err, collection) {
collection.insert(coll, {safe:true}, function(err, result) {
console.log(result.length);
});
});
};
var users = [];
users.name = 'users';
users.items= [
{name: 'tim', email: 'mckenna.tim#gmail.com', lists:[]},
{name: 'peri', email: 'perimckenna#gmail.com', lists:[]},
{name: 'tim2', email: 'mckt_jp#yahoo.com', lists:[]}
];
How would I write this test? This code plus package.json and dropDb.js is here: https://github.com/mckennatim/tdd
You're not calling done. If you don't call done in an asynchronous test you are guaranteed to get a timeout. Modify the test to call done at the end of your callback. Like this:
it('should have 3 users', function(done){
var db = mongoskin.db('mongodb://localhost:27017/stuffTest', {safe:true});
db.collection('users').find().toArray(function (err,result){
console.log(result.length);
assert.equal(result.length,3);
done();
});
});
When I am trying to run the mocha test i am getting "Cannot determine state of server"
since the mongoose connection is in connecting state.
Please suggest how to handle this scenario.
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
console.log('conn ready: '+mongoose.connection.readyState);
// "conn ready: 2" i.e connecting for test case as well as from user register form
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId,
UserSchema = new Schema({
// schemas
});
UserSchema.statics.newUser = function (uname, email, pass) {
var instance = new User();
instance.uname = uname;
instance.email = email;
instance.pass = pass;
console.log("conn state: "+mongoose.connection.readyState);
// "conn state: 2" i.e connecting for test case. But 1 i.e connected for user register form
instance.save(function (err) {
// Do rest
});
};
var User = mongoose.model('User', UserSchema);
exports.User = User;
DB connections happens asynchronously so when you check up on it straight after calling connect it's likely going to report that it's still connecting. If you want to do something after connection, you need to pass in a callback
mongoose.connect('mongodb://localhost/test', function (error) {
// Do things once connected
});
As for how to handle it in your scenario, my suggestion is to separate connection from your models and connect to MongoDB when required
So if you're testing your user model in mocha, this could be done in the Before hook
var mongoose = require("mongoose");
// Load in your user model wherever that is
var User = require("../models/user");
describe("My user model tests", function () {
// Connect to mongodb here before you start testing
before(function (done) {
mongoose.connect('mongodb://localhost/test', function (error) {
if (error) throw error; // Handle failed connection
console.log('conn ready: '+mongoose.connection.readyState);
done();
});
});
// And include disconnect afterwards
after(function (done) {
mongoose.disconnect(done);
});
// Test your user model down here
it("passes some tests");
});
Depending on how you've structured your app, I'd suggest you move DB connection to a sensible location (e.g. server configuration). When you test your entire app (e.g. integration testing), you would start your server in the Before hook
In addition, if you have your mongoose connection routines in another file (like me), during the asynchronous nature of JS, you should wait a little for the readyState to be 'connected' (1). I solved it in 'before':
var app = require('../server'); //I have mongoose connection in this file
var mongoose = require('mongoose');
var context = describe;
describe('Initial DB routines', function() {
before(function (done) {
mongoose.connection.on('connected', done);
});
it('Should connect to MongoDB', function(done) {
mongoose.connection.readyState === 1 ? done(): done(false);
});
});
I am trying to figure out the best way to pass a mysql connection (using node-mysql) between my routes for express.js. I am dynamically adding each route (using a for each file loop in routes), meaning I can't just pass in the connection to routes that need it. I either need to pass it to every route or none at all. I didn't like the idea of passing it to ones that dont need it so I created a dbConnection.js that the routes can individually import if they need. The problem is that I dont think I am doing it correctly. As of now, my dbConnection.js contains:
var mysql = require('mysql');
var db = null;
module.exports = function () {
if(!db) {
db = mysql.createConnection({
socketPath: '/tmp/mysql.sock',
user: '*********',
password: '*********',
database: '**********'
});
}
return db;
};
And I am importing it into each route using:
var db = require('../dbConnection.js');
var connection = new db();
But I would like to do it like this:
var connection = require('../dbConnection.js');
When I try it like this, however, I get an error saying connection has no method 'query' when I try to make a query.
I find it more reliable to use node-mysql's pool object. Here's how I set mine up. I use environment variable for database information. Keeps it out of the repo.
database.js
var mysql = require('mysql');
var pool = mysql.createPool({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASS,
database: process.env.MYSQL_DB,
connectionLimit: 10,
supportBigNumbers: true
});
// Get records from a city
exports.getRecords = function(city, callback) {
var sql = "SELECT name FROM users WHERE city=?";
// get a connection from the pool
pool.getConnection(function(err, connection) {
if(err) { console.log(err); callback(true); return; }
// make the query
connection.query(sql, [city], function(err, results) {
connection.release();
if(err) { console.log(err); callback(true); return; }
callback(false, results);
});
});
};
Route
var db = require('../database');
exports.GET = function(req, res) {
db.getRecords("San Francisco", function(err, results) {
if(err) { res.send(500,"Server Error"); return;
// Respond with results as JSON
res.send(results);
});
};
your solution will work if use db() instead of new db(), which returns an object and not the db connection
var db = require('../dbConnection.js');
//var connection = new db();
var connection = db();
I am trying to run a simple mongoose/node example which I found here on stackoverflow:
var mongoose = require('mongoose'),
db = mongoose.connect('mongodb://localhost/db'),
Schema = mongoose.Schema;
var sentinel = setTimeout(function(){
throw "failed to connect to MongoDB after one minute!";
}, 60*1000); // 60 seconds
mongoose.model('User', new Schema({
properties: {
name : { type: String, index: true }
}
}));
var User = db.model('User');
var u = new User();
u.name = 'Foo';
u.save();
User.find().all(function(arr) {
clearTimeout(sentinel); // cancel the timeout sentinel
console.log('Users found');
console.log(arr);
console.log('length='+arr.length);
});
process.stdin.resume();
If I get the code right there should be an output in the terminal at the end of the script, where the message "Users found" and all users from the collection should be printed. But I just get the timeout message. Why that?
I am running my server on an Amazon EC2 micro instance. Node, Mongodb and mongoose are installed and a Mongodb server is running (I can interact with it from the terminal via "mongo"). I have also created the directory /data/db.
I don't know about mongoose but u.save() might be asynchronous because it writes to the DB. Try
u.save(function (err){
if(err) console.log(err);
User.find().all(function(arr) {
clearTimeout(sentinel); // cancel the timeout sentinel
console.log('Users found');
console.log(arr);
console.log('length='+arr.length);
});
});
Edit: This works fine
var mongoose = require('mongoose');
var connection = mongoose.connect('mongodb://localhost/my_database');
var Schema = mongoose.Schema
var User = new Schema({
author : String
, type : String
});
var MyUserModel = mongoose.model('User', User); //create and access the model User
var u = new MyUserModel();
u.author = 'authorname';
u.save(function(err){
if (err) console.log(err);
});
MyUserModel.find({}, function (err,docs) {
console.log(docs);
});
I handled this problem by adding one additional step in each router where I use DB.
It's a little bit messy but it works and 100% no leaks.
Something like this:
// file: 'routes/api/v0/users.js'
router
var User = require('../../../models/user').User,
rest = require('../../../controllers/api/v0/rest')(User),
checkDB = require('../../../middleware/checkDB');
module.exports = function (app) {
app.get('/api/v0/users', checkDB, rest.get);
app.get('/api/v0/users/:id', checkDB, rest.getById);
app.post('/api/v0/users', checkDB, rest.post);
app.delete('/api/v0/users', checkDB, rest.deleteById);
app.put('/api/v0/users', checkDB, rest.putById);
};
// file: 'middleware/checkDB.js'
var HttpError = require('../error').HttpError,
mongoose = require('../lib/mongoose');
// method which checks is DB ready for work or not
module.exports = function(req, res, next) {
if (mongoose.connection.readyState !== 1) {
return next(new HttpError(500, "DataBase disconnected"));
}
next();
};
PS If you know solution better, please let me know.