private boolean sendHeartbeatToBrokerV2(long id, String brokerName, String addr, HeartbeatData heartbeatDataWithSub,
        HeartbeatData heartbeatDataWithoutSub, int currentHeartbeatFingerprint) {
        try {
            int version = 0;
            boolean isBrokerSupportV2 = brokerSupportV2HeartbeatSet.contains(addr);
            HeartbeatV2Result heartbeatV2Result = null;
            if (isBrokerSupportV2 && null != brokerAddrHeartbeatFingerprintTable.get(addr) && brokerAddrHeartbeatFingerprintTable.get(addr) == currentHeartbeatFingerprint) {
                heartbeatV2Result = this.mQClientAPIImpl.sendHeartbeatV2(addr, heartbeatDataWithoutSub, clientConfig.getMqClientApiTimeout());
                if (heartbeatV2Result.isSubChange()) {
                    brokerAddrHeartbeatFingerprintTable.remove(addr);
                }
                log.info("sendHeartbeatToAllBrokerV2 simple brokerName: {} subChange: {} brokerAddrHeartbeatFingerprintTable: {}", brokerName, heartbeatV2Result.isSubChange(), JSON.toJSONString(brokerAddrHeartbeatFingerprintTable));
            } else {
                heartbeatV2Result = this.mQClientAPIImpl.sendHeartbeatV2(addr, heartbeatDataWithSub, clientConfig.getMqClientApiTimeout());
                if (heartbeatV2Result.isSupportV2()) {
                    brokerSupportV2HeartbeatSet.add(addr);
                    if (heartbeatV2Result.isSubChange()) {
                        brokerAddrHeartbeatFingerprintTable.remove(addr);
                    } else if (!brokerAddrHeartbeatFingerprintTable.containsKey(addr) || brokerAddrHeartbeatFingerprintTable.get(addr) != currentHeartbeatFingerprint) {
                        brokerAddrHeartbeatFingerprintTable.put(addr, currentHeartbeatFingerprint);
                    }
                }
                log.info("sendHeartbeatToAllBrokerV2 normal brokerName: {} subChange: {} brokerAddrHeartbeatFingerprintTable: {}", brokerName, heartbeatV2Result.isSubChange(), JSON.toJSONString(brokerAddrHeartbeatFingerprintTable));
            }
            version = heartbeatV2Result.getVersion();
            if (!this.brokerVersionTable.containsKey(brokerName)) {
                this.brokerVersionTable.put(brokerName, new HashMap<>(4));
            }
            this.brokerVersionTable.get(brokerName).put(addr, version);
            long times = this.sendHeartbeatTimesTotal.getAndIncrement();
            if (times % 20 == 0) {
                log.info("send heart beat to broker[{} {} {}] success", brokerName, id, addr);
                log.info(heartbeatDataWithSub.toString());
            }
            return true;
        } catch (Exception e) {
            if (this.isBrokerInNameServer(addr)) {
                log.warn("sendHeartbeatToAllBrokerV2 send heart beat to broker[{} {} {}] failed", brokerName, id, addr, e);
            } else {
                log.warn("sendHeartbeatToAllBrokerV2 send heart beat to broker[{} {} {}] exception, because the broker not up, forget it", brokerName, id, addr, e);
            }
        }
        return false;
    }
@Test
    public void testSendHeartbeatToBrokerV2() throws MQBrokerException, RemotingException, InterruptedException {
        consumerTable.put(group, createMQConsumerInner());
        when(clientConfig.isUseHeartbeatV2()).thenReturn(true);
        HeartbeatV2Result heartbeatV2Result = mock(HeartbeatV2Result.class);
        when(heartbeatV2Result.isSupportV2()).thenReturn(true);
        when(mQClientAPIImpl.sendHeartbeatV2(any(), any(HeartbeatData.class), anyLong())).thenReturn(heartbeatV2Result);
        assertTrue(mqClientInstance.sendHeartbeatToBroker(0L, defaultBroker, defaultBrokerAddr));
    }