/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.dirt.listener;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Set;
import java.util.UUID;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.KeeperException;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.cluster.Container;
import org.springframework.xd.dirt.cluster.ContainerAttributes;
import org.springframework.xd.dirt.container.store.ContainerRepository;
import org.springframework.xd.dirt.container.store.ZooKeeperContainerRepository;
import org.springframework.xd.dirt.listener.ZooKeeperContainerRepositoryTests.ZooKeeperContainerRepositoryTestsConfig;
import org.springframework.xd.dirt.module.store.ZooKeeperModuleMetadataRepository;
import org.springframework.xd.dirt.stream.zookeeper.ZooKeeperJobRepository;
import org.springframework.xd.dirt.stream.zookeeper.ZooKeeperStreamRepository;
import org.springframework.xd.dirt.zookeeper.EmbeddedZooKeeper;
import org.springframework.xd.dirt.zookeeper.Paths;
import org.springframework.xd.dirt.zookeeper.ZooKeeperAccessException;
import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection;
/**
* Integration test of {@link ZooKeeperContainerRepository}.
*
* @author Jennifer Hickey
* @author Gary Russell
* @author Ilayaperumal Gopinathan
* @author Mark Fisher
*/
@ContextConfiguration(classes = ZooKeeperContainerRepositoryTestsConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ZooKeeperContainerRepositoryTests {
@Autowired
private ContainerRepository containerRepository;
@Autowired
private ZooKeeperConnection zooKeeperConnection;
private final String id = "test" + UUID.randomUUID().toString();
private final String id2 = "test" + UUID.randomUUID().toString();
private final int pid = 123;
private final String host = "test";
private final String ip = "127.0.0.1";
private final Set<String> groups = StringUtils.commaDelimitedListToSet("g1,g2,g3");
@Rule
public ExpectedException exception = ExpectedException.none();
@Before
public void setUp() throws Exception {
try {
zooKeeperConnection.getClient().create().creatingParentsIfNeeded().forPath(Paths.CONTAINERS);
}
catch (KeeperException.NodeExistsException e) {
// ignore
}
ContainerAttributes containerAttributes = new ContainerAttributes(id).setPid(pid).setHost(host).setIp(ip);
containerAttributes.put("groups", "g1,g2,g3");
Container entity = new Container(id, containerAttributes);
Container savedContainer = containerRepository.save(entity);
assertNotNull(savedContainer);
ContainerAttributes savedAttributes = savedContainer.getAttributes();
assertEquals(id, savedAttributes.getId());
assertEquals(pid, savedAttributes.getPid());
assertEquals(host, savedAttributes.getHost());
assertEquals(ip, savedAttributes.getIp());
assertEquals(groups, savedAttributes.getGroups());
containerAttributes = new ContainerAttributes(id2).setPid(pid).setHost(host).setIp(ip);
entity = new Container(id2, containerAttributes);
savedContainer = containerRepository.save(entity);
assertNotNull(savedContainer);
assertSavedContainer(id2, containerAttributes);
}
/**
* Assert if the saved container exists in the {@link ContainerRepository}
*
* @param id the containerId
*/
private void assertSavedContainer(String id, ContainerAttributes containerAttributes) {
long timeout = System.currentTimeMillis() + 15000;
boolean foundContainer = false;
while (!foundContainer && System.currentTimeMillis() < timeout) {
try {
Thread.sleep(200);
Container container = containerRepository.findOne(id);
if (container != null && compareContainerAttributes(container.getAttributes(), containerAttributes)) {
foundContainer = true;
}
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
assertTrue("Container repository is not updated with the test containers", foundContainer);
}
/**
* Check if the container attributes equal.
*
* @param attr1 container attributes
* @param attr2 container attributes
* @return true if the container attributes match
*/
private boolean compareContainerAttributes(ContainerAttributes attr1, ContainerAttributes attr2) {
return (attr1.getId().equals(attr2.getId()) &&
attr1.getHost().equals(attr2.getHost()) &&
attr1.getIp().equals(attr2.getIp()) && (attr1.getPid() == attr2.getPid()));
}
@Test
public void findContainerAttributesById() {
Container foundContainer = containerRepository.findOne(id);
assertNotNull(foundContainer);
ContainerAttributes attributes = foundContainer.getAttributes();
assertNotNull(attributes);
assertEquals(id, attributes.getId());
assertEquals(pid, attributes.getPid());
assertEquals(host, attributes.getHost());
assertEquals(ip, attributes.getIp());
assertEquals(groups, attributes.getGroups());
}
@Test
public void updateContainerAttributes() {
Container foundContainer = containerRepository.findOne(id);
assertNotNull(foundContainer);
ContainerAttributes containerAttributes = new ContainerAttributes(id).setPid(12345).setHost("randomHost").setIp(
"randomIP");
containerAttributes.put("groups", "test1,test2");
Container entity = new Container(id, containerAttributes);
containerRepository.update(entity);
assertSavedContainer(id, containerAttributes);
}
@Test
public void updateNonExistingContainer() {
exception.expect(ZooKeeperAccessException.class);
exception.expectMessage("Could not find container with id " + id + 10);
ContainerAttributes containerAttributes = new ContainerAttributes(id + 10).setPid(12345).setHost("randomHost").setIp(
"randomIP");
containerAttributes.put("groups", "test1,test2");
Container entity = new Container(id + 10, containerAttributes);
containerRepository.update(entity);
}
@Test
public void findContainerNoGroups() {
Container foundContainer = containerRepository.findOne(id2);
assertNotNull(foundContainer);
ContainerAttributes attributes = foundContainer.getAttributes();
assertNotNull(attributes);
assertEquals(id2, attributes.getId());
assertEquals(pid, attributes.getPid());
assertEquals(host, attributes.getHost());
assertEquals(ip, attributes.getIp());
assertEquals(0, attributes.getGroups().size());
}
@Configuration
public static class ZooKeeperContainerRepositoryTestsConfig {
@Bean
public EmbeddedZooKeeper embeddedZooKeeper() {
return new EmbeddedZooKeeper();
}
@Bean
public ZooKeeperConnection zooKeeperConnection() {
return new ZooKeeperConnection("localhost:" + embeddedZooKeeper().getClientPort());
}
@Bean
public ZooKeeperModuleMetadataRepository zooKeeperModuleMetadataRepo() {
return new ZooKeeperModuleMetadataRepository(zooKeeperConnection(), new ZooKeeperStreamRepository(
zooKeeperConnection()), new ZooKeeperJobRepository(zooKeeperConnection()));
}
@Bean
public ContainerRepository containerRepository() {
return new ZooKeeperContainerRepository(zooKeeperConnection(), zooKeeperModuleMetadataRepo());
}
}
@After
public void tearDown() throws Exception {
CuratorFramework client = zooKeeperConnection.getClient();
for (String path : client.getChildren().forPath(Paths.CONTAINERS)) {
client.delete().deletingChildrenIfNeeded().forPath(Paths.build(Paths.CONTAINERS, path));
}
}
}