Move Code From Leader Module To spring-cloud-kubernetes-commons (#690)

* Deprecate KubernetesAutoServiceRegistration

* Document service registry in kubernetes.  Fixes #348

* Refactor leader election module to put common code in spring-cloud-kubernetes-commons
This commit is contained in:
Ryan Baxter
2020-12-10 19:22:14 -05:00
committed by GitHub
parent ea1a22f367
commit 6933fca17e
22 changed files with 337 additions and 189 deletions

View File

@@ -30,6 +30,11 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.leader;
package org.springframework.cloud.kubernetes.commons.leader;
import java.util.Objects;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.leader;
package org.springframework.cloud.kubernetes.commons.leader;
import org.springframework.integration.leader.Candidate;
import org.springframework.integration.leader.Context;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.leader;
package org.springframework.cloud.kubernetes.commons.leader;
import java.util.HashMap;
import java.util.Map;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.leader;
package org.springframework.cloud.kubernetes.commons.leader;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.fabric8.leader;
package org.springframework.cloud.kubernetes.commons.leader;
import java.time.Duration;

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2013-2020 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
*
* https://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.commons.leader;
/**
* @author Ryan Baxter
*/
public interface LeaderRecordWatcher {
void start();
void stop();
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright 2013-2020 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
*
* https://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.commons.leader;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.leader.Candidate;
import org.springframework.integration.leader.Context;
import org.springframework.integration.leader.event.LeaderEventPublisher;
/**
* @author Ryan Baxter
*/
public abstract class LeadershipController {
private static final Logger LOGGER = LoggerFactory.getLogger(LeadershipController.class);
protected static final String PROVIDER_KEY = "provider";
protected static final String PROVIDER = "spring-cloud-kubernetes";
protected static final String KIND_KEY = "kind";
protected static final String KIND = "leaders";
protected Candidate candidate;
protected Leader localLeader;
protected LeaderProperties leaderProperties;
protected LeaderEventPublisher leaderEventPublisher;
protected PodReadinessWatcher leaderReadinessWatcher;
public LeadershipController(Candidate candidate, LeaderProperties leaderProperties,
LeaderEventPublisher leaderEventPublisher) {
this.candidate = candidate;
this.leaderProperties = leaderProperties;
this.leaderEventPublisher = leaderEventPublisher;
}
public Optional<Leader> getLocalLeader() {
return Optional.ofNullable(this.localLeader);
}
public abstract void update();
public abstract void revoke();
protected String getLeaderKey() {
return this.leaderProperties.getLeaderIdPrefix() + this.candidate.getRole();
}
protected Map<String, String> getLeaderData(Candidate candidate) {
String leaderKey = getLeaderKey();
return Collections.singletonMap(leaderKey, candidate.getId());
}
protected Leader extractLeader(Map<String, String> data) {
if (data == null) {
return null;
}
String leaderKey = getLeaderKey();
String leaderId = data.get(leaderKey);
if (leaderId == null) {
return null;
}
return new Leader(this.candidate.getRole(), leaderId);
}
protected void handleLeaderChange(Leader newLeader) {
if (Objects.equals(this.localLeader, newLeader)) {
LOGGER.debug("Leader is still '{}'", this.localLeader);
return;
}
Leader oldLeader = this.localLeader;
this.localLeader = newLeader;
if (oldLeader != null && oldLeader.isCandidate(this.candidate)) {
notifyOnRevoked();
}
else if (newLeader != null && newLeader.isCandidate(this.candidate)) {
notifyOnGranted();
}
restartLeaderReadinessWatcher();
LOGGER.debug("New leader is '{}'", this.localLeader);
}
protected void notifyOnGranted() {
LOGGER.debug("Leadership has been granted for '{}'", this.candidate);
Context context = new LeaderContext(this.candidate, this);
this.leaderEventPublisher.publishOnGranted(this, context, this.candidate.getRole());
try {
this.candidate.onGranted(context);
}
catch (InterruptedException e) {
LOGGER.warn(e.getMessage());
Thread.currentThread().interrupt();
}
}
protected void notifyOnRevoked() {
LOGGER.debug("Leadership has been revoked for '{}'", this.candidate);
Context context = new LeaderContext(this.candidate, this);
this.leaderEventPublisher.publishOnRevoked(this, context, this.candidate.getRole());
this.candidate.onRevoked(context);
}
protected void notifyOnFailedToAcquire() {
if (this.leaderProperties.isPublishFailedEvents()) {
Context context = new LeaderContext(this.candidate, this);
this.leaderEventPublisher.publishOnFailedToAcquire(this, context, this.candidate.getRole());
}
}
protected void restartLeaderReadinessWatcher() {
if (this.leaderReadinessWatcher != null) {
this.leaderReadinessWatcher.stop();
this.leaderReadinessWatcher = null;
}
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
this.leaderReadinessWatcher = createPodReadinessWatcher(this.localLeader.getId());
this.leaderReadinessWatcher.start();
}
}
protected abstract PodReadinessWatcher createPodReadinessWatcher(String localLeaderId);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2013-2020 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
*
* https://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.commons.leader;
/**
* @author Ryan Baxter
*/
public interface PodReadinessWatcher {
void start();
void stop();
}

View File

@@ -27,6 +27,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.kubernetes.commons.leader.LeaderInfoContributor;
import org.springframework.cloud.kubernetes.commons.leader.LeaderInitiator;
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -42,7 +45,7 @@ import org.springframework.integration.leader.event.LeaderEventPublisher;
@EnableConfigurationProperties(LeaderProperties.class)
@ConditionalOnBean(KubernetesClient.class)
@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", matchIfMissing = true)
public class LeaderAutoConfiguration {
public class Fabric8LeaderAutoConfiguration {
@Bean
@ConditionalOnMissingBean(LeaderEventPublisher.class)
@@ -59,33 +62,36 @@ public class LeaderAutoConfiguration {
}
@Bean
public LeadershipController leadershipController(Candidate candidate, LeaderProperties leaderProperties,
public Fabric8LeadershipController leadershipController(Candidate candidate, LeaderProperties leaderProperties,
LeaderEventPublisher leaderEventPublisher, KubernetesClient kubernetesClient) {
return new LeadershipController(candidate, leaderProperties, leaderEventPublisher, kubernetesClient);
return new Fabric8LeadershipController(candidate, leaderProperties, leaderEventPublisher, kubernetesClient);
}
@Bean
public LeaderRecordWatcher leaderRecordWatcher(LeaderProperties leaderProperties,
LeadershipController leadershipController, KubernetesClient kubernetesClient) {
return new LeaderRecordWatcher(leaderProperties, leadershipController, kubernetesClient);
public Fabric8LeaderRecordWatcher leaderRecordWatcher(LeaderProperties leaderProperties,
Fabric8LeadershipController fabric8LeadershipController, KubernetesClient kubernetesClient) {
return new Fabric8LeaderRecordWatcher(leaderProperties, fabric8LeadershipController, kubernetesClient);
}
@Bean
public PodReadinessWatcher hostPodWatcher(Candidate candidate, KubernetesClient kubernetesClient,
LeadershipController leadershipController) {
return new PodReadinessWatcher(candidate.getId(), kubernetesClient, leadershipController);
public Fabric8PodReadinessWatcher hostPodWatcher(Candidate candidate, KubernetesClient kubernetesClient,
Fabric8LeadershipController fabric8LeadershipController) {
return new Fabric8PodReadinessWatcher(candidate.getId(), kubernetesClient, fabric8LeadershipController);
}
@Bean(destroyMethod = "stop")
public LeaderInitiator leaderInitiator(LeaderProperties leaderProperties, LeadershipController leadershipController,
LeaderRecordWatcher leaderRecordWatcher, PodReadinessWatcher hostPodWatcher) {
return new LeaderInitiator(leaderProperties, leadershipController, leaderRecordWatcher, hostPodWatcher);
public LeaderInitiator leaderInitiator(LeaderProperties leaderProperties,
Fabric8LeadershipController fabric8LeadershipController,
Fabric8LeaderRecordWatcher fabric8LeaderRecordWatcher, Fabric8PodReadinessWatcher hostPodWatcher) {
return new LeaderInitiator(leaderProperties, fabric8LeadershipController, fabric8LeaderRecordWatcher,
hostPodWatcher);
}
@Bean
@ConditionalOnClass(InfoContributor.class)
public LeaderInfoContributor leaderInfoContributor(LeadershipController leadershipController, Candidate candidate) {
return new LeaderInfoContributor(leadershipController, candidate);
public LeaderInfoContributor leaderInfoContributor(Fabric8LeadershipController fabric8LeadershipController,
Candidate candidate) {
return new LeaderInfoContributor(fabric8LeadershipController, candidate);
}
}

View File

@@ -24,16 +24,19 @@ import io.fabric8.kubernetes.client.Watcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
/**
* @author Gytis Trikleris
*/
public class LeaderRecordWatcher implements Watcher<ConfigMap> {
public class Fabric8LeaderRecordWatcher
implements org.springframework.cloud.kubernetes.commons.leader.LeaderRecordWatcher, Watcher<ConfigMap> {
private static final Logger LOGGER = LoggerFactory.getLogger(LeaderRecordWatcher.class);
private static final Logger LOGGER = LoggerFactory.getLogger(Fabric8LeaderRecordWatcher.class);
private final Object lock = new Object();
private final LeadershipController leadershipController;
private final Fabric8LeadershipController fabric8LeadershipController;
private final LeaderProperties leaderProperties;
@@ -41,9 +44,9 @@ public class LeaderRecordWatcher implements Watcher<ConfigMap> {
private Watch watch;
public LeaderRecordWatcher(LeaderProperties leaderProperties, LeadershipController leadershipController,
KubernetesClient kubernetesClient) {
this.leadershipController = leadershipController;
public Fabric8LeaderRecordWatcher(LeaderProperties leaderProperties,
Fabric8LeadershipController fabric8LeadershipController, KubernetesClient kubernetesClient) {
this.fabric8LeadershipController = fabric8LeadershipController;
this.leaderProperties = leaderProperties;
this.kubernetesClient = kubernetesClient;
}
@@ -78,7 +81,7 @@ public class LeaderRecordWatcher implements Watcher<ConfigMap> {
LOGGER.debug("'{}' event received, triggering leadership update", action);
if (!Action.ERROR.equals(action)) {
this.leadershipController.update();
this.fabric8LeadershipController.update();
}
}

View File

@@ -16,10 +16,7 @@
package org.springframework.cloud.kubernetes.fabric8.leader;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
@@ -28,49 +25,29 @@ import io.fabric8.kubernetes.client.KubernetesClientException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.kubernetes.commons.leader.Leader;
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
import org.springframework.cloud.kubernetes.commons.leader.LeadershipController;
import org.springframework.cloud.kubernetes.commons.leader.PodReadinessWatcher;
import org.springframework.integration.leader.Candidate;
import org.springframework.integration.leader.Context;
import org.springframework.integration.leader.event.LeaderEventPublisher;
/**
* @author Gytis Trikleris
*/
public class LeadershipController {
public class Fabric8LeadershipController extends LeadershipController {
private static final String PROVIDER_KEY = "provider";
private static final String PROVIDER = "spring-cloud-kubernetes";
private static final String KIND_KEY = "kind";
private static final String KIND = "leaders";
private static final Logger LOGGER = LoggerFactory.getLogger(LeadershipController.class);
private final Candidate candidate;
private final LeaderProperties leaderProperties;
private final LeaderEventPublisher leaderEventPublisher;
private static final Logger LOGGER = LoggerFactory.getLogger(Fabric8LeadershipController.class);
private final KubernetesClient kubernetesClient;
private Leader localLeader;
private PodReadinessWatcher leaderReadinessWatcher;
public LeadershipController(Candidate candidate, LeaderProperties leaderProperties,
public Fabric8LeadershipController(Candidate candidate, LeaderProperties leaderProperties,
LeaderEventPublisher leaderEventPublisher, KubernetesClient kubernetesClient) {
this.candidate = candidate;
this.leaderProperties = leaderProperties;
this.leaderEventPublisher = leaderEventPublisher;
super(candidate, leaderProperties, leaderEventPublisher);
this.kubernetesClient = kubernetesClient;
}
public Optional<Leader> getLocalLeader() {
return Optional.ofNullable(this.localLeader);
}
@Override
public synchronized void update() {
LOGGER.debug("Checking leader state");
ConfigMap configMap = getConfigMap();
@@ -137,91 +114,17 @@ public class LeadershipController {
}
}
private void handleLeaderChange(Leader newLeader) {
if (Objects.equals(this.localLeader, newLeader)) {
LOGGER.debug("Leader is still '{}'", this.localLeader);
return;
}
Leader oldLeader = this.localLeader;
this.localLeader = newLeader;
if (oldLeader != null && oldLeader.isCandidate(this.candidate)) {
notifyOnRevoked();
}
else if (newLeader != null && newLeader.isCandidate(this.candidate)) {
notifyOnGranted();
}
restartLeaderReadinessWatcher();
LOGGER.debug("New leader is '{}'", this.localLeader);
}
private void notifyOnGranted() {
LOGGER.debug("Leadership has been granted for '{}'", this.candidate);
Context context = new LeaderContext(this.candidate, this);
this.leaderEventPublisher.publishOnGranted(this, context, this.candidate.getRole());
try {
this.candidate.onGranted(context);
}
catch (InterruptedException e) {
LOGGER.warn(e.getMessage());
Thread.currentThread().interrupt();
}
}
private void notifyOnRevoked() {
LOGGER.debug("Leadership has been revoked for '{}'", this.candidate);
Context context = new LeaderContext(this.candidate, this);
this.leaderEventPublisher.publishOnRevoked(this, context, this.candidate.getRole());
this.candidate.onRevoked(context);
}
private void notifyOnFailedToAcquire() {
if (this.leaderProperties.isPublishFailedEvents()) {
Context context = new LeaderContext(this.candidate, this);
this.leaderEventPublisher.publishOnFailedToAcquire(this, context, this.candidate.getRole());
}
}
private void restartLeaderReadinessWatcher() {
if (this.leaderReadinessWatcher != null) {
this.leaderReadinessWatcher.stop();
this.leaderReadinessWatcher = null;
}
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
this.leaderReadinessWatcher = new PodReadinessWatcher(this.localLeader.getId(), this.kubernetesClient,
this);
this.leaderReadinessWatcher.start();
}
}
private String getLeaderKey() {
return this.leaderProperties.getLeaderIdPrefix() + this.candidate.getRole();
}
private Map<String, String> getLeaderData(Candidate candidate) {
String leaderKey = getLeaderKey();
return Collections.singletonMap(leaderKey, candidate.getId());
@Override
protected PodReadinessWatcher createPodReadinessWatcher(String localLeaderId) {
return new Fabric8PodReadinessWatcher(localLeaderId, this.kubernetesClient, this);
}
private Leader extractLeader(ConfigMap configMap) {
if (configMap == null || configMap.getData() == null) {
if (configMap == null) {
return null;
}
Map<String, String> data = configMap.getData();
String leaderKey = getLeaderKey();
String leaderId = data.get(leaderKey);
if (leaderId == null) {
return null;
}
return new Leader(this.candidate.getRole(), leaderId);
return extractLeader(configMap.getData());
}
private boolean isPodReady(String name) {

View File

@@ -27,12 +27,14 @@ import io.fabric8.kubernetes.client.internal.readiness.Readiness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.kubernetes.commons.leader.PodReadinessWatcher;
/**
* @author Gytis Trikleris
*/
public class PodReadinessWatcher implements Watcher<Pod> {
public class Fabric8PodReadinessWatcher implements PodReadinessWatcher, Watcher<Pod> {
private static final Logger LOGGER = LoggerFactory.getLogger(PodReadinessWatcher.class);
private static final Logger LOGGER = LoggerFactory.getLogger(Fabric8PodReadinessWatcher.class);
private final Object lock = new Object();
@@ -40,19 +42,20 @@ public class PodReadinessWatcher implements Watcher<Pod> {
private final KubernetesClient kubernetesClient;
private final LeadershipController leadershipController;
private final Fabric8LeadershipController fabric8LeadershipController;
private boolean previousState;
private Watch watch;
public PodReadinessWatcher(String podName, KubernetesClient kubernetesClient,
LeadershipController leadershipController) {
public Fabric8PodReadinessWatcher(String podName, KubernetesClient kubernetesClient,
Fabric8LeadershipController fabric8LeadershipController) {
this.podName = podName;
this.kubernetesClient = kubernetesClient;
this.leadershipController = leadershipController;
this.fabric8LeadershipController = fabric8LeadershipController;
}
@Override
public void start() {
if (this.watch == null) {
synchronized (this.lock) {
@@ -66,6 +69,7 @@ public class PodReadinessWatcher implements Watcher<Pod> {
}
}
@Override
public void stop() {
if (this.watch != null) {
synchronized (this.lock) {
@@ -87,7 +91,7 @@ public class PodReadinessWatcher implements Watcher<Pod> {
LOGGER.debug("'{}' readiness status changed to '{}', triggering leadership update", this.podName,
currentState);
this.previousState = currentState;
this.leadershipController.update();
this.fabric8LeadershipController.update();
}
}
}

View File

@@ -1,2 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.kubernetes.fabric8.leader.LeaderAutoConfiguration
org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeaderAutoConfiguration

View File

@@ -34,7 +34,7 @@ import static org.hamcrest.Matchers.containsString;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
// Make sure test passes without Kubernetes cluster
"spring.cloud.kubernetes.leader.autoStartup=false" })
public class LeaderAutoConfigurationTests {
public class Fabric8LeaderAutoConfigurationTests {
@Value("${local.server.port}")
private int port;

View File

@@ -32,6 +32,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -40,13 +42,13 @@ import static org.mockito.Mockito.verify;
* @author Gytis Trikleris
*/
@ExtendWith(MockitoExtension.class)
public class LeaderRecordWatcherTest {
public class Fabric8LeaderRecordWatcherTest {
@Mock
private LeaderProperties mockLeaderProperties;
@Mock
private LeadershipController mockLeadershipController;
private Fabric8LeadershipController mockFabric8LeadershipController;
@Mock
private KubernetesClient mockKubernetesClient;
@@ -69,11 +71,11 @@ public class LeaderRecordWatcherTest {
@Mock
private KubernetesClientException mockKubernetesClientException;
private LeaderRecordWatcher watcher;
private Fabric8LeaderRecordWatcher watcher;
@BeforeEach
public void before() {
this.watcher = new LeaderRecordWatcher(this.mockLeaderProperties, this.mockLeadershipController,
this.watcher = new Fabric8LeaderRecordWatcher(this.mockLeaderProperties, this.mockFabric8LeadershipController,
this.mockKubernetesClient);
}
@@ -102,14 +104,14 @@ public class LeaderRecordWatcherTest {
this.watcher.eventReceived(Watcher.Action.DELETED, this.mockConfigMap);
this.watcher.eventReceived(Watcher.Action.MODIFIED, this.mockConfigMap);
verify(this.mockLeadershipController, times(3)).update();
verify(this.mockFabric8LeadershipController, times(3)).update();
}
@Test
public void shouldIgnoreErrorEvent() {
this.watcher.eventReceived(Watcher.Action.ERROR, this.mockConfigMap);
verify(this.mockLeadershipController, times(0)).update();
verify(this.mockFabric8LeadershipController, times(0)).update();
}
@Test

View File

@@ -23,6 +23,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
import org.springframework.integration.leader.Candidate;
import org.springframework.integration.leader.event.LeaderEventPublisher;
@@ -32,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Gytis Trikleris
*/
@ExtendWith(MockitoExtension.class)
public class LeadershipControllerTest {
public class Fabric8LeadershipControllerTest {
@Mock
private Candidate mockCandidate;
@@ -46,17 +47,17 @@ public class LeadershipControllerTest {
@Mock
private KubernetesClient mockKubernetesClient;
private LeadershipController leadershipController;
private Fabric8LeadershipController fabric8LeadershipController;
@BeforeEach
public void before() {
this.leadershipController = new LeadershipController(this.mockCandidate, this.mockLeaderProperties,
this.mockLeaderEventPublisher, this.mockKubernetesClient);
this.fabric8LeadershipController = new Fabric8LeadershipController(this.mockCandidate,
this.mockLeaderProperties, this.mockLeaderEventPublisher, this.mockKubernetesClient);
}
@Test
public void shouldGetEmptyLocalLeader() {
assertThat(this.leadershipController.getLocalLeader().isPresent()).isFalse();
assertThat(this.fabric8LeadershipController.getLocalLeader().isPresent()).isFalse();
}
}

View File

@@ -40,12 +40,12 @@ import static org.mockito.Mockito.verify;
* @author Gytis Trikleris
*/
@ExtendWith(MockitoExtension.class)
public class PodReadinessWatcherTest {
public class Fabric8PodReadinessWatcherTest {
private static final String POD_NAME = "test-pod";
@Mock
private LeadershipController mockLeadershipController;
private Fabric8LeadershipController mockFabric8LeadershipController;
@Mock
private KubernetesClient mockKubernetesClient;
@@ -68,11 +68,12 @@ public class PodReadinessWatcherTest {
@Mock
private KubernetesClientException mockKubernetesClientException;
private PodReadinessWatcher watcher;
private Fabric8PodReadinessWatcher watcher;
@BeforeEach
public void before() {
this.watcher = new PodReadinessWatcher(POD_NAME, this.mockKubernetesClient, this.mockLeadershipController);
this.watcher = new Fabric8PodReadinessWatcher(POD_NAME, this.mockKubernetesClient,
this.mockFabric8LeadershipController);
}
@Test
@@ -103,7 +104,7 @@ public class PodReadinessWatcherTest {
this.watcher.start();
this.watcher.eventReceived(Watcher.Action.ADDED, this.mockPod);
verify(this.mockLeadershipController).update();
verify(this.mockFabric8LeadershipController).update();
}
@Test
@@ -114,7 +115,7 @@ public class PodReadinessWatcherTest {
this.watcher.start();
this.watcher.eventReceived(Watcher.Action.ADDED, this.mockPod);
verify(this.mockLeadershipController, times(0)).update();
verify(this.mockFabric8LeadershipController, times(0)).update();
}
@Test

View File

@@ -24,6 +24,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.kubernetes.commons.leader.Leader;
import org.springframework.cloud.kubernetes.commons.leader.LeaderContext;
import org.springframework.integration.leader.Candidate;
import static org.assertj.core.api.Assertions.assertThat;
@@ -40,7 +42,7 @@ public class LeaderContextTest {
private Candidate mockCandidate;
@Mock
private LeadershipController mockLeadershipController;
private Fabric8LeadershipController mockFabric8LeadershipController;
@Mock
private Leader mockLeader;
@@ -49,12 +51,12 @@ public class LeaderContextTest {
@BeforeEach
public void before() {
this.leaderContext = new LeaderContext(this.mockCandidate, this.mockLeadershipController);
this.leaderContext = new LeaderContext(this.mockCandidate, this.mockFabric8LeadershipController);
}
@Test
public void testIsLeaderWithoutLeader() {
given(this.mockLeadershipController.getLocalLeader()).willReturn(Optional.empty());
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.empty());
boolean result = this.leaderContext.isLeader();
@@ -63,7 +65,7 @@ public class LeaderContextTest {
@Test
public void testIsLeaderWithAnotherLeader() {
given(this.mockLeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
boolean result = this.leaderContext.isLeader();
@@ -72,7 +74,7 @@ public class LeaderContextTest {
@Test
public void testIsLeaderWhenLeader() {
given(this.mockLeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockLeader.isCandidate(this.mockCandidate)).willReturn(true);
boolean result = this.leaderContext.isLeader();
@@ -84,7 +86,7 @@ public class LeaderContextTest {
public void shouldYieldLeadership() {
this.leaderContext.yield();
verify(this.mockLeadershipController).revoke();
verify(this.mockFabric8LeadershipController).revoke();
}
}

View File

@@ -26,6 +26,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.actuate.info.Info;
import org.springframework.cloud.kubernetes.commons.leader.Leader;
import org.springframework.cloud.kubernetes.commons.leader.LeaderInfoContributor;
import org.springframework.integration.leader.Candidate;
import static org.assertj.core.api.Assertions.assertThat;
@@ -38,7 +40,7 @@ public class LeaderInfoContributorTest {
private Candidate mockCandidate;
@Mock
private LeadershipController mockLeadershipController;
private Fabric8LeadershipController mockFabric8LeadershipController;
@Mock
private Leader mockLeader;
@@ -47,7 +49,8 @@ public class LeaderInfoContributorTest {
@BeforeEach
public void before() {
this.leaderInfoContributor = new LeaderInfoContributor(this.mockLeadershipController, this.mockCandidate);
this.leaderInfoContributor = new LeaderInfoContributor(this.mockFabric8LeadershipController,
this.mockCandidate);
}
@SuppressWarnings("unchecked")
@@ -64,7 +67,7 @@ public class LeaderInfoContributorTest {
@SuppressWarnings("unchecked")
@Test
public void infoWhenLeader() {
given(this.mockLeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockLeader.isCandidate(this.mockCandidate)).willReturn(true);
given(this.mockLeader.getRole()).willReturn("testRole");
given(this.mockLeader.getId()).willReturn("id");
@@ -81,7 +84,7 @@ public class LeaderInfoContributorTest {
@SuppressWarnings("unchecked")
@Test
public void infoWhenAnotherIsLeader() {
given(this.mockLeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
given(this.mockLeader.getRole()).willReturn("testRole");
given(this.mockLeader.getId()).willReturn("id");
Info.Builder builder = new Info.Builder();

View File

@@ -25,6 +25,9 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.kubernetes.commons.leader.LeaderInitiator;
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
@@ -40,13 +43,13 @@ public class LeaderInitiatorTest {
private LeaderProperties mockLeaderProperties;
@Mock
private LeadershipController mockLeadershipController;
private Fabric8LeadershipController mockFabric8LeadershipController;
@Mock
private LeaderRecordWatcher mockLeaderRecordWatcher;
private Fabric8LeaderRecordWatcher mockFabric8LeaderRecordWatcher;
@Mock
private PodReadinessWatcher mockPodReadinessWatcher;
private Fabric8PodReadinessWatcher mockFabric8PodReadinessWatcher;
@Mock
private Runnable mockRunnable;
@@ -55,8 +58,8 @@ public class LeaderInitiatorTest {
@BeforeEach
public void before() {
this.leaderInitiator = new LeaderInitiator(this.mockLeaderProperties, this.mockLeadershipController,
this.mockLeaderRecordWatcher, this.mockPodReadinessWatcher);
this.leaderInitiator = new LeaderInitiator(this.mockLeaderProperties, this.mockFabric8LeadershipController,
this.mockFabric8LeaderRecordWatcher, this.mockFabric8PodReadinessWatcher);
}
@AfterEach
@@ -78,10 +81,10 @@ public class LeaderInitiatorTest {
this.leaderInitiator.start();
assertThat(this.leaderInitiator.isRunning()).isTrue();
verify(this.mockLeaderRecordWatcher).start();
verify(this.mockPodReadinessWatcher).start();
verify(this.mockFabric8LeaderRecordWatcher).start();
verify(this.mockFabric8PodReadinessWatcher).start();
Thread.sleep(10);
verify(this.mockLeadershipController, atLeastOnce()).update();
verify(this.mockFabric8LeadershipController, atLeastOnce()).update();
}
@Test
@@ -91,7 +94,7 @@ public class LeaderInitiatorTest {
this.leaderInitiator.start();
this.leaderInitiator.start();
verify(this.mockLeaderRecordWatcher).start();
verify(this.mockFabric8LeaderRecordWatcher).start();
}
@Test
@@ -102,9 +105,9 @@ public class LeaderInitiatorTest {
this.leaderInitiator.stop();
assertThat(this.leaderInitiator.isRunning()).isFalse();
verify(this.mockLeaderRecordWatcher).stop();
verify(this.mockPodReadinessWatcher).start();
verify(this.mockLeadershipController).revoke();
verify(this.mockFabric8LeaderRecordWatcher).stop();
verify(this.mockFabric8PodReadinessWatcher).start();
verify(this.mockFabric8LeadershipController).revoke();
}
@Test
@@ -115,7 +118,7 @@ public class LeaderInitiatorTest {
this.leaderInitiator.stop();
this.leaderInitiator.stop();
verify(this.mockLeaderRecordWatcher).stop();
verify(this.mockFabric8LeaderRecordWatcher).stop();
}
@Test
@@ -126,9 +129,9 @@ public class LeaderInitiatorTest {
this.leaderInitiator.stop(this.mockRunnable);
assertThat(this.leaderInitiator.isRunning()).isFalse();
verify(this.mockLeaderRecordWatcher).stop();
verify(this.mockPodReadinessWatcher).start();
verify(this.mockLeadershipController).revoke();
verify(this.mockFabric8LeaderRecordWatcher).stop();
verify(this.mockFabric8PodReadinessWatcher).start();
verify(this.mockFabric8LeadershipController).revoke();
verify(this.mockRunnable).run();
}

View File

@@ -22,6 +22,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.kubernetes.commons.leader.Leader;
import org.springframework.integration.leader.Candidate;
import static org.assertj.core.api.Assertions.assertThat;