Mocha 使用 Knex 测试 PostgreSQL 时出现 MigrationLocked 错误

Mocha testing PostgreSQL with Knex is giving me a MigrationLocked error

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

这是我的配置:

//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 table。我可以在网上找到的唯一支持是 this 线程,它建议使用 DELETE FROM Migrations_lock where id <> 0; 清除锁 table,但是我的锁 table 只有一个 is_locked 列值为零。

知道发生了什么吗?

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

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

比如我的测试文件:

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);

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

因此,当测试 运行 时,我的应用程序抛出错误,因为它试图写入正在滚动的数据库 back/migrated/seeded 等

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

在你的情况下,我会冒险猜测你何时测试 运行这一行 import app from '../../server'; 您的 app/server 代码正在尝试 运行 对数据库进行一些查询。

对于遇到此问题的任何人,问题实际上来自 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 函数之前导入此文件,导致锁定。我通过在测试时添加一个子句来阻止这个 运行ning 来解决这个问题:

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

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