package org.openstack.atlas.api.async;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.openstack.atlas.api.async.util.STMTestBase;
import org.openstack.atlas.api.integration.ReverseProxyLoadBalancerStmService;
import org.openstack.atlas.cfg.ConfigurationKey;
import org.openstack.atlas.cfg.RestApiConfiguration;
import org.openstack.atlas.service.domain.entities.*;
import org.openstack.atlas.service.domain.events.UsageEvent;
import org.openstack.atlas.service.domain.events.entities.CategoryType;
import org.openstack.atlas.service.domain.events.entities.EventSeverity;
import org.openstack.atlas.service.domain.events.entities.EventType;
import org.openstack.atlas.service.domain.exceptions.EntityNotFoundException;
import org.openstack.atlas.service.domain.services.LoadBalancerService;
import org.openstack.atlas.service.domain.services.LoadBalancerStatusHistoryService;
import org.openstack.atlas.service.domain.services.NotificationService;
import org.openstack.atlas.service.domain.services.helpers.AlertType;
import org.openstack.atlas.usagerefactor.collection.UsageEventCollection;
import javax.jms.ObjectMessage;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
public class CreateLoadBalancerListenerTest extends STMTestBase {
private Integer LOAD_BALANCER_ID;
private Integer ACCOUNT_ID;
private String USERNAME = "SOME_USERNAME";
private String LOAD_BALANCER_NAME = "SOME NAME";
private Integer HEALTH_MONITOR_ID = 15;
private HealthMonitor healthMonitor;
private Integer ACCESS_LIST_ID = 20;
private AccessList accessList;
private Integer CONNECTION_LIMIT_ID = 25;
private ConnectionLimit connectionLimit;
private Integer VIRTUAL_IP4_ID = 30;
private LoadBalancerJoinVip virtualIp4;
private Integer VIRTUAL_IP6_ID = 35;
private LoadBalancerJoinVip6 virtualIp6;
private Integer NODE_ID = 40;
private Node node;
@Mock
private ObjectMessage objectMessage;
@Mock
private LoadBalancerService loadBalancerService;
@Mock
private NotificationService notificationService;
@Mock
private ReverseProxyLoadBalancerStmService reverseProxyLoadBalancerStmService;
@Mock
private LoadBalancerStatusHistoryService loadBalancerStatusHistoryService;
@Mock
private UsageEventCollection usageEventCollection;
@Mock
private RestApiConfiguration config;
private CreateLoadBalancerListener createLoadBalancerListener;
@Before
public void standUp() {
MockitoAnnotations.initMocks(this);
setupIvars();
LOAD_BALANCER_ID = lb.getId();
ACCOUNT_ID = lb.getAccountId();
lb.setUserName(USERNAME);
lb.setName(LOAD_BALANCER_NAME);
lb.setAlgorithm(LoadBalancerAlgorithm.ROUND_ROBIN);
lb.setPort(80);
lb.setProtocol(LoadBalancerProtocol.HTTP);
lb.setHealthMonitor(setupHealthMonitor());
lb.setAccessLists(setupAccessList());
lb.setNodes(setupNodes());
lb.setSessionPersistence(SessionPersistence.HTTP_COOKIE);
lb.setLoadBalancerJoinVipSet(setupVip4());
lb.setLoadBalancerJoinVip6Set(setupVip6());
lb.setConnectionLimit(setupConnectionLimit());
lb.setConnectionLogging(true);
createLoadBalancerListener = new CreateLoadBalancerListener();
createLoadBalancerListener.setLoadBalancerService(loadBalancerService);
createLoadBalancerListener.setNotificationService(notificationService);
createLoadBalancerListener.setReverseProxyLoadBalancerStmService(reverseProxyLoadBalancerStmService);
createLoadBalancerListener.setLoadBalancerStatusHistoryService(loadBalancerStatusHistoryService);
createLoadBalancerListener.setUsageEventCollection(usageEventCollection);
createLoadBalancerListener.setConfiguration(config);
}
@After
public void tearDown() {
}
// I started doing this with mocks, but it turns out it's easier to just use a real object
private HealthMonitor setupHealthMonitor() {
healthMonitor = mock(HealthMonitor.class);
when(healthMonitor.getId()).thenReturn(HEALTH_MONITOR_ID);
when(healthMonitor.getType()).thenReturn(HealthMonitorType.CONNECT);
when(healthMonitor.getDelay()).thenReturn(10);
when(healthMonitor.getTimeout()).thenReturn(20);
when(healthMonitor.getAttemptsBeforeDeactivation()).thenReturn(25);
when(healthMonitor.getPath()).thenReturn("SOME_PATH");
when(healthMonitor.getStatusRegex()).thenReturn("SOME_STATUS_REGEX");
when(healthMonitor.getBodyRegex()).thenReturn("SOME_BODY_REGEX");
return healthMonitor;
}
private Set<AccessList> setupAccessList() {
Set<AccessList> accessLists = new HashSet<AccessList>();
accessList = mock(AccessList.class);
when(accessList.getId()).thenReturn(ACCESS_LIST_ID);
// Could set up more of this class, but not sure if it matters.
accessLists.add(accessList);
return accessLists;
}
private Set<Node> setupNodes() {
Set<Node> nodes = new HashSet<Node>();
node = new Node();
node.setId(NODE_ID);
nodes.add(node);
return nodes;
}
private Set<LoadBalancerJoinVip> setupVip4() {
Set<LoadBalancerJoinVip> joinVips = new HashSet<LoadBalancerJoinVip>();
VirtualIp virtualIp = new VirtualIp();
virtualIp.setIpVersion(IpVersion.IPV4);
virtualIp.setId(VIRTUAL_IP4_ID);
virtualIp4 = new LoadBalancerJoinVip();
virtualIp4.setId(new LoadBalancerJoinVip.Id(LOAD_BALANCER_ID, VIRTUAL_IP4_ID));
virtualIp4.setLoadBalancer(lb);
virtualIp4.setPort(80);
virtualIp4.setVirtualIp(virtualIp);
joinVips.add(virtualIp4);
return joinVips;
}
private Set<LoadBalancerJoinVip6> setupVip6() {
Set<LoadBalancerJoinVip6> joinVips = new HashSet<LoadBalancerJoinVip6>();
Cluster cluster = new Cluster();
cluster.setClusterIpv6Cidr("0:0:0:0:0:0");
VirtualIpv6 virtualIp = new VirtualIpv6();
virtualIp.setId(VIRTUAL_IP6_ID);
virtualIp.setCluster(cluster);
virtualIp6 = new LoadBalancerJoinVip6();
virtualIp6.setId(new LoadBalancerJoinVip6.Id(LOAD_BALANCER_ID, VIRTUAL_IP6_ID));
virtualIp6.setLoadBalancer(lb);
virtualIp6.setPort(80);
virtualIp6.setVirtualIp(virtualIp);
joinVips.add(virtualIp6);
return joinVips;
}
private ConnectionLimit setupConnectionLimit() {
connectionLimit = new ConnectionLimit();
connectionLimit.setId(CONNECTION_LIMIT_ID);
return connectionLimit;
}
private Boolean checkNodeHelper(Set<Node> nodes, NodeStatus status) {
Boolean good = true;
for (Node node : nodes) {
if (node.getCondition() == NodeCondition.DISABLED || node.getCondition() == NodeCondition.DRAINING) {
if (node.getStatus() != NodeStatus.OFFLINE) good = false;
} else {
if (node.getStatus() != status) good = false;
}
}
return good;
}
@Test
public void testCreateValidLoadBalancer() throws Exception {
when(objectMessage.getObject()).thenReturn(lb);
when(loadBalancerService.get(LOAD_BALANCER_ID, ACCOUNT_ID)).thenReturn(lb);
when(loadBalancerService.update(lb)).thenReturn(lb);
when(config.getString(Matchers.<ConfigurationKey>any())).thenReturn("REST");
createLoadBalancerListener.doOnMessage(objectMessage);
verify(reverseProxyLoadBalancerStmService).createLoadBalancer(lb);
verify(usageEventCollection).processZeroUsageEvent(eq(lb), eq(UsageEvent.CREATE_LOADBALANCER), Matchers.any(Calendar.class));
Assert.assertEquals(lb.getStatus(), LoadBalancerStatus.ACTIVE);
Assert.assertTrue(checkNodeHelper(lb.getNodes(), NodeStatus.ONLINE)); // This is how I decided to test NodesHelper
verify(loadBalancerService).update(lb);
verify(loadBalancerStatusHistoryService).save(ACCOUNT_ID, LOAD_BALANCER_ID, LoadBalancerStatus.ACTIVE);
//Atom Entries
verify(notificationService).saveLoadBalancerEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), anyString(), anyString(), eq(EventType.CREATE_LOADBALANCER), eq(CategoryType.CREATE), eq(EventSeverity.INFO));
verify(notificationService).saveNodeEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(NODE_ID), anyString(), anyString(), eq(EventType.CREATE_NODE), eq(CategoryType.CREATE), eq(EventSeverity.INFO));
verify(notificationService).saveVirtualIpEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(VIRTUAL_IP4_ID), anyString(), anyString(), eq(EventType.CREATE_VIRTUAL_IP), eq(CategoryType.CREATE), eq(EventSeverity.INFO));
verify(notificationService).saveVirtualIpEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(VIRTUAL_IP6_ID), anyString(), anyString(), eq(EventType.CREATE_VIRTUAL_IP), eq(CategoryType.CREATE), eq(EventSeverity.INFO));
verify(notificationService).saveHealthMonitorEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(HEALTH_MONITOR_ID), anyString(), anyString(), eq(EventType.UPDATE_HEALTH_MONITOR), eq(CategoryType.UPDATE), eq(EventSeverity.INFO));
verify(notificationService).saveSessionPersistenceEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), anyString(), anyString(), eq(EventType.UPDATE_SESSION_PERSISTENCE), eq(CategoryType.UPDATE), eq(EventSeverity.INFO));
verify(notificationService).saveLoadBalancerEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), anyString(), anyString(), eq(EventType.UPDATE_CONNECTION_LOGGING), eq(CategoryType.UPDATE), eq(EventSeverity.INFO));
verify(notificationService).saveConnectionLimitEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(CONNECTION_LIMIT_ID), anyString(), anyString(), eq(EventType.UPDATE_CONNECTION_THROTTLE), eq(CategoryType.UPDATE), eq(EventSeverity.INFO));
verify(notificationService).saveAccessListEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(ACCESS_LIST_ID), anyString(), anyString(), eq(EventType.UPDATE_ACCESS_LIST), eq(CategoryType.UPDATE), eq(EventSeverity.INFO));
//TODO: Verify usage now that its been updated...
// verify(usageEventHelper).processUsageEvent(eq(lb), eq(UsageEvent.CREATE_LOADBALANCER), eq(0l), eq(0l), eq(0), eq(0l), eq(0l), eq(0), Matchers.any(Calendar.class));
}
@Test
public void testUpdateInvalidLoadBalancer() throws Exception { //This is named oddly for this specific test, but left it alone for consistency
EntityNotFoundException entityNotFoundException = new EntityNotFoundException();
when(objectMessage.getObject()).thenReturn(lb);
when(loadBalancerService.get(LOAD_BALANCER_ID, ACCOUNT_ID)).thenThrow(entityNotFoundException);
createLoadBalancerListener.doOnMessage(objectMessage);
verify(notificationService).saveAlert(eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(entityNotFoundException), eq(AlertType.DATABASE_FAILURE.name()), anyString());
verify(notificationService).saveLoadBalancerEvent(eq(USERNAME), eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), anyString(), anyString(), eq(EventType.CREATE_LOADBALANCER), eq(CategoryType.CREATE), eq(EventSeverity.CRITICAL));
}
@Test
public void testCreateInvalidLoadBalancer() throws Exception {
Exception exception = new Exception();
when(objectMessage.getObject()).thenReturn(lb);
when(loadBalancerService.get(LOAD_BALANCER_ID, ACCOUNT_ID)).thenReturn(lb);
doThrow(exception).when(reverseProxyLoadBalancerStmService).createLoadBalancer(lb);
when(config.getString(Matchers.<ConfigurationKey>any())).thenReturn("REST");
createLoadBalancerListener.doOnMessage(objectMessage);
verify(reverseProxyLoadBalancerStmService).createLoadBalancer(lb);
Assert.assertEquals(lb.getStatus(), LoadBalancerStatus.ERROR);
Assert.assertTrue(checkNodeHelper(lb.getNodes(), NodeStatus.OFFLINE)); // This is how I decided to test NodesHelper
verify(loadBalancerService).update(lb);
verify(notificationService).saveAlert(eq(ACCOUNT_ID), eq(LOAD_BALANCER_ID), eq(exception), eq(AlertType.ZEUS_FAILURE.name()), anyString());
verify(loadBalancerStatusHistoryService).save(ACCOUNT_ID, LOAD_BALANCER_ID, LoadBalancerStatus.ERROR);
//TODO: Verify usage now that its been updated...
// verify(usageEventHelper).processUsageEvent(eq(lb), eq(UsageEvent.CREATE_LOADBALANCER), eq(0l), eq(0l), eq(0), eq(0l), eq(0l), eq(0), Matchers.any(Calendar.class));
verify(usageEventCollection).processZeroUsageEvent(eq(lb), eq(UsageEvent.CREATE_LOADBALANCER), Matchers.any(Calendar.class));
}
}