replication.test.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import type { AbstractDialect, ConnectionOptions, Options } from '@sequelize/core';
  2. import { DataTypes } from '@sequelize/core';
  3. import type { SqliteDialect } from '@sequelize/sqlite3';
  4. import { expect } from 'chai';
  5. import pick from 'lodash/pick';
  6. import sinon from 'sinon';
  7. import { CONFIG } from '../config/config';
  8. import {
  9. sequelize as baseSequelize,
  10. beforeEach2,
  11. createSequelizeInstance,
  12. destroySequelizeAfterTest,
  13. getSqliteDatabasePath,
  14. getTestDialect,
  15. getTestDialectTeaser,
  16. setResetMode,
  17. } from './support';
  18. const dialectName = getTestDialect();
  19. describe(getTestDialectTeaser('Replication'), () => {
  20. if (dialectName === 'ibmi') {
  21. return;
  22. }
  23. setResetMode('none');
  24. describe('connection objects', () => {
  25. const deps = beforeEach2(async () => {
  26. function getConnectionOptions(): ConnectionOptions<AbstractDialect> {
  27. const out = pick(
  28. CONFIG[getTestDialect()],
  29. baseSequelize.dialect.getSupportedConnectionOptions(),
  30. );
  31. if (dialectName === 'sqlite3') {
  32. (out as Options<SqliteDialect>).storage = getSqliteDatabasePath('replication.db');
  33. }
  34. return out;
  35. }
  36. const sandbox = sinon.createSandbox();
  37. const sequelize = createSequelizeInstance({
  38. replication: {
  39. write: getConnectionOptions(),
  40. read: [getConnectionOptions()],
  41. },
  42. });
  43. destroySequelizeAfterTest(sequelize);
  44. expect(sequelize.pool.write).to.be.ok;
  45. expect(sequelize.pool.read).to.be.ok;
  46. const User = sequelize.define('User', {
  47. firstName: {
  48. type: DataTypes.STRING,
  49. columnName: 'first_name',
  50. },
  51. });
  52. await User.sync({ force: true });
  53. const readSpy = sandbox.spy(sequelize.pool.read!, 'acquire');
  54. const writeSpy = sandbox.spy(sequelize.pool.write, 'acquire');
  55. return {
  56. User,
  57. sequelize,
  58. sandbox,
  59. readSpy,
  60. writeSpy,
  61. };
  62. });
  63. afterEach(() => {
  64. deps.sandbox.restore();
  65. });
  66. function expectReadCalls() {
  67. expect(deps.readSpy.callCount).least(1);
  68. expect(deps.writeSpy.notCalled).eql(true);
  69. }
  70. function expectWriteCalls() {
  71. expect(deps.writeSpy.callCount).least(1);
  72. expect(deps.readSpy.notCalled).eql(true);
  73. }
  74. it('should be able to make a write', async () => {
  75. await deps.User.create({
  76. firstName: Math.random().toString(),
  77. });
  78. expectWriteCalls();
  79. });
  80. it('should be able to make a read', async () => {
  81. await deps.User.findAll();
  82. expectReadCalls();
  83. });
  84. it('should run read-only transactions on the replica', async () => {
  85. await deps.sequelize.transaction({ readOnly: true }, async transaction => {
  86. return deps.User.findAll({ transaction });
  87. });
  88. expectReadCalls();
  89. });
  90. it('should run non-read-only transactions on the primary', async () => {
  91. await deps.sequelize.transaction(async transaction => {
  92. return deps.User.findAll({ transaction });
  93. });
  94. expectWriteCalls();
  95. });
  96. });
  97. });