-- Gossip protocol implementation tests -- https://github.com/alexandruantochi/ local gossipSubmodules = loadfile('gossip.lua')('test'); local gossip = gossipSubmodules._gossip; local constants = gossipSubmodules._constants; local utils = gossipSubmodules._utils; local network = gossipSubmodules._network; local state = gossipSubmodules._state; -- test constants and mocks local function dummy() return nil; end -- luacheck: push allow defined tmr = {}; tmr.time = function() return 200; end sjson = {}; sjson.decode = function(data) return data; end file = {}; file.exists = dummy file.putcontents = dummy -- luacheck: pop local Ip_1 = '192.168.0.1'; local Ip_2 = '192.168.0.2'; local Ip_own = '192.168.0.3'; -- test runner local Test = {}; local RunTests = function() local failures = {}; print('\nRunning tests...\n'); for testName, test in pairs(Test) do if type(test) == 'function' then local result = testName .. ': '; local passed, res = pcall(test); if passed then result = result .. ' Passed.'; else result = result .. ' Failed ->'; result = '>>>' .. result .. res; table.insert(failures, testName); end print(result); end end if (#failures ~= 0) then print('\n\n'); print('Failed tests (' .. #failures .. '): \n'); for k in pairs(failures) do print(failures[k]); end print('\n'); end end -- utils function Test.utils_contains() local seedList = {}; assert(not utils.contains(seedList, Ip_1)); table.insert(seedList, Ip_1); assert(utils.contains(seedList, Ip_1)); table.insert(seedList, Ip_2); assert(utils.contains(seedList, Ip_1) and utils.contains(seedList, Ip_2)); end function Test.utils_setConfig() local config = { seedList = {Ip_1}, roundInterval = 1500, comPort = 8000, junk = 'junk' }; gossip.config = constants.defaultConfig; utils.setConfig(config); assert(#gossip.config.seedList == 1, 'Config failed when adding seedList'); assert(gossip.config.seedList[1] == Ip_1, 'Config failed to add ip to seedList'); assert(gossip.config.roundInterval == 1500, 'Config failed to add round interval.'); assert(gossip.config.comPort == 8000, 'Config failed to add comPort.'); assert(gossip.config.debug == false, 'Debug should be false.'); assert(gossip.config.junk == nil, 'Junk data inserted in config.'); gossip.config = constants.defaultConfig; end function Test.utils_compare() assert(utils.compare(1, 2) == 1); assert(utils.compare(2, 1) == -1); assert(utils.compare(0, 0) == 0); end function Test.utils_compareNodeData_on_revision() local networkData_1 = { revision = 1, heartbeat = 500, state = constants.nodeState.UP }; local networkData_2 = { revision = 2, heartbeat = 500, state = constants.nodeState.UP }; assert(utils.compareNodeData(networkData_1, networkData_2) == 1); assert(utils.compareNodeData(networkData_2, networkData_1) == -1); networkData_1.revision = networkData_2.revision; assert(utils.compareNodeData(networkData_1, networkData_2) == 0); end function Test.utils_compareNodeData_on_heartbeat() local networkData_1 = { revision = 1, heartbeat = 500, state = constants.nodeState.UP }; local networkData_2 = { revision = 1, heartbeat = 600, state = constants.nodeState.UP }; assert(utils.compareNodeData(networkData_1, networkData_2) == 1); assert(utils.compareNodeData(networkData_2, networkData_1) == -1); networkData_1.heartbeat = networkData_2.heartbeat; assert(utils.compareNodeData(networkData_1, networkData_2) == 0); end function Test.utils_compareNodeData_on_state() local networkData_1 = { revision = 1, heartbeat = 500, state = constants.nodeState.UP }; local networkData_2 = { revision = 1, heartbeat = 500, state = constants.nodeState.SUSPECT }; assert(utils.compareNodeData(networkData_1, networkData_2) == 1); assert(utils.compareNodeData(networkData_2, networkData_1) == -1); networkData_1.state = networkData_2.state; assert(utils.compareNodeData(networkData_1, networkData_2) == 0); end function Test.utils_compareNodeData_on_bad_data() local networkData_1 = { revision = 1, heartbeat = nil, state = constants.nodeState.UP }; local networkData_2 = { revision = 1, heartbeat = 600, state = constants.nodeState.UP }; assert(utils.compareNodeData(networkData_1, networkData_2) == 1); assert(utils.compareNodeData(networkData_2, networkData_1) == -1); networkData_2.state = nil; assert(utils.compareNodeData(networkData_1, networkData_2) == 0); end function Test.utils_getMinus() local data1 = {}; local data2 = {}; data1[Ip_1] = { revision = 1, heartbeat = 500, state = constants.nodeState.UP }; data1[Ip_2] = { revision = 1, heartbeat = 400, state = constants.nodeState.UP }; data2[Ip_1] = { revision = 1, heartbeat = 400, state = constants.nodeState.UP }; data2[Ip_2] = { revision = 1, heartbeat = 400, state = constants.nodeState.SUSPECT; }; local diff1 = utils.getMinus(data1, data2); local diff2 = utils.getMinus(data2, data1); assert(diff1[Ip_1] ~= nil and diff1[Ip_2] == nil); assert(diff2[Ip_1] == nil and diff2[Ip_2] ~= nil); end -- state function Test.state_setRev() gossip.ip = Ip_own; gossip.networkState[Ip_own] = {}; gossip.networkState[Ip_own].revision = -1; assert(state.setRev() == 0, 'Revision not initialized to 0.'); end function Test.state_tickNodeState() local ip_1 = Ip_1; local ip_2 = Ip_2; gossip.networkState[ip_1] = {}; gossip.networkState[ip_2] = {}; gossip.networkState[ip_1].state = constants.nodeState.UP; gossip.networkState[ip_2].state = constants.nodeState.DOWN; state.tickNodeState(ip_1); state.tickNodeState(ip_2); assert(gossip.networkState[ip_1].state == constants.nodeState.UP + constants.nodeState.TICK); assert(gossip.networkState[ip_2].state == constants.nodeState.REMOVE); state.tickNodeState(ip_1); assert(gossip.networkState[ip_1].state == constants.nodeState.SUSPECT); gossip.networkState = {}; end -- network function Test.network_updateNetworkState_no_callback() gossip.ip = Ip_own; local updateData = {} updateData[Ip_1] = { revision = 1, heartbeat = 400, state = constants.nodeState.UP }; updateData[Ip_2] = { revision = 1, heartbeat = 700, state = constants.nodeState.DOWN }; updateData[Ip_own] = { revision = 1, heartbeat = 800, state = constants.nodeState.DOWN }; network.updateNetworkState(updateData); -- send duplicate data network.updateNetworkState(updateData); assert(#gossip.config.seedList == 2); assert(gossip.config.seedList[1] == Ip_1); assert(gossip.config.seedList[2] == Ip_2); assert(gossip.networkState[Ip_1] ~= nil and gossip.networkState[Ip_2] ~= nil); gossip.networkState = {}; gossip.config = constants.defaultConfig; end function Test.network_updateNetworkState_with_callback() local callbackTriggered = false; local function updateCallback() callbackTriggered = true; end gossip.updateCallback = updateCallback; Test.network_updateNetworkState_no_callback(); assert(callbackTriggered); gossip.updateCallback = nil; end function Test.network_receiveData_when_receive_syn() local originalReceiveSyn = network.receiveSyn; local receiveSynCalled = false; network.receiveSyn = function() receiveSynCalled = true; end network.receiveData('socket', {type = constants.updateType.SYN}); network.receiveSyn = originalReceiveSyn; assert(receiveSynCalled); end function Test.network_receiveData_when_receive_ack() local originalReceiveAck = network.receiveAck; local receiveAckCalled = false; network.receiveAck = function() receiveAckCalled = true; end network.receiveData('socket', {type = constants.updateType.ACK}); network.receiveAck = originalReceiveAck; assert(receiveAckCalled); end -- run tests RunTests();