UNPKG

@libp2p/interface-stream-muxer-compliance-tests

Version:
153 lines 7.27 kB
import { isValidTick } from '@libp2p/interface-compliance-tests/is-valid-tick'; import { expect } from 'aegir/chai'; import all from 'it-all'; import drain from 'it-drain'; import map from 'it-map'; import { duplexPair } from 'it-pair/duplex'; import { pipe } from 'it-pipe'; import defer from 'p-defer'; import { Uint8ArrayList } from 'uint8arraylist'; import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'; import { toString as uint8ArrayToString } from 'uint8arrays/to-string'; async function drainAndClose(stream) { await pipe([], stream, drain); } export default (common) => { describe('base', () => { it('Open a stream from the dialer', async () => { const p = duplexPair(); const dialerFactory = await common.setup(); const dialer = dialerFactory.createStreamMuxer({ direction: 'outbound' }); const onStreamPromise = defer(); const onStreamEndPromise = defer(); const listenerFactory = await common.setup(); const listener = listenerFactory.createStreamMuxer({ direction: 'inbound', onIncomingStream: (stream) => { onStreamPromise.resolve(stream); }, onStreamEnd: (stream) => { onStreamEndPromise.resolve(stream); } }); void pipe(p[0], dialer, p[0]); void pipe(p[1], listener, p[1]); const conn = await dialer.newStream(); expect(dialer.streams).to.include(conn); expect(isValidTick(conn.stat.timeline.open)).to.equal(true); void drainAndClose(conn); const stream = await onStreamPromise.promise; expect(isValidTick(stream.stat.timeline.open)).to.equal(true); // Make sure the stream is being tracked expect(listener.streams).to.include(stream); void drainAndClose(stream); // Make sure stream is closed properly const endedStream = await onStreamEndPromise.promise; expect(listener.streams).to.not.include(endedStream); if (endedStream.stat.timeline.close == null) { throw new Error('timeline had no close time'); } // Make sure the stream is removed from tracking expect(isValidTick(endedStream.stat.timeline.close)).to.equal(true); await drainAndClose(dialer); await drainAndClose(listener); // ensure we have no streams left expect(dialer.streams).to.have.length(0); expect(listener.streams).to.have.length(0); }); it('Open a stream from the listener', async () => { const p = duplexPair(); const onStreamPromise = defer(); const dialerFactory = await common.setup(); const dialer = dialerFactory.createStreamMuxer({ direction: 'outbound', onIncomingStream: (stream) => { onStreamPromise.resolve(stream); } }); const listenerFactory = await common.setup(); const listener = listenerFactory.createStreamMuxer({ direction: 'inbound' }); void pipe(p[0], dialer, p[0]); void pipe(p[1], listener, p[1]); const conn = await listener.newStream(); void drainAndClose(conn); const stream = await onStreamPromise.promise; expect(isValidTick(stream.stat.timeline.open)).to.equal(true); expect(listener.streams).to.include(conn); expect(isValidTick(conn.stat.timeline.open)).to.equal(true); void drainAndClose(stream); await drainAndClose(dialer); await drainAndClose(listener); }); it('Open a stream on both sides', async () => { const p = duplexPair(); const onDialerStreamPromise = defer(); const onListenerStreamPromise = defer(); const dialerFactory = await common.setup(); const dialer = dialerFactory.createStreamMuxer({ direction: 'outbound', onIncomingStream: (stream) => { onDialerStreamPromise.resolve(stream); } }); const listenerFactory = await common.setup(); const listener = listenerFactory.createStreamMuxer({ direction: 'inbound', onIncomingStream: (stream) => { onListenerStreamPromise.resolve(stream); } }); void pipe(p[0], dialer, p[0]); void pipe(p[1], listener, p[1]); const dialerInitiatorStream = await dialer.newStream(); const listenerInitiatorStream = await listener.newStream(); await Promise.all([ drainAndClose(dialerInitiatorStream), drainAndClose(listenerInitiatorStream), onDialerStreamPromise.promise.then(async (stream) => { await drainAndClose(stream); }), onListenerStreamPromise.promise.then(async (stream) => { await drainAndClose(stream); }) ]); await Promise.all([ drainAndClose(dialer), drainAndClose(listener) ]); }); it('Open a stream on one side, write, open a stream on the other side', async () => { const toString = (source) => map(source, (u) => uint8ArrayToString(u.subarray())); const p = duplexPair(); const onDialerStreamPromise = defer(); const onListenerStreamPromise = defer(); const dialerFactory = await common.setup(); const dialer = dialerFactory.createStreamMuxer({ direction: 'outbound', onIncomingStream: (stream) => { onDialerStreamPromise.resolve(stream); } }); const listenerFactory = await common.setup(); const listener = listenerFactory.createStreamMuxer({ direction: 'inbound', onIncomingStream: (stream) => { onListenerStreamPromise.resolve(stream); } }); void pipe(p[0], dialer, p[0]); void pipe(p[1], listener, p[1]); const dialerConn = await dialer.newStream(); const listenerConn = await listener.newStream(); void pipe([new Uint8ArrayList(uint8ArrayFromString('hey'))], dialerConn); void pipe([new Uint8ArrayList(uint8ArrayFromString('hello'))], listenerConn); const [dialerStream, listenerStream] = await Promise.all([ onDialerStreamPromise.promise, onListenerStreamPromise.promise ]); const [listenerChunks, dialerChunks] = await Promise.all([ pipe(listenerStream, toString, async (source) => all(source)), pipe(dialerStream, toString, async (source) => all(source)) ]); expect(listenerChunks).to.be.eql(['hey']); expect(dialerChunks).to.be.eql(['hello']); }); }); }; //# sourceMappingURL=base-test.js.map