dev-mcps/postgres-mcp/test/connection-failure.test.js

33 lines
2.0 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { PostgresService, describeConnectionFailure } from "../src/postgres-service.js";
// What the network library says carries the address it tried; what the model and the logs are told says where to
// look instead, and nothing of the connection.
test("each way of never reaching PostgreSQL is said in words that point at the cause", () => {
const cases = [
[{ code: "ENOTFOUND", message: "getaddrinfo ENOTFOUND db.example.org" }, /does not resolve/],
[{ code: "ECONNREFUSED", message: "connect ECONNREFUSED 10.0.0.5:5432" }, /refused/],
[{ message: "timeout expired" }, /timed out.*firewall or security group/],
[{ message: "Connection terminated due to connection timeout" }, /timed out/],
[{ code: "EHOSTUNREACH" }, /cannot be reached/],
[{ message: "Connection terminated unexpectedly" }, /closed before PostgreSQL answered/],
[{ message: "The server does not support SSL connections" }, /does not accept TLS/],
[{ code: "ERR_TLS_CERT_ALTNAME_INVALID", message: "Hostname/IP does not match certificate's altnames: Host: db.example.org" }, /TLS handshake failed \(ERR_TLS_CERT_ALTNAME_INVALID\)/],
[{ code: "EPROTO" }, /TLS handshake failed/]
];
for (const [error, expected] of cases) {
const said = describeConnectionFailure(error);
assert.match(said, expected, JSON.stringify(error));
assert.doesNotMatch(said, /10\.0\.0\.5|db\.example\.org/, "nothing of the connection");
}
});
test("a real refused connection and a real unresolvable name say so", async () => {
for (const [host, port, expected] of [["127.0.0.1", 1, /refused/], ["no-such-host.invalid", 5432, /does not resolve/]]) {
const service = new PostgresService({ host, port, database: "d", user: "u", password: "p", sslmode: "disable" });
await assert.rejects(service.verify(), (error) => expected.test(error.message) && /^PostgreSQL connection failed: /.test(error.message));
service.destroy();
}
});