Fabric leader clean up 6 (#1647)
This commit is contained in:
@@ -21,9 +21,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.core.log.LogAccessor;
|
||||
import org.springframework.integration.leader.Candidate;
|
||||
import org.springframework.integration.leader.Context;
|
||||
import org.springframework.integration.leader.event.LeaderEventPublisher;
|
||||
@@ -34,7 +32,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class LeadershipController {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LeadershipController.class);
|
||||
private static final LogAccessor LOGGER = new LogAccessor(LeadershipController.class);
|
||||
|
||||
protected static final String PROVIDER_KEY = "provider";
|
||||
|
||||
@@ -62,7 +60,7 @@ public abstract class LeadershipController {
|
||||
}
|
||||
|
||||
public Optional<Leader> getLocalLeader() {
|
||||
return Optional.ofNullable(this.localLeader);
|
||||
return Optional.ofNullable(localLeader);
|
||||
}
|
||||
|
||||
public abstract void update();
|
||||
@@ -70,7 +68,7 @@ public abstract class LeadershipController {
|
||||
public abstract void revoke();
|
||||
|
||||
protected String getLeaderKey() {
|
||||
return this.leaderProperties.getLeaderIdPrefix() + this.candidate.getRole();
|
||||
return leaderProperties.getLeaderIdPrefix() + candidate.getRole();
|
||||
}
|
||||
|
||||
protected Map<String, String> getLeaderData(Candidate candidate) {
|
||||
@@ -89,68 +87,68 @@ public abstract class LeadershipController {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Leader(this.candidate.getRole(), leaderId);
|
||||
return new Leader(candidate.getRole(), leaderId);
|
||||
}
|
||||
|
||||
protected void handleLeaderChange(Leader newLeader) {
|
||||
if (Objects.equals(this.localLeader, newLeader)) {
|
||||
LOGGER.debug("Leader is still '{}'", this.localLeader);
|
||||
if (Objects.equals(localLeader, newLeader)) {
|
||||
LOGGER.debug(() -> "Leader is still : " + localLeader);
|
||||
return;
|
||||
}
|
||||
|
||||
Leader oldLeader = this.localLeader;
|
||||
this.localLeader = newLeader;
|
||||
Leader oldLeader = localLeader;
|
||||
localLeader = newLeader;
|
||||
|
||||
if (oldLeader != null && oldLeader.isCandidate(this.candidate)) {
|
||||
if (oldLeader != null && oldLeader.isCandidate(candidate)) {
|
||||
notifyOnRevoked();
|
||||
}
|
||||
else if (newLeader != null && newLeader.isCandidate(this.candidate)) {
|
||||
else if (newLeader != null && newLeader.isCandidate(candidate)) {
|
||||
notifyOnGranted();
|
||||
}
|
||||
|
||||
restartLeaderReadinessWatcher();
|
||||
|
||||
LOGGER.debug("New leader is '{}'", this.localLeader);
|
||||
LOGGER.debug(() -> "New leader is " + localLeader);
|
||||
}
|
||||
|
||||
protected void notifyOnGranted() {
|
||||
LOGGER.debug("Leadership has been granted for '{}'", this.candidate);
|
||||
LOGGER.debug(() -> "Leadership has been granted for :" + candidate);
|
||||
|
||||
Context context = new LeaderContext(this.candidate, this);
|
||||
this.leaderEventPublisher.publishOnGranted(this, context, this.candidate.getRole());
|
||||
Context context = new LeaderContext(candidate, this);
|
||||
leaderEventPublisher.publishOnGranted(this, context, candidate.getRole());
|
||||
try {
|
||||
this.candidate.onGranted(context);
|
||||
candidate.onGranted(context);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
LOGGER.warn(e::getMessage);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyOnRevoked() {
|
||||
LOGGER.debug("Leadership has been revoked for '{}'", this.candidate);
|
||||
LOGGER.debug(() -> "Leadership has been revoked for :" + candidate);
|
||||
|
||||
Context context = new LeaderContext(this.candidate, this);
|
||||
this.leaderEventPublisher.publishOnRevoked(this, context, this.candidate.getRole());
|
||||
this.candidate.onRevoked(context);
|
||||
Context context = new LeaderContext(candidate, this);
|
||||
leaderEventPublisher.publishOnRevoked(this, context, candidate.getRole());
|
||||
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());
|
||||
if (leaderProperties.isPublishFailedEvents()) {
|
||||
Context context = new LeaderContext(candidate, this);
|
||||
leaderEventPublisher.publishOnFailedToAcquire(this, context, candidate.getRole());
|
||||
}
|
||||
}
|
||||
|
||||
protected void restartLeaderReadinessWatcher() {
|
||||
if (this.leaderReadinessWatcher != null) {
|
||||
this.leaderReadinessWatcher.stop();
|
||||
this.leaderReadinessWatcher = null;
|
||||
if (leaderReadinessWatcher != null) {
|
||||
leaderReadinessWatcher.stop();
|
||||
leaderReadinessWatcher = null;
|
||||
}
|
||||
|
||||
if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) {
|
||||
this.leaderReadinessWatcher = createPodReadinessWatcher(this.localLeader.getId());
|
||||
this.leaderReadinessWatcher.start();
|
||||
if (localLeader != null && !localLeader.isCandidate(candidate)) {
|
||||
leaderReadinessWatcher = createPodReadinessWatcher(localLeader.getId());
|
||||
leaderReadinessWatcher.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.leader.LeaderRecordWatcher;
|
||||
|
||||
/**
|
||||
* @author Gytis Trikleris
|
||||
*/
|
||||
public class Fabric8LeaderRecordWatcher
|
||||
implements org.springframework.cloud.kubernetes.commons.leader.LeaderRecordWatcher, Watcher<ConfigMap> {
|
||||
public class Fabric8LeaderRecordWatcher implements LeaderRecordWatcher, Watcher<ConfigMap> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Fabric8LeaderRecordWatcher.class);
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ public class Fabric8PodReadinessWatcher implements PodReadinessWatcher, Watcher<
|
||||
guarded(lock, () -> {
|
||||
if (watch == null) {
|
||||
LOGGER.debug(() -> "Starting pod readiness watcher for :" + podName);
|
||||
PodResource podResource = kubernetesClient.pods().withName(this.podName);
|
||||
PodResource podResource = kubernetesClient.pods().withName(podName);
|
||||
previousState = podResource.isReady();
|
||||
watch = podResource.watch(this);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -17,8 +17,6 @@
|
||||
package org.springframework.cloud.kubernetes.fabric8.leader;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
@@ -30,12 +28,11 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.autoStartup=false",
|
||||
"management.endpoints.web.exposure.include=info", "management.endpoint.info.show-details=always",
|
||||
"management.info.kubernetes.enabled=true" })
|
||||
public class Fabric8LeaderAutoConfigurationTests {
|
||||
class Fabric8LeaderAutoConfigurationTests {
|
||||
|
||||
@LocalManagementPort
|
||||
private int port;
|
||||
@@ -44,13 +41,13 @@ public class Fabric8LeaderAutoConfigurationTests {
|
||||
private WebTestClient webClient;
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void infoEndpointShouldContainLeaderElection() {
|
||||
this.webClient.get().uri("http://localhost:{port}/actuator/info", this.port).accept(MediaType.APPLICATION_JSON)
|
||||
.exchange().expectStatus().isOk().expectBody(String.class).value(containsString("kubernetes"));
|
||||
void infoEndpointShouldContainLeaderElection() {
|
||||
webClient.get().uri("http://localhost:{port}/actuator/info", port).accept(MediaType.APPLICATION_JSON).exchange()
|
||||
.expectStatus().isOk().expectBody(String.class).value(containsString("kubernetes"));
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -27,112 +27,99 @@ import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
|
||||
import io.fabric8.kubernetes.client.dsl.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Gytis Trikleris
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class Fabric8LeaderRecordWatcherTest {
|
||||
class Fabric8LeaderRecordWatcherTest {
|
||||
|
||||
@Mock
|
||||
private LeaderProperties mockLeaderProperties;
|
||||
private final LeaderProperties mockLeaderProperties = Mockito.mock(LeaderProperties.class);
|
||||
|
||||
@Mock
|
||||
private Fabric8LeadershipController mockFabric8LeadershipController;
|
||||
private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
|
||||
.mock(Fabric8LeadershipController.class);
|
||||
|
||||
@Mock
|
||||
private KubernetesClient mockKubernetesClient;
|
||||
private final KubernetesClient mockKubernetesClient = Mockito.mock(KubernetesClient.class);
|
||||
|
||||
@Mock
|
||||
private MixedOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> mockConfigMapsOperation;
|
||||
@SuppressWarnings("unchecked")
|
||||
private final MixedOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> mockConfigMapsOperation = Mockito
|
||||
.mock(MixedOperation.class);
|
||||
|
||||
@Mock
|
||||
private NonNamespaceOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> mockInNamespaceOperation;
|
||||
@SuppressWarnings("unchecked")
|
||||
private final NonNamespaceOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> mockInNamespaceOperation = Mockito
|
||||
.mock(NonNamespaceOperation.class);
|
||||
|
||||
@Mock
|
||||
private Resource<ConfigMap> mockWithNameResource;
|
||||
@SuppressWarnings("unchecked")
|
||||
private final Resource<ConfigMap> mockWithNameResource = Mockito.mock(Resource.class);
|
||||
|
||||
@Mock
|
||||
private Watch mockWatch;
|
||||
private final Watch mockWatch = Mockito.mock(Watch.class);
|
||||
|
||||
@Mock
|
||||
private ConfigMap mockConfigMap;
|
||||
private final ConfigMap mockConfigMap = Mockito.mock(ConfigMap.class);
|
||||
|
||||
@Mock
|
||||
private WatcherException mockKubernetesClientException;
|
||||
private final WatcherException mockKubernetesClientException = Mockito.mock(WatcherException.class);
|
||||
|
||||
private Fabric8LeaderRecordWatcher watcher;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
this.watcher = new Fabric8LeaderRecordWatcher(this.mockLeaderProperties, this.mockFabric8LeadershipController,
|
||||
this.mockKubernetesClient);
|
||||
void beforeEach() {
|
||||
watcher = new Fabric8LeaderRecordWatcher(mockLeaderProperties, mockFabric8LeadershipController,
|
||||
mockKubernetesClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStartOnce() {
|
||||
void shouldStartOnce() {
|
||||
initStubs();
|
||||
this.watcher.start();
|
||||
this.watcher.start();
|
||||
|
||||
verify(this.mockWithNameResource).watch(this.watcher);
|
||||
watcher.start();
|
||||
watcher.start();
|
||||
verify(mockWithNameResource).watch(watcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStopOnce() {
|
||||
void shouldStopOnce() {
|
||||
initStubs();
|
||||
this.watcher.start();
|
||||
this.watcher.stop();
|
||||
this.watcher.stop();
|
||||
|
||||
verify(this.mockWatch).close();
|
||||
watcher.start();
|
||||
watcher.stop();
|
||||
watcher.stop();
|
||||
verify(mockWatch).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleEvent() {
|
||||
this.watcher.eventReceived(Watcher.Action.ADDED, this.mockConfigMap);
|
||||
this.watcher.eventReceived(Watcher.Action.DELETED, this.mockConfigMap);
|
||||
this.watcher.eventReceived(Watcher.Action.MODIFIED, this.mockConfigMap);
|
||||
|
||||
verify(this.mockFabric8LeadershipController, times(3)).update();
|
||||
void shouldHandleEvent() {
|
||||
watcher.eventReceived(Watcher.Action.ADDED, mockConfigMap);
|
||||
watcher.eventReceived(Watcher.Action.DELETED, mockConfigMap);
|
||||
watcher.eventReceived(Watcher.Action.MODIFIED, mockConfigMap);
|
||||
verify(mockFabric8LeadershipController, times(3)).update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreErrorEvent() {
|
||||
this.watcher.eventReceived(Watcher.Action.ERROR, this.mockConfigMap);
|
||||
|
||||
verify(this.mockFabric8LeadershipController, times(0)).update();
|
||||
void shouldIgnoreErrorEvent() {
|
||||
watcher.eventReceived(Watcher.Action.ERROR, mockConfigMap);
|
||||
verify(mockFabric8LeadershipController, times(0)).update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleClose() {
|
||||
void shouldHandleClose() {
|
||||
initStubs();
|
||||
this.watcher.onClose(this.mockKubernetesClientException);
|
||||
|
||||
verify(this.mockWithNameResource).watch(this.watcher);
|
||||
watcher.onClose(mockKubernetesClientException);
|
||||
verify(mockWithNameResource).watch(watcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreCloseWithoutCause() {
|
||||
this.watcher.onClose(null);
|
||||
|
||||
verify(this.mockWithNameResource, times(0)).watch(this.watcher);
|
||||
void shouldIgnoreCloseWithoutCause() {
|
||||
watcher.onClose(null);
|
||||
verify(mockWithNameResource, times(0)).watch(watcher);
|
||||
}
|
||||
|
||||
private void initStubs() {
|
||||
given(this.mockKubernetesClient.configMaps()).willReturn(this.mockConfigMapsOperation);
|
||||
given(this.mockConfigMapsOperation.inNamespace(null)).willReturn(this.mockInNamespaceOperation);
|
||||
given(this.mockInNamespaceOperation.withName(null)).willReturn(this.mockWithNameResource);
|
||||
given(this.mockWithNameResource.watch(this.watcher)).willReturn(this.mockWatch);
|
||||
Mockito.when(mockKubernetesClient.configMaps()).thenReturn(mockConfigMapsOperation);
|
||||
Mockito.when(mockConfigMapsOperation.inNamespace(null)).thenReturn(mockInNamespaceOperation);
|
||||
Mockito.when(mockInNamespaceOperation.withName(null)).thenReturn(mockWithNameResource);
|
||||
Mockito.when(mockWithNameResource.watch(watcher)).thenReturn(mockWatch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -16,16 +16,15 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.fabric8.leader;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.ConfigMapList;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
|
||||
import io.fabric8.kubernetes.client.dsl.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
@@ -43,42 +42,41 @@ import static org.mockito.Mockito.when;
|
||||
/**
|
||||
* @author Gytis Trikleris
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class Fabric8LeadershipControllerTest {
|
||||
|
||||
@Mock
|
||||
private Candidate mockCandidate;
|
||||
private final Candidate mockCandidate = Mockito.mock(Candidate.class);
|
||||
|
||||
@Mock
|
||||
private LeaderProperties mockLeaderProperties;
|
||||
private final LeaderProperties mockLeaderProperties = Mockito.mock(LeaderProperties.class);
|
||||
|
||||
@Mock
|
||||
private LeaderEventPublisher mockLeaderEventPublisher;
|
||||
private final LeaderEventPublisher mockLeaderEventPublisher = Mockito.mock(LeaderEventPublisher.class);
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private KubernetesClient mockKubernetesClient;
|
||||
private final KubernetesClient mockKubernetesClient = Mockito.mock(KubernetesClient.class,
|
||||
Mockito.RETURNS_DEEP_STUBS);
|
||||
|
||||
private Fabric8LeadershipController fabric8LeadershipController;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
this.fabric8LeadershipController = new Fabric8LeadershipController(this.mockCandidate,
|
||||
this.mockLeaderProperties, this.mockLeaderEventPublisher, this.mockKubernetesClient);
|
||||
void beforeEach() {
|
||||
fabric8LeadershipController = new Fabric8LeadershipController(mockCandidate, mockLeaderProperties,
|
||||
mockLeaderEventPublisher, mockKubernetesClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetEmptyLocalLeader() {
|
||||
assertThat(this.fabric8LeadershipController.getLocalLeader().isPresent()).isFalse();
|
||||
void shouldGetEmptyLocalLeader() {
|
||||
assertThat(fabric8LeadershipController.getLocalLeader().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
@Test
|
||||
void whenNonExistentConfigmapAndCreationNotAllowedStopLeadershipAcquire(CapturedOutput output) {
|
||||
// given
|
||||
String testNamespace = "test-namespace";
|
||||
String testConfigmap = "test-configmap";
|
||||
Resource mockResource = Mockito.mock(Resource.class);
|
||||
NonNamespaceOperation mockNonNamespaceOperation = Mockito.mock(NonNamespaceOperation.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Resource<ConfigMap> mockResource = Mockito.mock(Resource.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
NonNamespaceOperation<ConfigMap, ConfigMapList, Resource<ConfigMap>> mockNonNamespaceOperation = Mockito
|
||||
.mock(NonNamespaceOperation.class);
|
||||
|
||||
Fabric8LeadershipController fabric8LeadershipController = new Fabric8LeadershipController(mockCandidate,
|
||||
mockLeaderProperties, mockLeaderEventPublisher, mockKubernetesClient);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -27,115 +27,98 @@ import io.fabric8.kubernetes.client.dsl.MixedOperation;
|
||||
import io.fabric8.kubernetes.client.dsl.PodResource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Gytis Trikleris
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class Fabric8PodReadinessWatcherTest {
|
||||
|
||||
private static final String POD_NAME = "test-pod";
|
||||
|
||||
@Mock
|
||||
private Fabric8LeadershipController mockFabric8LeadershipController;
|
||||
private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
|
||||
.mock(Fabric8LeadershipController.class);
|
||||
|
||||
@Mock
|
||||
private KubernetesClient mockKubernetesClient;
|
||||
private final KubernetesClient mockKubernetesClient = Mockito.mock(KubernetesClient.class);
|
||||
|
||||
@Mock
|
||||
private MixedOperation<Pod, PodList, PodResource> mockPodsOperation;
|
||||
@SuppressWarnings("unchecked")
|
||||
private final MixedOperation<Pod, PodList, PodResource> mockPodsOperation = Mockito.mock(MixedOperation.class);
|
||||
|
||||
@Mock
|
||||
private PodResource mockPodResource;
|
||||
private final PodResource mockPodResource = Mockito.mock(PodResource.class);
|
||||
|
||||
@Mock
|
||||
private Pod mockPod;
|
||||
private final Pod mockPod = Mockito.mock(Pod.class);
|
||||
|
||||
@Mock
|
||||
private PodStatus mockPodStatus;
|
||||
private final PodStatus mockPodStatus = Mockito.mock(PodStatus.class);
|
||||
|
||||
@Mock
|
||||
private Watch mockWatch;
|
||||
private final Watch mockWatch = Mockito.mock(Watch.class);
|
||||
|
||||
@Mock
|
||||
private WatcherException mockKubernetesClientException;
|
||||
private final WatcherException mockKubernetesClientException = Mockito.mock(WatcherException.class);
|
||||
|
||||
private Fabric8PodReadinessWatcher watcher;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
this.watcher = new Fabric8PodReadinessWatcher(POD_NAME, this.mockKubernetesClient,
|
||||
this.mockFabric8LeadershipController);
|
||||
void beforeEach() {
|
||||
watcher = new Fabric8PodReadinessWatcher(POD_NAME, mockKubernetesClient, mockFabric8LeadershipController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStartOnce() {
|
||||
void shouldStartOnce() {
|
||||
initStubs();
|
||||
this.watcher.start();
|
||||
this.watcher.start();
|
||||
|
||||
verify(this.mockPodResource).watch(this.watcher);
|
||||
watcher.start();
|
||||
watcher.start();
|
||||
verify(mockPodResource).watch(watcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStopOnce() {
|
||||
void shouldStopOnce() {
|
||||
initStubs();
|
||||
this.watcher.start();
|
||||
this.watcher.stop();
|
||||
this.watcher.stop();
|
||||
|
||||
verify(this.mockWatch).close();
|
||||
watcher.start();
|
||||
watcher.stop();
|
||||
watcher.stop();
|
||||
verify(mockWatch).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleEventWithStateChange() {
|
||||
void shouldHandleEventWithStateChange() {
|
||||
initStubs();
|
||||
given(this.mockPodResource.isReady()).willReturn(true);
|
||||
given(this.mockPod.getStatus()).willReturn(this.mockPodStatus);
|
||||
Mockito.when(mockPodResource.isReady()).thenReturn(true);
|
||||
Mockito.when(mockPod.getStatus()).thenReturn(mockPodStatus);
|
||||
|
||||
this.watcher.start();
|
||||
this.watcher.eventReceived(Watcher.Action.ADDED, this.mockPod);
|
||||
|
||||
verify(this.mockFabric8LeadershipController).update();
|
||||
watcher.start();
|
||||
watcher.eventReceived(Watcher.Action.ADDED, mockPod);
|
||||
verify(mockFabric8LeadershipController).update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreEventIfStateDoesNotChange() {
|
||||
void shouldIgnoreEventIfStateDoesNotChange() {
|
||||
initStubs();
|
||||
given(this.mockPod.getStatus()).willReturn(this.mockPodStatus);
|
||||
Mockito.when(mockPod.getStatus()).thenReturn(mockPodStatus);
|
||||
|
||||
this.watcher.start();
|
||||
this.watcher.eventReceived(Watcher.Action.ADDED, this.mockPod);
|
||||
|
||||
verify(this.mockFabric8LeadershipController, times(0)).update();
|
||||
watcher.start();
|
||||
watcher.eventReceived(Watcher.Action.ADDED, mockPod);
|
||||
verify(mockFabric8LeadershipController, times(0)).update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleClose() {
|
||||
void shouldHandleClose() {
|
||||
initStubs();
|
||||
this.watcher.onClose(this.mockKubernetesClientException);
|
||||
|
||||
verify(this.mockPodResource).watch(this.watcher);
|
||||
watcher.onClose(mockKubernetesClientException);
|
||||
verify(mockPodResource).watch(watcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreCloseWithoutCause() {
|
||||
this.watcher.onClose(null);
|
||||
|
||||
verify(this.mockPodResource, times(0)).watch(this.watcher);
|
||||
void shouldIgnoreCloseWithoutCause() {
|
||||
watcher.onClose(null);
|
||||
verify(mockPodResource, times(0)).watch(watcher);
|
||||
}
|
||||
|
||||
private void initStubs() {
|
||||
given(this.mockKubernetesClient.pods()).willReturn(this.mockPodsOperation);
|
||||
given(this.mockPodsOperation.withName(POD_NAME)).willReturn(this.mockPodResource);
|
||||
given(this.mockPodResource.watch(this.watcher)).willReturn(this.mockWatch);
|
||||
Mockito.when(mockKubernetesClient.pods()).thenReturn(mockPodsOperation);
|
||||
Mockito.when(mockPodsOperation.withName(POD_NAME)).thenReturn(mockPodResource);
|
||||
Mockito.when(mockPodResource.watch(watcher)).thenReturn(mockWatch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -20,73 +20,60 @@ import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
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;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Gytis Trikleris
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class LeaderContextTest {
|
||||
|
||||
@Mock
|
||||
private Candidate mockCandidate;
|
||||
private final Candidate mockCandidate = Mockito.mock(Candidate.class);
|
||||
|
||||
@Mock
|
||||
private Fabric8LeadershipController mockFabric8LeadershipController;
|
||||
private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
|
||||
.mock(Fabric8LeadershipController.class);
|
||||
|
||||
@Mock
|
||||
private Leader mockLeader;
|
||||
private final Leader mockLeader = Mockito.mock(Leader.class);
|
||||
|
||||
private LeaderContext leaderContext;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
this.leaderContext = new LeaderContext(this.mockCandidate, this.mockFabric8LeadershipController);
|
||||
void beforeEach() {
|
||||
leaderContext = new LeaderContext(mockCandidate, mockFabric8LeadershipController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsLeaderWithoutLeader() {
|
||||
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.empty());
|
||||
|
||||
boolean result = this.leaderContext.isLeader();
|
||||
|
||||
void testIsLeaderWithoutLeader() {
|
||||
Mockito.when(mockFabric8LeadershipController.getLocalLeader()).thenReturn(Optional.empty());
|
||||
boolean result = leaderContext.isLeader();
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsLeaderWithAnotherLeader() {
|
||||
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
|
||||
|
||||
boolean result = this.leaderContext.isLeader();
|
||||
|
||||
void testIsLeaderWithAnotherLeader() {
|
||||
Mockito.when(mockFabric8LeadershipController.getLocalLeader()).thenReturn(Optional.of(mockLeader));
|
||||
boolean result = leaderContext.isLeader();
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsLeaderWhenLeader() {
|
||||
given(this.mockFabric8LeadershipController.getLocalLeader()).willReturn(Optional.of(this.mockLeader));
|
||||
given(this.mockLeader.isCandidate(this.mockCandidate)).willReturn(true);
|
||||
|
||||
void testIsLeaderWhenLeader() {
|
||||
Mockito.when(mockFabric8LeadershipController.getLocalLeader()).thenReturn(Optional.of(mockLeader));
|
||||
Mockito.when(mockLeader.isCandidate(mockCandidate)).thenReturn(true);
|
||||
boolean result = this.leaderContext.isLeader();
|
||||
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldYieldLeadership() {
|
||||
this.leaderContext.yield();
|
||||
|
||||
verify(this.mockFabric8LeadershipController).revoke();
|
||||
void shouldYieldLeadership() {
|
||||
leaderContext.yield();
|
||||
verify(mockFabric8LeadershipController).revoke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,123 +18,113 @@ package org.springframework.cloud.kubernetes.fabric8.leader;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
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;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce;
|
||||
|
||||
/**
|
||||
* @author Gytis Trikleris
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class LeaderInitiatorTest {
|
||||
|
||||
@Mock
|
||||
private LeaderProperties mockLeaderProperties;
|
||||
private final LeaderProperties leaderProperties = new LeaderProperties();
|
||||
|
||||
@Mock
|
||||
private Fabric8LeadershipController mockFabric8LeadershipController;
|
||||
private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
|
||||
.mock(Fabric8LeadershipController.class);
|
||||
|
||||
@Mock
|
||||
private Fabric8LeaderRecordWatcher mockFabric8LeaderRecordWatcher;
|
||||
private final Fabric8LeaderRecordWatcher mockFabric8LeaderRecordWatcher = Mockito
|
||||
.mock(Fabric8LeaderRecordWatcher.class);
|
||||
|
||||
@Mock
|
||||
private Fabric8PodReadinessWatcher mockFabric8PodReadinessWatcher;
|
||||
private final Fabric8PodReadinessWatcher mockFabric8PodReadinessWatcher = Mockito
|
||||
.mock(Fabric8PodReadinessWatcher.class);
|
||||
|
||||
@Mock
|
||||
private Runnable mockRunnable;
|
||||
private final Runnable runnable = Mockito.mock(Runnable.class);
|
||||
|
||||
private LeaderInitiator leaderInitiator;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
this.leaderInitiator = new LeaderInitiator(this.mockLeaderProperties, this.mockFabric8LeadershipController,
|
||||
this.mockFabric8LeaderRecordWatcher, this.mockFabric8PodReadinessWatcher);
|
||||
void beforeEach() {
|
||||
leaderInitiator = new LeaderInitiator(leaderProperties, mockFabric8LeadershipController,
|
||||
mockFabric8LeaderRecordWatcher, mockFabric8PodReadinessWatcher);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
this.leaderInitiator.stop();
|
||||
void afterEach() {
|
||||
leaderInitiator.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAutoStartup() {
|
||||
given(this.mockLeaderProperties.isAutoStartup()).willReturn(true);
|
||||
|
||||
assertThat(this.leaderInitiator.isAutoStartup()).isTrue();
|
||||
void testIsAutoStartup() {
|
||||
assertThat(leaderInitiator.isAutoStartup()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStart() throws InterruptedException {
|
||||
given(this.mockLeaderProperties.getUpdatePeriod()).willReturn(Duration.ofMillis(1L));
|
||||
void shouldStart() {
|
||||
leaderProperties.setUpdatePeriod(Duration.ofMillis(1L));
|
||||
|
||||
this.leaderInitiator.start();
|
||||
leaderInitiator.start();
|
||||
|
||||
assertThat(this.leaderInitiator.isRunning()).isTrue();
|
||||
verify(this.mockFabric8LeaderRecordWatcher).start();
|
||||
verify(this.mockFabric8PodReadinessWatcher).start();
|
||||
assertThat(leaderInitiator.isRunning()).isTrue();
|
||||
verify(mockFabric8LeaderRecordWatcher).start();
|
||||
verify(mockFabric8PodReadinessWatcher).start();
|
||||
boolean[] updateCalled = new boolean[1];
|
||||
Mockito.doAnswer(x -> {
|
||||
updateCalled[0] = true;
|
||||
return null;
|
||||
}).when(mockFabric8LeadershipController).update();
|
||||
|
||||
// TODO this tests needs to be reviewed not to use sleep
|
||||
Thread.sleep(1000);
|
||||
verify(this.mockFabric8LeadershipController, atLeastOnce()).update();
|
||||
Awaitility.await().atMost(Duration.ofSeconds(3)).until(() -> updateCalled[0]);
|
||||
|
||||
verify(mockFabric8LeadershipController, atLeastOnce()).update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStartOnlyOnce() {
|
||||
given(this.mockLeaderProperties.getUpdatePeriod()).willReturn(Duration.ofMillis(10000L));
|
||||
void shouldStartOnlyOnce() {
|
||||
leaderInitiator.start();
|
||||
leaderInitiator.start();
|
||||
|
||||
this.leaderInitiator.start();
|
||||
this.leaderInitiator.start();
|
||||
|
||||
verify(this.mockFabric8LeaderRecordWatcher).start();
|
||||
verify(mockFabric8LeaderRecordWatcher).start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStop() {
|
||||
given(this.mockLeaderProperties.getUpdatePeriod()).willReturn(Duration.ofMillis(10000L));
|
||||
void shouldStop() {
|
||||
leaderInitiator.start();
|
||||
leaderInitiator.stop();
|
||||
|
||||
this.leaderInitiator.start();
|
||||
this.leaderInitiator.stop();
|
||||
|
||||
assertThat(this.leaderInitiator.isRunning()).isFalse();
|
||||
verify(this.mockFabric8LeaderRecordWatcher).stop();
|
||||
verify(this.mockFabric8PodReadinessWatcher).start();
|
||||
verify(this.mockFabric8LeadershipController).revoke();
|
||||
assertThat(leaderInitiator.isRunning()).isFalse();
|
||||
verify(mockFabric8LeaderRecordWatcher).stop();
|
||||
verify(mockFabric8PodReadinessWatcher).start();
|
||||
verify(mockFabric8LeadershipController).revoke();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStopOnlyOnce() {
|
||||
given(this.mockLeaderProperties.getUpdatePeriod()).willReturn(Duration.ofMillis(10000L));
|
||||
void shouldStopOnlyOnce() {
|
||||
leaderInitiator.start();
|
||||
leaderInitiator.stop();
|
||||
leaderInitiator.stop();
|
||||
|
||||
this.leaderInitiator.start();
|
||||
this.leaderInitiator.stop();
|
||||
this.leaderInitiator.stop();
|
||||
|
||||
verify(this.mockFabric8LeaderRecordWatcher).stop();
|
||||
verify(mockFabric8LeaderRecordWatcher).stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStopAndExecuteCallback() {
|
||||
given(this.mockLeaderProperties.getUpdatePeriod()).willReturn(Duration.ofMillis(10000L));
|
||||
void shouldStopAndExecuteCallback() {
|
||||
leaderInitiator.start();
|
||||
leaderInitiator.stop(runnable);
|
||||
|
||||
this.leaderInitiator.start();
|
||||
this.leaderInitiator.stop(this.mockRunnable);
|
||||
|
||||
assertThat(this.leaderInitiator.isRunning()).isFalse();
|
||||
verify(this.mockFabric8LeaderRecordWatcher).stop();
|
||||
verify(this.mockFabric8PodReadinessWatcher).start();
|
||||
verify(this.mockFabric8LeadershipController).revoke();
|
||||
verify(this.mockRunnable).run();
|
||||
assertThat(leaderInitiator.isRunning()).isFalse();
|
||||
verify(mockFabric8LeaderRecordWatcher).stop();
|
||||
verify(mockFabric8PodReadinessWatcher).start();
|
||||
verify(mockFabric8LeadershipController).revoke();
|
||||
verify(runnable).run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user