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 68b888d1 BIGTOP-4392: Add unit test for command stage classes in
server module (#192)
68b888d1 is described below
commit 68b888d1541686b7f58c1f243dccbef06519c1d4
Author: xianrenzw <[email protected]>
AuthorDate: Tue Mar 25 17:10:11 2025 +0800
BIGTOP-4392: Add unit test for command stage classes in server module (#192)
---
.../command/stage/AbstractComponentStage.java | 2 +-
.../server/command/stage/AbstractStage.java | 5 -
.../command/stage/AbstractComponentStageTest.java | 91 ++++
.../command/stage/ComponentAddStageTest.java | 76 +++
.../command/stage/ComponentCheckStageTest.java | 76 +++
.../command/stage/ComponentConfigureStageTest.java | 76 +++
.../command/stage/ComponentInitStageTest.java | 76 +++
.../command/stage/ComponentPrepareStageTest.java | 76 +++
.../server/command/stage/ComponentStageTest.java | 159 ------
.../command/stage/ComponentStartStageTest.java | 76 +++
.../command/stage/ComponentStopStageTest.java | 76 +++
.../server/command/stage/HostCheckStageTest.java | 82 +---
.../server/command/stage/SetupJdkStageTest.java | 82 +---
.../server/command/stage/StageContextTest.java | 189 ++++++++
.../services/kafka/configuration/kafka-broker.xml | 537 +++++++++++++++++++++
.../services/kafka/configuration/kafka-env.xml | 71 +++
.../services/kafka/configuration/kafka-log4j.xml | 143 ++++++
.../services/kafka/configuration/kafka.conf.xml | 54 +++
.../bigtop/3.3.0/services/kafka/metainfo.xml | 63 +++
.../stacks/bigtop/3.3.0/services/kafka/order.json | 8 +
.../services/zookeeper/configuration/zoo.cfg.xml | 128 +++++
.../zookeeper/configuration/zookeeper-env.xml | 58 +++
.../bigtop/3.3.0/services/zookeeper/metainfo.xml | 64 +++
.../bigtop/3.3.0/services/zookeeper/order.json | 5 +
24 files changed, 1980 insertions(+), 293 deletions(-)
diff --git
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java
index 8d35b8d8..ce610b8b 100644
---
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java
+++
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java
@@ -85,7 +85,7 @@ public abstract class AbstractComponentStage extends
AbstractStage {
return taskContext;
}
- private Map<String, List<String>> getClusterHosts() {
+ protected Map<String, List<String>> getClusterHosts() {
Map<String, List<String>> clusterHosts = new HashMap<>();
for (ClusterPO clusterPO : clusterDao.findAll()) {
List<String> hosts = new ArrayList<>();
diff --git
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java
index 15b821cd..47f99871 100644
---
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java
+++
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java
@@ -161,9 +161,4 @@ public abstract class AbstractStage implements Stage {
return stagePO;
}
-
- protected void setStageContextAndTasksForTest(StageContext stageContext,
List<Task> tasks) {
- this.stageContext = stageContext;
- this.tasks = tasks;
- }
}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStageTest.java
new file mode 100644
index 00000000..c921a054
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStageTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.dao.po.ClusterPO;
+import org.apache.bigtop.manager.server.command.task.TaskContext;
+
+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 org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class AbstractComponentStageTest {
+
+ @Mock
+ private AbstractComponentStage stage;
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testCreateTaskContext() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ClusterPO clusterPO = new ClusterPO();
+ clusterPO.setId(1L);
+ clusterPO.setName("test");
+ clusterPO.setRootDir("/opt");
+ clusterPO.setUserGroup("test");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+ ReflectionTestUtils.setField(stage, "clusterPO", clusterPO);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ Map<String, List<String>> componentHosts = new HashMap<>();
+ componentHosts.put("test", List.of("host1"));
+
+ when(stage.getClusterHosts()).thenReturn(componentHosts);
+ doCallRealMethod().when(stage).createTaskContext(any());
+ TaskContext taskContext = stage.createTaskContext("host1");
+
+ assertEquals(1L, taskContext.getClusterId());
+ assertEquals("test", taskContext.getClusterName());
+ assertEquals("zookeeper", taskContext.getServiceName());
+ assertEquals("zookeeper_server", taskContext.getComponentName());
+ assertEquals("ZooKeeper Server",
taskContext.getComponentDisplayName());
+ assertEquals("zookeeper", taskContext.getServiceUser());
+ assertEquals("test", taskContext.getUserGroup());
+ assertEquals("/opt", taskContext.getRootDir());
+
+ Map<String, Object> properties = taskContext.getProperties();
+ Map<String, List<String>> clusterHosts = (Map<String, List<String>>)
properties.get("clusterHosts");
+ assertEquals(1, taskContext.getProperties().size());
+ assertEquals(1, clusterHosts.size());
+ assertEquals("host1", clusterHosts.get("test").get(0));
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentAddStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentAddStageTest.java
new file mode 100644
index 00000000..e2b213e5
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentAddStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentAddTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentAddStageTest {
+
+ @Mock
+ private ComponentAddStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentAddTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentAddTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Add ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentCheckStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentCheckStageTest.java
new file mode 100644
index 00000000..2db9eda9
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentCheckStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentCheckTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentCheckStageTest {
+
+ @Mock
+ private ComponentCheckStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentCheckTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentCheckTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Check ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentConfigureStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentConfigureStageTest.java
new file mode 100644
index 00000000..0967eb0a
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentConfigureStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentConfigureTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentConfigureStageTest {
+
+ @Mock
+ private ComponentConfigureStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentConfigureTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentConfigureTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Configure ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentInitStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentInitStageTest.java
new file mode 100644
index 00000000..9457b703
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentInitStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentInitTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentInitStageTest {
+
+ @Mock
+ private ComponentInitStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentInitTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentInitTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Init ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentPrepareStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentPrepareStageTest.java
new file mode 100644
index 00000000..20339b66
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentPrepareStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentPrepareTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentPrepareStageTest {
+
+ @Mock
+ private ComponentPrepareStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentPrepareTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentPrepareTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Prepare ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStageTest.java
deleted file mode 100644
index c8a19bed..00000000
---
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStageTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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.server.command.stage;
-
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.repository.ClusterDao;
-import org.apache.bigtop.manager.dao.repository.HostDao;
-import org.apache.bigtop.manager.dao.repository.StageDao;
-import org.apache.bigtop.manager.server.command.task.Task;
-import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-
-import org.junit.jupiter.api.AfterEach;
-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.Spy;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.lenient;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@ExtendWith(MockitoExtension.class)
-public class ComponentStageTest {
-
- private MockedStatic<SpringContextHolder> springContextHolderMockedStatic;
-
- @Mock
- private StageDao stageDao;
-
- @Mock
- private HostDao hostDao;
-
- @Mock
- private ClusterDao clusterDao;
-
- @Spy
- private StageContext stageContext;
-
- @Mock
- private List<Task> tasks;
-
- @Spy
- private StagePO stagePO;
-
- private ComponentAddStage componentStage;
-
- @BeforeEach
- public void setUp() {
- springContextHolderMockedStatic =
mockStatic(SpringContextHolder.class);
- when(SpringContextHolder.getBean(StageDao.class)).thenReturn(stageDao);
- when(SpringContextHolder.getBean(HostDao.class)).thenReturn(hostDao);
-
when(SpringContextHolder.getBean(ClusterDao.class)).thenReturn(clusterDao);
-
- componentStage = mock(ComponentAddStage.class);
-
- stageContext.setComponentName("TestComponentName");
- stageContext.setServiceName("TestServiceName");
- stageContext.setClusterId(123L);
-
-
doCallRealMethod().when(componentStage).setStageContextAndTasksForTest(any(),
any());
- componentStage.setStageContextAndTasksForTest(stageContext, tasks);
-
- doCallRealMethod().when(componentStage).injectBeans();
- componentStage.injectBeans();
-
- doCallRealMethod().when(componentStage).loadStagePO(any());
- lenient().when(componentStage.getStagePO()).thenCallRealMethod();
- componentStage.loadStagePO(stagePO);
- }
-
- @AfterEach
- public void tearDown() {
- springContextHolderMockedStatic.close();
- }
-
- @Test
- public void testInjectBeans() {
- springContextHolderMockedStatic.verify(() ->
SpringContextHolder.getBean(any(Class.class)), times(3));
- }
-
- @Test
- public void testBeforeCreateTasks() {
- doCallRealMethod().when(componentStage).beforeCreateTasks();
- componentStage.beforeCreateTasks();
- verify(clusterDao, times(1)).findById(123L);
- }
-
- @Test
- public void tesGetServiceName() {
- doCallRealMethod().when(componentStage).getServiceName();
- assertEquals("TestServiceName", componentStage.getServiceName());
- }
-
- @Test
- public void tesGetComponentName() {
- doCallRealMethod().when(componentStage).getComponentName();
- assertEquals("TestComponentName", componentStage.getComponentName());
- }
-
- @Test
- public void testBeforeRun() {
- doCallRealMethod().when(componentStage).beforeRun();
- componentStage.beforeRun();
- verify(stageDao, times(1)).partialUpdateById(any());
- }
-
- @Test
- public void testOnSuccess() {
- doCallRealMethod().when(componentStage).onSuccess();
- componentStage.onSuccess();
- verify(stageDao, times(1)).partialUpdateById(any());
- }
-
- @Test
- public void testOnFailure() {
- doCallRealMethod().when(componentStage).onFailure();
- componentStage.onFailure();
- verify(stageDao, times(1)).partialUpdateById(any());
- }
-
- @Test
- public void testGetStageContext() {
- doCallRealMethod().when(componentStage).getStageContext();
- assertEquals(stageContext, componentStage.getStageContext());
- }
-
- @Test
- public void testGetTasks() {
- doCallRealMethod().when(componentStage).getTasks();
- assertEquals(tasks, componentStage.getTasks());
- }
-}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStartStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStartStageTest.java
new file mode 100644
index 00000000..d625e8e8
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStartStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentStartTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentStartStageTest {
+
+ @Mock
+ private ComponentStartStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentStartTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentStartTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Start ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStopStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStopStageTest.java
new file mode 100644
index 00000000..de6e0b54
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/ComponentStopStageTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.common.utils.Environments;
+import org.apache.bigtop.manager.server.command.task.ComponentStopTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ComponentStopStageTest {
+
+ @Mock
+ private ComponentStopStage stage;
+
+ @Test
+ public void testCreateTask() {
+ MockedConstruction<?> mocked =
mockConstruction(ComponentStopTask.class);
+
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
+
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(ComponentStopTask.class, task);
+
+ mocked.close();
+ }
+
+ @Test
+ public void testGetName() {
+ StageContext stageContext = new StageContext();
+ stageContext.setServiceName("zookeeper");
+ stageContext.setComponentName("zookeeper_server");
+
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
+
+ MockedStatic<Environments> mocked = mockStatic(Environments.class);
+ when(Environments.isDevMode()).thenReturn(true);
+
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Stop ZooKeeper Server", stage.getName());
+
+ mocked.close();
+ }
+}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/HostCheckStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/HostCheckStageTest.java
index 317ccd82..285d47ed 100644
---
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/HostCheckStageTest.java
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/HostCheckStageTest.java
@@ -18,93 +18,47 @@
*/
package org.apache.bigtop.manager.server.command.stage;
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.repository.HostDao;
-import org.apache.bigtop.manager.dao.repository.StageDao;
+import org.apache.bigtop.manager.server.command.task.HostCheckTask;
import org.apache.bigtop.manager.server.command.task.Task;
-import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.junit.jupiter.api.AfterEach;
-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.Spy;
+import org.mockito.MockedConstruction;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.lenient;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mockConstruction;
@ExtendWith(MockitoExtension.class)
public class HostCheckStageTest {
- private MockedStatic<SpringContextHolder> springContextHolderMockedStatic;
-
@Mock
- private StageDao stageDao;
-
- @Mock
- private HostDao hostDao;
-
- @Spy
- private StageContext stageContext;
-
- @Mock
- private List<Task> tasks;
-
- @Spy
- private StagePO stagePO;
-
- private HostCheckStage hostCheckStage;
+ private HostCheckStage stage;
- @BeforeEach
- public void setUp() {
- springContextHolderMockedStatic =
mockStatic(SpringContextHolder.class);
- when(SpringContextHolder.getBean(StageDao.class)).thenReturn(stageDao);
- when(SpringContextHolder.getBean(HostDao.class)).thenReturn(hostDao);
-
- hostCheckStage = mock(HostCheckStage.class);
+ @Test
+ public void testCreateTask() {
+ StageContext stageContext = new StageContext();
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
-
doCallRealMethod().when(hostCheckStage).setStageContextAndTasksForTest(any(),
any());
- hostCheckStage.setStageContextAndTasksForTest(stageContext, tasks);
+ MockedConstruction<?> mocked = mockConstruction(HostCheckTask.class);
- doCallRealMethod().when(hostCheckStage).injectBeans();
- hostCheckStage.injectBeans();
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
- doCallRealMethod().when(hostCheckStage).loadStagePO(any());
- lenient().when(hostCheckStage.getStagePO()).thenCallRealMethod();
- hostCheckStage.loadStagePO(stagePO);
- }
-
- @AfterEach
- public void tearDown() {
- springContextHolderMockedStatic.close();
- }
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(HostCheckTask.class, task);
- @Test
- public void testInjectBeans() {
- springContextHolderMockedStatic.verify(() ->
SpringContextHolder.getBean(any(Class.class)), times(2));
- }
-
- @Test
- public void testBeforeCreateTasks() {
- doCallRealMethod().when(hostCheckStage).beforeCreateTasks();
- assertDoesNotThrow(() -> hostCheckStage.beforeCreateTasks());
+ mocked.close();
}
@Test
public void tesGetName() {
- doCallRealMethod().when(hostCheckStage).getName();
- assertEquals("Check hosts", hostCheckStage.getName());
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Check hosts", stage.getName());
}
}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/SetupJdkStageTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/SetupJdkStageTest.java
index 0c18be92..3f11cf8f 100644
---
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/SetupJdkStageTest.java
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/SetupJdkStageTest.java
@@ -18,93 +18,47 @@
*/
package org.apache.bigtop.manager.server.command.stage;
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.repository.HostDao;
-import org.apache.bigtop.manager.dao.repository.StageDao;
+import org.apache.bigtop.manager.server.command.task.SetupJdkTask;
import org.apache.bigtop.manager.server.command.task.Task;
-import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.junit.jupiter.api.AfterEach;
-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.Spy;
+import org.mockito.MockedConstruction;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.lenient;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mockConstruction;
@ExtendWith(MockitoExtension.class)
public class SetupJdkStageTest {
- private MockedStatic<SpringContextHolder> springContextHolderMockedStatic;
-
@Mock
- private StageDao stageDao;
-
- @Mock
- private HostDao hostDao;
-
- @Spy
- private StageContext stageContext;
-
- @Mock
- private List<Task> tasks;
-
- @Spy
- private StagePO stagePO;
-
- private SetupJdkStage setupJdkStage;
+ private SetupJdkStage stage;
- @BeforeEach
- public void setUp() {
- springContextHolderMockedStatic =
mockStatic(SpringContextHolder.class);
- when(SpringContextHolder.getBean(StageDao.class)).thenReturn(stageDao);
- when(SpringContextHolder.getBean(HostDao.class)).thenReturn(hostDao);
-
- setupJdkStage = mock(SetupJdkStage.class);
+ @Test
+ public void testCreateTask() {
+ StageContext stageContext = new StageContext();
+ ReflectionTestUtils.setField(stage, "stageContext", stageContext);
-
doCallRealMethod().when(setupJdkStage).setStageContextAndTasksForTest(any(),
any());
- setupJdkStage.setStageContextAndTasksForTest(stageContext, tasks);
+ MockedConstruction<?> mocked = mockConstruction(SetupJdkTask.class);
- doCallRealMethod().when(setupJdkStage).injectBeans();
- setupJdkStage.injectBeans();
+ doCallRealMethod().when(stage).createTask(any());
+ Task task = stage.createTask("host1");
- doCallRealMethod().when(setupJdkStage).loadStagePO(any());
- lenient().when(setupJdkStage.getStagePO()).thenCallRealMethod();
- setupJdkStage.loadStagePO(stagePO);
- }
-
- @AfterEach
- public void tearDown() {
- springContextHolderMockedStatic.close();
- }
+ assertEquals(1, mocked.constructed().size());
+ assertInstanceOf(SetupJdkTask.class, task);
- @Test
- public void testInjectBeans() {
- springContextHolderMockedStatic.verify(() ->
SpringContextHolder.getBean(any(Class.class)), times(2));
- }
-
- @Test
- public void testBeforeCreateTasks() {
- doCallRealMethod().when(setupJdkStage).beforeCreateTasks();
- assertDoesNotThrow(() -> setupJdkStage.beforeCreateTasks());
+ mocked.close();
}
@Test
public void tesGetName() {
- doCallRealMethod().when(setupJdkStage).getName();
- assertEquals("Setup JDK", setupJdkStage.getName());
+ doCallRealMethod().when(stage).getName();
+ assertEquals("Setup JDK", stage.getName());
}
}
diff --git
a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/StageContextTest.java
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/StageContextTest.java
new file mode 100644
index 00000000..5745f138
--- /dev/null
+++
b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/command/stage/StageContextTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.server.command.stage;
+
+import org.apache.bigtop.manager.dao.po.ClusterPO;
+import org.apache.bigtop.manager.dao.repository.ClusterDao;
+import org.apache.bigtop.manager.server.enums.CommandLevel;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+import org.apache.bigtop.manager.server.model.dto.HostDTO;
+import org.apache.bigtop.manager.server.model.dto.command.ClusterCommandDTO;
+import org.apache.bigtop.manager.server.model.dto.command.HostCommandDTO;
+
+import org.junit.jupiter.api.AfterEach;
+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 java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class StageContextTest {
+
+ @Mock
+ private ClusterDao clusterDao;
+
+ private MockedStatic<SpringContextHolder> springContextHolderMockedStatic;
+
+ @BeforeEach
+ void setUp() {
+ springContextHolderMockedStatic =
mockStatic(SpringContextHolder.class);
+
when(SpringContextHolder.getBean(ClusterDao.class)).thenReturn(clusterDao);
+ }
+
+ @AfterEach
+ void tearDown() {
+ springContextHolderMockedStatic.close();
+ }
+
+ @Test
+ void testWithClusterIdAndClusterCommand() {
+ // Mock database cluster info
+ ClusterPO mockCluster = new ClusterPO();
+ mockCluster.setId(1L);
+ mockCluster.setName("test-cluster");
+ mockCluster.setUserGroup("test-user-group");
+ mockCluster.setRootDir("/data/bigtop");
+ when(clusterDao.findById(1L)).thenReturn(mockCluster);
+
+ // Create test HostDTOs
+ HostDTO host1 = new HostDTO();
+ host1.setHostnames(List.of("host1.example.com"));
+ HostDTO host2 = new HostDTO();
+ host2.setHostnames(List.of("host2.example.com"));
+
+ // Build CLUSTER-level command
+ ClusterCommandDTO clusterCommand = new ClusterCommandDTO();
+ clusterCommand.setHosts(List.of(host1, host2));
+ clusterCommand.setName("should-not-use-this-name");
+ clusterCommand.setUserGroup("should-not-use-this-group");
+ clusterCommand.setRootDir("/should/not/use/this");
+
+ CommandDTO commandDTO = new CommandDTO();
+ commandDTO.setClusterId(1L);
+ commandDTO.setCommandLevel(CommandLevel.CLUSTER);
+ commandDTO.setClusterCommand(clusterCommand);
+
+ // Execute conversion
+ StageContext context = StageContext.fromCommandDTO(commandDTO);
+
+ // Verify cluster info comes from database
+ assertEquals(1L, context.getClusterId());
+ assertEquals("test-cluster", context.getClusterName());
+ assertEquals("test-user-group", context.getUserGroup());
+ assertEquals("/data/bigtop", context.getRootDir());
+
+ // Verify hostnames not set (skip processing when clusterId exists)
+ assertNull(context.getHostnames());
+
+ // Ensure redundant command info is not used
+ assertEquals("test-cluster", context.getClusterName());
+ }
+
+ @Test
+ void testClusterCommandWithoutClusterId() {
+ // Create test HostDTOs
+ HostDTO host1 = new HostDTO();
+ host1.setHostnames(List.of("hostA.example.com"));
+ HostDTO host2 = new HostDTO();
+ host2.setHostnames(List.of("hostB.example.com"));
+
+ // Build CLUSTER-level command (no clusterId)
+ ClusterCommandDTO clusterCommand = new ClusterCommandDTO();
+ clusterCommand.setHosts(List.of(host1, host2));
+ clusterCommand.setName("new-cluster");
+ clusterCommand.setUserGroup("new-group");
+ clusterCommand.setRootDir("/new/root");
+
+ CommandDTO commandDTO = new CommandDTO();
+ commandDTO.setClusterId(null);
+ commandDTO.setCommandLevel(CommandLevel.CLUSTER);
+ commandDTO.setClusterCommand(clusterCommand);
+
+ // Execute conversion
+ StageContext context = StageContext.fromCommandDTO(commandDTO);
+
+ // Verify info comes from command payload
+ assertNull(context.getClusterId());
+ assertEquals(List.of("hostA.example.com", "hostB.example.com"),
context.getHostnames());
+ assertEquals("new-cluster", context.getClusterName());
+ assertEquals("new-group", context.getUserGroup());
+ assertEquals("/new/root", context.getRootDir());
+ }
+
+ @Test
+ void testHostCommand() {
+ // Create HostCommandDTO test objects
+ HostCommandDTO host1 = new HostCommandDTO();
+ host1.setHostnames(List.of("host-01.example.com",
"host-01-alias.example.com"));
+ HostCommandDTO host2 = new HostCommandDTO();
+ host2.setHostnames(List.of("host-02.example.com"));
+
+ CommandDTO commandDTO = new CommandDTO();
+ commandDTO.setCommandLevel(CommandLevel.HOST);
+ commandDTO.setHostCommands(List.of(host1, host2));
+
+ // Execute conversion
+ StageContext context = StageContext.fromCommandDTO(commandDTO);
+
+ // Verify merged hostnames
+ assertEquals(
+ List.of("host-01.example.com", "host-01-alias.example.com",
"host-02.example.com"),
+ context.getHostnames());
+
+ // Verify other fields not set
+ assertNull(context.getClusterId());
+ assertNull(context.getClusterName());
+ }
+
+ @Test
+ void testServiceCommand() {
+ // Build SERVICE-level command
+ CommandDTO commandDTO = new CommandDTO();
+ commandDTO.setCommandLevel(CommandLevel.SERVICE);
+
+ StageContext context = StageContext.fromCommandDTO(commandDTO);
+
+ // Verify no other fields set
+ assertNull(context.getClusterId());
+ assertNull(context.getHostnames());
+ }
+
+ @Test
+ void testComponentCommand() {
+ // Build component level command
+ CommandDTO commandDTO = new CommandDTO();
+ commandDTO.setCommandLevel(CommandLevel.COMPONENT);
+
+ StageContext context = StageContext.fromCommandDTO(commandDTO);
+
+ // Verify no other fields set
+ assertNull(context.getClusterId());
+ assertNull(context.getHostnames());
+ }
+}
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-broker.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-broker.xml
new file mode 100644
index 00000000..2e915dc9
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-broker.xml
@@ -0,0 +1,537 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<configuration>
+ <property>
+ <name>log.dirs</name>
+ <display-name>Log directories</display-name>
+ <value>/kafka-logs</value>
+ <description>
+ A comma-separated list of one or more directories in which Kafka
data is stored.
+ Each new partition that is created will be placed in the directory
which currently has the fewest
+ partitions.
+ </description>
+ </property>
+ <property>
+ <name>zookeeper.connect</name>
+ <value><![CDATA[<#if zk_server_list?? ><#list zk_server_list as
host>${host}:2181<#sep>,</#sep></#list><#else>localhost:2181</#if>]]></value>
+ <description>
+ Zookeeper also allows you to add a "chroot" path which will make
all kafka data for this cluster appear
+ under a particular path.
+ This is a way to setup multiple Kafka clusters or other
applications on the same zookeeper cluster.
+ To do this give a connection string in the form
hostname1:port1,hostname2:port2,hostname3:port3/chroot/path
+ which would put all this cluster's data under the path
/chroot/path. Note that consumers must use the same
+ connection string.
+ </description>
+ </property>
+ <property>
+ <name>listeners</name>
+ <value><![CDATA[PLAINTEXT://<#if host??
>${host}:9092<#else>localhost:9092</#if>]]></value>
+ <description>
+ host and port where kafka broker will be accepting connections.
localhost will be substituted with hostname.
+ </description>
+ </property>
+ <property>
+ <name>advertised.listeners</name>
+ <value><![CDATA[PLAINTEXT://<#if host??
>${host}:9092<#else>localhost:9092</#if>]]></value>
+ <description>
+ Listeners to publish to ZooKeeper for clients to use, if different
than the listeners config property.
+ </description>
+ </property>
+ <property>
+ <name>message.max.bytes</name>
+ <value>1000000</value>
+ <description>
+ The maximum size of a message that the server can receive.
+ It is important that this property be in sync with the maximum
fetch size your consumers use or
+ else an unruly producer will be able to publish messages too large
for consumers to consume.
+ </description>
+ </property>
+ <property>
+ <name>num.network.threads</name>
+ <value>3</value>
+ <description>
+ The number of network threads that the server uses for handling
network requests.
+ You probably don't need to change this.
+ </description>
+ </property>
+ <property>
+ <name>num.io.threads</name>
+ <value>8</value>
+ <description>
+ The number of I/O threads that the server uses for executing
requests. You should have at least as many
+ threads as you have disks.
+ </description>
+ </property>
+ <property>
+ <name>queued.max.requests</name>
+ <value>500</value>
+ <description>
+ The number of requests that can be queued up for processing by the
I/O threads before the network threads
+ stop reading in new requests.
+ </description>
+ </property>
+ <property>
+ <name>socket.send.buffer.bytes</name>
+ <value>102400</value>
+ <description>The SO_SNDBUFF buffer the server prefers for socket
connections.</description>
+ </property>
+ <property>
+ <name>socket.receive.buffer.bytes</name>
+ <value>102400</value>
+ <description>The SO_RCVBUFF buffer the server prefers for socket
connections.</description>
+ </property>
+ <property>
+ <name>socket.request.max.bytes</name>
+ <value>104857600</value>
+ <description>
+ The maximum request size the server will allow. This prevents the
server from running out of memory and
+ should be smaller than the Java heap size.
+ </description>
+ </property>
+ <property>
+ <name>num.partitions</name>
+ <value>1</value>
+ <description>The default number of partitions per topic.</description>
+ </property>
+ <property>
+ <name>log.segment.bytes</name>
+ <value>1073741824</value>
+ <description>
+ The maximum request size the server will allow.
+ This prevents the server from running out of memory and should be
smaller than the Java heap size.
+ </description>
+ </property>
+ <property>
+ <name>log.roll.hours</name>
+ <value>168</value>
+ <description>
+ This setting will force Kafka to roll a new log segment even if
the log.segment.bytes size has not been
+ reached.
+ </description>
+ </property>
+ <property>
+ <name>log.retention.bytes</name>
+ <value>-1</value>
+ <description>
+ The amount of data to retain in the log for each topic-partitions.
Note that this is the limit per-partition
+ so multiply by the number of partitions to get the total data
retained for the topic.
+ Also note that if both log.retention.hours and log.retention.bytes
are both set we delete a segment when
+ either limit is exceeded.
+ </description>
+ </property>
+ <property>
+ <name>log.retention.hours</name>
+ <value>168</value>
+ <description>
+ The number of hours to keep a log segment before it is deleted,
i.e. the default data retention window for
+ all topics.
+ Note that if both log.retention.hours and log.retention.bytes are
both set we delete a segment when either
+ limit is exceeded.
+ </description>
+ </property>
+ <property>
+ <name>log.cleanup.interval.mins</name>
+ <value>10</value>
+ <description>
+ The frequency in minutes that the log cleaner checks whether any
log segment is eligible for deletion to
+ meet the retention policies.
+ </description>
+ </property>
+ <property>
+ <name>log.retention.check.interval.ms</name>
+ <value>600000</value>
+ <description>
+ The frequency in milliseconds that the log cleaner checks whether
any log segment is eligible for deletion
+ to meet the retention policies.
+ </description>
+ </property>
+ <property>
+ <name>log.index.size.max.bytes</name>
+ <value>10485760</value>
+ <description>
+ The maximum size in bytes we allow for the offset index for each
log segment.
+ Note that we will always pre-allocate a sparse file with this much
space and shrink it down when the log
+ rolls.
+ If the index fills up we will roll a new log segment even if we
haven't reached the log.segment.bytes limit.
+ </description>
+ </property>
+ <property>
+ <name>log.index.interval.bytes</name>
+ <value>4096</value>
+ <description>
+ The byte interval at which we add an entry to the offset index.
+ When executing a fetch request the server must do a linear scan
for up to this many bytes to find the
+ correct position in the log to begin and end the fetch.
+ So setting this value to be larger will mean larger index files
(and a bit more memory usage) but less
+ scanning.
+ However the server will never add more than one index entry per
log append (even if more than
+ log.index.interval worth of messages are appended).
+ In general you probably don't need to mess with this value.
+ </description>
+ </property>
+ <property>
+ <name>auto.create.topics.enable</name>
+ <value>true</value>
+ <description>
+ Enable auto creation of topic on the server.
+ If this is set to true then attempts to produce, consume, or fetch
metadata for a non-existent topic will
+ automatically create it with the default replication factor and
number of partitions.
+ </description>
+ </property>
+ <property>
+ <name>controller.socket.timeout.ms</name>
+ <value>30000</value>
+ <description>
+ The socket timeout for commands from the partition management
controller to the replicas.
+ </description>
+ </property>
+ <property>
+ <name>controller.message.queue.size</name>
+ <value>10</value>
+ <description>The buffer size for
controller-to-broker-channels</description>
+ </property>
+ <property>
+ <name>default.replication.factor</name>
+ <value>1</value>
+ <description>The default replication factor for automatically created
topics.</description>
+ </property>
+ <property>
+ <name>replica.lag.time.max.ms</name>
+ <value>10000</value>
+ <description>
+ If a follower hasn't sent any fetch requests for this window of
time, the leader will remove the follower
+ from ISR (in-sync replicas) and treat it as dead.
+ </description>
+ </property>
+ <property>
+ <name>replica.lag.max.messages</name>
+ <value>4000</value>
+ <description>
+ If a replica falls more than this many messages behind the leader,
the leader will remove the follower from
+ ISR and treat it as dead.
+ </description>
+ </property>
+ <property>
+ <name>replica.socket.timeout.ms</name>
+ <value>30000</value>
+ <description>The socket timeout for network requests to the leader for
replicating data.</description>
+ </property>
+ <property>
+ <name>replica.socket.receive.buffer.bytes</name>
+ <value>65536</value>
+ <description>The socket receive buffer for network requests to the
leader for replicating data.</description>
+ </property>
+ <property>
+ <name>replica.fetch.max.bytes</name>
+ <value>1048576</value>
+ <description>
+ The number of byes of messages to attempt to fetch for each
partition in the fetch requests the replicas
+ send to the leader.
+ </description>
+ </property>
+ <property>
+ <name>replica.fetch.wait.max.ms</name>
+ <value>500</value>
+ <description>
+ The maximum amount of time to wait time for data to arrive on the
leader in the fetch requests sent by the
+ replicas to the leader.
+ </description>
+ </property>
+ <property>
+ <name>replica.fetch.min.bytes</name>
+ <value>1</value>
+ <description>
+ Minimum bytes expected for each fetch response for the fetch
requests from the replica to the leader.
+ If not enough bytes, wait up to replica.fetch.wait.max.ms for this
many bytes to arrive.
+ </description>
+ </property>
+ <property>
+ <name>num.replica.fetchers</name>
+ <value>1</value>
+ <description>
+ Number of threads used to replicate messages from leaders.
+ Increasing this value can increase the degree of I/O parallelism
in the follower broker.
+ </description>
+ </property>
+ <property>
+ <name>replica.high.watermark.checkpoint.interval.ms</name>
+ <value>5000</value>
+ <description>
+ The frequency with which each replica saves its high watermark to
disk to handle recovery.
+ </description>
+ </property>
+ <property>
+ <name>fetch.purgatory.purge.interval.requests</name>
+ <value>10000</value>
+ <description>The purge interval (in number of requests) of the fetch
request purgatory.</description>
+ </property>
+ <property>
+ <name>producer.purgatory.purge.interval.requests</name>
+ <value>10000</value>
+ <description>The purge interval (in number of requests) of the
producer request purgatory.</description>
+ </property>
+ <property>
+ <name>zookeeper.session.timeout.ms</name>
+ <value>30000</value>
+ <description>
+ Zookeeper session timeout.
+ If the server fails to heartbeat to zookeeper within this period
of time it is considered dead.
+ If you set this too low the server may be falsely considered dead;
if you set it too high it may take too
+ long to recognize a truly dead server.
+ </description>
+ </property>
+ <property>
+ <name>zookeeper.connection.timeout.ms</name>
+ <value>25000</value>
+ <description>
+ The maximum amount of time that the client waits to establish a
connection to zookeeper.
+ </description>
+ </property>
+ <property>
+ <name>zookeeper.sync.time.ms</name>
+ <value>2000</value>
+ <description>How far a ZK follower can be behind a ZK
leader.</description>
+ </property>
+ <property>
+ <name>controlled.shutdown.max.retries</name>
+ <value>3</value>
+ <description>
+ Number of retries to complete the controlled shutdown successfully
before executing an unclean shutdown.
+ </description>
+ </property>
+ <property>
+ <name>controlled.shutdown.retry.backoff.ms</name>
+ <value>5000</value>
+ <description>Backoff time between shutdown retries.</description>
+ </property>
+ <property>
+ <name>controlled.shutdown.enable</name>
+ <value>true</value>
+ <description>
+ Enable controlled shutdown of the broker.
+ If enabled, the broker will move all leaders on it to some other
brokers before shutting itself down.
+ This reduces the unavailability window during shutdown.
+ </description>
+ </property>
+ <property>
+ <name>auto.leader.rebalance.enable</name>
+ <value>true</value>
+ <description>
+ Enables auto leader balancing.
+ A background thread checks and triggers leader balance if required
at regular intervals.
+ </description>
+ </property>
+ <property>
+ <name>num.recovery.threads.per.data.dir</name>
+ <value>1</value>
+ <description>
+ The number of threads per data directory to be used for log
recovery at startup and flushing at shutdown
+ </description>
+ </property>
+ <property>
+ <name>min.insync.replicas</name>
+ <value>1</value>
+ <description>
+ define the minimum number of replicas in ISR needed to satisfy a
produce request with required.acks=-1 (or
+ all)
+ </description>
+ </property>
+ <property>
+ <name>leader.imbalance.per.broker.percentage</name>
+ <value>10</value>
+ <description>
+ The ratio of leader imbalance allowed per broker.
+ The controller would trigger a leader balance if it goes above
this value per broker.
+ The value is specified in percentage.
+ </description>
+ </property>
+ <property>
+ <name>leader.imbalance.check.interval.seconds</name>
+ <value>300</value>
+ <description>
+ The frequency with which the partition re-balance check is
triggered by the controller
+ </description>
+ </property>
+ <property>
+ <name>offset.metadata.max.bytes</name>
+ <value>4096</value>
+ <description>The maximum size for a metadata entry associated with an
offset commit</description>
+ </property>
+ <property>
+ <name>offsets.load.buffer.size</name>
+ <value>5242880</value>
+ <description>
+ Batch size for reading from the offsets segments when loading
offsets into the cache.
+ </description>
+ </property>
+ <property>
+ <name>offsets.topic.replication.factor</name>
+ <value>3</value>
+ <description>
+ The replication factor for the offsets topic (set higher to ensure
availability).
+ To ensure that the effective replication factor of the offsets
topic is the configured
+ value, the number of alive brokers has to be at least the
replication factor at the time of the first
+ request for the offsets topic.
+ If not, either the offsets topic creation will fail or it will get
a replication factor of min(alive
+ brokers, configured replication factor).
+ </description>
+ </property>
+ <property>
+ <name>offsets.topic.num.partitions</name>
+ <value>50</value>
+ <description>
+ The number of partitions for the offset commit topic (should not
change after deployment)
+ </description>
+ </property>
+ <property>
+ <name>offsets.topic.segment.bytes</name>
+ <value>104857600</value>
+ <description>
+ The offsets topic segment bytes should be kept relatively small in
order to facilitate faster log compaction
+ and cache loads
+ </description>
+ </property>
+ <property>
+ <name>offsets.topic.compression.codec</name>
+ <value>0</value>
+ <description>
+ Compression codec for the offsets topic - compression may be used
to achieve \"atomic\" commits.
+ Default is NoCompression.
+ For Gzip add value 1 , SnappyCompression add value 2,
LZ4CompressionCodec 3.
+ </description>
+ </property>
+ <property>
+ <name>offsets.retention.minutes</name>
+ <value>86400000</value>
+ <description>Log retention window in minutes for offsets
topic</description>
+ </property>
+ <property>
+ <name>offsets.retention.check.interval.ms</name>
+ <value>600000</value>
+ <description>Frequency at which to check for stale
offsets</description>
+ </property>
+ <property>
+ <name>offsets.commit.timeout.ms</name>
+ <value>5000</value>
+ <description>
+ Offset commit will be delayed until all replicas for the offsets
topic receive the commit or this timeout is
+ reached. This is similar to the producer request timeout.
+ </description>
+ </property>
+ <property>
+ <name>offsets.commit.required.acks</name>
+ <value>-1</value>
+ <description>
+ The required acks before the commit can be accepted.
+ In general, the default (-1) should not be overridden
+ </description>
+ </property>
+ <property>
+ <name>delete.topic.enable</name>
+ <value>true</value>
+ <description>
+ Enables delete topic.
+ Delete topic through the admin tool will have no effect if this
config is turned off
+ </description>
+ </property>
+ <property>
+ <name>compression.type</name>
+ <value>producer</value>
+ <description>
+ Specify the final compression type for a given topic.
+ This configuration accepts the standard compression codecs
('gzip', 'snappy', lz4).
+ It additionally accepts 'uncompressed' which is equivalent to no
compression; and 'producer' which means
+ retain the original compression codec set by the producer.
+ </description>
+ </property>
+ <property>
+ <name>external.kafka.metrics.exclude.prefix</name>
+
<value>kafka.network.RequestMetrics,kafka.server.DelayedOperationPurgatory,kafka.server.BrokerTopicMetrics.BytesRejectedPerSec</value>
+ <description>Exclude metrics starting with these prefixes from being
collected.</description>
+ </property>
+ <property>
+ <name>external.kafka.metrics.include.prefix</name>
+
<value>kafka.network.RequestMetrics.ResponseQueueTimeMs.request.OffsetCommit.98percentile,kafka.network.RequestMetrics.ResponseQueueTimeMs.request.Offsets.95percentile,kafka.network.RequestMetrics.ResponseSendTimeMs.request.Fetch.95percentile,kafka.network.RequestMetrics.RequestsPerSec.request</value>
+ <description>
+ These metrics would be included even if the exclude prefix omits
them.
+ </description>
+ </property>
+ <property>
+ <name>sasl.enabled.mechanisms</name>
+ <value>GSSAPI</value>
+ <description>
+ The list of SASL mechanisms enabled in the Kafka server.
+ The list may contain any mechanism for which a security provider
is available.
+ Only GSSAPI is enabled by default.
+ </description>
+ </property>
+ <property>
+ <name>security.inter.broker.protocol</name>
+ <value>PLAINTEXT</value>
+ <description>
+ Security protocol used to communicate between brokers.
+ Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL.
+ It is an error to set this and inter.broker.listener.name
properties at the same time.
+ </description>
+ </property>
+ <property>
+ <name>sasl.mechanism.inter.broker.protocol</name>
+ <value>GSSAPI</value>
+ <description>SASL mechanism used for inter-broker communication.
Default is GSSAPI.</description>
+ </property>
+ <property>
+ <name>ssl.client.auth</name>
+ <value>none</value>
+ <description>Configures kafka broker to request client
authentication.</description>
+ </property>
+ <property>
+ <name>ssl.key.password</name>
+ <value/>
+ <description>The password of private key in the key store
file.</description>
+ </property>
+ <property>
+ <name>ssl.keystore.location</name>
+ <value/>
+ <description>The location of key store file.</description>
+ </property>
+ <property>
+ <name>ssl.keystore.password</name>
+ <value/>
+ <description>The store password for key store file.</description>
+ </property>
+ <property>
+ <name>ssl.truststore.location</name>
+ <value/>
+ <description>The location of trust store file.</description>
+ </property>
+ <property>
+ <name>ssl.truststore.password</name>
+ <value/>
+ <description>
+ The password for trust store file.
+ If a password is not set access to the truststore is still
available, but integrity checking is disabled
+ </description>
+ </property>
+ <property>
+ <name>producer.metrics.enable</name>
+ <value>false</value>
+ </property>
+</configuration>
\ No newline at end of file
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-env.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-env.xml
new file mode 100644
index 00000000..e51666ce
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-env.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<configuration>
+ <property>
+ <name>kafka_log_dir</name>
+ <display-name>Kafka Log directory</display-name>
+ <value>/var/log/kafka</value>
+ <description />
+ </property>
+ <property>
+ <name>kafka_pid_dir</name>
+ <value>/var/run/kafka</value>
+ <display-name>Kafka PID dir</display-name>
+ <description />
+ </property>
+ <property>
+ <name>kafka_user_nofile_limit</name>
+ <value>128000</value>
+ <description>Max open files limit setting for kafka user.</description>
+ </property>
+ <property>
+ <name>kafka_user_nproc_limit</name>
+ <value>65536</value>
+ <description>Max number of processes limit setting for kafka
user.</description>
+ </property>
+
+ <property>
+ <name>content</name>
+ <display-name>kafka-env template</display-name>
+ <description>This is the freemarker template for kafka-env.sh
file</description>
+ <value><![CDATA[
+#!/bin/bash
+
+# Set KAFKA specific environment variables here.
+
+# The java implementation to use.
+export JAVA_HOME=${java_home!}
+<#noparse>export PATH=$PATH:${JAVA_HOME}/bin</#noparse>
+export PID_DIR=${kafka_pid_dir!}
+export LOG_DIR=${kafka_log_dir!}
+<#if security_enabled >
+export KAFKA_OPTS="-Djavax.security.auth.useSubjectCredsOnly=false
{{kafka_kerberos_params}}"
+<#else>
+export KAFKA_OPTS={{kafka_kerberos_params}}
+</#if>
+export CLASSPATH=$CLASSPATH:${kafka_conf_dir}
+]]>
+ </value>
+ <attrs>
+ <type>longtext</type>
+ </attrs>
+ </property>
+</configuration>
\ No newline at end of file
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-log4j.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-log4j.xml
new file mode 100644
index 00000000..f6f76a09
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka-log4j.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<configuration>
+ <property>
+ <name>kafkaLogMaxFileSize</name>
+ <value>256</value>
+ <description>The maximum size of backup file before the log is
rotated</description>
+ <display-name>Kafka Log: backup file size</display-name>
+ </property>
+ <property>
+ <name>kafkaLogMaxBackupIndex</name>
+ <value>20</value>
+ <description>The number of backup files</description>
+ <display-name>Kafka Log: # of backup files</display-name>
+ </property>
+ <property>
+ <name>controllerLogMaxFileSize</name>
+ <value>256</value>
+ <description>The maximum size of backup file before the log is
rotated</description>
+ <display-name>Kafka Controller Log: backup file size</display-name>
+ </property>
+ <property>
+ <name>controllerLogMaxBackupIndex</name>
+ <value>20</value>
+ <description>The number of backup files</description>
+ <display-name>Kafka Controller Log: # of backup files</display-name>
+ </property>
+ <property>
+ <name>content</name>
+ <display-name>kafka-log4j template</display-name>
+ <description>Custom log4j.properties</description>
+ <value><![CDATA[
+#
+#
+# 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.
+#
+#
+#
+kafka.logs.dir=logs
+
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{ISO8601}] %p %m (%c)%n
+
+log4j.appender.kafkaAppender=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.kafkaAppender.DatePattern='.'yyyy-MM-dd-HH
+<#noparse>log4j.appender.kafkaAppender.File=${kafka.logs.dir}/server.log</#noparse>
+log4j.appender.kafkaAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.kafkaAppender.layout.ConversionPattern=[%d{ISO8601}] %p %m
(%c)%n
+log4j.appender.kafkaAppender.MaxFileSize = ${kafkaLogMaxFileSize}MB
+log4j.appender.kafkaAppender.MaxBackupIndex = ${kafkaLogMaxBackupIndex}
+
+log4j.appender.stateChangeAppender=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.stateChangeAppender.DatePattern='.'yyyy-MM-dd-HH
+<#noparse>log4j.appender.stateChangeAppender.File=${kafka.logs.dir}/state-change.log</#noparse>
+log4j.appender.stateChangeAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.stateChangeAppender.layout.ConversionPattern=[%d{ISO8601}] %p
%m (%c)%n
+
+log4j.appender.requestAppender=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.requestAppender.DatePattern='.'yyyy-MM-dd-HH
+<#noparse>log4j.appender.requestAppender.File=${kafka.logs.dir}/kafka-request.log</#noparse>
+log4j.appender.requestAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.requestAppender.layout.ConversionPattern=[%d{ISO8601}] %p %m
(%c)%n
+
+log4j.appender.cleanerAppender=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.cleanerAppender.DatePattern='.'yyyy-MM-dd-HH
+<#noparse>log4j.appender.cleanerAppender.File=${kafka.logs.dir}/log-cleaner.log</#noparse>
+log4j.appender.cleanerAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.cleanerAppender.layout.ConversionPattern=[%d{ISO8601}] %p %m
(%c)%n
+
+log4j.appender.controllerAppender=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.controllerAppender.DatePattern='.'yyyy-MM-dd-HH
+<#noparse>log4j.appender.controllerAppender.File=${kafka.logs.dir}/controller.log</#noparse>
+log4j.appender.controllerAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.controllerAppender.layout.ConversionPattern=[%d{ISO8601}] %p %m
(%c)%n
+log4j.appender.controllerAppender.MaxFileSize = ${controllerLogMaxFileSize}MB
+log4j.appender.controllerAppender.MaxBackupIndex =
${controllerLogMaxBackupIndex}
+# Turn on all our debugging info
+#log4j.logger.kafka.producer.async.DefaultEventHandler=DEBUG, kafkaAppender
+#log4j.logger.kafka.client.ClientUtils=DEBUG, kafkaAppender
+#log4j.logger.kafka.perf=DEBUG, kafkaAppender
+<#noparse>#log4j.logger.kafka.perf.ProducerPerformance$ProducerThread=DEBUG,
kafkaAppender</#noparse>
+#log4j.logger.org.I0Itec.zkclient.ZkClient=DEBUG
+log4j.logger.kafka=INFO, kafkaAppender
+<#noparse>log4j.logger.kafka.network.RequestChannel$=WARN,
requestAppender</#noparse>
+<#noparse>log4j.additivity.kafka.network.RequestChannel$=false</#noparse>
+
+#log4j.logger.kafka.network.Processor=TRACE, requestAppender
+#log4j.logger.kafka.server.KafkaApis=TRACE, requestAppender
+#log4j.additivity.kafka.server.KafkaApis=false
+log4j.logger.kafka.request.logger=WARN, requestAppender
+log4j.additivity.kafka.request.logger=false
+
+log4j.logger.kafka.controller=TRACE, controllerAppender
+log4j.additivity.kafka.controller=false
+
+log4j.logger.kafka.log.LogCleaner=INFO, cleanerAppender
+log4j.additivity.kafka.log.LogCleaner=false
+
+log4j.logger.state.change.logger=TRACE, stateChangeAppender
+log4j.additivity.state.change.logger=false
+]]>
+ </value>
+ <attrs>
+ <type>longtext</type>
+ </attrs>
+ </property>
+</configuration>
\ No newline at end of file
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka.conf.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka.conf.xml
new file mode 100644
index 00000000..48076cd6
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/configuration/kafka.conf.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<configuration>
+ <property>
+ <name>content</name>
+ <display-name>kafka.conf template</display-name>
+ <description>This is the freemarker template for kafka-env.sh
file</description>
+ <value><![CDATA[
+#
+# 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.
+#
+
+${kafka_user} - nofile ${kafka_user_nofile_limit}
+${kafka_group} - nproc ${kafka_user_nproc_limit}
+
+]]>
+ </value>
+ <attrs>
+ <type>longtext</type>
+ </attrs>
+ </property>
+</configuration>
\ No newline at end of file
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/metainfo.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/metainfo.xml
new file mode 100644
index 00000000..562bd378
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/metainfo.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<metainfo>
+ <service>
+ <name>kafka</name>
+ <display-name>Kafka</display-name>
+ <desc>
+ Apache Kafka is an open-source distributed event streaming
platform used by thousands of companies for
+ high-performance data pipelines, streaming analytics, data
integration, and mission-critical
+ applications.
+ </desc>
+ <version>2.8.2-1</version>
+ <user>kafka</user>
+ <license>Apache-2.0</license>
+
+ <components>
+ <component>
+ <name>kafka_broker</name>
+ <display-name>Kafka Broker</display-name>
+ <category>server</category>
+ <cardinality>1+</cardinality>
+ </component>
+ </components>
+
+ <package-specifics>
+ <package-specific>
+ <architectures>
+ <arch>x86_64</arch>
+ <arch>aarch64</arch>
+ </architectures>
+ <packages>
+ <package>
+ <name>kafka-2.8.2-1.tgz</name>
+
<checksum>SHA-256:30a2d69ef081813624273d8a406c9b803c5868df998484e27207f85ea217870f</checksum>
+ </package>
+ </packages>
+ </package-specific>
+ </package-specifics>
+
+ <required-services>
+ <service>zookeeper</service>
+ </required-services>
+
+ </service>
+</metainfo>
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/order.json
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/order.json
new file mode 100644
index 00000000..2f55e86d
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/kafka/order.json
@@ -0,0 +1,8 @@
+{
+ "KAFKA_BROKER-START": [
+ "ZOOKEEPER_SERVER-START"
+ ],
+ "KAFKA_BROKER-RESTART": [
+ "ZOOKEEPER_SERVER-RESTART"
+ ]
+}
\ No newline at end of file
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/configuration/zoo.cfg.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/configuration/zoo.cfg.xml
new file mode 100644
index 00000000..bd09086c
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/configuration/zoo.cfg.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<configuration>
+ <property>
+ <name>tickTime</name>
+ <value>3000</value>
+ <display-name>Length of single Tick</display-name>
+ <description>
+ The length of a single tick in milliseconds, which is the basic
time unit used by ZooKeeper
+ </description>
+ </property>
+ <property>
+ <name>initLimit</name>
+ <value>10</value>
+ <display-name>Ticks to allow for sync at Init</display-name>
+ <description>Ticks to allow for sync at Init.</description>
+ </property>
+ <property>
+ <name>syncLimit</name>
+ <value>5</value>
+ <display-name>Ticks to allow for sync at Runtime</display-name>
+ <description>Ticks to allow for sync at Runtime.</description>
+ </property>
+ <property>
+ <name>clientPort</name>
+ <value>2181</value>
+ <display-name>Port for running ZK Server</display-name>
+ <description>Port for running ZK Server.</description>
+ </property>
+ <property>
+ <name>dataDir</name>
+ <value>/hadoop/zookeeper</value>
+ <display-name>ZooKeeper directory</display-name>
+ <description>Data directory for ZooKeeper.</description>
+ </property>
+ <property>
+ <name>autopurge.snapRetainCount</name>
+ <value>30</value>
+ <description>
+ ZooKeeper purge feature retains the autopurge.
+ snapRetainCount most recent snapshots and the corresponding
transaction logs in the dataDir and dataLogDir
+ respectively and deletes the rest.
+ </description>
+ </property>
+ <property>
+ <name>autopurge.purgeInterval</name>
+ <value>24</value>
+ <description>
+ The time interval in hours for which the purge task has to be
triggered.
+ Set to a positive integer (1 and above) to enable the auto purging.
+ </description>
+ </property>
+ <property>
+ <name>4lw.commands.whitelist</name>
+ <value>ruok</value>
+ <description>
+ A list of comma separated Four Letter Words commands that user
wants to use.
+ A valid Four Letter Words command must be put in this list else
ZooKeeper server will not enable the
+ command.
+ By default the whitelist only contains "srvr" command which
zkServer.sh uses.
+ The rest of four letter word commands are disabled by default.
+ </description>
+ </property>
+ <property>
+ <name>admin.enableServer</name>
+ <value>true</value>
+ <description>Set to "false" to disable the AdminServer. By default the
AdminServer is enabled.</description>
+ </property>
+ <property>
+ <name>admin.serverPort</name>
+ <value>9393</value>
+ <description>The port the embedded Jetty server listens on. Defaults
to 8080.</description>
+ </property>
+ <property>
+ <name>content</name>
+ <description>The port the embedded Jetty server listens on. Defaults
to 8080.</description>
+ <value><![CDATA[
+<#compress>
+<#list model as key,value>
+ <#if value??>
+ <#if value?string == 'true'>
+ ${key}=true
+ <#elseif value?string == 'false'>
+ ${key}=false
+ <#else>
+ ${key}=${value}
+ </#if>
+ </#if>
+</#list>
+</#compress>
+
+<#noparse>
+<#if zk_server_str?? >
+${zk_server_str}
+</#if>
+
+<#if security_enabled?? && security_enabled >
+authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
+jaasLoginRenew=3600000
+kerberos.removeHostFromPrincipal=true
+kerberos.removeRealmFromPrincipal=true
+</#if>
+</#noparse>
+]]>
+ </value>
+ <attrs>
+ <type>longtext</type>
+ </attrs>
+ </property>
+</configuration>
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/configuration/zookeeper-env.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/configuration/zookeeper-env.xml
new file mode 100644
index 00000000..a947ff69
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/configuration/zookeeper-env.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<configuration>
+ <property>
+ <name>zookeeper_log_dir</name>
+ <value>/var/log/zookeeper</value>
+ <display-name>ZooKeeper Log Dir</display-name>
+ <description>ZooKeeper Log Dir</description>
+ </property>
+ <property>
+ <name>zookeeper_pid_dir</name>
+ <value>/var/run/zookeeper</value>
+ <display-name>ZooKeeper PID Dir</display-name>
+ <description>ZooKeeper Pid Dir</description>
+ </property>
+ <!-- zookeeper-env.sh -->
+ <property>
+ <name>content</name>
+ <display-name>zookeeper-env template</display-name>
+ <description>This is the freemarker template for zookeeper-env.sh
file</description>
+ <value><![CDATA[
+export JAVA_HOME=${java_home!}
+export ZOOKEEPER_HOME=${zookeeper_home!}
+export ZOO_LOG_DIR=${zookeeper_log_dir!}
+export ZOOPIDFILE=${zookeeper_pid_file!}
+export SERVER_JVMFLAGS=${SERVER_JVMFLAGS!}
+<#noparse>export JAVA=${JAVA_HOME}/bin/java</#noparse>
+export CLASSPATH=$CLASSPATH:/usr/share/zookeeper/*
+
+<#if securityEnabled?? && securityEnabled >
+export SERVER_JVMFLAGS="$SERVER_JVMFLAGS
-Djava.security.auth.login.config=${zk_server_jaas_file!}"
+export CLIENT_JVMFLAGS="$CLIENT_JVMFLAGS
-Djava.security.auth.login.config=${zk_client_jaas_file!}
-Dzookeeper.sasl.client.username=${zk_principal_user!}"
+</#if>
+]]>
+ </value>
+ <attrs>
+ <type>longtext</type>
+ </attrs>
+ </property>
+</configuration>
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/metainfo.xml
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/metainfo.xml
new file mode 100644
index 00000000..913b576c
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/metainfo.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<!--
+ ~ 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.
+-->
+
+<metainfo>
+ <service>
+ <name>zookeeper</name>
+ <display-name>ZooKeeper</display-name>
+ <desc>
+ Apache ZooKeeper is an effort to develop and maintain an
open-source server which enables highly
+ reliable distributed coordination.
+ </desc>
+ <version>3.7.2-1</version>
+ <user>zookeeper</user>
+ <license>Apache-2.0</license>
+
+ <components>
+ <component>
+ <name>zookeeper_server</name>
+ <display-name>ZooKeeper Server</display-name>
+ <category>server</category>
+ <cardinality>1+</cardinality>
+ </component>
+
+ <component>
+ <name>zookeeper_client</name>
+ <display-name>ZooKeeper Client</display-name>
+ <category>client</category>
+ <cardinality>1+</cardinality>
+ </component>
+ </components>
+
+ <package-specifics>
+ <package-specific>
+ <architectures>
+ <arch>x86_64</arch>
+ <arch>aarch64</arch>
+ </architectures>
+ <packages>
+ <package>
+ <name>zookeeper-3.7.2-1.tar.gz</name>
+
<checksum>SHA-256:83e07f914eb3477c77245f4dc44031b82ea6ef1be3691687f469ddc4b8c720bb</checksum>
+ </package>
+ </packages>
+ </package-specific>
+ </package-specifics>
+ </service>
+</metainfo>
\ No newline at end of file
diff --git
a/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/order.json
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/order.json
new file mode 100644
index 00000000..0da47175
--- /dev/null
+++
b/bigtop-manager-server/src/test/resources/stacks/bigtop/3.3.0/services/zookeeper/order.json
@@ -0,0 +1,5 @@
+{
+ "ZOOKEEPER_SERVER-STOP": [
+ "KAFKA_BROKER-STOP"
+ ]
+}
\ No newline at end of file