|
@@ -0,0 +1,302 @@
|
|
|
+/**
|
|
|
+ * 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.ozone.container.common.states.endpoint;
|
|
|
+
|
|
|
+import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
|
|
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.ContainerInfo;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.ContainerAction;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.CommandStatusReportsProto;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.ContainerReportsProto;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.NodeReportProto;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.SCMHeartbeatResponseProto;
|
|
|
+import org.apache.hadoop.hdds.protocol.proto
|
|
|
+ .StorageContainerDatanodeProtocolProtos.SCMHeartbeatRequestProto;
|
|
|
+import org.apache.hadoop.ozone.container.common.statemachine
|
|
|
+ .DatanodeStateMachine;
|
|
|
+import org.apache.hadoop.ozone.container.common.statemachine
|
|
|
+ .DatanodeStateMachine.DatanodeStates;
|
|
|
+import org.apache.hadoop.ozone.container.common.statemachine
|
|
|
+ .EndpointStateMachine;
|
|
|
+import org.apache.hadoop.ozone.container.common.statemachine.StateContext;
|
|
|
+import org.apache.hadoop.ozone.protocolPB
|
|
|
+ .StorageContainerDatanodeProtocolClientSideTranslatorPB;
|
|
|
+
|
|
|
+import org.junit.Assert;
|
|
|
+import org.junit.Test;
|
|
|
+import org.mockito.ArgumentCaptor;
|
|
|
+import org.mockito.Mockito;
|
|
|
+
|
|
|
+import java.util.UUID;
|
|
|
+
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
+
|
|
|
+/**
|
|
|
+ * This class tests the functionality of HeartbeatEndpointTask.
|
|
|
+ */
|
|
|
+public class TestHeartbeatEndpointTask {
|
|
|
+
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testheartbeatWithoutReports() throws Exception {
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB scm =
|
|
|
+ Mockito.mock(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB.class);
|
|
|
+ ArgumentCaptor<SCMHeartbeatRequestProto> argument = ArgumentCaptor
|
|
|
+ .forClass(SCMHeartbeatRequestProto.class);
|
|
|
+ Mockito.when(scm.sendHeartbeat(argument.capture()))
|
|
|
+ .thenAnswer(invocation ->
|
|
|
+ SCMHeartbeatResponseProto.newBuilder()
|
|
|
+ .setDatanodeUUID(
|
|
|
+ ((SCMHeartbeatRequestProto)invocation.getArgument(0))
|
|
|
+ .getDatanodeDetails().getUuid())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ HeartbeatEndpointTask endpointTask = getHeartbeatEndpointTask(scm);
|
|
|
+ endpointTask.call();
|
|
|
+ SCMHeartbeatRequestProto heartbeat = argument.getValue();
|
|
|
+ Assert.assertTrue(heartbeat.hasDatanodeDetails());
|
|
|
+ Assert.assertFalse(heartbeat.hasNodeReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasCommandStatusReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerActions());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testheartbeatWithNodeReports() throws Exception {
|
|
|
+ Configuration conf = new OzoneConfiguration();
|
|
|
+ StateContext context = new StateContext(conf, DatanodeStates.RUNNING,
|
|
|
+ Mockito.mock(DatanodeStateMachine.class));
|
|
|
+
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB scm =
|
|
|
+ Mockito.mock(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB.class);
|
|
|
+ ArgumentCaptor<SCMHeartbeatRequestProto> argument = ArgumentCaptor
|
|
|
+ .forClass(SCMHeartbeatRequestProto.class);
|
|
|
+ Mockito.when(scm.sendHeartbeat(argument.capture()))
|
|
|
+ .thenAnswer(invocation ->
|
|
|
+ SCMHeartbeatResponseProto.newBuilder()
|
|
|
+ .setDatanodeUUID(
|
|
|
+ ((SCMHeartbeatRequestProto)invocation.getArgument(0))
|
|
|
+ .getDatanodeDetails().getUuid())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ HeartbeatEndpointTask endpointTask = getHeartbeatEndpointTask(
|
|
|
+ conf, context, scm);
|
|
|
+ context.addReport(NodeReportProto.getDefaultInstance());
|
|
|
+ endpointTask.call();
|
|
|
+ SCMHeartbeatRequestProto heartbeat = argument.getValue();
|
|
|
+ Assert.assertTrue(heartbeat.hasDatanodeDetails());
|
|
|
+ Assert.assertTrue(heartbeat.hasNodeReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasCommandStatusReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerActions());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testheartbeatWithContainerReports() throws Exception {
|
|
|
+ Configuration conf = new OzoneConfiguration();
|
|
|
+ StateContext context = new StateContext(conf, DatanodeStates.RUNNING,
|
|
|
+ Mockito.mock(DatanodeStateMachine.class));
|
|
|
+
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB scm =
|
|
|
+ Mockito.mock(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB.class);
|
|
|
+ ArgumentCaptor<SCMHeartbeatRequestProto> argument = ArgumentCaptor
|
|
|
+ .forClass(SCMHeartbeatRequestProto.class);
|
|
|
+ Mockito.when(scm.sendHeartbeat(argument.capture()))
|
|
|
+ .thenAnswer(invocation ->
|
|
|
+ SCMHeartbeatResponseProto.newBuilder()
|
|
|
+ .setDatanodeUUID(
|
|
|
+ ((SCMHeartbeatRequestProto)invocation.getArgument(0))
|
|
|
+ .getDatanodeDetails().getUuid())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ HeartbeatEndpointTask endpointTask = getHeartbeatEndpointTask(
|
|
|
+ conf, context, scm);
|
|
|
+ context.addReport(ContainerReportsProto.getDefaultInstance());
|
|
|
+ endpointTask.call();
|
|
|
+ SCMHeartbeatRequestProto heartbeat = argument.getValue();
|
|
|
+ Assert.assertTrue(heartbeat.hasDatanodeDetails());
|
|
|
+ Assert.assertFalse(heartbeat.hasNodeReport());
|
|
|
+ Assert.assertTrue(heartbeat.hasContainerReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasCommandStatusReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerActions());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testheartbeatWithCommandStatusReports() throws Exception {
|
|
|
+ Configuration conf = new OzoneConfiguration();
|
|
|
+ StateContext context = new StateContext(conf, DatanodeStates.RUNNING,
|
|
|
+ Mockito.mock(DatanodeStateMachine.class));
|
|
|
+
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB scm =
|
|
|
+ Mockito.mock(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB.class);
|
|
|
+ ArgumentCaptor<SCMHeartbeatRequestProto> argument = ArgumentCaptor
|
|
|
+ .forClass(SCMHeartbeatRequestProto.class);
|
|
|
+ Mockito.when(scm.sendHeartbeat(argument.capture()))
|
|
|
+ .thenAnswer(invocation ->
|
|
|
+ SCMHeartbeatResponseProto.newBuilder()
|
|
|
+ .setDatanodeUUID(
|
|
|
+ ((SCMHeartbeatRequestProto)invocation.getArgument(0))
|
|
|
+ .getDatanodeDetails().getUuid())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ HeartbeatEndpointTask endpointTask = getHeartbeatEndpointTask(
|
|
|
+ conf, context, scm);
|
|
|
+ context.addReport(CommandStatusReportsProto.getDefaultInstance());
|
|
|
+ endpointTask.call();
|
|
|
+ SCMHeartbeatRequestProto heartbeat = argument.getValue();
|
|
|
+ Assert.assertTrue(heartbeat.hasDatanodeDetails());
|
|
|
+ Assert.assertFalse(heartbeat.hasNodeReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerReport());
|
|
|
+ Assert.assertTrue(heartbeat.hasCommandStatusReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerActions());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testheartbeatWithContainerActions() throws Exception {
|
|
|
+ Configuration conf = new OzoneConfiguration();
|
|
|
+ StateContext context = new StateContext(conf, DatanodeStates.RUNNING,
|
|
|
+ Mockito.mock(DatanodeStateMachine.class));
|
|
|
+
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB scm =
|
|
|
+ Mockito.mock(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB.class);
|
|
|
+ ArgumentCaptor<SCMHeartbeatRequestProto> argument = ArgumentCaptor
|
|
|
+ .forClass(SCMHeartbeatRequestProto.class);
|
|
|
+ Mockito.when(scm.sendHeartbeat(argument.capture()))
|
|
|
+ .thenAnswer(invocation ->
|
|
|
+ SCMHeartbeatResponseProto.newBuilder()
|
|
|
+ .setDatanodeUUID(
|
|
|
+ ((SCMHeartbeatRequestProto)invocation.getArgument(0))
|
|
|
+ .getDatanodeDetails().getUuid())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ HeartbeatEndpointTask endpointTask = getHeartbeatEndpointTask(
|
|
|
+ conf, context, scm);
|
|
|
+ context.addContainerAction(getContainerAction());
|
|
|
+ endpointTask.call();
|
|
|
+ SCMHeartbeatRequestProto heartbeat = argument.getValue();
|
|
|
+ Assert.assertTrue(heartbeat.hasDatanodeDetails());
|
|
|
+ Assert.assertFalse(heartbeat.hasNodeReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasContainerReport());
|
|
|
+ Assert.assertFalse(heartbeat.hasCommandStatusReport());
|
|
|
+ Assert.assertTrue(heartbeat.hasContainerActions());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testheartbeatWithAllReports() throws Exception {
|
|
|
+ Configuration conf = new OzoneConfiguration();
|
|
|
+ StateContext context = new StateContext(conf, DatanodeStates.RUNNING,
|
|
|
+ Mockito.mock(DatanodeStateMachine.class));
|
|
|
+
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB scm =
|
|
|
+ Mockito.mock(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB.class);
|
|
|
+ ArgumentCaptor<SCMHeartbeatRequestProto> argument = ArgumentCaptor
|
|
|
+ .forClass(SCMHeartbeatRequestProto.class);
|
|
|
+ Mockito.when(scm.sendHeartbeat(argument.capture()))
|
|
|
+ .thenAnswer(invocation ->
|
|
|
+ SCMHeartbeatResponseProto.newBuilder()
|
|
|
+ .setDatanodeUUID(
|
|
|
+ ((SCMHeartbeatRequestProto)invocation.getArgument(0))
|
|
|
+ .getDatanodeDetails().getUuid())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ HeartbeatEndpointTask endpointTask = getHeartbeatEndpointTask(
|
|
|
+ conf, context, scm);
|
|
|
+ context.addReport(NodeReportProto.getDefaultInstance());
|
|
|
+ context.addReport(ContainerReportsProto.getDefaultInstance());
|
|
|
+ context.addReport(CommandStatusReportsProto.getDefaultInstance());
|
|
|
+ context.addContainerAction(getContainerAction());
|
|
|
+ endpointTask.call();
|
|
|
+ SCMHeartbeatRequestProto heartbeat = argument.getValue();
|
|
|
+ Assert.assertTrue(heartbeat.hasDatanodeDetails());
|
|
|
+ Assert.assertTrue(heartbeat.hasNodeReport());
|
|
|
+ Assert.assertTrue(heartbeat.hasContainerReport());
|
|
|
+ Assert.assertTrue(heartbeat.hasCommandStatusReport());
|
|
|
+ Assert.assertTrue(heartbeat.hasContainerActions());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates HeartbeatEndpointTask for the given StorageContainerManager proxy.
|
|
|
+ *
|
|
|
+ * @param proxy StorageContainerDatanodeProtocolClientSideTranslatorPB
|
|
|
+ *
|
|
|
+ * @return HeartbeatEndpointTask
|
|
|
+ */
|
|
|
+ private HeartbeatEndpointTask getHeartbeatEndpointTask(
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB proxy) {
|
|
|
+ Configuration conf = new OzoneConfiguration();
|
|
|
+ StateContext context = new StateContext(conf, DatanodeStates.RUNNING,
|
|
|
+ Mockito.mock(DatanodeStateMachine.class));
|
|
|
+ return getHeartbeatEndpointTask(conf, context, proxy);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates HeartbeatEndpointTask with the given conf, context and
|
|
|
+ * StorageContainerManager client side proxy.
|
|
|
+ *
|
|
|
+ * @param conf Configuration
|
|
|
+ * @param context StateContext
|
|
|
+ * @param proxy StorageContainerDatanodeProtocolClientSideTranslatorPB
|
|
|
+ *
|
|
|
+ * @return HeartbeatEndpointTask
|
|
|
+ */
|
|
|
+ private HeartbeatEndpointTask getHeartbeatEndpointTask(
|
|
|
+ Configuration conf,
|
|
|
+ StateContext context,
|
|
|
+ StorageContainerDatanodeProtocolClientSideTranslatorPB proxy) {
|
|
|
+ DatanodeDetails datanodeDetails = DatanodeDetails.newBuilder()
|
|
|
+ .setUuid(UUID.randomUUID().toString())
|
|
|
+ .setHostName("localhost")
|
|
|
+ .setIpAddress("127.0.0.1")
|
|
|
+ .build();
|
|
|
+ EndpointStateMachine endpointStateMachine = Mockito
|
|
|
+ .mock(EndpointStateMachine.class);
|
|
|
+ Mockito.when(endpointStateMachine.getEndPoint()).thenReturn(proxy);
|
|
|
+ return HeartbeatEndpointTask.newBuilder()
|
|
|
+ .setConfig(conf)
|
|
|
+ .setDatanodeDetails(datanodeDetails)
|
|
|
+ .setContext(context)
|
|
|
+ .setEndpointStateMachine(endpointStateMachine)
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private ContainerAction getContainerAction() {
|
|
|
+ ContainerAction.Builder builder = ContainerAction.newBuilder();
|
|
|
+ ContainerInfo containerInfo = ContainerInfo.newBuilder()
|
|
|
+ .setContainerID(1L)
|
|
|
+ .build();
|
|
|
+ builder.setContainer(containerInfo)
|
|
|
+ .setAction(ContainerAction.Action.CLOSE)
|
|
|
+ .setReason(ContainerAction.Reason.CONTAINER_FULL);
|
|
|
+ return builder.build();
|
|
|
+ }
|
|
|
+}
|