DefaultTunnelManager implements TunnelManager { @VisibleForTesting protected void doClean() { Set<Channel> keys = Sets.newHashSet(cache.keySet()); for(Channel channel : keys) { if (!channel.isActive()) { Tunnel tunnel = cache.remove(channel); try { tunnel.release(); } catch (Exception e) { logger.error("[cleaner] tunnel release error: ", e); } } else { Tunnel tunnel = cache.get(channel); logger.info("[doClean] check tunnel, {}", tunnel.getTunnelMeta()); if (tunnel.getState().equals(new TunnelClosed(null))) { cache.remove(channel); } } } }  @PostConstruct void cleaner(); @PreDestroy void preDestroy(); @Override Tunnel create(Channel frontendChannel, ProxyConnectProtocol protocol); @Override void remove(Channel frontendChannel); @Override List<Tunnel> tunnels(); @Override Tunnel getById(String id); @Override void release(); @Override void update(Object args, Observable observable); @VisibleForTesting DefaultTunnelManager setConfig(ProxyConfig config); @VisibleForTesting DefaultTunnelManager setProxyResourceManager(ResourceManager manager); DefaultTunnelManager setTunnelMonitorManager(TunnelMonitorManager tunnelMonitorManager);  }
@Test public void testDoClean() throws Exception { startListenServer(8009); Channel frontChannel1 = fakeChannel(); Channel frontChannel2 = fakeChannel(); manager.create(frontChannel1, protocol("Proxy Route proxy: manager.create(frontChannel2, protocol("Proxy Route proxy: Assert.assertEquals(2, manager.tunnels().size()); when(frontChannel1.isActive()).thenReturn(false); when(frontChannel2.isActive()).thenReturn(true); manager.doClean(); Assert.assertEquals(1, manager.tunnels().size()); }