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));
+            }
+        }
+    }
+}


Reply via email to