require('../test_utils.js')() var cluster = require('../lib/cluster.js') var stripAnsi = require('strip-ansi') describe('Cluster Command Internals', function() { it('detect added and removed objects', function() { var a = [ { 'id': 'server1', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3000 } } } ] var b = [ { 'id': 'server1', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3000 } } }, { 'id': 'server2', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3001 } } } ] var c = [ { 'id': 'server1', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3000 } } }, { 'id': 'server3', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3002 } } } ] cluster.getDifference(b, a)[0].id.should.equal('server2') cluster.getDifference(c, a)[0].id.should.equal('server3') cluster.getDifference(a, b).should.be.empty cluster.getDifference(a, c).should.be.empty cluster.getDifference(b, c)[0].id.should.equal('server2') cluster.getDifference(c, b)[0].id.should.equal('server3') cluster.getDifference(a, a).should.be.empty cluster.getDifference(b, b).should.be.empty cluster.getDifference(c, c).should.be.empty }) it('detect changes in objects', function() { var a = [ { 'id': 'server1', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3000 } } } ] var b = [ { 'id': 'server1', 'type': 'servers', 'attributes': { 'parameters': { 'address': '127.0.0.1', 'port': 3001 } } } ] cluster.getDifference(a, b).should.be.empty cluster.getDifference(b, a).should.be.empty cluster.getDifference(a, a).should.be.empty cluster.getDifference(b, b).should.be.empty var obj = cluster.getChangedObjects(a, b)[0] obj.id.should.equal('server1') obj.attributes.parameters.port.should.equal(3000) }) it('detect extra services', function() { var a = { 'services': { data: [ { 'id': 'CLI', 'type': 'services', 'attributes': { 'parameters': {} }, 'relationships': {}, } ] } } var b = { 'services': { data: [ a.services.data[0], { 'id': 'CLI2', 'type': 'services', 'attributes': { 'parameters': { }, }, 'relationships': {}, } ] } } cluster.haveExtraServices(a, b, 'test1', 'test2').should.be.rejected cluster.haveExtraServices(b, a, 'test2', 'test1').should.be.rejected expect(cluster.haveExtraServices(a, a, 'test1', 'test2')).to.equal(undefined) expect(cluster.haveExtraServices(b, b, 'test1', 'test2')).to.equal(undefined) }) }); describe('Cluster Sync', function() { before(startDoubleMaxScale) it('sync after server creation', function() { return doCommand('create server server5 127.0.0.1 3003 --hosts ' + secondary_host) .then(() => verifyCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host, 'servers/server5')) }) it('sync after server alteration', function() { return doCommand('alter server server2 port 3000 --hosts ' + secondary_host) .then(() => verifyCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host, 'servers/server2')) .then(function(res) { res.data.attributes.parameters.port.should.equal(3000) }) }) it('sync after server deletion', function() { return doCommand('destroy server server5 --hosts ' + secondary_host) .then(() => verifyCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host, 'servers/server5')) .should.be.rejected }) it('sync after monitor creation', function() { return doCommand('create monitor my-monitor-2 mysqlmon --hosts ' + secondary_host) .then(() => verifyCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host, 'monitors/my-monitor-2')) }) it('sync after monitor alteration', function() { return doCommand('alter monitor MariaDB-Monitor monitor_interval 12345 --hosts ' + secondary_host) .then(() => verifyCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host, 'monitors/MariaDB-Monitor')) .then(function(res) { res.data.attributes.parameters.monitor_interval.should.equal(12345) }) }) it('sync after monitor deletion', function() { return doCommand('destroy monitor my-monitor-2 --hosts ' + secondary_host) .then(() => doCommand('show monitor my-monitor-2 --hosts ' + primary_host)) .then(() => doCommand('show monitor my-monitor-2 --hosts ' + secondary_host).should.be.rejected) .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) .then(() => doCommand('show monitor my-monitor-2 --hosts ' + primary_host).should.be.rejected) .then(() => doCommand('show monitor my-monitor-2 --hosts ' + secondary_host).should.be.rejected) }) it('sync after service alteration', function() { return doCommand('alter service RW-Split-Router enable_root_user true --hosts ' + secondary_host) .then(() => verifyCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host, 'services/RW-Split-Router')) .then(function(res) { res.data.attributes.parameters.enable_root_user.should.be.true }) }) // As the listeners cannot be truly deleted, since there's no code for actually closing a socket at runtime, // we do the listener tests last it('sync listener creation/deletion', function() { if (primary_host == '127.0.0.1:8989' && secondary_host == '127.0.0.1:8990') { // Test with both MaxScales on the same machine return doCommand('create listener RW-Split-Router my-listener-2 5999 --hosts ' + secondary_host) // As both MaxScales are on the same machine, both can't listen on the same port. The sync should fail due to this .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host).should.be.rejected) // Create the listener on the second MaxScale to avoid it being synced later on .then(() => doCommand('create listener RW-Split-Router my-listener-2 5998 --hosts ' + primary_host)) // Sync after creation should succeed .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) // Destroy the created server, should succeed .then(() => doCommand('destroy listener RW-Split-Router my-listener-2')) .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) } else { // MaxScales are on different machines return doCommand('create listener RW-Split-Router my-listener-2 5999 --hosts ' + secondary_host) // As both MaxScales are on the same machine, both can't listen on the same port. The sync should fail due to this .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) .then(() => doCommand('destroy listener RW-Split-Router my-listener-2')) .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) } }) after(stopDoubleMaxScale) }) function isJSON(line) { return line.match(/['',\[\]{}:]/) } function getOperation(line) { var op = null line = line.trim() if (line.match(/Deleted:/)) { op = 'removed' } else if (line.match(/New:/)){ op = 'added' } else if (line.match(/Changed:/)) { op = 'changed' } return op } // Convert a string format diff into a JSON object function parseDiff(str) { var lines = stripAnsi(str).split(require('os').EOL) var rval = {} while (lines.length > 0) { // Operation is first line, object type second var op = getOperation(lines.shift()) var type = lines.shift() var obj = '' while (lines.length > 0 && isJSON(lines[0]) && getOperation(lines[0]) == null) { obj += lines.shift().trim() } _.set(rval, op + '.' + type, JSON.parse(obj)) } return rval } describe('Cluster Diff', function() { before(startDoubleMaxScale) it('diff after server creation', function() { return doCommand('create server server5 127.0.0.1 3003 --hosts ' + secondary_host) .then(() => doCommand('cluster diff ' + secondary_host + ' --hosts ' + primary_host)) .then(function(res) { var d = parseDiff(res) d.removed.servers.length.should.equal(1) d.removed.servers[0].id.should.equal('server5') }) .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) }) it('diff after server alteration', function() { return doCommand('alter server server2 port 3000 --hosts ' + secondary_host) .then(() => doCommand('cluster diff ' + secondary_host + ' --hosts ' + primary_host)) .then(function(res) { var d = parseDiff(res) d.changed.servers.length.should.equal(1) d.changed.servers[0].id.should.equal('server2') }) .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) }) it('diff after server deletion', function() { return doCommand('destroy server server5 --hosts ' + secondary_host) .then(() => doCommand('cluster diff ' + secondary_host + ' --hosts ' + primary_host)) .then(function(res) { var d = parseDiff(res) d.added.servers.length.should.equal(1) d.added.servers[0].id.should.equal('server5') }) .then(() => doCommand('cluster sync ' + secondary_host + ' --hosts ' + primary_host)) }) after(stopDoubleMaxScale) })