This is an automated email from the ASF dual-hosted git repository.
wuzhiguo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git
The following commit(s) were added to refs/heads/main by this push:
new 9b005a52 BIGTOP-4329: Add some unit tests for agent module (#149)
9b005a52 is described below
commit 9b005a5257f088663e78eb1c4fde628cf050b7f1
Author: xianrenzw <[email protected]>
AuthorDate: Mon Jan 20 23:43:53 2025 +0800
BIGTOP-4329: Add some unit tests for agent module (#149)
---
.../agent/service/CommandServiceGrpcImpl.java | 2 +-
.../agent/holder/SpringContextHolderTest.java | 78 +++++++
.../agent/monitoring/AgentHostMonitoringTest.java | 227 +++++++++++++++++++++
.../agent/service/CommandServiceGrpcImplTest.java | 218 ++++++++++++++++++++
.../ComponentStatusServiceGrpcImplTest.java | 128 ++++++++++++
.../agent/service/HostInfoServiceGrpcImplTest.java | 121 +++++++++++
.../agent/service/JobCacheServiceGrpcImplTest.java | 106 ++++++++++
7 files changed, 879 insertions(+), 1 deletion(-)
diff --git
a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImpl.java
b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImpl.java
index 920e418b..6bff53ca 100644
---
a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImpl.java
+++
b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImpl.java
@@ -63,7 +63,7 @@ public class CommandServiceGrpcImpl extends
CommandServiceGrpc.CommandServiceImp
}
}
- private void truncateLogFile(Long taskId) {
+ protected void truncateLogFile(Long taskId) {
String filePath = ProjectPathUtils.getLogFilePath(taskId);
File file = new File(filePath);
if (file.exists()) {
diff --git
a/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/holder/SpringContextHolderTest.java
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/holder/SpringContextHolderTest.java
new file mode 100644
index 00000000..4eb0e7d6
--- /dev/null
+++
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/holder/SpringContextHolderTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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
+ *
+ * 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.apache.bigtop.manager.agent.holder;
+
+import org.apache.bigtop.manager.agent.executor.CommandExecutor;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.context.ApplicationContext;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SpringContextHolderTest {
+
+ @Mock
+ private ApplicationContext mockApplicationContext;
+
+ @Mock
+ private CommandExecutor mockCommandExecutor;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ MockitoAnnotations.openMocks(this);
+
+ // Use reflection to set the static variable applicationContext
+ Field field =
SpringContextHolder.class.getDeclaredField("applicationContext");
+ field.setAccessible(true);
+ field.set(null, mockApplicationContext);
+ }
+
+ @Test
+ public void testGetCommandExecutors() {
+ // Prepare test data
+ Map<String, CommandExecutor> commandExecutorsMap = new HashMap<>();
+ commandExecutorsMap.put("commandExecutor1", mockCommandExecutor);
+
when(mockApplicationContext.getBeansOfType(CommandExecutor.class)).thenReturn(commandExecutorsMap);
+
+ // Execute the method under test
+ Map<String, CommandExecutor> result =
SpringContextHolder.getCommandExecutors();
+
+ // Validate the result
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ assertTrue(result.containsKey("commandExecutor1"));
+ assertSame(mockCommandExecutor, result.get("commandExecutor1"));
+
+ // Verify method calls
+ verify(mockApplicationContext,
times(1)).getBeansOfType(CommandExecutor.class);
+ }
+}
diff --git
a/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/monitoring/AgentHostMonitoringTest.java
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/monitoring/AgentHostMonitoringTest.java
new file mode 100644
index 00000000..8fcb8cbc
--- /dev/null
+++
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/monitoring/AgentHostMonitoringTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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
+ *
+ * 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.apache.bigtop.manager.agent.monitoring;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.micrometer.core.instrument.MultiGauge;
+import oshi.SystemInfo;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.OperatingSystem;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class AgentHostMonitoringTest {
+
+ @Mock
+ private SystemInfo systemInfo;
+
+ @Mock
+ private HardwareAbstractionLayer hardwareAbstractionLayer;
+
+ @Mock
+ private GlobalMemory globalMemory;
+
+ @Mock
+ private MultiGauge diskMultiGauge;
+
+ @Mock
+ private MultiGauge memMultiGauge;
+
+ @Mock
+ private MultiGauge cpuMultiGauge;
+
+ @Mock
+ private MultiGauge diskIOMultiGauge;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+
when(systemInfo.getOperatingSystem()).thenReturn(mock(OperatingSystem.class));
+ when(systemInfo.getHardware()).thenReturn(hardwareAbstractionLayer);
+ when(hardwareAbstractionLayer.getMemory()).thenReturn(globalMemory);
+ when(globalMemory.getAvailable()).thenReturn(100000L);
+ when(globalMemory.getTotal()).thenReturn(200000L);
+ }
+
+ @Test
+ void testGetHostInfo() throws UnknownHostException {
+ JsonNode hostInfo = AgentHostMonitoring.getHostInfo();
+
+ // Check if the host information contains expected fields
+ assertTrue(hostInfo.has(AgentHostMonitoring.AGENT_BASE_INFO));
+ assertTrue(hostInfo.has(AgentHostMonitoring.BOOT_TIME));
+ assertTrue(hostInfo.has(AgentHostMonitoring.MEM_IDLE));
+ assertTrue(hostInfo.has(AgentHostMonitoring.MEM_TOTAL));
+ }
+
+ @Test
+ void testGetDiskGauge() {
+ // Create a mock JsonNode object
+ JsonNode agentMonitoring = mock(JsonNode.class);
+
+ // Create a mock agentHostInfo object and set its fields
+ ObjectNode agentHostInfo = mock(ObjectNode.class);
+
when(agentMonitoring.get(AgentHostMonitoring.AGENT_BASE_INFO)).thenReturn(agentHostInfo);
+
when(agentHostInfo.fieldNames()).thenReturn(Collections.emptyIterator());
+
+ // Create a mock disksBaseInfo object and set its fields
+ ArrayNode disksBaseInfo = mock(ArrayNode.class);
+
when(agentMonitoring.get(AgentHostMonitoring.DISKS_BASE_INFO)).thenReturn(disksBaseInfo);
+
+ // Create a mock diskJsonNode object and set its fields
+ ObjectNode diskJsonNode = mock(ObjectNode.class);
+ when(disksBaseInfo.get(0)).thenReturn(diskJsonNode);
+
when(diskJsonNode.get(AgentHostMonitoring.DISK_NAME)).thenReturn(mock(JsonNode.class));
+
when(diskJsonNode.get(AgentHostMonitoring.DISK_IDLE)).thenReturn(mock(JsonNode.class));
+
when(diskJsonNode.get(AgentHostMonitoring.DISK_TOTAL)).thenReturn(mock(JsonNode.class));
+
when(diskJsonNode.get(AgentHostMonitoring.DISK_NAME).asText()).thenReturn("disk1");
+
when(diskJsonNode.get(AgentHostMonitoring.DISK_IDLE).asDouble()).thenReturn(0.9);
+
when(diskJsonNode.get(AgentHostMonitoring.DISK_TOTAL).asDouble()).thenReturn(100.0);
+
+ // Call the getDiskGauge method
+ Map<ArrayList<String>, Map<ArrayList<String>, Double>> diskGauge =
+ AgentHostMonitoring.getDiskGauge(agentMonitoring);
+
+ // Assert that the disk gauge data is populated correctly
+ assertNotNull(diskGauge);
+ assertFalse(diskGauge.isEmpty());
+ }
+
+ @Test
+ void testGetCPUGauge() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ ObjectNode agentMonitoring = objectMapper.createObjectNode();
+ ObjectNode agentHostInfo = objectMapper.createObjectNode();
+
+ // Set AGENT_BASE_INFO fields
+ agentHostInfo.put("field1", "value1");
+ agentHostInfo.put("field2", "value2");
+ agentMonitoring.set(AgentHostMonitoring.AGENT_BASE_INFO,
agentHostInfo);
+
+ // Set CPU related fields
+ agentMonitoring
+ .put(AgentHostMonitoring.CPU_LOAD_AVG_MIN_1, 1.0)
+ .put(AgentHostMonitoring.CPU_LOAD_AVG_MIN_5, 5.0)
+ .put(AgentHostMonitoring.CPU_LOAD_AVG_MIN_15, 15.0)
+ .put(AgentHostMonitoring.CPU_USAGE, 10.0);
+
+ Map<ArrayList<String>, Map<ArrayList<String>, Double>> cpuGauge =
+ AgentHostMonitoring.getCPUGauge(agentMonitoring);
+
+ // Assert that the CPU gauge data is populated correctly
+ assertNotNull(cpuGauge);
+ assertFalse(cpuGauge.isEmpty());
+ }
+
+ @Test
+ void testGetMEMGauge() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ ObjectNode agentMonitoring = objectMapper.createObjectNode();
+ ObjectNode agentHostInfo = objectMapper.createObjectNode();
+
+ // Set AGENT_BASE_INFO fields
+ agentHostInfo.put("field1", "value1");
+ agentHostInfo.put("field2", "value2");
+ agentMonitoring.set(AgentHostMonitoring.AGENT_BASE_INFO,
agentHostInfo);
+
+ // Set MEM related fields
+ agentMonitoring.put(AgentHostMonitoring.MEM_IDLE,
2000.0).put(AgentHostMonitoring.MEM_TOTAL, 4000.0);
+
+ Map<ArrayList<String>, Map<ArrayList<String>, Double>> memGauge =
+ AgentHostMonitoring.getMEMGauge(agentMonitoring);
+
+ // Assert that the MEM gauge data is populated correctly
+ assertNotNull(memGauge);
+ assertFalse(memGauge.isEmpty());
+ }
+
+ @Test
+ void testMultiGaugeUpdateData() {
+ // Create a mock Map object
+ Map<ArrayList<String>, Map<ArrayList<String>, Double>> diskGauge = new
HashMap<>();
+ Map<ArrayList<String>, Double> innerMap = new HashMap<>();
+ innerMap.put(new ArrayList<>(Arrays.asList("label1", "label2")), 1.0);
+ diskGauge.put(new ArrayList<>(Arrays.asList("label1", "label2")),
innerMap);
+
+ // Create a mock MultiGauge object
+ MultiGauge diskMultiGauge = mock(MultiGauge.class);
+
+ // Call the test method
+ AgentHostMonitoring.multiGaugeUpdateData(diskMultiGauge, diskGauge);
+
+ // Verify that the register method is called once
+ verify(diskMultiGauge, times(1)).register(anyList(), eq(true));
+ }
+
+ @Test
+ void testDiskMultiGaugeUpdateData() {
+ AgentHostMonitoring.diskMultiGaugeUpdateData(diskMultiGauge);
+
+ // Verify that the multi-gauge update method was called
+ verify(diskMultiGauge, times(1)).register(anyList(), eq(true));
+ }
+
+ @Test
+ void testMemMultiGaugeUpdateData() {
+ AgentHostMonitoring.memMultiGaugeUpdateData(memMultiGauge);
+
+ // Verify that the multi-gauge update method was called
+ verify(memMultiGauge, times(1)).register(anyList(), eq(true));
+ }
+
+ @Test
+ void testCpuMultiGaugeUpdateData() {
+ AgentHostMonitoring.cpuMultiGaugeUpdateData(cpuMultiGauge);
+
+ // Verify that the multi-gauge update method was called
+ verify(cpuMultiGauge, times(1)).register(anyList(), eq(true));
+ }
+
+ @Test
+ void testDiskIOMultiGaugeUpdateData() {
+ AgentHostMonitoring.diskIOMultiGaugeUpdateData(diskIOMultiGauge);
+
+ // Verify that the multi-gauge update method was called
+ verify(diskIOMultiGauge, times(1)).register(anyList(), eq(true));
+ }
+}
diff --git
a/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImplTest.java
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImplTest.java
new file mode 100644
index 00000000..add9773c
--- /dev/null
+++
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/CommandServiceGrpcImplTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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
+ *
+ * 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.apache.bigtop.manager.agent.service;
+
+import org.apache.bigtop.manager.agent.executor.CommandExecutor;
+import org.apache.bigtop.manager.agent.executor.CommandExecutors;
+import org.apache.bigtop.manager.agent.holder.SpringContextHolder;
+import org.apache.bigtop.manager.grpc.generated.CommandReply;
+import org.apache.bigtop.manager.grpc.generated.CommandRequest;
+import org.apache.bigtop.manager.grpc.generated.CommandType;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.context.ApplicationContext;
+
+import io.grpc.StatusRuntimeException;
+import io.grpc.stub.StreamObserver;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class CommandServiceGrpcImplTest {
+
+ private CommandServiceGrpcImpl commandServiceGrpc;
+
+ @BeforeEach
+ public void setUp() {
+ SpringContextHolder springContextHolder = new SpringContextHolder();
+ ApplicationContext mockApplicationContext =
mock(ApplicationContext.class);
+
+ CommandExecutor mockExecutor = mock(CommandExecutor.class);
+ lenient()
+
.when(mockApplicationContext.getBeansOfType(CommandExecutor.class))
+ .thenReturn(Map.of("mockExecutor", mockExecutor));
+
+ springContextHolder.setApplicationContext(mockApplicationContext);
+
+ // Initialize CommandServiceGrpcImpl
+ commandServiceGrpc = new CommandServiceGrpcImpl();
+ }
+
+ @Test
+ public void testExecCommand() {
+ // Arrange
+ CommandRequest request = CommandRequest.newBuilder()
+ .setPayload("Test Payload")
+ .setTaskId(1L)
+ .setType(CommandType.COMPONENT)
+ .build();
+
+ CommandReply expectedReply = CommandReply.newBuilder()
+ .setCode(0)
+ .setResult("Success")
+ .setTaskId(1L)
+ .build();
+
+ CommandExecutor mockExecutor = mock(CommandExecutor.class);
+
when(CommandExecutors.getCommandExecutor(CommandType.COMPONENT)).thenReturn(mockExecutor);
+ when(mockExecutor.execute(request)).thenReturn(expectedReply);
+
+ StreamObserver<CommandReply> responseObserver =
mock(StreamObserver.class);
+ ArgumentCaptor<CommandReply> captor =
ArgumentCaptor.forClass(CommandReply.class);
+
+ // Act
+ commandServiceGrpc.exec(request, responseObserver);
+
+ // Assert
+ verify(responseObserver).onNext(captor.capture());
+ verify(responseObserver).onCompleted();
+
+ CommandReply actualReply = captor.getValue();
+ assertEquals(expectedReply.getCode(), actualReply.getCode());
+ assertEquals(expectedReply.getResult(), actualReply.getResult());
+ assertEquals(expectedReply.getTaskId(), actualReply.getTaskId());
+ }
+
+ @Test
+ public void testExecCommandExecutorThrowsException() {
+ // Arrange
+ CommandRequest request = CommandRequest.newBuilder()
+ .setPayload("Test Payload")
+ .setTaskId(1L)
+ .setType(CommandType.COMPONENT)
+ .build();
+
+ when(CommandExecutors.getCommandExecutor(CommandType.COMPONENT))
+ .thenThrow(new RuntimeException("Executor not found"));
+
+ StreamObserver<CommandReply> responseObserver =
mock(StreamObserver.class);
+
+ // Act
+ commandServiceGrpc.exec(request, responseObserver);
+
+ // Assert
+ verify(responseObserver).onError(any(RuntimeException.class));
+ }
+
+ @Test
+ public void testExecCommandExecutionThrowsException() {
+ // Arrange
+ CommandRequest request = CommandRequest.newBuilder()
+ .setPayload("Test Payload")
+ .setTaskId(1L)
+ .setType(CommandType.COMPONENT)
+ .build();
+
+ CommandExecutor mockExecutor = mock(CommandExecutor.class);
+
when(CommandExecutors.getCommandExecutor(CommandType.COMPONENT)).thenReturn(mockExecutor);
+ when(mockExecutor.execute(request)).thenThrow(new
RuntimeException("Execution failed"));
+
+ StreamObserver<CommandReply> responseObserver =
mock(StreamObserver.class);
+
+ // Act
+ commandServiceGrpc.exec(request, responseObserver);
+
+ // Assert
+ verify(responseObserver).onError(any(RuntimeException.class));
+ }
+
+ @Test
+ public void testExecCommandLogFileOperationFails() {
+ // Arrange
+ CommandRequest request = CommandRequest.newBuilder()
+ .setPayload("Test Payload")
+ .setTaskId(1L)
+ .setType(CommandType.COMPONENT)
+ .build();
+
+ CommandReply expectedReply = CommandReply.newBuilder()
+ .setCode(1)
+ .setResult("File operation failed")
+ .setTaskId(1L)
+ .build();
+
+ CommandExecutor mockExecutor = mock(CommandExecutor.class);
+ lenient()
+
.when(CommandExecutors.getCommandExecutor(CommandType.COMPONENT))
+ .thenReturn(mockExecutor);
+
lenient().when(mockExecutor.execute(request)).thenReturn(expectedReply);
+
+ StreamObserver<CommandReply> responseObserver =
mock(StreamObserver.class);
+
+ // Mock truncateLogFile to throw an exception
+ CommandServiceGrpcImpl commandServiceGrpcSpy = spy(commandServiceGrpc);
+ doThrow(new RuntimeException("File operation failed"))
+ .when(commandServiceGrpcSpy)
+ .truncateLogFile(anyLong());
+
+ // Act
+ commandServiceGrpcSpy.exec(request, responseObserver);
+
+ // Assert
+ verify(responseObserver, never()).onCompleted();
+ verify(responseObserver).onError(any(StatusRuntimeException.class));
+ }
+
+ @Test
+ public void testExecCommandResponseObserverThrowsException() {
+ // Arrange
+ CommandRequest request = CommandRequest.newBuilder()
+ .setPayload("Test Payload")
+ .setTaskId(1L)
+ .setType(CommandType.COMPONENT)
+ .build();
+
+ CommandReply expectedReply = CommandReply.newBuilder()
+ .setCode(0)
+ .setResult("Success")
+ .setTaskId(1L)
+ .build();
+
+ CommandExecutor mockExecutor = mock(CommandExecutor.class);
+ lenient()
+
.when(CommandExecutors.getCommandExecutor(CommandType.COMPONENT))
+ .thenReturn(mockExecutor);
+
lenient().when(mockExecutor.execute(request)).thenReturn(expectedReply);
+
+ StreamObserver<CommandReply> responseObserver =
mock(StreamObserver.class);
+ doThrow(new RuntimeException("Observer
failed")).when(responseObserver).onNext(any());
+
+ // Act
+ commandServiceGrpc.exec(request, responseObserver);
+
+ // Assert
+ verify(responseObserver, never()).onCompleted(); // Ensure onCompleted
is not called
+ verify(responseObserver).onError(any(StatusRuntimeException.class));
+ }
+}
diff --git
a/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/ComponentStatusServiceGrpcImplTest.java
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/ComponentStatusServiceGrpcImplTest.java
new file mode 100644
index 00000000..5b9b2a2f
--- /dev/null
+++
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/ComponentStatusServiceGrpcImplTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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
+ *
+ * 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.apache.bigtop.manager.agent.service;
+
+import org.apache.bigtop.manager.common.message.entity.payload.CommandPayload;
+import org.apache.bigtop.manager.common.shell.ShellResult;
+import org.apache.bigtop.manager.grpc.generated.ComponentStatusReply;
+import org.apache.bigtop.manager.grpc.generated.ComponentStatusRequest;
+import org.apache.bigtop.manager.stack.core.executor.StackExecutor;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import io.grpc.Status;
+import io.grpc.StatusRuntimeException;
+import io.grpc.stub.StreamObserver;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentStatusServiceGrpcImplTest {
+
+ private final ComponentStatusServiceGrpcImpl service = new
ComponentStatusServiceGrpcImpl();
+
+ @Test
+ public void testGetComponentStatusSuccess() {
+ try (MockedStatic<StackExecutor> mockedStatic =
mockStatic(StackExecutor.class)) {
+ // Arrange
+ ComponentStatusRequest request =
ComponentStatusRequest.newBuilder()
+ .setStackName("TestStack")
+ .setStackVersion("1.0")
+ .setServiceName("TestService")
+ .setServiceUser("TestUser")
+ .setComponentName("TestComponent")
+ .build();
+
+ ShellResult shellResult = new ShellResult();
+ shellResult.setExitCode(0);
+
+ // Mock StackExecutor
+ mockedStatic
+ .when(() ->
StackExecutor.execute(any(CommandPayload.class)))
+ .thenReturn(shellResult);
+
+ StreamObserver<ComponentStatusReply> responseObserver =
mock(StreamObserver.class);
+ ArgumentCaptor<ComponentStatusReply> captor =
ArgumentCaptor.forClass(ComponentStatusReply.class);
+
+ // Act
+ service.getComponentStatus(request, responseObserver);
+
+ // Assert
+ verify(responseObserver).onNext(captor.capture());
+ verify(responseObserver).onCompleted();
+
+ ComponentStatusReply reply = captor.getValue();
+ assertEquals(0, reply.getStatus());
+ }
+ }
+
+ @Test
+ public void testGetComponentStatusExecutionFailure() {
+ try (MockedStatic<StackExecutor> mockedStatic =
mockStatic(StackExecutor.class)) {
+ // Arrange
+ ComponentStatusRequest request =
ComponentStatusRequest.newBuilder()
+ .setStackName("TestStack")
+ .setStackVersion("1.0")
+ .setServiceName("TestService")
+ .setServiceUser("TestUser")
+ .setComponentName("TestComponent")
+ .build();
+
+ // Mock StackExecutor to throw an exception
+ mockedStatic
+ .when(() ->
StackExecutor.execute(any(CommandPayload.class)))
+ .thenThrow(new RuntimeException("Execution failed"));
+
+ StreamObserver<ComponentStatusReply> responseObserver =
mock(StreamObserver.class);
+
+ // Act
+ service.getComponentStatus(request, responseObserver);
+
+ // Assert
+
verify(responseObserver).onError(any(StatusRuntimeException.class));
+
+ // Capture the exception and verify its message
+ ArgumentCaptor<Throwable> captor =
ArgumentCaptor.forClass(Throwable.class);
+ verify(responseObserver).onError(captor.capture());
+
+ // Get the captured exception
+ Throwable actualException = captor.getValue();
+
+ // Check if it is an instance of StatusRuntimeException
+ assertInstanceOf(StatusRuntimeException.class, actualException,
"Expected StatusRuntimeException");
+
+ StatusRuntimeException statusRuntimeException =
(StatusRuntimeException) actualException;
+
+ // Check that the status code is UNKNOWN and the message contains
the expected error message
+ assertEquals(
+ Status.UNKNOWN.getCode(),
statusRuntimeException.getStatus().getCode());
+ assertTrue(statusRuntimeException.getMessage().contains("Execution
failed"));
+ }
+ }
+}
diff --git
a/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/HostInfoServiceGrpcImplTest.java
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/HostInfoServiceGrpcImplTest.java
new file mode 100644
index 00000000..2c4b87e9
--- /dev/null
+++
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/HostInfoServiceGrpcImplTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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
+ *
+ * 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.apache.bigtop.manager.agent.service;
+
+import org.apache.bigtop.manager.common.utils.os.OSDetection;
+import org.apache.bigtop.manager.grpc.generated.HostInfoReply;
+import org.apache.bigtop.manager.grpc.generated.HostInfoRequest;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.sun.management.OperatingSystemMXBean;
+import io.grpc.StatusRuntimeException;
+import io.grpc.stub.StreamObserver;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class HostInfoServiceGrpcImplTest {
+
+ @InjectMocks
+ private HostInfoServiceGrpcImpl service;
+
+ @Test
+ public void testGetHostInfoSuccess() {
+ // Arrange
+ HostInfoRequest request = HostInfoRequest.newBuilder().build();
+
+ // Mock InetAddress
+ InetAddress mockInetAddress = mock(InetAddress.class);
+ lenient().when(mockInetAddress.getHostName()).thenReturn("localhost");
+
lenient().when(mockInetAddress.getHostAddress()).thenReturn("192.168.0.100");
+
+ // Mock static methods of OSDetection using MockedStatic
+ try (MockedStatic<OSDetection> mockedStatic =
mockStatic(OSDetection.class);
+ MockedStatic<ManagementFactory> mockManagementFactory =
mockStatic(ManagementFactory.class)) {
+ long oneGBInBytes = 1024L * 1024L * 1024L;
+ long freeDiskInBytes = 100L * oneGBInBytes;
+ long totalDiskInBytes = 500L * oneGBInBytes;
+ // Mock static methods for disk size
+
mockedStatic.when(OSDetection::freeDisk).thenReturn(freeDiskInBytes);
+
mockedStatic.when(OSDetection::totalDisk).thenReturn(totalDiskInBytes);
+
+ // Mock OSDetection static methods for OS, version, and arch
+ mockedStatic.when(OSDetection::getOS).thenReturn("Linux");
+ mockedStatic.when(OSDetection::getVersion).thenReturn("1.0");
+ mockedStatic.when(OSDetection::getArch).thenReturn("x86_64");
+
+ // Mock OperatingSystemMXBean methods
+ OperatingSystemMXBean mockOsBean =
mock(OperatingSystemMXBean.class);
+ mockManagementFactory
+ .when(ManagementFactory::getOperatingSystemMXBean)
+ .thenReturn(mockOsBean);
+ when(mockOsBean.getAvailableProcessors()).thenReturn(4);
+ when(mockOsBean.getProcessCpuTime()).thenReturn(100L);
+ when(mockOsBean.getTotalMemorySize()).thenReturn(1024L * 1024 *
1024);
+ when(mockOsBean.getFreeMemorySize()).thenReturn(512L * 1024 *
1024);
+ when(mockOsBean.getTotalSwapSpaceSize()).thenReturn(2048L * 1024 *
1024);
+ when(mockOsBean.getFreeSwapSpaceSize()).thenReturn(1024L * 1024 *
1024);
+ when(mockOsBean.getCommittedVirtualMemorySize()).thenReturn(4096L
* 1024 * 1024);
+ when(mockOsBean.getCpuLoad()).thenReturn(0.75);
+ when(mockOsBean.getProcessCpuLoad()).thenReturn(0.50);
+ when(mockOsBean.getSystemLoadAverage()).thenReturn(1.5);
+
+ StreamObserver<HostInfoReply> mockResponseObserver =
mock(StreamObserver.class);
+
+ // Act
+ service.getHostInfo(request, mockResponseObserver);
+
+ // Assert
+ verify(mockResponseObserver).onNext(any(HostInfoReply.class));
+ verify(mockResponseObserver).onCompleted();
+ }
+ }
+
+ @Test
+ public void testGetHostInfoFailure() {
+ // Arrange
+ HostInfoRequest request = HostInfoRequest.newBuilder().build();
+
+ try (MockedStatic<InetAddress> mockInetAddress =
mockStatic(InetAddress.class)) {
+ // Simulate an exception during execution
+ mockInetAddress.when(InetAddress::getLocalHost).thenThrow(new
RuntimeException("Network error"));
+
+ StreamObserver<HostInfoReply> mockResponseObserver =
mock(StreamObserver.class);
+
+ // Act
+ service.getHostInfo(request, mockResponseObserver);
+
+ // Assert
+
verify(mockResponseObserver).onError(any(StatusRuntimeException.class));
+ }
+ }
+}
diff --git
a/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/JobCacheServiceGrpcImplTest.java
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/JobCacheServiceGrpcImplTest.java
new file mode 100644
index 00000000..61e13878
--- /dev/null
+++
b/bigtop-manager-agent/src/test/java/org/apache/bigtop/manager/agent/service/JobCacheServiceGrpcImplTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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
+ *
+ * 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.apache.bigtop.manager.agent.service;
+
+import org.apache.bigtop.manager.common.utils.ProjectPathUtils;
+import org.apache.bigtop.manager.grpc.generated.JobCacheReply;
+import org.apache.bigtop.manager.grpc.generated.JobCacheRequest;
+
+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.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import io.grpc.stub.StreamObserver;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+
+@ExtendWith(MockitoExtension.class)
+public class JobCacheServiceGrpcImplTest {
+
+ private JobCacheServiceGrpcImpl jobCacheServiceGrpcImpl;
+
+ @Mock
+ private StreamObserver<JobCacheReply> responseObserver;
+
+ @BeforeEach
+ public void setUp() {
+ // Initialize mock objects
+ jobCacheServiceGrpcImpl = new JobCacheServiceGrpcImpl();
+ }
+
+ @Test
+ public void testSaveSuccess() {
+ // Mock the static behavior of ProjectPathUtils.getAgentCachePath
method
+ try (MockedStatic<ProjectPathUtils> mockedStatic =
mockStatic(ProjectPathUtils.class)) {
+ String cacheDir = "mock/cache/dir";
+
mockedStatic.when(ProjectPathUtils::getAgentCachePath).thenReturn(cacheDir);
+
+ // Construct JobCacheRequest
+ String payloadJson = "{\"configurations\": {\"configKey\":
{\"subKey\": \"subValue\"}}}";
+ JobCacheRequest request = JobCacheRequest.newBuilder()
+ .setJobId(123L)
+ .setPayload(payloadJson)
+ .build();
+
+ // Execute the save method
+ jobCacheServiceGrpcImpl.save(request, responseObserver);
+
+ // Verify that JsonUtils.writeToFile method was called correctly
+ verify(responseObserver).onNext(any(JobCacheReply.class));
+ verify(responseObserver).onCompleted();
+ }
+ }
+
+ @Test
+ public void testSaveDirectoryCreationFailure() {
+ // Mock the static behavior of ProjectPathUtils.getAgentCachePath
method
+ try (MockedStatic<ProjectPathUtils> mockedStatic =
mockStatic(ProjectPathUtils.class)) {
+ String cacheDir = "mock/cache/dir";
+
mockedStatic.when(ProjectPathUtils::getAgentCachePath).thenReturn(cacheDir);
+
+ // Mock Files.createDirectories to throw an exception
+ try (MockedStatic<Files> mockedFiles = mockStatic(Files.class)) {
+ mockedFiles
+ .when(() -> Files.createDirectories(any(Path.class)))
+ .thenThrow(new RuntimeException("Directory creation
failed"));
+
+ // Construct JobCacheRequest
+ String payloadJson = "{\"configurations\": {\"configKey\":
{\"subKey\": \"subValue\"}}}";
+ JobCacheRequest request = JobCacheRequest.newBuilder()
+ .setJobId(123L)
+ .setPayload(payloadJson)
+ .build();
+
+ // Execute the save method, expecting onError to be called
+ jobCacheServiceGrpcImpl.save(request, responseObserver);
+
+ // Verify that onError was called with the expected exception
+ verify(responseObserver).onError(any(RuntimeException.class));
+ }
+ }
+ }
+}