"use strict";
var import_vitest = require("vitest");
var import_connection_pool = require("./connection_pool.cjs");
(0, import_vitest.describe)("ConnectionPool", () => {
  (0, import_vitest.afterEach)(() => {
    import_vitest.vi.useRealTimers();
  });
  const makeConnectCb = () => {
    let n = 0;
    return import_vitest.vi.fn(async (_timeout) => `conn_${++n}`);
  };
  (0, import_vitest.describe)("basic operations", () => {
    (0, import_vitest.it)("should create and return a connection", async () => {
      const connections = [];
      const connectCb = import_vitest.vi.fn(async (_timeout) => {
        const conn3 = `conn_${connections.length}`;
        connections.push(conn3);
        return conn3;
      });
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const conn = await pool.get();
      (0, import_vitest.expect)(conn).toBe("conn_0");
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
      pool.put(conn);
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).toBe("conn_0");
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
    });
    (0, import_vitest.it)("should create new connection when none available", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const conn1 = await pool.get();
      pool.put(conn1);
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn1).toBe(conn2);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
    });
    (0, import_vitest.it)("should remove connection from pool", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const conn = await pool.get();
      pool.put(conn);
      pool.remove(conn);
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).not.toBe(conn);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(2);
      (0, import_vitest.expect)(closeCb).toHaveBeenCalledTimes(1);
    });
  });
  (0, import_vitest.describe)("maxSessionDuration", () => {
    (0, import_vitest.it)("should expire connections after maxSessionDuration", async () => {
      import_vitest.vi.useFakeTimers();
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb,
        maxSessionDuration: 100
        // 100ms
      });
      const conn1 = await pool.get();
      pool.put(conn1);
      await import_vitest.vi.advanceTimersByTimeAsync(150);
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).not.toBe(conn1);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(2);
      (0, import_vitest.expect)(closeCb).toHaveBeenCalledTimes(1);
    });
    (0, import_vitest.it)("should refresh connection timestamp when markRefreshedOnGet is true", async () => {
      import_vitest.vi.useFakeTimers();
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb,
        maxSessionDuration: 200,
        // 200ms
        markRefreshedOnGet: true
      });
      const conn1 = await pool.get();
      pool.put(conn1);
      await import_vitest.vi.advanceTimersByTimeAsync(100);
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).toBe(conn1);
      pool.put(conn2);
      await import_vitest.vi.advanceTimersByTimeAsync(100);
      const conn3 = await pool.get();
      (0, import_vitest.expect)(conn3).toBe(conn1);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
    });
  });
  (0, import_vitest.describe)("withConnection", () => {
    (0, import_vitest.it)("should return connection to pool on success", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      let capturedConn;
      await pool.withConnection(async (conn) => {
        capturedConn = conn;
        return "result";
      });
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).toBe(capturedConn);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
    });
    (0, import_vitest.it)("should remove connection from pool on error", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      let capturedConn;
      try {
        await pool.withConnection(async (conn) => {
          capturedConn = conn;
          throw new Error("test error");
        });
      } catch (e) {
      }
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).not.toBe(capturedConn);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(2);
      (0, import_vitest.expect)(closeCb).toHaveBeenCalledTimes(1);
    });
    (0, import_vitest.it)("should handle abort signal", async () => {
      import_vitest.vi.useFakeTimers();
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const abortController = new AbortController();
      let capturedConn;
      const promise = pool.withConnection(
        async (conn) => {
          capturedConn = conn;
          await new Promise((resolve) => setTimeout(resolve, 1e3));
          return "result";
        },
        { signal: abortController.signal }
      );
      setTimeout(() => abortController.abort(), 10);
      const rejection = (0, import_vitest.expect)(promise).rejects.toThrow();
      await import_vitest.vi.advanceTimersByTimeAsync(10);
      await rejection;
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).not.toBe(capturedConn);
      (0, import_vitest.expect)(closeCb).toHaveBeenCalledTimes(1);
    });
  });
  (0, import_vitest.describe)("prewarm", () => {
    (0, import_vitest.it)("should create connection in background", async () => {
      import_vitest.vi.useFakeTimers();
      let n = 0;
      const connectCb = import_vitest.vi.fn(async (_timeout) => {
        await new Promise((resolve) => setTimeout(resolve, 50));
        return `conn_${++n}`;
      });
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      pool.prewarm();
      await import_vitest.vi.advanceTimersByTimeAsync(50);
      const conn = await pool.get();
      (0, import_vitest.expect)(conn).toBeDefined();
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
    });
    (0, import_vitest.it)("should not prewarm if connections already exist", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const conn1 = await pool.get();
      pool.put(conn1);
      pool.prewarm();
      const conn2 = await pool.get();
      (0, import_vitest.expect)(conn2).toBe(conn1);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(1);
    });
  });
  (0, import_vitest.describe)("close", () => {
    (0, import_vitest.it)("should close all connections", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const conn1 = await pool.get();
      const conn2 = await pool.get();
      pool.put(conn1);
      pool.put(conn2);
      await pool.close();
      (0, import_vitest.expect)(closeCb).toHaveBeenCalledTimes(2);
    });
    (0, import_vitest.it)("should invalidate all connections", async () => {
      const connectCb = makeConnectCb();
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const conn1 = await pool.get();
      const conn2 = await pool.get();
      pool.put(conn1);
      pool.put(conn2);
      pool.invalidate();
      await pool.close();
      (0, import_vitest.expect)(closeCb).toHaveBeenCalledTimes(2);
    });
  });
  (0, import_vitest.describe)("concurrent access", () => {
    (0, import_vitest.it)("should handle concurrent get requests", async () => {
      const connectCb = import_vitest.vi.fn(async (_timeout) => {
        await new Promise((resolve) => setTimeout(resolve, 10));
        return `conn_${Date.now()}_${Math.random()}`;
      });
      const closeCb = import_vitest.vi.fn(async (_conn) => {
      });
      const pool = new import_connection_pool.ConnectionPool({
        connectCb,
        closeCb
      });
      const promises = Array.from({ length: 5 }, () => pool.get());
      const connections = await Promise.all(promises);
      const uniqueConnections = new Set(connections);
      (0, import_vitest.expect)(uniqueConnections.size).toBe(5);
      (0, import_vitest.expect)(connectCb).toHaveBeenCalledTimes(5);
    });
  });
});
//# sourceMappingURL=connection_pool.test.cjs.map