diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/CustomMonotonicClock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/CustomMonotonicClock.java new file mode 100644 index 00000000000..b01aa61bcdb --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/CustomMonotonicClock.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * http://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.apache.hadoop.yarn.util; + +/** + * Implementation of {@link Clock} that gives the current time from the system + * clock in milliseconds and guarantees that every getTime() call returns a + * greater time value than it had returned before. + */ +public final class CustomMonotonicClock implements Clock { + private long lastReturned = 0L; + + public CustomMonotonicClock() { + // do nothing + } + + public long getTime() { + long currentTime = System.currentTimeMillis(); + + if (lastReturned == currentTime) { + ++lastReturned; + } else { + lastReturned = currentTime; + } + return lastReturned; + } +} \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/container/TestContainer.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/container/TestContainer.java index 1a263eea197..f49bd88e12b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/container/TestContainer.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/container/TestContainer.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; @@ -31,6 +32,7 @@ import static org.mockito.Mockito.atLeastOnce; import java.io.IOException; +import java.lang.reflect.Field; import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.util.AbstractMap.SimpleEntry; @@ -105,17 +107,27 @@ import org.apache.hadoop.yarn.server.nodemanager.NodeStatusUpdater; import org.apache.hadoop.yarn.server.nodemanager.recovery.NMNullStateStoreService; import org.apache.hadoop.yarn.server.utils.BuilderUtils; +import org.apache.hadoop.yarn.util.Clock; import org.apache.hadoop.yarn.util.ControlledClock; +import org.apache.hadoop.yarn.util.CustomMonotonicClock; import org.junit.Assert; import org.junit.Test; import org.mockito.ArgumentMatcher; import org.mockito.Mockito; +import org.mockito.internal.matchers.GreaterThan; public class TestContainer { final NodeManagerMetrics metrics = NodeManagerMetrics.create(); final Configuration conf = new YarnConfiguration(); final String FAKE_LOCALIZATION_ERROR = "Fake localization error"; + + private void replaceClock(Clock clock) throws NoSuchFieldException, + IllegalAccessException { + Field clockField = ContainerImpl.class.getDeclaredField("clock"); + clockField.setAccessible(true); + clockField.set(null, clock); + } /** * Verify correct container request events sent to localizer. @@ -574,6 +586,10 @@ public void testKillOnNew() throws Exception { WrappedContainer wc = null; try { + // need to replace clock as default SystemClock sometimes returned + // the same values for two consecutive getTime() calls as the execution + // was too fast + replaceClock(new CustomMonotonicClock()); wc = new WrappedContainer(13, 314159265358979L, 4344, "yak"); assertEquals(ContainerState.NEW, wc.c.getContainerState()); int killed = metrics.getKilledContainers(); @@ -591,9 +607,8 @@ public void testKillOnNew() throws Exception { Assert.assertEquals(ContainerExitStatus.KILLED_BY_RESOURCEMANAGER, containerMetrics.exitCode.value()); Assert.assertTrue(containerMetrics.startTime.value() > 0); - Assert.assertTrue( - containerMetrics.finishTime.value() > containerMetrics.startTime - .value()); + assertThat(containerMetrics.finishTime.value(), + new GreaterThan<>(containerMetrics.startTime.value())); Assert.assertEquals(ContainerEventType.KILL_CONTAINER, wc.initStateToEvent.get(ContainerState.NEW)); Assert.assertEquals(ContainerState.DONE, @@ -1612,4 +1627,5 @@ public SlidingWindowRetryPolicy getRetryPolicy() { return ((ContainerImpl)c).getRetryPolicy(); } } + }