From 5b1251e028a7db4f3226bd00e11b26c670c710f6 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Wed, 7 Oct 2020 18:13:45 +0200 Subject: [PATCH 1/2] MONGOSH-383 - e2e repl tests --- packages/shell-api/src/replica-set.spec.ts | 160 ++++++++++++++++++++- packages/shell-api/src/replica-set.ts | 2 +- 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/packages/shell-api/src/replica-set.spec.ts b/packages/shell-api/src/replica-set.spec.ts index f6b0f88751..e5b99578ba 100644 --- a/packages/shell-api/src/replica-set.spec.ts +++ b/packages/shell-api/src/replica-set.spec.ts @@ -12,6 +12,7 @@ import { ALL_SERVER_VERSIONS, ALL_TOPOLOGIES } from './enums'; +import { CliServiceProvider } from '../../service-provider-server'; describe('ReplicaSet', () => { describe('help', () => { @@ -49,14 +50,14 @@ describe('ReplicaSet', () => { }); }); - describe('commands', () => { + describe('unit', () => { let mongo: Mongo; let serviceProvider: StubbedInstance; let rs: ReplicaSet; let bus: StubbedInstance; let internalState: ShellInternalState; - const findResolvesWith = (expectedResult) => { + const findResolvesWith = (expectedResult): void => { const findCursor = stubInterface(); findCursor.next.resolves(expectedResult); serviceProvider.find.returns(findCursor); @@ -133,7 +134,7 @@ describe('ReplicaSet', () => { expect(serviceProvider.runCommandWithCheck).to.have.been.calledWith( ADMIN_DB, { - replSetReconfig: 1 + replSetGetConfig: 1 } ); }); @@ -585,4 +586,157 @@ describe('ReplicaSet', () => { }); }); }); + + describe.skip('integration', () => { + const port0 = 27017; + const host = '127.0.0.1'; + const replId = 'rs0'; + const connectionString = `mongodb://${host}:${port0}`; // startTestServer(); + const cfg = { + _id: replId, + members: [ + { _id: 0, host: `${host}:${port0}`, priority: 1 }, + { _id: 1, host: `${host}:${port0 + 1}`, priority: 0 }, + { _id: 2, host: `${host}:${port0 + 2}`, priority: 0 } + ] + }; + let serviceProvider: CliServiceProvider; + let internalState; + let mongo; + let rs; + + const ensureMaster = (done, timeout): void => { + if (timeout > 8000) expect.fail(`Waited for ${host}:${port0} to become master, never happened`); + return rs.isMaster().then((res) => { + if (res.ismaster) { + done(); + } else { // try again but wait double + return setTimeout(async() => { + if ((await rs.isMaster()).ismaster) { + expect((await rs.conf()).members.length).to.equal(3); + done(); + } else { + ensureMaster(done, timeout * 2); + } + }, timeout); + } + }); + }; + + before(async() => { + serviceProvider = await CliServiceProvider.connect(connectionString); + internalState = new ShellInternalState(serviceProvider); + mongo = internalState.currentDb.getMongo(); + rs = new ReplicaSet(mongo); + + // check replset uninitialized + try { + await rs.status(); + } catch (error) { + // eslint-disable-next-line no-console + console.log('WARNING: Initializing new replset'); + expect(error.message).to.include('no replset config'); + const result = await rs.initiate(cfg); + expect(result.ok).to.equal(1); + return expect(result.$clusterTime).to.not.be.undefined; + } + // eslint-disable-next-line no-console + console.log('WARNING: Using existing replset'); + }); + + beforeEach((done) => { + ensureMaster(done, 1000); + }); + + after(() => { + return serviceProvider.close(true); + }); + + describe('replica set info', () => { + it('returns the status', async() => { + const result = await rs.status(); + expect(result.set).to.equal(replId); + }); + it('returns the config', async() => { + const result = await rs.conf(); + expect(result._id).to.equal(replId); + }); + it('is connected to master', async() => { + const result = await rs.isMaster(); + expect(result.ismaster).to.be.true; + }); + it('returns StatsResult for print secondary replication info', async() => { + const result = await rs.printSecondaryReplicationInfo(); + expect(result.type).to.equal('StatsResult'); + }); + it('returns StatsResult for print replication info', async() => { + const result = await rs.printSecondaryReplicationInfo(); + expect(result.type).to.equal('StatsResult'); + }); + it('returns data for db.getReplicationInfo', async() => { + const result = await rs._mongo.getDB('any').getReplicationInfo(); + expect(Object.keys(result)).to.include('logSizeMB'); + }); + }); + describe('reconfig', () => { + it('reconfig with one less secondary', async() => { + const newcfg = { + _id: replId, + members: [ cfg.members[0], cfg.members[1] ] + }; + const version = (await rs.conf()).version; + const result = await rs.reconfig(newcfg); + expect(result.ok).to.equal(1); + const status = await rs.conf(); + expect(status.members.length).to.equal(2); + expect(status.version).to.equal(version + 1); + }); + afterEach(async() => { + await rs.reconfig(cfg); + const status = await rs.conf(); + expect(status.members.length).to.equal(3); + }); + }); + + describe('add member', () => { + it('adds a regular member to the config', async() => { + const version = (await rs.conf()).version; + const result = await rs.add(`${host}:${port0 + 3}`); + expect(result.ok).to.equal(1); + const conf = await rs.conf(); + expect(conf.members.length).to.equal(4); + expect(conf.version).to.equal(version + 1); + }); + it('adds a arbiter member to the config', async() => { + const version = (await rs.conf()).version; + const result = await rs.addArb(`${host}:${port0 + 3}`); + expect(result.ok).to.equal(1); + const conf = await rs.conf(); + expect(conf.members.length).to.equal(4); + expect(conf.members[3].arbiterOnly).to.equal(true); + expect(conf.version).to.equal(version + 1); + }); + afterEach(async() => { + await rs.reconfig(cfg); + const status = await rs.conf(); + expect(status.members.length).to.equal(3); + }); + }); + + describe('remove member', () => { + it('removes a member of the config', async() => { + const version = (await rs.conf()).version; + const result = await rs.remove(`${host}:${port0 + 2}`); + expect(result.ok).to.equal(1); + const conf = await rs.conf(); + expect(conf.members.length).to.equal(2); + expect(conf.version).to.equal(version + 1); + }); + afterEach(async() => { + await rs.reconfig(cfg); + const status = await rs.conf(); + expect(status.members.length).to.equal(3); + }); + }); + }); }); diff --git a/packages/shell-api/src/replica-set.ts b/packages/shell-api/src/replica-set.ts index 7829629763..b18530cea2 100644 --- a/packages/shell-api/src/replica-set.ts +++ b/packages/shell-api/src/replica-set.ts @@ -46,7 +46,7 @@ export default class ReplicaSet extends ShellApiClass { try { const result = await this._mongo._serviceProvider.runCommandWithCheck( ADMIN_DB, - { replSetReconfig: 1 } + { replSetGetConfig: 1 } ); if (result.config === undefined) { throw new MongoshInternalError('Documented returned from command replSetReconfig does not contain \'config\''); From 41817e2dfb9af2e2ae25ffe05105cf8c7f4d21f1 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Fri, 9 Oct 2020 16:48:21 +0200 Subject: [PATCH 2/2] use x instead of skip; cr comments --- packages/shell-api/src/replica-set.spec.ts | 31 +++++++++------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/packages/shell-api/src/replica-set.spec.ts b/packages/shell-api/src/replica-set.spec.ts index e5b99578ba..e415918ad2 100644 --- a/packages/shell-api/src/replica-set.spec.ts +++ b/packages/shell-api/src/replica-set.spec.ts @@ -13,6 +13,7 @@ import { ALL_TOPOLOGIES } from './enums'; import { CliServiceProvider } from '../../service-provider-server'; +import util from 'util'; describe('ReplicaSet', () => { describe('help', () => { @@ -587,7 +588,7 @@ describe('ReplicaSet', () => { }); }); - describe.skip('integration', () => { + xdescribe('integration', () => { const port0 = 27017; const host = '127.0.0.1'; const replId = 'rs0'; @@ -605,22 +606,16 @@ describe('ReplicaSet', () => { let mongo; let rs; - const ensureMaster = (done, timeout): void => { - if (timeout > 8000) expect.fail(`Waited for ${host}:${port0} to become master, never happened`); - return rs.isMaster().then((res) => { - if (res.ismaster) { - done(); - } else { // try again but wait double - return setTimeout(async() => { - if ((await rs.isMaster()).ismaster) { - expect((await rs.conf()).members.length).to.equal(3); - done(); - } else { - ensureMaster(done, timeout * 2); - } - }, timeout); + const delay = util.promisify(setTimeout); + const ensureMaster = async(timeout): Promise => { + while (!(await rs.isMaster()).ismaster) { + if (timeout > 8000) { + return expect.fail(`Waited for ${host}:${port0} to become master, never happened`); } - }); + await delay(timeout); + timeout *= 2; // try again but wait double + } + expect((await rs.conf()).members.length).to.equal(3); }; before(async() => { @@ -644,8 +639,8 @@ describe('ReplicaSet', () => { console.log('WARNING: Using existing replset'); }); - beforeEach((done) => { - ensureMaster(done, 1000); + beforeEach(async() => { + await ensureMaster(1000); }); after(() => {