public Status refreshConfiguration(final CliClientService cliClientService, final String groupId,
                                       final int timeoutMs) throws InterruptedException, TimeoutException {
        Requires.requireTrue(!StringUtils.isBlank(groupId), "Blank group id");
        Requires.requireTrue(timeoutMs > 0, "Invalid timeout: " + timeoutMs);

        final Configuration conf = getConfiguration(groupId);
        if (conf == null) {
            return new Status(RaftError.ENOENT,
                "Group %s is not registered in RouteTable, forgot to call updateConfiguration?", groupId);
        }
        final Status st = Status.OK();
        PeerId leaderId = selectLeader(groupId);
        if (leaderId == null) {
            refreshLeader(cliClientService, groupId, timeoutMs);
            leaderId = selectLeader(groupId);
        }
        if (leaderId == null) {
            st.setError(-1, "Fail to get leader of group %s", groupId);
            return st;
        }
        if (!cliClientService.connect(leaderId.getEndpoint())) {
            st.setError(-1, "Fail to init channel to %s", leaderId);
            return st;
        }
        final CliRequests.GetPeersRequest.Builder rb = CliRequests.GetPeersRequest.newBuilder();
        rb.setGroupId(groupId);
        rb.setLeaderId(leaderId.toString());
        try {
            final Message result = cliClientService.getPeers(leaderId.getEndpoint(), rb.build(), null).get(timeoutMs,
                TimeUnit.MILLISECONDS);
            if (result instanceof CliRequests.GetPeersResponse) {
                final CliRequests.GetPeersResponse resp = (CliRequests.GetPeersResponse) result;
                final Configuration newConf = new Configuration();
                for (final String peerIdStr : resp.getPeersList()) {
                    final PeerId newPeer = new PeerId();
                    newPeer.parse(peerIdStr);
                    newConf.addPeer(newPeer);
                }
                for (final String learnerIdStr : resp.getLearnersList()) {
                    final PeerId newLearner = new PeerId();
                    newLearner.parse(learnerIdStr);
                    newConf.addLearner(newLearner);
                }
                if (!conf.equals(newConf)) {
                    LOG.info("Configuration of replication group {} changed from {} to {}", groupId, conf, newConf);
                }
                updateConfiguration(groupId, newConf);
            } else {
                final RpcRequests.ErrorResponse resp = (RpcRequests.ErrorResponse) result;
                st.setError(resp.getErrorCode(), resp.getErrorMsg());
            }
        } catch (final Exception e) {
            st.setError(-1, e.getMessage());
        }
        return st;
    }
@Test
    public void testRefreshConfiguration() throws Exception {
        final RouteTable rt = RouteTable.getInstance();
        final List<PeerId> partConf = new ArrayList<>();
        partConf.add(cluster.getLeader().getLeaderId());
        // part of peers conf, only contains leader peer
        rt.updateConfiguration(groupId, new Configuration(partConf));
        // fetch all conf
        final Status st = rt.refreshConfiguration(cliClientService, groupId, 10000);
        assertTrue(st.isOk());
        final Configuration newCnf = rt.getConfiguration(groupId);
        assertArrayEquals(new HashSet<>(cluster.getPeers()).toArray(), new HashSet<>(newCnf.getPeerSet()).toArray());
    }