OverviewFilesCommitsIssuesDocsReleasesPeers

pgh-sidecar / test / overlay-conn-release.test.js

69 lines · javascript ref:
/**
 * The sidecar must release overlay per-mux state when an overlay-swarm
 * connection dies.
 *
 * OverlayProtocol keeps `_peers` (pruned by the channel's own onclose) and
 * `_paired` (pruned ONLY by detach). The sidecar holds ONE _overlayProtocolV2
 * for the whole daemon and attaches it to every inbound overlay connection, so
 * an un-detached pairing pins the mux and its stream for the life of an
 * always-on process.
 *
 * This is the third instance of one defect: hyper-deploy 0.4.11 fixed
 * DeployServer._onConnection, 0.4.13 fixed the public
 * DeployServer.serveOnConnection, and this is the attach site the sidecar owns
 * directly (lib/index.js, overlay-swarm 'connection' handler).
 *
 * Drives the real OverlayProtocol over a real Protomux on a real SecretStream
 * pair — a stubbed protocol here would only certify whatever the stub does.
 */

import test from 'brittle'
import SecretStream from '@hyperswarm/secret-stream'
import { OverlayProtocol } from 'hyper-overlay/protocol'

import { Sidecar } from '../lib/index.js'

function pair () {
  const a = new SecretStream(true)
  const b = new SecretStream(false)
  a.rawStream.pipe(b.rawStream).pipe(a.rawStream)
  return { a, b }
}

async function waitFor (fn, timeoutMs = 5000) {
  const t0 = Date.now()
  while (Date.now() - t0 < timeoutMs) {
    if (fn()) return true
    await new Promise((r) => setTimeout(r, 25))
  }
  return false
}

test('overlay pairings are released when the connection closes', async (t) => {
  t.timeout(30000)

  const proto = new OverlayProtocol(null, null)
  // Only _attachOverlayConn is under test; it touches _overlayProtocolV2 alone.
  const sidecar = { _overlayProtocolV2: proto }
  const attach = Sidecar.prototype._attachOverlayConn.bind(sidecar)

  const N = 5
  const conns = []
  for (let i = 0; i < N; i++) {
    const p = pair()
    conns.push(p)
    t.ok(attach(p.a), 'attached connection ' + i)
  }

  t.is(proto._paired.size, N, 'one paired mux per live connection')

  for (const p of conns) {
    p.a.destroy()
    p.b.destroy()
  }

  await waitFor(() => proto._paired.size === 0)

  t.is(proto._paired.size, 0, 'paired muxes released on close — otherwise every overlay connection the sidecar ever accepted is pinned for the life of the daemon')
})