/* * Copyright (C) 2014 RetailMeNot, Inc. * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package com.rmn.qa.task; import com.rmn.qa.*; import junit.framework.Assert; import org.junit.After; import org.junit.Test; import org.openqa.grid.common.SeleniumProtocol; import org.openqa.grid.internal.ProxySet; import org.openqa.grid.internal.TestSlot; import org.openqa.selenium.remote.CapabilityType; import java.util.*; public class AutomationNodeCleanupTaskTest { @After public void tearDown() { AutomationContext.refreshContext(); } @Test // Tests that the hard coded name of the task is correct public void testTaskName() { AutomationNodeCleanupTask task = new AutomationNodeCleanupTask(null,null,null); Assert.assertEquals("Name should be the same",AutomationNodeCleanupTask.NAME, task.getDescription() ); } @Test // Tests that the status of a new node does not change after the task runs. This should not happen // until the node has reached the configured age public void testNodeNotOldEnough() { MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),new MockRequestMatcher()); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); AutomationDynamicNode node = new AutomationDynamicNode("testUuid","dummyId",null,null,new Date(),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); task.run(); Assert.assertEquals("Status should not be changed as node was not old enough", AutomationDynamicNode.STATUS.RUNNING,node.getStatus()); } @Test // Tests that the node is set to expired after the configured amount of time public void testNodeSetToExpired() { MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),new MockRequestMatcher()); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); AutomationDynamicNode node = new AutomationDynamicNode("testUuid","dummyId",null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); task.run(); Assert.assertEquals("Node should be expired as the end date was old enough", AutomationDynamicNode.STATUS.EXPIRED,node.getStatus()); } @Test // Tests that the node is not automatically shutdown (terminated) because its currently running tests public void testNodeCantBeShutDown() { MockRequestMatcher matcher = new MockRequestMatcher(); matcher.setThreadsToReturn(4); MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),matcher); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); String nodeId = "dummyId"; AutomationDynamicNode node = new AutomationDynamicNode(nodeId,"dummyId",null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxySet.add(proxy); Map<String,Object> config = new HashMap<String, Object>(); config.put(AutomationConstants.INSTANCE_ID,nodeId); proxy.setConfig(config); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); Map<String,Object> capabilities = new HashMap<String,Object>(); capabilities.put(CapabilityType.BROWSER_NAME,"firefox"); TestSlot testSlot = new TestSlot(proxy, SeleniumProtocol.WebDriver,null,capabilities); // Assign a session to the test slot testSlot.getNewSession(capabilities); proxy.setMultipleTestSlots(testSlot, 5); matcher.setInProgressTests("firefox",5); task.run(); Assert.assertEquals("There should not be sufficient free capacity to cause the node to get shut down", AutomationDynamicNode.STATUS.RUNNING,node.getStatus()); } @Test // Tests that the node cannot be shutdown because a new run has been registered and just not started yet public void testNodeCantBeShutDownDueToNewRun() { MockRequestMatcher matcher = new MockRequestMatcher(); matcher.setThreadsToReturn(4); MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),matcher); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); String nodeId = "dummyId"; AutomationDynamicNode node = new AutomationDynamicNode(nodeId,"dummyId",null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxySet.add(proxy); Map<String,Object> config = new HashMap<String, Object>(); config.put(AutomationConstants.INSTANCE_ID,nodeId); proxy.setConfig(config); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); Map<String,Object> capabilities = new HashMap<String,Object>(); capabilities.put(CapabilityType.BROWSER_NAME,"firefox"); TestSlot testSlot = new TestSlot(proxy, SeleniumProtocol.WebDriver,null,capabilities); // Assign a session to the test slot testSlot.getNewSession(capabilities); proxy.setMultipleTestSlots(testSlot, 5); matcher.setInProgressTests("firefox",5); task.run(); Assert.assertEquals("There should not be sufficient free capacity to cause the node to get shut down", AutomationDynamicNode.STATUS.RUNNING,node.getStatus()); } @Test // Tests that if new registered run does not match the node capabilities, it can be shut down public void testNodeShutDownNoMatchingInProgressTests() { MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),new MockRequestMatcher()); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); AutomationDynamicNode node = new AutomationDynamicNode("testUuid","dummyId",null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); AutomationRunRequest newRequest = new AutomationRunRequest("uuid",10,"firefox"); AutomationContext.getContext().addRun(newRequest); task.run(); Assert.assertEquals("Node should NOT be expired as a new run has started", AutomationDynamicNode.STATUS.RUNNING,node.getStatus()); } @Test // Tests that a node can be terminated if it is empty public void testNodeSetToTerminatedEmpty() { MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),new MockRequestMatcher()); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); AutomationDynamicNode node = new AutomationDynamicNode("testUuid","dummyId",null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); task.run(); Assert.assertEquals("Status should change to expired first", AutomationDynamicNode.STATUS.EXPIRED, node.getStatus()); task.run(); Assert.assertEquals("Node should be terminated as it was empty", AutomationDynamicNode.STATUS.TERMINATED, node.getStatus()); } @Test // Tests that if a node still has tests running against it will only get set to expired and not terminated public void testNodeNotSetToTerminatedNotEmpty() { String nodeId = "nodeId"; MockRequestMatcher matcher = new MockRequestMatcher(); matcher.setThreadsToReturn(10); MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),matcher); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); AutomationDynamicNode node = new AutomationDynamicNode("testUuid",nodeId,null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxySet.add(proxy); Map<String,Object> config = new HashMap<String, Object>(); config.put(AutomationConstants.INSTANCE_ID,nodeId); proxy.setConfig(config); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); Map<String,Object> capabilities = new HashMap<String,Object>(); capabilities.put(CapabilityType.BROWSER_NAME,"firefox"); TestSlot testSlot = new TestSlot(proxy, SeleniumProtocol.WebDriver,null,capabilities); // Assign a session to the test slot testSlot.getNewSession(capabilities); proxy.setMultipleTestSlots(testSlot, 5); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); task.run(); Assert.assertEquals("Status should change to expired first", AutomationDynamicNode.STATUS.EXPIRED,node.getStatus()); task.run(); Assert.assertEquals("Node should be expired as it was not empty", AutomationDynamicNode.STATUS.EXPIRED,node.getStatus()); } @Test // Tests that the node is not terminated if it is in the next billing cycle public void testNodeNotTerminatedNextBillingCycle() { MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),new MockRequestMatcher()); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); Date startDate = new Date(); AutomationDynamicNode node = new AutomationDynamicNode("testUuid","dummyId",null,null,AutomationUtils.modifyDate(startDate,-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); task.run(); Assert.assertEquals("Status should change to expired first", AutomationDynamicNode.STATUS.EXPIRED, node.getStatus()); Date newEndDate = AutomationUtils.modifyDate(new Date(),-61, Calendar.MINUTE); node.setEndDate(newEndDate); task.run(); Assert.assertEquals("Node should be running as its in the next billing cycle", AutomationDynamicNode.STATUS.RUNNING, node.getStatus()); Assert.assertTrue("End date should be increased",node.getEndDate().after(AutomationUtils.modifyDate(newEndDate,54,Calendar.MINUTE))); } @Test // Tests that with an even number of tests (4 tests) among 6 (3 nodes, 2 tests each) capable nodes, that only // 1 node will be terminated public void testMultipleNodesNotSufficientLoad() { AutomationRequestMatcher matcher = new AutomationRequestMatcher(); MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),matcher); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); String nodeId = "dummyId"; String nodeId2 = "dummyId2"; String nodeId3 = "dummyId3"; List<AutomationDynamicNode> nodes = new ArrayList<>(); AutomationDynamicNode node = new AutomationDynamicNode("dummyUuid",nodeId,null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationDynamicNode node2 = new AutomationDynamicNode("dummyUuid2",nodeId2,null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationDynamicNode node3 = new AutomationDynamicNode("dummyUuid3",nodeId3,null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); nodes.add(node); nodes.add(node2); nodes.add(node3); AutomationContext.getContext().addNode(node); AutomationContext.getContext().addNode(node2); AutomationContext.getContext().addNode(node3); MockRemoteProxy proxy = new MockRemoteProxy(); MockRemoteProxy proxy2 = new MockRemoteProxy(); MockRemoteProxy proxy3 = new MockRemoteProxy(); proxySet.add(proxy); proxySet.add(proxy2); proxySet.add(proxy3); Map<String,Object> config = new HashMap<>(); config.put(AutomationConstants.INSTANCE_ID,nodeId); proxy.setConfig(config); proxy.setMaxNumberOfConcurrentTestSessions(4); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); Map<String,Object> config2 = new HashMap<>(); config2.put(AutomationConstants.INSTANCE_ID,nodeId2); proxy2.setMaxNumberOfConcurrentTestSessions(4); proxy2.setConfig(config2); proxy2.setCapabilityMatcher(new AutomationCapabilityMatcher()); Map<String,Object> config3 = new HashMap<>(); config3.put(AutomationConstants.INSTANCE_ID,nodeId3); proxy3.setMaxNumberOfConcurrentTestSessions(4); proxy3.setConfig(config3); proxy3.setCapabilityMatcher(new AutomationCapabilityMatcher()); Map<String,Object> capabilities = new HashMap<>(); capabilities.put(CapabilityType.BROWSER_NAME,"firefox"); TestSlot testSlotUsed = new TestSlot(proxy, SeleniumProtocol.WebDriver,null,capabilities); TestSlot testSlotNotUsed = new TestSlot(proxy, SeleniumProtocol.WebDriver,null,capabilities); // Assign a session to the test slot testSlotUsed.getNewSession(capabilities); proxy.setMultipleTestSlots(testSlotUsed, 2); proxy.setMultipleTestSlots(testSlotNotUsed, 2); TestSlot testSlotUsed2 = new TestSlot(proxy2, SeleniumProtocol.WebDriver,null,capabilities); TestSlot testSlotNotUsed2 = new TestSlot(proxy2, SeleniumProtocol.WebDriver,null,capabilities); // Assign a session to the test slot testSlotUsed2.getNewSession(capabilities); proxy2.setMultipleTestSlots(testSlotUsed2, 2); proxy2.setMultipleTestSlots(testSlotNotUsed2, 2); TestSlot testSlotUsed3 = new TestSlot(proxy3, SeleniumProtocol.WebDriver,null,capabilities); TestSlot testSlotNotUsed3 = new TestSlot(proxy3, SeleniumProtocol.WebDriver,null,capabilities); // Assign a session to the test slot testSlotUsed3.getNewSession(capabilities); proxy3.setMultipleTestSlots(testSlotUsed3, 2); proxy3.setMultipleTestSlots(testSlotNotUsed3, 2); task.run(); int numRunning=0; int numExpired=0; for(int i =0;i<nodes.size();i++) { if(nodes.get(i).getStatus() == AutomationDynamicNode.STATUS.RUNNING) { numRunning++; } else if(nodes.get(i).getStatus() == AutomationDynamicNode.STATUS.EXPIRED) { numExpired++; } } Assert.assertEquals("Number of nodes still running is incorrect", 2,numRunning); Assert.assertEquals("Only one node should have been marked expired", 1,numExpired); } @Test // Tests that a terminated node is removed from tracking after the configured amount of time public void testNodeRemovedAfterTime() { MockAutomationNodeCleanupTask task = new MockAutomationNodeCleanupTask(null,new MockVmManager(),new MockRequestMatcher()); ProxySet proxySet = new ProxySet(false); task.setProxySet(proxySet); AutomationDynamicNode node = new AutomationDynamicNode("testUuid","dummyId",null,null,AutomationUtils.modifyDate(new Date(),-56, Calendar.MINUTE),10); AutomationContext.getContext().addNode(node); MockRemoteProxy proxy = new MockRemoteProxy(); proxy.setCapabilityMatcher(new AutomationCapabilityMatcher()); task.run(); Assert.assertEquals("Status should change to expired first", AutomationDynamicNode.STATUS.EXPIRED, node.getStatus()); task.run(); Assert.assertEquals("Node should be terminated as it was empty", AutomationDynamicNode.STATUS.TERMINATED, node.getStatus()); Assert.assertNotNull("Node should be tracked",AutomationContext.getContext().getNode(node.getInstanceId())); node.setEndDate(AutomationUtils.modifyDate(new Date(), -45, Calendar.MINUTE)); task.run(); Assert.assertNull("Node should not be tracked after its been terminated for 30 minutes", AutomationContext.getContext().getNode(node.getInstanceId())); } }