11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst { kClients } = require('../core/symbols')
41cb0ef41Sopenharmony_ciconst Agent = require('../agent')
51cb0ef41Sopenharmony_ciconst {
61cb0ef41Sopenharmony_ci  kAgent,
71cb0ef41Sopenharmony_ci  kMockAgentSet,
81cb0ef41Sopenharmony_ci  kMockAgentGet,
91cb0ef41Sopenharmony_ci  kDispatches,
101cb0ef41Sopenharmony_ci  kIsMockActive,
111cb0ef41Sopenharmony_ci  kNetConnect,
121cb0ef41Sopenharmony_ci  kGetNetConnect,
131cb0ef41Sopenharmony_ci  kOptions,
141cb0ef41Sopenharmony_ci  kFactory
151cb0ef41Sopenharmony_ci} = require('./mock-symbols')
161cb0ef41Sopenharmony_ciconst MockClient = require('./mock-client')
171cb0ef41Sopenharmony_ciconst MockPool = require('./mock-pool')
181cb0ef41Sopenharmony_ciconst { matchValue, buildMockOptions } = require('./mock-utils')
191cb0ef41Sopenharmony_ciconst { InvalidArgumentError, UndiciError } = require('../core/errors')
201cb0ef41Sopenharmony_ciconst Dispatcher = require('../dispatcher')
211cb0ef41Sopenharmony_ciconst Pluralizer = require('./pluralizer')
221cb0ef41Sopenharmony_ciconst PendingInterceptorsFormatter = require('./pending-interceptors-formatter')
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciclass FakeWeakRef {
251cb0ef41Sopenharmony_ci  constructor (value) {
261cb0ef41Sopenharmony_ci    this.value = value
271cb0ef41Sopenharmony_ci  }
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci  deref () {
301cb0ef41Sopenharmony_ci    return this.value
311cb0ef41Sopenharmony_ci  }
321cb0ef41Sopenharmony_ci}
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciclass MockAgent extends Dispatcher {
351cb0ef41Sopenharmony_ci  constructor (opts) {
361cb0ef41Sopenharmony_ci    super(opts)
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci    this[kNetConnect] = true
391cb0ef41Sopenharmony_ci    this[kIsMockActive] = true
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci    // Instantiate Agent and encapsulate
421cb0ef41Sopenharmony_ci    if ((opts && opts.agent && typeof opts.agent.dispatch !== 'function')) {
431cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('Argument opts.agent must implement Agent')
441cb0ef41Sopenharmony_ci    }
451cb0ef41Sopenharmony_ci    const agent = opts && opts.agent ? opts.agent : new Agent(opts)
461cb0ef41Sopenharmony_ci    this[kAgent] = agent
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci    this[kClients] = agent[kClients]
491cb0ef41Sopenharmony_ci    this[kOptions] = buildMockOptions(opts)
501cb0ef41Sopenharmony_ci  }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  get (origin) {
531cb0ef41Sopenharmony_ci    let dispatcher = this[kMockAgentGet](origin)
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci    if (!dispatcher) {
561cb0ef41Sopenharmony_ci      dispatcher = this[kFactory](origin)
571cb0ef41Sopenharmony_ci      this[kMockAgentSet](origin, dispatcher)
581cb0ef41Sopenharmony_ci    }
591cb0ef41Sopenharmony_ci    return dispatcher
601cb0ef41Sopenharmony_ci  }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  dispatch (opts, handler) {
631cb0ef41Sopenharmony_ci    // Call MockAgent.get to perform additional setup before dispatching as normal
641cb0ef41Sopenharmony_ci    this.get(opts.origin)
651cb0ef41Sopenharmony_ci    return this[kAgent].dispatch(opts, handler)
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  async close () {
691cb0ef41Sopenharmony_ci    await this[kAgent].close()
701cb0ef41Sopenharmony_ci    this[kClients].clear()
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  deactivate () {
741cb0ef41Sopenharmony_ci    this[kIsMockActive] = false
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  activate () {
781cb0ef41Sopenharmony_ci    this[kIsMockActive] = true
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  enableNetConnect (matcher) {
821cb0ef41Sopenharmony_ci    if (typeof matcher === 'string' || typeof matcher === 'function' || matcher instanceof RegExp) {
831cb0ef41Sopenharmony_ci      if (Array.isArray(this[kNetConnect])) {
841cb0ef41Sopenharmony_ci        this[kNetConnect].push(matcher)
851cb0ef41Sopenharmony_ci      } else {
861cb0ef41Sopenharmony_ci        this[kNetConnect] = [matcher]
871cb0ef41Sopenharmony_ci      }
881cb0ef41Sopenharmony_ci    } else if (typeof matcher === 'undefined') {
891cb0ef41Sopenharmony_ci      this[kNetConnect] = true
901cb0ef41Sopenharmony_ci    } else {
911cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('Unsupported matcher. Must be one of String|Function|RegExp.')
921cb0ef41Sopenharmony_ci    }
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  disableNetConnect () {
961cb0ef41Sopenharmony_ci    this[kNetConnect] = false
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  // This is required to bypass issues caused by using global symbols - see:
1001cb0ef41Sopenharmony_ci  // https://github.com/nodejs/undici/issues/1447
1011cb0ef41Sopenharmony_ci  get isMockActive () {
1021cb0ef41Sopenharmony_ci    return this[kIsMockActive]
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  [kMockAgentSet] (origin, dispatcher) {
1061cb0ef41Sopenharmony_ci    this[kClients].set(origin, new FakeWeakRef(dispatcher))
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  [kFactory] (origin) {
1101cb0ef41Sopenharmony_ci    const mockOptions = Object.assign({ agent: this }, this[kOptions])
1111cb0ef41Sopenharmony_ci    return this[kOptions] && this[kOptions].connections === 1
1121cb0ef41Sopenharmony_ci      ? new MockClient(origin, mockOptions)
1131cb0ef41Sopenharmony_ci      : new MockPool(origin, mockOptions)
1141cb0ef41Sopenharmony_ci  }
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  [kMockAgentGet] (origin) {
1171cb0ef41Sopenharmony_ci    // First check if we can immediately find it
1181cb0ef41Sopenharmony_ci    const ref = this[kClients].get(origin)
1191cb0ef41Sopenharmony_ci    if (ref) {
1201cb0ef41Sopenharmony_ci      return ref.deref()
1211cb0ef41Sopenharmony_ci    }
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci    // If the origin is not a string create a dummy parent pool and return to user
1241cb0ef41Sopenharmony_ci    if (typeof origin !== 'string') {
1251cb0ef41Sopenharmony_ci      const dispatcher = this[kFactory]('http://localhost:9999')
1261cb0ef41Sopenharmony_ci      this[kMockAgentSet](origin, dispatcher)
1271cb0ef41Sopenharmony_ci      return dispatcher
1281cb0ef41Sopenharmony_ci    }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci    // If we match, create a pool and assign the same dispatches
1311cb0ef41Sopenharmony_ci    for (const [keyMatcher, nonExplicitRef] of Array.from(this[kClients])) {
1321cb0ef41Sopenharmony_ci      const nonExplicitDispatcher = nonExplicitRef.deref()
1331cb0ef41Sopenharmony_ci      if (nonExplicitDispatcher && typeof keyMatcher !== 'string' && matchValue(keyMatcher, origin)) {
1341cb0ef41Sopenharmony_ci        const dispatcher = this[kFactory](origin)
1351cb0ef41Sopenharmony_ci        this[kMockAgentSet](origin, dispatcher)
1361cb0ef41Sopenharmony_ci        dispatcher[kDispatches] = nonExplicitDispatcher[kDispatches]
1371cb0ef41Sopenharmony_ci        return dispatcher
1381cb0ef41Sopenharmony_ci      }
1391cb0ef41Sopenharmony_ci    }
1401cb0ef41Sopenharmony_ci  }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  [kGetNetConnect] () {
1431cb0ef41Sopenharmony_ci    return this[kNetConnect]
1441cb0ef41Sopenharmony_ci  }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  pendingInterceptors () {
1471cb0ef41Sopenharmony_ci    const mockAgentClients = this[kClients]
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci    return Array.from(mockAgentClients.entries())
1501cb0ef41Sopenharmony_ci      .flatMap(([origin, scope]) => scope.deref()[kDispatches].map(dispatch => ({ ...dispatch, origin })))
1511cb0ef41Sopenharmony_ci      .filter(({ pending }) => pending)
1521cb0ef41Sopenharmony_ci  }
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  assertNoPendingInterceptors ({ pendingInterceptorsFormatter = new PendingInterceptorsFormatter() } = {}) {
1551cb0ef41Sopenharmony_ci    const pending = this.pendingInterceptors()
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    if (pending.length === 0) {
1581cb0ef41Sopenharmony_ci      return
1591cb0ef41Sopenharmony_ci    }
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci    const pluralizer = new Pluralizer('interceptor', 'interceptors').pluralize(pending.length)
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci    throw new UndiciError(`
1641cb0ef41Sopenharmony_ci${pluralizer.count} ${pluralizer.noun} ${pluralizer.is} pending:
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci${pendingInterceptorsFormatter.format(pending)}
1671cb0ef41Sopenharmony_ci`.trim())
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_cimodule.exports = MockAgent
172