【问题标题】:Mocha testing PostgreSQL with Knex is giving me a MigrationLocked errorMocha 用 Knex 测试 PostgreSQL 给了我一个 MigrationLocked 错误
【发布时间】:2017-02-23 15:44:40
【问题描述】:

我有一个适用于 Node/PostgreSQL/Knex 的本地开发环境,因为我可以使用 API 发布到我机器上的开发数据库。我现在正在尝试为此功能创建测试,但出现错误。

这是我的配置:

//knexfile.js
module.exports = {
  development: {
    client: 'pg',
    connection: {
        host: '127.0.0.1',
        user: 'dbUser',
        password: 'dbpword',
        port: 5432,
        database: 'example-name'
    },
    migrations: {
      directory: __dirname + '/db/migrations'
    },
    seeds: {
      directory: __dirname + '/db/seeds/development'
    }
  },
}

//db.js
const config = require('../knexfile.js');
const env = process.env.NODE_ENV || 'development';
const knex = require("knex")(config[env]);

module.exports = knex;

knex.migrate.latest([config]);

然后是我的测试:

import chai from 'chai';
import { expect } from 'chai';
import chaiHttp from 'chai-http';
import knex from '../../db/db';
import app from '../../server';

chai.use(chaiHttp);

describe('Tokens API', () => {

  beforeEach((done) => {
   knex.migrate.rollback()
   .then(() => {
     knex.migrate.latest()
     .then(() => {
       return knex.seed.run()
       .then(() => {
        done();
       });
     });
   });
});

afterEach((done) => {
  knex.migrate.rollback()
  .then(() => {
    done();
  });
});

describe('POST /users', () => {
  it('posts a list of users to the database with all mandatory fields', (done) => {
    chai.request(app)
    .post('/users')
    .send({
        "users": [
              "steve",
              "whoever",
              "matt",
              "another"]})
      .end((err, res) => {
        expect(err).to.be.null;
        expect(res).to.have.status(200);
        expect(res).to.be.json;
        done();
      });
    });
  });
});

当我运行它时,我两次收到以下错误 - 我认为是 beforeEach 块中的 knex 调用:

Knex:warning - Can't take lock to run migrations: Migration table is already locked
Knex:warning - If you are sure migrations are not running you can release the lock manually by deleting all the rows from migrations lock table: knex_migrations_lock
Unhandled rejection MigrationLocked: Migration table is already locked

我尝试了很多方法——包括清除 knex_migrations_lock 表。我在网上能找到的唯一支持是this 线程,它建议使用DELETE FROM Migrations_lock where id <> 0; 清除锁表,但是我的锁表只有一个is_locked 列为零值。

知道发生了什么吗?

编辑: 我刚刚意识到,如果你编辑掉所有的 knex 调用,测试实际上就通过了。这可能是因为我有效地调用了 knex 两次——一次来自db.js,一次间接通过server.js?如果是这种情况,我该如何避免这样做 - 因为我肯定需要调用 knex 设置以便 Node 运行它?

【问题讨论】:

    标签: node.js postgresql mocha.js knex.js


    【解决方案1】:

    有完全相同的问题,最终是由于我的 API 在被超测库初始化时调用了数据库。

    比如我的测试文件:

    var db = require('../db');
    var api = require('../api');
    
    var supertest = require('supertest')(api);
    
    describe('Session routes', () => {
      beforeEach((done) => {
        db.migrate.rollback()
          .then(() => {
            db.migrate.latest()
              .then(() => {
                return db.seed.run()
                  .then(() => {
                    done();
                  });
              });
          });
      });
    
      afterEach((done) => {
        db.migrate.rollback()
          .then(() => {
            done();
          });
      });
    
      it('GET /session should error with no token', (done) => {
        supertest
          .get('/session')
          .set('Accept', 'application/json')
          .expect('Content-Type', /json/)
          .expect(401, {
            error: 'Unauthorized'
          }, done);
      });
    });
    

    在第 2 行,它需要我的 api - 当需要我的 api 时,以下代码会立即运行以初始化我的 api 的外部服务 API:

    var db = require('./other-postgres-library');
    var servicesApi = require('./services/api')(db);
    

    这将连接到一堆外部服务并将结果写入数据库。

    所以当测试运行时,我的应用程序抛出错误,因为它试图写入正在回滚/迁移/种子等的数据库。

    我将内部服务 API 更改为延迟初始化,我的所有问题都消失了。

    在您的情况下,我会冒险猜测您的测试何时运行此行 import app from '../../server';您的应用程序/服务器代码正在尝试对数据库运行一些查询。

    【讨论】:

      【解决方案2】:

      对于遇到此问题的任何人来说,问题实际上来自db.js,特别是最后一行:

      const config = require('../knexfile.js');
      const env = process.env.NODE_ENV || 'development';
      const knex = require("knex")(config[env]);
      
      module.exports = knex;
      
      knex.migrate.latest([config]);
      

      当然这是异步的,测试在尝试运行自己的 knex 函数之前导入了这个文件,导致了锁。我通过添加一个子句来阻止这个在测试时运行来解决这个问题:

      if(process.env.NODE_ENV != 'test') {
         knex.migrate.latest([config])
      }
      

      然后,您可以通过将process.env.NODE_ENV='test' 添加到每个规范文件或安装npm env test 模块来创建测试环境。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-25
        • 2016-11-02
        • 1970-01-01
        • 1970-01-01
        • 2022-01-08
        • 2023-03-20
        • 2017-02-13
        • 1970-01-01
        相关资源
        最近更新 更多