@Test
  public void subProcedureTest() throws Exception {
    EnvFactory.getEnv().initClusterEnvironment(1, 1);

    SyncConfigNodeIServiceClient leaderClient =
        (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection();
    leaderClient.callSpecialProcedure(TTestOperation.TEST_SUB_PROCEDURE);

    boolean checkBeforeConfigNodeRestart = false;
    try {
      Awaitility.await()
          .pollDelay(1, SECONDS)
          .atMost(10, SECONDS)
          .until(
              () -> {
                TShowDatabaseResp resp = leaderClient.showDatabase(showAllDatabasesReq);
                return resp.getDatabaseInfoMap()
                    .containsKey(AddNeverFinishSubProcedureProcedure.FAIL_DATABASE_NAME);
              });
    } catch (ConditionTimeoutException e) {
      checkBeforeConfigNodeRestart = true;
    }
    if (!checkBeforeConfigNodeRestart) {
      throw new Exception("checkBeforeConfigNodeRestart fail");
    }

    // Restart the ConfigNode
    final int leaderConfigNodeIndex = EnvFactory.getEnv().getLeaderConfigNodeIndex();
    EnvFactory.getEnv().getConfigNodeWrapperList().get(leaderConfigNodeIndex).stopForcibly();
    EnvFactory.getEnv().getConfigNodeWrapperList().get(leaderConfigNodeIndex).start();
    SyncConfigNodeIServiceClient newLeaderClient =
        (SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection();
    // Make sure leader ConfigNode is working
    Awaitility.await()
        .pollDelay(1, SECONDS)
        .atMost(10, SECONDS)
        .until(
            () -> {
              try {
                newLeaderClient.showDatabase(showAllDatabasesReq);
              } catch (Exception e) {
                return false;
              }
              return true;
            });

    boolean checkAfterConfigNodeRestart = false;
    try {
      Awaitility.await()
          .pollDelay(1, SECONDS)
          .atMost(10, SECONDS)
          .until(
              () -> {
                TShowDatabaseResp resp = newLeaderClient.showDatabase(showAllDatabasesReq);
                return resp.getDatabaseInfoMap()
                    .containsKey(AddNeverFinishSubProcedureProcedure.FAIL_DATABASE_NAME);
              });
    } catch (ConditionTimeoutException e) {
      checkAfterConfigNodeRestart = true;
    }
    if (!checkAfterConfigNodeRestart) {
      throw new Exception("checkAfterConfigNodeRestart fail");
    }

    LOGGER.info("test pass");
  }
Testing the sub-procedure functionality of the Procedure framework: the parent procedure will
not execute before the sub-procedure finishing.
integration-test/src/test/java/org/apache/iotdb/confignode/it/procedure/IoTDBProcedureIT.java