neumino / rethinkdbdash

An advanced Node.js driver for RethinkDB with a connection pool, support for streams etc.
MIT License
848 stars 108 forks source link

ReqlDriverError: None of the pools have an opened connection and failed to open a new one with automated mocha tests #336

Closed YannisMarios closed 7 years ago

YannisMarios commented 7 years ago

Hello everybody, I have the following issue and I was wondering if anyone can help me:

my package.json scripts section:

"scripts": {
    "prestart": "babel-node src/server/startMessage.js",
    "start": "nodemon --watch src --exec 'npm run -s security-check & babel-node src/server/server.js & npm run -s lint:watch & npm run -s test:watch'",
    "lint": "esw src --color",
    "lint:watch": "npm run lint -- --watch",
    "test": "mocha --opts src/server/test/mocha.opts src/server/test/ --recursive",
    "test:watch": "npm run test -- --watch",
    "security-check": "nsp check",
    "init-users": "babel-node src/server/config/init.users.js"
  }

My database config:

const CONFIG = {
    "PORT": 3000,
    "DATABASE": {
        host: "localhost",
        port: 28015,
        db: "starter",
    },
}

export default CONFIG;

utility to export rethinkdbdash (db.util.server.js)

import rethinkdbdash from 'rethinkdbdash';
import CONFIG from '../config/config.server';

const r = rethinkdbdash(CONFIG.DATABASE);

export default r;

My class is (role.model.server.js)

import Schema from '../../../lib/schemas/users/role.schema.lib';
import r from '../../utils/db.util.server';
import ajv from 'ajv';

/* eslint-disable no-console */

class Role {
    constructor()
    {
        this.table = "Roles";
        this.ajv = new ajv({allErrors: true});
        this.r = r;
    }
    async validate(role) {
        try {
            const validate = await this.ajv.compile(Schema);
            return await validate(role);
        } catch(e) {
            return this.ajv.errors;
        }
    }
    async get(id) {
        try {
            let role = await r.table(this.table).get(id).run();
            console.log(role);
            r.getPool().drain();
            return role;
        } catch(e) {
            throw new Error(e)
            //throw new Error(`Role document with id: '${id}' was not found`)
        }
    }
    async save(role) {
        try {
            let valid = this.validate(role)
            if(!valid)
                throw new Error(this.ajv.errors)
            else {
                let res = await r.table(this.table).insert(role).run();
                r.getPool().drain();
                return res;
            }
        } catch(e) {
            throw new Error(`Could not save document. Error: ${e}`);
        }
    }

}

export default Role;

My test (role.model.server.test.js):

import 'babel-polyfill';
import chai from 'chai';
import Role from '../../../models/users/role.model.server';
import RoleFake from '../../../../lib/fakes/users/role.fake.lib';

/* eslint-disable no-console */
const expect = chai.expect;
const Fake = new RoleFake();
const role = new Role();

// HAPPY PATH
let fake = null;
describe('Test validate', () => {
    it('should validate a new Role against a schema', async () => {
        fake = await Fake.getFake();
        let isValid = await role.validate(fake);
        expect(isValid).to.be.true;
    });
});

describe('Test save', () => {
    it('should save a new Role in the database', async () => {
        let res = await role.save(fake);
        fake.id = res.generated_keys;
        expect(res.inserted).to.equal(1);
    });
});

describe('Test get', () => {
    it('should get a role from the database', async () => {
        let res = await role.get(fake.id);
        console.log(res)
        expect(res.id).to.equal(fake.id);
    });
});

Test save runs ok and saves the doc in the database Test get gives error:

Error: ReqlDriverError: None of the pools have an opened connection and failed to open a new one.
      at Role._callee2$ (src/server/models/users/role.model.server.js:29:10)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:65:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:303:22)
      at Generator.prototype.(anonymous function) [as throw] (node_modules/regenerator-runtime/runtime.js:117:21)
      at step (src/server/models/users/role.model.server.js:23:191)
      at src/server/models/users/role.model.server.js:23:402

as you can see in my class above I am draining the pool after each call to the database...

This is a known problem with this driver and automated tests, has anyone managed to solve this issue?

I know I shouldn't test against a real database but I haven't found a way to mock rethinkdb with sinon or any other tool. Any suggestions on how to mock rethinkdb are welcome.

Thank you

neumino commented 7 years ago

Why are you draining every time? If you don't it should work no?

YannisMarios commented 7 years ago

So when should i drain? I mean ok in these tests I could write a method to drain the pool like this...

after(async () => { role.drainPool(); });

But when this goes in production when should I drain the pool?

Let's say this API class instance makes writes to the database...drains the pool and then immediately after another class instance let's say Group tries to write to the database...

This would give the same error...

It is not clear to me when I should drain the pool

On Thu, Jun 1, 2017, 08:10 Michel notifications@github.com wrote:

Why are you draining every time? If you don't it should work no?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/neumino/rethinkdbdash/issues/336#issuecomment-305390659, or mute the thread https://github.com/notifications/unsubscribe-auth/AKxC0oKwz2SgzdWfvekBeB-APXSQxctYks5r_kfdgaJpZM4NrAt6 .

GeoffreyPlitt commented 7 years ago

+1

neumino commented 7 years ago

You should never drain the pool I think. You want to drain it when you want your program to never run a query again.