From be7c8496b92dec6ee77e86fc166c7df45e9e5eab Mon Sep 17 00:00:00 2001 From: Tom Pantelis Date: Wed, 15 Feb 2017 11:02:57 -0500 Subject: [PATCH] Fix intermittent failure in testCloseCandidateRegistrationInQuickSuccession java.lang.IllegalStateException: Optional.get() cannot be called on an absent value at com.google.common.base.Absent.get(Absent.java:47) at org.opendaylight.controller.cluster.datastore.entityownership.DistributedEntityOwnershipIntegrationTest.testCloseCandidateRegistrationInQuickSuccession(DistributedEntityOwnershipIntegrationTest.java:512) Code: if (!leaderEntityOwnershipService.getOwnershipState(ENTITY1).isPresent() || leaderEntityOwnershipService.getOwnershipState(ENTITY1).get() == EntityOwnershipState.NO_OWNER The code inlines calls to getOwnershipState so it's possible the first call returns a present Optional and the second call returns absent which leads to the failure. It's safer to capture the Optional in a lcoal var. Change-Id: I9baa120efc9924dc820435dd63217b4598731a13 Signed-off-by: Tom Pantelis --- ...ributedEntityOwnershipIntegrationTest.java | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipIntegrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipIntegrationTest.java index 3a481feb81..fba0d19e13 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipIntegrationTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/entityownership/DistributedEntityOwnershipIntegrationTest.java @@ -43,6 +43,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.exceptions.base.MockitoException; import org.opendaylight.controller.cluster.datastore.DatastoreContext; import org.opendaylight.controller.cluster.datastore.DistributedDataStore; import org.opendaylight.controller.cluster.datastore.IntegrationTestKit; @@ -468,10 +469,15 @@ public class DistributedEntityOwnershipIntegrationTest { final DOMEntityOwnershipCandidateRegistration candidate1 = leaderEntityOwnershipService.registerCandidate(ENTITY1); verify(leaderMockListener, timeout(5000)).ownershipChanged(ownershipChange(ENTITY1, false, true, true)); - final DOMEntityOwnershipCandidateRegistration candidate2 = follower1EntityOwnershipService.registerCandidate(ENTITY1); - final DOMEntityOwnershipCandidateRegistration candidate3 = follower2EntityOwnershipService.registerCandidate(ENTITY1); + final DOMEntityOwnershipCandidateRegistration candidate2 = + follower1EntityOwnershipService.registerCandidate(ENTITY1); + verify(follower1MockListener, timeout(5000)).ownershipChanged(ownershipChange(ENTITY1, false, false, true)); + + final DOMEntityOwnershipCandidateRegistration candidate3 = + follower2EntityOwnershipService.registerCandidate(ENTITY1); + verify(follower2MockListener, timeout(5000)).ownershipChanged(ownershipChange(ENTITY1, false, false, true)); - Mockito.reset(leaderMockListener); + Mockito.reset(leaderMockListener, follower1MockListener, follower2MockListener); ArgumentCaptor leaderChangeCaptor = ArgumentCaptor.forClass(DOMEntityOwnershipChange.class); ArgumentCaptor follower1ChangeCaptor = ArgumentCaptor.forClass(DOMEntityOwnershipChange.class); @@ -487,15 +493,20 @@ public class DistributedEntityOwnershipIntegrationTest { boolean passed = false; for(int i=0;i<100;i++) { Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); - if(!leaderEntityOwnershipService.getOwnershipState(ENTITY1).isPresent() || - leaderEntityOwnershipService.getOwnershipState(ENTITY1).get() == EntityOwnershipState.NO_OWNER && - follower1EntityOwnershipService.getOwnershipState(ENTITY1).isPresent() && - follower1EntityOwnershipService.getOwnershipState(ENTITY1).get() == EntityOwnershipState.NO_OWNER && - follower2EntityOwnershipService.getOwnershipState(ENTITY1).isPresent() && - follower2EntityOwnershipService.getOwnershipState(ENTITY1).get() == EntityOwnershipState.NO_OWNER && - leaderChangeCaptor.getAllValues().size() > 0 && !leaderChangeCaptor.getValue().getState().hasOwner() && - leaderChangeCaptor.getAllValues().size() > 0 && !follower1ChangeCaptor.getValue().getState().hasOwner() && - leaderChangeCaptor.getAllValues().size() > 0 && !follower2ChangeCaptor.getValue().getState().hasOwner()) { + final Optional leaderState = leaderEntityOwnershipService.getOwnershipState(ENTITY1); + final Optional follower1State = + follower1EntityOwnershipService.getOwnershipState(ENTITY1); + final Optional follower2State = + follower2EntityOwnershipService.getOwnershipState(ENTITY1); + final Optional leaderChange = getValueSafely(leaderChangeCaptor); + final Optional follower1Change = getValueSafely(follower1ChangeCaptor); + final Optional follower2Change = getValueSafely(follower2ChangeCaptor); + if (!leaderState.isPresent() || leaderState.get() == EntityOwnershipState.NO_OWNER + && follower1State.isPresent() && follower1State.get() == EntityOwnershipState.NO_OWNER + && follower2State.isPresent() && follower2State.get() == EntityOwnershipState.NO_OWNER + && leaderChange.isPresent() && !leaderChange.get().getState().hasOwner() + && follower1Change.isPresent() && !follower1Change.get().getState().hasOwner() + && follower2Change.isPresent() && !follower2Change.get().getState().hasOwner()) { passed = true; break; } @@ -504,6 +515,15 @@ public class DistributedEntityOwnershipIntegrationTest { assertTrue("No ownership change message was sent with hasOwner=false", passed); } + private static Optional getValueSafely(ArgumentCaptor captor) { + try { + return Optional.fromNullable(captor.getValue()); + } catch (MockitoException e) { + // No value was captured + return Optional.absent(); + } + } + /** * Tests bootstrapping the entity-ownership shard when there's no shards initially configured for local * member. The entity-ownership shard is initially created as inactive (ie remains a follower), requiring -- 2.36.6