Fabric leader clean up 6 (#1647)

This commit is contained in:
erabii
2024-04-29 21:20:48 +03:00
committed by GitHub
parent 279ee4d5ad
commit 4336a5b59c
9 changed files with 224 additions and 284 deletions

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}