audiobookshelf/test/server/migrations/v2.15.2-index-creation.test.js
2026-08-02 18:19:06 -04:00

98 lines
3.7 KiB
JavaScript

const { expect } = require('chai')
const { Sequelize, DataTypes } = require('sequelize')
const sinon = require('sinon')
const Logger = require('../../../server/Logger')
const { up, down } = require('../../../server/migrations/v2.15.2-index-creation')
describe('migration-v2.15.2-index-creation', () => {
let sequelize
let queryInterface
beforeEach(async () => {
sequelize = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
queryInterface = sequelize.getQueryInterface()
await queryInterface.createTable('bookAuthors', {
id: { type: DataTypes.INTEGER, primaryKey: true },
authorId: { type: DataTypes.INTEGER }
})
await queryInterface.createTable('bookSeries', {
id: { type: DataTypes.INTEGER, primaryKey: true },
seriesId: { type: DataTypes.INTEGER }
})
await queryInterface.createTable('podcastEpisodes', {
id: { type: DataTypes.INTEGER, primaryKey: true },
createdAt: { type: DataTypes.DATE },
podcastId: { type: DataTypes.INTEGER }
})
})
afterEach(async () => {
if (sequelize) await sequelize.close()
})
it('up should succeed when legacy podcast index is missing', async () => {
await up({ context: { queryInterface, logger: Logger } })
const indexes = await queryInterface.showIndex('podcastEpisodes')
expect(indexes.some((index) => index.name === 'podcastEpisode_createdAt_podcastId')).to.equal(true)
})
it('down should succeed when new podcast index is missing', async () => {
await down({ context: { queryInterface, logger: Logger } })
const indexes = await queryInterface.showIndex('podcastEpisodes')
expect(indexes.some((index) => index.name === 'podcast_episodes_created_at')).to.equal(true)
})
it('up should treat index names case-insensitively', async () => {
const qi = {
showIndex: sinon.stub(),
addIndex: sinon.stub().resolves(),
removeIndex: sinon.stub().resolves()
}
qi.showIndex.onCall(0).resolves([{ name: 'bookauthor_authorid' }])
qi.showIndex.onCall(1).resolves([{ name: 'bookseries_seriesid' }])
qi.showIndex.onCall(2).resolves([{ name: 'podcast_episodes_created_at' }])
qi.showIndex.onCall(3).resolves([{ name: 'podcastepisode_createdat_podcastid' }])
await up({ context: { queryInterface: qi, logger: Logger } })
expect(qi.addIndex.called).to.equal(false)
expect(qi.removeIndex.calledOnceWithExactly('podcastEpisodes', 'podcast_episodes_created_at')).to.equal(true)
})
it('up should continue when addIndex reports already exists', async () => {
const makePgExistsError = (sql) => {
const err = new Error('relation already exists')
err.name = 'SequelizeDatabaseError'
err.original = { code: '42P07' }
err.sql = sql
return err
}
const qi = {
showIndex: sinon.stub(),
addIndex: sinon.stub(),
removeIndex: sinon.stub().resolves()
}
qi.showIndex.onCall(0).resolves([])
qi.showIndex.onCall(1).resolves([])
qi.showIndex.onCall(2).resolves([{ name: 'podcast_episodes_created_at' }])
qi.showIndex.onCall(3).resolves([])
qi.addIndex.onCall(0).rejects(makePgExistsError('CREATE INDEX bookAuthor_authorId ON bookAuthors (authorId)'))
qi.addIndex.onCall(1).rejects(makePgExistsError('CREATE INDEX bookSeries_seriesId ON bookSeries (seriesId)'))
qi.addIndex.onCall(2).rejects(makePgExistsError('CREATE INDEX podcastEpisode_createdAt_podcastId ON podcastEpisodes (createdAt, podcastId)'))
await up({ context: { queryInterface: qi, logger: Logger } })
expect(qi.addIndex.callCount).to.equal(3)
expect(qi.removeIndex.calledOnceWithExactly('podcastEpisodes', 'podcast_episodes_created_at')).to.equal(true)
})
})