From 6cff7a3da06abbfe54204550982e601dccc6c213 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 27 Apr 2020 14:29:54 -0700 Subject: [PATCH] Introduce the MemberSuspectEvent class extends MembershipEvent to signal when a peer member of the distributd system (cluster) becomes suspect. A peer member of the distributed system (cluster) becomse suspect when it is no longer responsive to other peer members in the cluster. --- .../event/support/MemberSuspectEvent.java | 113 ++++++++++++++++++ .../support/MemberSuspectEventUnitTests.java | 95 +++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/support/MemberSuspectEvent.java create mode 100644 apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/support/MemberSuspectEventUnitTests.java diff --git a/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/support/MemberSuspectEvent.java b/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/support/MemberSuspectEvent.java new file mode 100644 index 00000000..a003b31f --- /dev/null +++ b/apache-geode-extensions/src/main/java/org/springframework/geode/distributed/event/support/MemberSuspectEvent.java @@ -0,0 +1,113 @@ +/* + * Copyright 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.geode.distributed.event.support; + +import java.util.Optional; + +import org.apache.geode.distributed.DistributedMember; +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.DistributionManager; + +import org.springframework.geode.distributed.event.MembershipEvent; + +/** + * {@link MembershipEvent} fired when a {@link DistributedMember} of the {@link DistributedSystem} is suspected + * of being unresponsive to other {@link DistributedMember peer members} in the cluster. + * + * @author John Blum + * @see org.apache.geode.distributed.DistributedMember + * @see org.apache.geode.distributed.DistributedSystem + * @see org.springframework.geode.distributed.event.MembershipEvent + * @since 1.3.0 + */ +public class MemberSuspectEvent extends MembershipEvent { + + private DistributedMember suspectMember; + + private String reason; + + /** + * Constructs a new instance of {@link MemberSuspectEvent} initialized with the given {@link DistributionManager}. + * + * @param distributionManager {@link DistributionManager} used as the {@link #getSource() source} of this event; + * must not be {@literal null}. + * @throws IllegalArgumentException if {@link DistributionManager} is {@literal null}. + * @see org.apache.geode.distributed.internal.DistributionManager + */ + public MemberSuspectEvent(DistributionManager distributionManager) { + super(distributionManager); + } + + /** + * Returns an {@link Optional} {@link String reason} describing the suspicion of the peer member. + * + * @return an {@link Optional} {@link String reason} describing the suspicion of the peer member. + * @see java.util.Optional + */ + public Optional getReason() { + return Optional.ofNullable(this.reason); + } + + /** + * Returns an {@link Optional} {@link DistributedMember} identified as the suspect in the {@link MembershipEvent}. + * + * @return an {@link Optional} {@link DistributedMember} identified as the suspect in the {@link MembershipEvent}. + * @see org.apache.geode.distributed.DistributedMember + * @see java.util.Optional + */ + public Optional getSuspectMember() { + return Optional.ofNullable(this.suspectMember); + } + + /** + * Builder method used to configure the {@link String reason} describing the suspicion of + * the {@link DistributedMember suspect member}. + * + * @param reason {@link String} describing the suspicion of the {@link DistributedMember peer member}; + * may be {@literal null}. + * @return this {@link MemberSuspectEvent}. + * @see #getReason() + */ + public MemberSuspectEvent withReason(String reason) { + + this.reason = reason; + + return this; + } + + /** + * Builder method used to configure the {@link DistributedMember peer member} that is the subject of the suspicion + * {@link MembershipEvent}. + * + * @param suspectMember {@link DistributedMember peer member} that is being suspected; may be {@literal null}. + * @return this {@link MemberSuspectEvent}. + * @see #getSuspectMember() + */ + public MemberSuspectEvent withSuspect(DistributedMember suspectMember) { + + this.suspectMember = suspectMember; + + return this; + } + + /** + * @inheritDoc + */ + @Override + public final Type getType() { + return Type.MEMBER_SUSPECT; + } +} diff --git a/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/support/MemberSuspectEventUnitTests.java b/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/support/MemberSuspectEventUnitTests.java new file mode 100644 index 00000000..15c811ce --- /dev/null +++ b/apache-geode-extensions/src/test/java/org/springframework/geode/distributed/event/support/MemberSuspectEventUnitTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 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.geode.distributed.event.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; + +import org.junit.Test; + +import org.apache.geode.distributed.DistributedMember; +import org.apache.geode.distributed.internal.DistributionManager; + +import org.springframework.geode.distributed.event.MembershipEvent; + +/** + * Unit Tests for {@link MemberSuspectEvent}. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.apache.geode.distributed.DistributedMember + * @see org.springframework.geode.distributed.event.MembershipEvent + * @see org.springframework.geode.distributed.event.support.MemberSuspectEvent + * @since 1.3.0 + */ +public class MemberSuspectEventUnitTests { + + @Test + public void constructsMemberSuspectEvent() { + + DistributionManager mockDistributionManager = mock(DistributionManager.class); + + MemberSuspectEvent event = new MemberSuspectEvent(mockDistributionManager); + + assertThat(event).isNotNull(); + assertThat(event.getDistributionManager()).isEqualTo(mockDistributionManager); + assertThat(event.getReason().orElse(null)).isNull(); + assertThat(event.getSuspectMember().orElse(null)).isNull(); + assertThat(event.getType()).isEqualTo(MembershipEvent.Type.MEMBER_SUSPECT); + + verifyNoInteractions(mockDistributionManager); + } + + @Test + public void setAndGetReason() { + + DistributionManager mockDistributionManager = mock(DistributionManager.class); + + MemberSuspectEvent event = new MemberSuspectEvent(mockDistributionManager); + + assertThat(event).isNotNull(); + assertThat(event.getReason().orElse(null)).isNull(); + assertThat(event.withReason("TEST")).isSameAs(event); + assertThat(event.getReason().orElse(null)).isEqualTo("TEST"); + assertThat(event.withReason(null)).isSameAs(event); + assertThat(event.getReason().orElse(null)).isNull(); + assertThat(event.withReason(" ")).isSameAs(event); + assertThat(event.getReason().orElse(null)).isEqualTo(" "); + assertThat(event.withReason(null)).isSameAs(event); + assertThat(event.getReason().orElse(null)).isNull(); + assertThat(event.withReason("")).isSameAs(event); + assertThat(event.getReason().orElse(null)).isEqualTo(""); + } + + @Test + public void setAndGetSuspectMember() { + + DistributedMember mockDistributedMember = mock(DistributedMember.class); + + DistributionManager mockDistributionManager = mock(DistributionManager.class); + + MemberSuspectEvent event = new MemberSuspectEvent(mockDistributionManager); + + assertThat(event).isNotNull(); + assertThat(event.getSuspectMember().orElse(null)).isNull(); + assertThat(event.withSuspect(mockDistributedMember)).isSameAs(event); + assertThat(event.getSuspectMember().orElse(null)).isEqualTo(mockDistributedMember); + assertThat(event.withSuspect(null)).isSameAs(event); + assertThat(event.getSuspectMember().orElse(null)).isNull(); + } +}