diff --git a/pom.xml b/pom.xml
index 204a4cf2..957bc101 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,7 +87,7 @@
spring-cloud-starter-kubernetes-zipkin
spring-cloud-starter-kubernetes-all
spring-cloud-kubernetes-examples
- spring-cloud-kubernetes-lock
+ spring-cloud-kubernetes-leader
diff --git a/spring-cloud-kubernetes-lock/pom.xml b/spring-cloud-kubernetes-leader/pom.xml
similarity index 95%
rename from spring-cloud-kubernetes-lock/pom.xml
rename to spring-cloud-kubernetes-leader/pom.xml
index a1a9c411..98a05b52 100644
--- a/spring-cloud-kubernetes-lock/pom.xml
+++ b/spring-cloud-kubernetes-leader/pom.xml
@@ -24,8 +24,8 @@
0.3.0.BUILD-SNAPSHOT
- spring-cloud-kubernetes-lock
- Spring Cloud Kubernetes :: Lock
+ spring-cloud-kubernetes-leader
+ Spring Cloud Kubernetes :: Leader
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/leader/Leader.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/Leader.java
similarity index 100%
rename from spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/leader/Leader.java
rename to spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/Leader.java
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java
similarity index 100%
rename from spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java
rename to spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java
similarity index 100%
rename from spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java
rename to spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepository.java b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepository.java
deleted file mode 100644
index 731bda59..00000000
--- a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepository.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2018 to the original 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.cloud.kubernetes.lock;
-
-import java.util.Optional;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.KubernetesClientException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ConfigMapLockRepository {
-
- static final String CONFIG_MAP_PREFIX = "lock";
-
- static final String HOLDER_KEY = "holder";
-
- static final String CREATED_AT_KEY = "created_at";
-
- static final String PROVIDER_LABEL = "provider";
-
- static final String PROVIDER_LABEL_VALUE = "spring-cloud-kubernetes";
-
- static final String KIND_LABEL = "kind";
-
- static final String KIND_LABEL_VALUE = "lock";
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ConfigMapLockRepository.class);
-
- private KubernetesClient kubernetesClient;
-
- private String namespace;
-
- public ConfigMapLockRepository(KubernetesClient kubernetesClient, String namespace) {
- this.kubernetesClient = kubernetesClient;
- this.namespace = namespace;
- }
-
- public Optional get(String name) {
- String configMapName = getConfigMapName(name);
- ConfigMap configMap = kubernetesClient.configMaps()
- .inNamespace(namespace)
- .withName(configMapName)
- .get();
-
- return Optional.ofNullable(configMap);
- }
-
- public boolean create(String name, String holder, long createdAt) {
- String configMapName = getConfigMapName(name);
- String createdAtString = String.valueOf(createdAt);
- ConfigMap configMap = new ConfigMapBuilder().withNewMetadata()
- .withName(configMapName)
- .addToLabels(PROVIDER_LABEL, PROVIDER_LABEL_VALUE)
- .addToLabels(KIND_LABEL, KIND_LABEL_VALUE)
- .endMetadata()
- .addToData(HOLDER_KEY, holder)
- .addToData(CREATED_AT_KEY, createdAtString)
- .build();
-
- try {
- kubernetesClient.configMaps()
- .inNamespace(namespace)
- .create(configMap);
- } catch (KubernetesClientException e) {
- LOGGER.warn("Failed to create ConfigMap for name '{}': ", name, e.getMessage());
- return false;
- }
-
- return true;
- }
-
- public void delete(String name) {
- // TODO make sure that only creator can delete the lock
- kubernetesClient.configMaps()
- .inNamespace(namespace)
- .withName(getConfigMapName(name))
- .delete();
- }
-
- public void deleteIfOlderThan(String name, long age) {
- get(name)
- .filter(m -> this.isOlder(m, age))
- // TODO what if someone else deletes and creates a lock in this gap?
- .ifPresent(c -> delete(name));
- }
-
- private boolean isOlder(ConfigMap configMap, long age) {
- String createdAtString = configMap.getData().get(CREATED_AT_KEY);
- return System.currentTimeMillis() - Long.valueOf(createdAtString) > age;
- }
-
- private String getConfigMapName(String name) {
- return String.format("%s-%s", CONFIG_MAP_PREFIX, name);
- }
-
-}
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java
deleted file mode 100644
index f13386c0..00000000
--- a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2018 to the original 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.cloud.kubernetes.lock;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-
-public class KubernetesLock implements Lock {
-
- static final long DEFAULT_TTL = 10000;
-
- private static final int LOCK_RETRY_INTERVAL = 100;
-
- private final ConfigMapLockRepository repository;
-
- private final String name;
-
- private final String holder;
-
- private final long createdAt;
-
- public KubernetesLock(ConfigMapLockRepository repository, String name, String holder, long createdAt) {
- this.repository = repository;
- this.name = name;
- this.holder = holder;
- this.createdAt = createdAt;
- }
-
- @Override
- public void lock() {
- while (true) {
- try {
- if (tryLock()) {
- return;
- }
- Thread.sleep(LOCK_RETRY_INTERVAL);
- } catch (InterruptedException e) {
- // This method cannot be interrupted
- }
- }
- }
-
- @Override
- public void lockInterruptibly() throws InterruptedException {
- while (true) {
- if (tryLock()) {
- return;
- }
- Thread.sleep(LOCK_RETRY_INTERVAL);
- }
- }
-
- @Override
- public boolean tryLock() {
- repository.deleteIfOlderThan(name, DEFAULT_TTL);
- return repository.create(name, holder, createdAt);
- }
-
- @Override
- public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
- long expiration = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(time, unit);
- while (true) {
- if (System.currentTimeMillis() > expiration) {
- return false;
- } else if (tryLock()) {
- return true;
- }
- Thread.sleep(LOCK_RETRY_INTERVAL);
- }
- }
-
- @Override
- public void unlock() {
- repository.delete(name);
- }
-
- @Override
- public Condition newCondition() {
- throw new UnsupportedOperationException("Condition is not supported");
- }
-
-}
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLockRegistry.java b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLockRegistry.java
deleted file mode 100644
index 01eafa13..00000000
--- a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLockRegistry.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 to the original 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.cloud.kubernetes.lock;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.locks.Lock;
-
-import org.springframework.integration.support.locks.ExpirableLockRegistry;
-import org.springframework.util.Assert;
-
-public class KubernetesLockRegistry implements ExpirableLockRegistry {
-
- private final ConfigMapLockRepository repository;
-
- private final String id;
-
- private final Map locks;
-
- public KubernetesLockRegistry(ConfigMapLockRepository repository, String id) {
- this.repository = repository;
- this.id = id;
- this.locks = new HashMap<>();
- }
-
- @Override
- public Lock obtain(Object key) {
- Assert.isInstanceOf(String.class, key);
- String name = (String) key;
-
- return locks.computeIfAbsent(name, n -> new KubernetesLock(repository, n, id, System.currentTimeMillis()));
- }
-
- @Override
- public void expireUnusedOlderThan(long age) {
- locks.forEach((n, l) -> repository.deleteIfOlderThan(n, age));
- }
-
-}
diff --git a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryIT.java b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryIT.java
deleted file mode 100644
index e973e865..00000000
--- a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryIT.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.springframework.cloud.kubernetes.lock;
-
-import java.util.Map;
-import java.util.Optional;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import org.arquillian.cube.kubernetes.api.Session;
-import org.arquillian.cube.kubernetes.impl.requirement.RequiresKubernetes;
-import org.arquillian.cube.requirement.ArquillianConditionalRunner;
-import org.jboss.arquillian.test.api.ArquillianResource;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.CREATED_AT_KEY;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.HOLDER_KEY;
-import static org.springframework.cloud.kubernetes.lock.KubernetesLock.DEFAULT_TTL;
-
-@RunWith(ArquillianConditionalRunner.class)
-@RequiresKubernetes
-public class ConfigMapLockRepositoryIT {
-
- private static final String NAME = "test-name";
-
- private static final String HOLDER = "test-holder";
-
- @ArquillianResource
- private KubernetesClient kubernetesClient;
-
- @ArquillianResource
- private Session session;
-
- private ConfigMapLockRepository repository;
-
- @Before
- public void before() {
- repository = new ConfigMapLockRepository(kubernetesClient, session.getNamespace());
- }
-
- @After
- public void after() {
- repository.delete(NAME);
- }
-
- @Test
- public void shouldCreate() {
- assertThat(repository.create(NAME, HOLDER, 1000)).isTrue();
-
- Optional optionalConfigMap = repository.get(NAME);
- assertThat(optionalConfigMap.isPresent()).isTrue();
-
- Map data = optionalConfigMap.get().getData();
- assertThat(data).containsEntry(HOLDER_KEY, HOLDER);
- assertThat(data).containsEntry(CREATED_AT_KEY, String.valueOf(1000));
- }
-
- @Test
- public void shouldNotOverwrite() {
- assertThat(repository.create(NAME, HOLDER, 0)).isTrue();
- assertThat(repository.create(NAME, HOLDER, 0)).isFalse();
- }
-
- @Test
- public void shouldDelete() {
- repository.create(NAME, HOLDER, 0);
- repository.delete(NAME);
- assertThat(repository.get(NAME).isPresent()).isFalse();
- }
-
- @Test
- public void shouldDeleteExpired() {
- repository.create(NAME, HOLDER, 0);
- repository.deleteIfOlderThan(NAME, DEFAULT_TTL);
- assertThat(repository.get(NAME).isPresent()).isFalse();
- }
-
- @Test
- public void shouldKeepNotExpired() {
- repository.create(NAME, HOLDER, System.currentTimeMillis());
- repository.deleteIfOlderThan(NAME, DEFAULT_TTL);
- assertThat(repository.get(NAME).isPresent()).isTrue();
- }
-
-}
diff --git a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryTest.java b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryTest.java
deleted file mode 100644
index 39a8e7d8..00000000
--- a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package org.springframework.cloud.kubernetes.lock;
-
-import java.util.Map;
-import java.util.Optional;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
-import io.fabric8.kubernetes.api.model.ConfigMapList;
-import io.fabric8.kubernetes.api.model.DoneableConfigMap;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.KubernetesClientException;
-import io.fabric8.kubernetes.client.dsl.MixedOperation;
-import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
-import io.fabric8.kubernetes.client.dsl.Resource;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.CONFIG_MAP_PREFIX;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.CREATED_AT_KEY;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.HOLDER_KEY;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.KIND_LABEL;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.KIND_LABEL_VALUE;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.PROVIDER_LABEL;
-import static org.springframework.cloud.kubernetes.lock.ConfigMapLockRepository.PROVIDER_LABEL_VALUE;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ConfigMapLockRepositoryTest {
-
- private static final String NAMESPACE = "test-namespace";
-
- private static final String NAME = "test-name";
-
- private static final String CONFIGMAP_NAME = String.format("%s-%s", CONFIG_MAP_PREFIX, NAME);
-
- private static final String HOLDER = "test-holder";
-
- @Mock
- private KubernetesClient mockKubernetesClient;
-
- @Mock
- private MixedOperation>
- mockConfigMapsOperation;
-
- @Mock
- private NonNamespaceOperation>
- mockInNamespaceOperation;
-
- @Mock
- private Resource mockWithNameResource;
-
- @Mock
- private ConfigMap mockConfigMap;
-
- @Mock
- private Map mockData;
-
- private ConfigMapLockRepository repository;
-
- @Before
- public void before() {
- given(mockKubernetesClient.configMaps()).willReturn(mockConfigMapsOperation);
- given(mockConfigMapsOperation.inNamespace(NAMESPACE)).willReturn(mockInNamespaceOperation);
- given(mockInNamespaceOperation.withName(CONFIGMAP_NAME)).willReturn(mockWithNameResource);
- given(mockWithNameResource.get()).willReturn(mockConfigMap);
- given(mockConfigMap.getData()).willReturn(mockData);
-
- repository = new ConfigMapLockRepository(mockKubernetesClient, NAMESPACE);
- }
-
- @Test
- public void shouldGet() {
- Optional optionalConfigMap = repository.get(NAME);
-
- assertThat(optionalConfigMap.isPresent()).isTrue();
- assertThat(optionalConfigMap.get()).isEqualTo(mockConfigMap);
- }
-
- @Test
- public void shouldNotGetNonExistent() {
- given(mockWithNameResource.get()).willReturn(null);
-
- Optional optionalConfigMap = repository.get(NAME);
-
- assertThat(optionalConfigMap.isPresent()).isFalse();
- }
-
- @Test
- public void shouldCreate() {
- boolean result = repository.create(NAME, HOLDER, 1000);
- assertThat(result).isTrue();
-
- verify(mockKubernetesClient).configMaps();
- verify(mockConfigMapsOperation).inNamespace(NAMESPACE);
-
- ConfigMap expectedConfigMap = new ConfigMapBuilder().withNewMetadata()
- .withName(CONFIGMAP_NAME)
- .addToLabels(PROVIDER_LABEL, PROVIDER_LABEL_VALUE)
- .addToLabels(KIND_LABEL, KIND_LABEL_VALUE)
- .endMetadata()
- .addToData(HOLDER_KEY, HOLDER)
- .addToData(CREATED_AT_KEY, "1000")
- .build();
- verify(mockInNamespaceOperation).create(eq(expectedConfigMap));
- }
-
- @Test
- public void shouldHandleCreationFailure() {
- given(mockKubernetesClient.configMaps()).willThrow(new KubernetesClientException("test exception"));
-
- boolean result = repository.create(NAME, HOLDER, 1000);
- assertThat(result).isFalse();
- }
-
- @Test
- public void shouldDelete() {
- repository.delete(NAME);
-
- verify(mockWithNameResource).delete();
- }
-
- @Test
- public void shouldDeleteOld() {
- given(mockData.get(CREATED_AT_KEY)).willReturn(String.valueOf(System.currentTimeMillis() - 1000));
-
- repository.deleteIfOlderThan(NAME, 100);
-
- verify(mockWithNameResource).delete();
- }
-
- @Test
- public void shouldNotDeleteNonExpired() {
- given(mockData.get(CREATED_AT_KEY)).willReturn(String.valueOf(System.currentTimeMillis()) + 1000);
-
- repository.deleteIfOlderThan(NAME, 100);
-
- verify(mockWithNameResource, times(0)).delete();
- }
-
-}
diff --git a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockRegistryTest.java b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockRegistryTest.java
deleted file mode 100644
index 153bbdf0..00000000
--- a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockRegistryTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.springframework.cloud.kubernetes.lock;
-
-import java.util.concurrent.locks.Lock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.verify;
-
-@RunWith(MockitoJUnitRunner.class)
-public class KubernetesLockRegistryTest {
-
- @Mock
- private ConfigMapLockRepository mockRepository;
-
- private KubernetesLockRegistry registry;
-
- @Before
- public void before() {
- registry = new KubernetesLockRegistry(mockRepository, "test-id");
- }
-
- @Test
- public void shouldObtain() {
- Lock actualLock = registry.obtain("test-name");
- KubernetesLock expectedLock = new KubernetesLock(mockRepository, "test-name", "test-id", System.currentTimeMillis());
-
- assertThat(actualLock).isEqualToComparingOnlyGivenFields(expectedLock, "name", "holder");
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void shouldFailToObtainWithNonStringKey() {
- registry.obtain(new Object());
- }
-
- @Test
- public void expireUnusedOlderThanShouldDelegate() {
- registry.obtain("test-name-1");
- registry.obtain("test-name-2");
- registry.expireUnusedOlderThan(100);
-
- verify(mockRepository).deleteIfOlderThan("test-name-1", 100);
- verify(mockRepository).deleteIfOlderThan("test-name-2", 100);
- }
-
-}
diff --git a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java
deleted file mode 100644
index 9f4eedd4..00000000
--- a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.springframework.cloud.kubernetes.lock;
-
-import java.util.concurrent.TimeUnit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.springframework.cloud.kubernetes.lock.KubernetesLock.DEFAULT_TTL;
-
-@RunWith(MockitoJUnitRunner.class)
-public class KubernetesLockTest {
-
- private static final String NAME = "test-name";
-
- private static final String HOLDER = "test-holder";
-
- @Mock
- private ConfigMapLockRepository repository;
-
- private KubernetesLock lock;
-
- @Before
- public void before() {
- lock = new KubernetesLock(repository, NAME, HOLDER, 0);
- }
-
- @Test
- public void shouldLock() {
- given(repository.create(NAME, HOLDER, 0)).willReturn(true);
-
- lock.lock();
-
- verify(repository).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void lockShouldWaitUntilLockCanBeAcquired() {
- given(repository.create(NAME, HOLDER, 0)).will(new LockInSecondCall());
-
- lock.lock();
-
- verify(repository, times(2)).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository, times(2)).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void lockShouldNotBeInterrupted() {
- given(repository.create(NAME, HOLDER, 0)).will(new InterrupFirstCall());
-
- lock.lock();
-
- verify(repository, times(2)).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository, times(2)).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void shouldLockWithLockInterruptibly() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).willReturn(true);
-
- lock.lockInterruptibly();
-
- verify(repository).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void lockInterruptiblyShouldWaitUntilLockCanBeAcquired() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).will(new LockInSecondCall());
-
- lock.lockInterruptibly();
-
- verify(repository, times(2)).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository, times(2)).create(NAME, HOLDER, 0);
- }
-
- @Test(expected = InterruptedException.class)
- public void lockInterruptiblyShouldBeInterrupted() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).will(new InterrupFirstCall());
-
- lock.lockInterruptibly();
- }
-
- @Test
- public void shouldLockWithTryLock() {
- given(repository.create(NAME, HOLDER, 0)).willReturn(true);
-
- assertThat(lock.tryLock()).isTrue();
-
- verify(repository).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void shouldFailToLockWithTryLock() {
- given(repository.create(NAME, HOLDER, 0)).willReturn(false);
-
- assertThat(lock.tryLock()).isFalse();
-
- verify(repository).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void shouldLockWithTryLockTimeout() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).willReturn(true);
-
- assertThat(lock.tryLock(2, TimeUnit.SECONDS)).isTrue();
-
- verify(repository).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void tryLockShouldWaitUntilLockIsAvailable() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).will(new LockInSecondCall());
-
- assertThat(lock.tryLock(2, TimeUnit.SECONDS)).isTrue();
-
- verify(repository, times(2)).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository, times(2)).create(NAME, HOLDER, 0);
- }
-
- @Test
- public void tryLockShouldTimeout() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).will(new LockInSecondCall());
-
- assertThat(lock.tryLock(90, TimeUnit.MILLISECONDS)).isFalse();
-
- verify(repository).deleteIfOlderThan(NAME, DEFAULT_TTL);
- verify(repository).create(NAME, HOLDER, 0);
- }
-
- @Test(expected = InterruptedException.class)
- public void tryLockShouldBeInterrupted() throws InterruptedException {
- given(repository.create(NAME, HOLDER, 0)).will(new InterrupFirstCall());
-
- lock.tryLock(90, TimeUnit.MILLISECONDS);
- }
-
- @Test
- public void shouldUnlock() {
- lock.unlock();
-
- verify(repository).delete(NAME);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void newConditionShouldFail() {
- lock.newCondition();
- }
-
- private static class LockInSecondCall implements Answer {
- private int callsCounter = 0;
-
- @Override
- public Boolean answer(InvocationOnMock invocationOnMock) {
- return callsCounter++ > 0;
- }
- }
-
- private static class InterrupFirstCall implements Answer {
- private int callsCounter = 0;
-
- @Override
- public Boolean answer(InvocationOnMock invocationOnMock) throws InterruptedException {
- if (callsCounter++ > 0) {
- return true;
- }
- throw new InterruptedException("test exception");
- }
- }
-
-}