4747import org .apache .iotdb .it .env .cluster .config .MppConfigNodeConfig ;
4848import org .apache .iotdb .it .env .cluster .config .MppDataNodeConfig ;
4949import org .apache .iotdb .it .env .cluster .config .MppJVMConfig ;
50- import org .apache .iotdb .it .env .cluster .node .AINodeWrapper ;
5150import org .apache .iotdb .it .env .cluster .node .AbstractNodeWrapper ;
5251import org .apache .iotdb .it .env .cluster .node .ConfigNodeWrapper ;
5352import org .apache .iotdb .it .env .cluster .node .DataNodeWrapper ;
@@ -101,14 +100,15 @@ public abstract class AbstractEnv implements BaseEnv {
101100 private final Random rand = new Random ();
102101 protected List <ConfigNodeWrapper > configNodeWrapperList = Collections .emptyList ();
103102 protected List <DataNodeWrapper > dataNodeWrapperList = Collections .emptyList ();
104- protected List <AINodeWrapper > aiNodeWrapperList = Collections .emptyList ();
103+ protected List <AbstractNodeWrapper > extraNodeWrappers = Collections .emptyList ();
105104 protected String testMethodName = null ;
106105 protected int index = 0 ;
107106 protected long startTime ;
108107 protected int retryCount = 30 ;
109108 private IClientManager <TEndPoint , SyncConfigNodeIServiceClient > clientManager ;
110109 private List <String > configNodeKillPoints = new ArrayList <>();
111110 private List <String > dataNodeKillPoints = new ArrayList <>();
111+ protected List <String > extraNodeKillPoints = new ArrayList <>();
112112
113113 /**
114114 * This config object stores the properties set by developers during the test. It will be cleared
@@ -169,17 +169,10 @@ protected void initEnvironment(final int configNodesNum, final int dataNodesNum)
169169
170170 protected void initEnvironment (
171171 final int configNodesNum , final int dataNodesNum , final int testWorkingRetryCount ) {
172- initEnvironment (configNodesNum , dataNodesNum , testWorkingRetryCount , false );
173- }
174-
175- protected void initEnvironment (
176- final int configNodesNum ,
177- final int dataNodesNum ,
178- final int retryCount ,
179- final boolean addAINode ) {
180- this .retryCount = retryCount ;
172+ this .retryCount = testWorkingRetryCount ;
181173 this .configNodeWrapperList = new ArrayList <>();
182174 this .dataNodeWrapperList = new ArrayList <>();
175+ this .extraNodeWrappers = new ArrayList <>();
183176
184177 clientManager =
185178 new IClientManager .Factory <TEndPoint , SyncConfigNodeIServiceClient >()
@@ -258,14 +251,34 @@ protected void initEnvironment(
258251 throw new AssertionError ();
259252 }
260253
261- if (addAINode ) {
262- this .aiNodeWrapperList = new ArrayList <>();
263- startAINode (seedConfigNode , this .dataNodeWrapperList .get (0 ).getPort (), testClassName );
264- }
254+ initExtraNodes (configNodeWrapperList , dataNodeWrapperList , testClassName );
265255
266256 checkClusterStatusWithoutUnknown ();
267257 }
268258
259+ /**
260+ * Hook method for subclasses to initialize and start extra node types beyond the core ConfigNode
261+ * and DataNode (e.g., AINode, StreamNode, ProxyNode).
262+ *
263+ * <p>Subclasses should create node wrappers, add them to {@link #extraNodeWrappers}, configure
264+ * kill points via {@link #extraNodeKillPoints}, and start the nodes. Subclasses have direct
265+ * access to protected fields: {@code testMethodName}, {@code index}, {@code startTime}.
266+ *
267+ * @param configNodeWrappers list of all ConfigNode wrappers in the cluster (unmodifiable)
268+ * @param dataNodeWrappers list of all DataNode wrappers in the cluster (unmodifiable)
269+ * @param testClassName the test class name for logging and identification purposes
270+ */
271+ protected void initExtraNodes (
272+ final List <ConfigNodeWrapper > configNodeWrappers ,
273+ final List <DataNodeWrapper > dataNodeWrappers ,
274+ final String testClassName ) {
275+ // Default: no extra nodes. Subclasses override to add nodes.
276+ }
277+
278+ protected void registerExtraNode (final AbstractNodeWrapper nodeWrapper ) {
279+ extraNodeWrappers .add (nodeWrapper );
280+ }
281+
269282 private ConfigNodeWrapper newConfigNode () {
270283 final ConfigNodeWrapper configNodeWrapper =
271284 new ConfigNodeWrapper (
@@ -309,39 +322,6 @@ private DataNodeWrapper newDataNode() {
309322 return dataNodeWrapper ;
310323 }
311324
312- private void startAINode (
313- final String seedConfigNode , final int clusterIngressPort , final String testClassName ) {
314- final String aiNodeEndPoint ;
315- final AINodeWrapper aiNodeWrapper =
316- new AINodeWrapper (
317- seedConfigNode ,
318- clusterIngressPort ,
319- testClassName ,
320- testMethodName ,
321- index ,
322- EnvUtils .searchAvailablePorts (),
323- startTime );
324- aiNodeWrapperList .add (aiNodeWrapper );
325- aiNodeEndPoint = aiNodeWrapper .getIpAndPortString ();
326- aiNodeWrapper .createNodeDir ();
327- aiNodeWrapper .createLogDir ();
328- final RequestDelegate <Void > aiNodesDelegate =
329- new ParallelRequestDelegate <>(
330- Collections .singletonList (aiNodeEndPoint ), NODE_START_TIMEOUT , this );
331-
332- aiNodesDelegate .addRequest (
333- () -> {
334- aiNodeWrapper .start ();
335- return null ;
336- });
337-
338- try {
339- aiNodesDelegate .requestAll ();
340- } catch (final SQLException e ) {
341- logger .error ("Start aiNodes failed" , e );
342- }
343- }
344-
345325 public String getTestClassName () {
346326 final StackTraceElement [] stack = Thread .currentThread ().getStackTrace ();
347327 for (final StackTraceElement stackTraceElement : stack ) {
@@ -433,7 +413,7 @@ public void checkClusterStatus(
433413 if (showClusterResp .getNodeStatus ().size ()
434414 != configNodeWrapperList .size ()
435415 + dataNodeWrapperList .size ()
436- + aiNodeWrapperList .size ()) {
416+ + extraNodeWrappers .size ()) {
437417 passed = false ;
438418 nodeSizePassed = false ;
439419 actualNodeSize = showClusterResp .getNodeStatusSize ();
@@ -465,7 +445,7 @@ public void checkClusterStatus(
465445 processStatusMap .put (nodeWrapper , 0 );
466446 }
467447 }
468- for (AINodeWrapper nodeWrapper : aiNodeWrapperList ) {
448+ for (AbstractNodeWrapper nodeWrapper : extraNodeWrappers ) {
469449 boolean alive = nodeWrapper .getInstance ().isAlive ();
470450 if (!alive ) {
471451 processStatusMap .put (nodeWrapper , nodeWrapper .getInstance ().waitFor ());
@@ -568,14 +548,14 @@ private void handleProcessStatus(Map<AbstractNodeWrapper, Integer> processStatus
568548 configNodeWrapper .start ();
569549 }
570550 }
571- for (AINodeWrapper aiNodeWrapper : aiNodeWrapperList ) {
572- if (portOccupationMap .containsValue (aiNodeWrapper .getPid ())) {
551+ for (AbstractNodeWrapper extraNodeWrapper : extraNodeWrappers ) {
552+ if (portOccupationMap .containsValue (extraNodeWrapper .getPid ())) {
573553 logger .info (
574- "A port is occupied by another AINode {}-{}, restart it" ,
575- aiNodeWrapper .getIpAndPortString (),
576- aiNodeWrapper .getPid ());
577- aiNodeWrapper .stop ();
578- aiNodeWrapper .start ();
554+ "A port is occupied by another node {}-{}, restart it" ,
555+ extraNodeWrapper .getIpAndPortString (),
556+ extraNodeWrapper .getPid ());
557+ extraNodeWrapper .stop ();
558+ extraNodeWrapper .start ();
579559 }
580560 }
581561 } catch (IOException e ) {
@@ -592,8 +572,8 @@ private void handleProcessStatus(Map<AbstractNodeWrapper, Integer> processStatus
592572 public void cleanClusterEnvironment () {
593573 final List <AbstractNodeWrapper > allNodeWrappers =
594574 Stream .concat (
595- dataNodeWrapperList .stream (),
596- Stream . concat ( configNodeWrapperList . stream (), aiNodeWrapperList . stream () ))
575+ Stream . concat ( configNodeWrapperList . stream (), dataNodeWrapperList .stream () ),
576+ extraNodeWrappers . stream ())
597577 .collect (Collectors .toList ());
598578 allNodeWrappers .stream ()
599579 .findAny ()
@@ -1045,6 +1025,7 @@ public void dumpTestJVMSnapshot() {
10451025 public List <AbstractNodeWrapper > getNodeWrapperList () {
10461026 final List <AbstractNodeWrapper > result = new ArrayList <>(configNodeWrapperList );
10471027 result .addAll (dataNodeWrapperList );
1028+ result .addAll (extraNodeWrappers );
10481029 return result ;
10491030 }
10501031
0 commit comments