@logtape/syslog 1.3.0-dev.387 → 1.3.0-dev.397

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import {
6
6
  assertRejects,
7
7
  assertThrows,
8
8
  } from "@std/assert";
9
- import type { LogRecord } from "@logtape/logtape";
9
+ import type { LogRecord, Sink } from "@logtape/logtape";
10
10
  import { createSocket } from "node:dgram";
11
11
  import { createServer } from "node:net";
12
12
  import {
@@ -20,6 +20,10 @@ import {
20
20
 
21
21
  const test = suite(import.meta);
22
22
 
23
+ type TestSink = Sink & AsyncDisposable & {
24
+ readonly _internal_lastPromise: Promise<void>;
25
+ };
26
+
23
27
  // RFC 5424 syslog message parser for testing
24
28
  interface ParsedSyslogMessage {
25
29
  priority: number;
@@ -1232,19 +1236,34 @@ if (typeof Deno !== "undefined") {
1232
1236
  });
1233
1237
 
1234
1238
  test("DenoTcpSyslogConnection instantiation", () => {
1235
- const connection = new DenoTcpSyslogConnection("localhost", 514, 5000);
1239
+ const connection = new DenoTcpSyslogConnection(
1240
+ "localhost",
1241
+ 514,
1242
+ 5000,
1243
+ false,
1244
+ );
1236
1245
  assertInstanceOf(connection, DenoTcpSyslogConnection);
1237
1246
  });
1238
1247
 
1239
1248
  test("DenoTcpSyslogConnection close without connection", () => {
1240
- const connection = new DenoTcpSyslogConnection("localhost", 514, 5000);
1249
+ const connection = new DenoTcpSyslogConnection(
1250
+ "localhost",
1251
+ 514,
1252
+ 5000,
1253
+ false,
1254
+ );
1241
1255
  // close() should not throw even without connection
1242
1256
  connection.close();
1243
1257
  });
1244
1258
 
1245
1259
  test("DenoTcpSyslogConnection connection timeout", async () => {
1246
1260
  // Use a non-routable IP address to ensure connection failure
1247
- const connection = new DenoTcpSyslogConnection("10.255.255.1", 9999, 100); // Very short timeout
1261
+ const connection = new DenoTcpSyslogConnection(
1262
+ "10.255.255.1",
1263
+ 9999,
1264
+ 100,
1265
+ false,
1266
+ ); // Very short timeout
1248
1267
 
1249
1268
  try {
1250
1269
  await assertRejects(
@@ -1258,7 +1277,12 @@ if (typeof Deno !== "undefined") {
1258
1277
  });
1259
1278
 
1260
1279
  test("DenoTcpSyslogConnection send without connection", async () => {
1261
- const connection = new DenoTcpSyslogConnection("localhost", 514, 5000);
1280
+ const connection = new DenoTcpSyslogConnection(
1281
+ "localhost",
1282
+ 514,
1283
+ 5000,
1284
+ false,
1285
+ );
1262
1286
 
1263
1287
  await assertRejects(
1264
1288
  () => connection.send("test message"),
@@ -1319,6 +1343,7 @@ if (typeof Deno !== "undefined") {
1319
1343
  "127.0.0.1",
1320
1344
  serverAddr.port,
1321
1345
  0,
1346
+ false,
1322
1347
  ); // No timeout
1323
1348
 
1324
1349
  await connection.connect();
@@ -1338,138 +1363,313 @@ if (typeof Deno !== "undefined") {
1338
1363
  await serverTask.catch(() => {}); // Wait for server cleanup
1339
1364
  }
1340
1365
  });
1366
+
1367
+ test("DenoTcpSyslogConnection secure connection attempt (TLS)", {
1368
+ // Disable sanitizers because TLS connection cleanup on Windows can take
1369
+ // longer than the test, causing false positive leak detection
1370
+ sanitizeOps: false,
1371
+ sanitizeResources: false,
1372
+ }, async () => {
1373
+ // Attempt to connect to a port where no TLS server is listening
1374
+ const connection = new DenoTcpSyslogConnection(
1375
+ "127.0.0.1",
1376
+ 1515,
1377
+ 100,
1378
+ true,
1379
+ ); // secure: true
1380
+ try {
1381
+ await assertRejects(
1382
+ () => connection.connect(),
1383
+ Error,
1384
+ // Expected error message for TLS connection failure (e.g., handshake error)
1385
+ // Deno's error for TLS connection failure can be generic "connection reset" or similar if no server
1386
+ // The important part is it should NOT connect successfully if unsecured
1387
+ );
1388
+ } finally {
1389
+ connection.close();
1390
+ }
1391
+ });
1392
+
1393
+ test("DenoTcpSyslogSink secure connection (TLS) with getSyslogSink", {
1394
+ // Disable sanitizers because TLS connection cleanup on Windows can take
1395
+ // longer than the test, causing false positive leak detection
1396
+ sanitizeOps: false,
1397
+ sanitizeResources: false,
1398
+ }, async () => {
1399
+ // This test would require a mock TLS server to properly verify data transmission.
1400
+ // For now, we'll verify that the sink attempts a secure connection.
1401
+ // Given no mock TLS server, this should reject.
1402
+ const sink = getSyslogSink({
1403
+ hostname: "127.0.0.1",
1404
+ port: 1516, // Different port for TLS test
1405
+ protocol: "tcp",
1406
+ secure: true,
1407
+ timeout: 100,
1408
+ });
1409
+ const sinkWithPromise = sink as TestSink;
1410
+
1411
+ try {
1412
+ await assertRejects(
1413
+ async () => {
1414
+ sink(createMockLogRecord("info", ["Test secure sink connection"]));
1415
+ await sinkWithPromise._internal_lastPromise;
1416
+ },
1417
+ Error,
1418
+ // The error message might vary depending on Deno's TLS implementation and OS.
1419
+ // It should indicate a connection problem, not a successful plaintext connection.
1420
+ );
1421
+ } finally {
1422
+ await sink[Symbol.asyncDispose]();
1423
+ }
1424
+ });
1341
1425
  }
1342
1426
 
1343
1427
  // Node.js/Bun-specific tests
1344
- test("NodeUdpSyslogConnection instantiation", () => {
1345
- const connection = new NodeUdpSyslogConnection("localhost", 514, 5000);
1346
- assertInstanceOf(connection, NodeUdpSyslogConnection);
1347
- });
1428
+ if (typeof Deno === "undefined") {
1429
+ test("NodeUdpSyslogConnection instantiation", () => {
1430
+ const connection = new NodeUdpSyslogConnection("localhost", 514, 5000);
1431
+ assertInstanceOf(connection, NodeUdpSyslogConnection);
1432
+ });
1348
1433
 
1349
- test("NodeUdpSyslogConnection connect and close", () => {
1350
- const connection = new NodeUdpSyslogConnection("localhost", 514, 5000);
1351
- // connect() should not throw for UDP
1352
- connection.connect();
1353
- // close() should not throw for UDP
1354
- connection.close();
1355
- });
1434
+ test("NodeUdpSyslogConnection connect and close", () => {
1435
+ const connection = new NodeUdpSyslogConnection("localhost", 514, 5000);
1436
+ // connect() should not throw for UDP
1437
+ connection.connect();
1438
+ // close() should not throw for UDP
1439
+ connection.close();
1440
+ });
1441
+
1442
+ test("NodeUdpSyslogConnection send timeout", async () => {
1443
+ // Use a non-routable IP to trigger timeout
1444
+ const connection = new NodeUdpSyslogConnection("10.255.255.1", 9999, 50); // Very short timeout
1445
+ connection.connect();
1446
+
1447
+ try {
1448
+ await connection.send("test message");
1449
+ // If we reach here, the send didn't timeout as expected
1450
+ // This might happen if the system is very fast or network conditions are unusual
1451
+ } catch (error) {
1452
+ // This is expected - either timeout or network unreachable
1453
+ assertEquals(typeof (error as Error).message, "string");
1454
+ } finally {
1455
+ connection.close();
1456
+ }
1457
+ });
1458
+
1459
+ test("NodeTcpSyslogConnection instantiation", () => {
1460
+ const connection = new NodeTcpSyslogConnection(
1461
+ "localhost",
1462
+ 514,
1463
+ 5000,
1464
+ false,
1465
+ );
1466
+ assertInstanceOf(connection, NodeTcpSyslogConnection);
1467
+ });
1356
1468
 
1357
- test("NodeUdpSyslogConnection send timeout", async () => {
1358
- // Use a non-routable IP to trigger timeout
1359
- const connection = new NodeUdpSyslogConnection("10.255.255.1", 9999, 50); // Very short timeout
1360
- connection.connect();
1361
-
1362
- try {
1363
- await connection.send("test message");
1364
- // If we reach here, the send didn't timeout as expected
1365
- // This might happen if the system is very fast or network conditions are unusual
1366
- } catch (error) {
1367
- // This is expected - either timeout or network unreachable
1368
- assertEquals(typeof (error as Error).message, "string");
1369
- } finally {
1469
+ test("NodeTcpSyslogConnection close without connection", () => {
1470
+ const connection = new NodeTcpSyslogConnection(
1471
+ "localhost",
1472
+ 514,
1473
+ 5000,
1474
+ false,
1475
+ );
1476
+ // close() should not throw even without connection
1370
1477
  connection.close();
1371
- }
1372
- });
1478
+ });
1373
1479
 
1374
- test("NodeTcpSyslogConnection instantiation", () => {
1375
- const connection = new NodeTcpSyslogConnection("localhost", 514, 5000);
1376
- assertInstanceOf(connection, NodeTcpSyslogConnection);
1377
- });
1480
+ test("NodeTcpSyslogConnection connection timeout", {
1481
+ sanitizeResources: false,
1482
+ sanitizeOps: false,
1483
+ }, async () => {
1484
+ // Use a non-routable IP address to ensure connection failure
1485
+ const connection = new NodeTcpSyslogConnection(
1486
+ "10.255.255.1",
1487
+ 9999,
1488
+ 100,
1489
+ false,
1490
+ ); // Very short timeout
1378
1491
 
1379
- test("NodeTcpSyslogConnection close without connection", () => {
1380
- const connection = new NodeTcpSyslogConnection("localhost", 514, 5000);
1381
- // close() should not throw even without connection
1382
- connection.close();
1383
- });
1492
+ try {
1493
+ await assertRejects(
1494
+ () => connection.connect(),
1495
+ Error,
1496
+ );
1497
+ } finally {
1498
+ // Ensure cleanup
1499
+ connection.close();
1500
+ }
1501
+ });
1384
1502
 
1385
- test("NodeTcpSyslogConnection connection timeout", {
1386
- sanitizeResources: false,
1387
- sanitizeOps: false,
1388
- }, async () => {
1389
- // Use a non-routable IP address to ensure connection failure
1390
- const connection = new NodeTcpSyslogConnection("10.255.255.1", 9999, 100); // Very short timeout
1503
+ test("NodeTcpSyslogConnection send without connection", () => {
1504
+ const connection = new NodeTcpSyslogConnection(
1505
+ "localhost",
1506
+ 514,
1507
+ 5000,
1508
+ false,
1509
+ );
1391
1510
 
1392
- try {
1393
- await assertRejects(
1394
- () => connection.connect(),
1511
+ assertThrows(
1512
+ () => connection.send("test message"),
1395
1513
  Error,
1514
+ "Connection not established",
1396
1515
  );
1397
- } finally {
1398
- // Ensure cleanup
1399
- connection.close();
1400
- }
1401
- });
1516
+ });
1402
1517
 
1403
- test("NodeTcpSyslogConnection send without connection", () => {
1404
- const connection = new NodeTcpSyslogConnection("localhost", 514, 5000);
1518
+ test("NodeUdpSyslogConnection actual send test", async () => {
1519
+ // Try to send to a local UDP port
1520
+ const connection = new NodeUdpSyslogConnection("127.0.0.1", 1514, 1000); // Non-privileged port
1521
+ connection.connect();
1405
1522
 
1406
- assertThrows(
1407
- () => connection.send("test message"),
1408
- Error,
1409
- "Connection not established",
1410
- );
1411
- });
1523
+ try {
1524
+ // This will likely fail (no server listening), but should handle gracefully
1525
+ await connection.send("test syslog message");
1526
+ // If it succeeds, that's also fine - might have a server running
1527
+ } catch (error) {
1528
+ // Expected - likely no server listening, but the send mechanism should work
1529
+ const errorMessage = (error as Error).message;
1530
+ // Should contain either timeout or connection/network error
1531
+ assertEquals(typeof errorMessage, "string");
1532
+ } finally {
1533
+ connection.close();
1534
+ }
1535
+ });
1412
1536
 
1413
- test("NodeUdpSyslogConnection actual send test", async () => {
1414
- // Try to send to a local UDP port
1415
- const connection = new NodeUdpSyslogConnection("127.0.0.1", 1514, 1000); // Non-privileged port
1416
- connection.connect();
1417
-
1418
- try {
1419
- // This will likely fail (no server listening), but should handle gracefully
1420
- await connection.send("test syslog message");
1421
- // If it succeeds, that's also fine - might have a server running
1422
- } catch (error) {
1423
- // Expected - likely no server listening, but the send mechanism should work
1424
- const errorMessage = (error as Error).message;
1425
- // Should contain either timeout or connection/network error
1426
- assertEquals(typeof errorMessage, "string");
1427
- } finally {
1428
- connection.close();
1429
- }
1430
- });
1537
+ test("NodeTcpSyslogConnection actual send test with mock server", async () => {
1538
+ // Import Node.js modules for creating a server
1431
1539
 
1432
- test("NodeTcpSyslogConnection actual send test with mock server", async () => {
1433
- // Import Node.js modules for creating a server
1540
+ let receivedData = "";
1434
1541
 
1435
- let receivedData = "";
1542
+ // Create a simple TCP server
1543
+ const server = createServer((socket) => {
1544
+ socket.on("data", (data) => {
1545
+ receivedData = data.toString();
1546
+ socket.end();
1547
+ });
1548
+ });
1436
1549
 
1437
- // Create a simple TCP server
1438
- const server = createServer((socket) => {
1439
- socket.on("data", (data) => {
1440
- receivedData = data.toString();
1441
- socket.end();
1550
+ // Start server on random port
1551
+ await new Promise<void>((resolve) => {
1552
+ server.listen(0, "127.0.0.1", resolve);
1442
1553
  });
1443
- });
1444
1554
 
1445
- // Start server on random port
1446
- await new Promise<void>((resolve) => {
1447
- server.listen(0, "127.0.0.1", resolve);
1448
- });
1555
+ const address = server.address() as { port: number };
1556
+
1557
+ try {
1558
+ // Connect and send message
1559
+ const connection = new NodeTcpSyslogConnection(
1560
+ "127.0.0.1",
1561
+ address.port,
1562
+ 5000,
1563
+ false,
1564
+ );
1565
+
1566
+ await connection.connect();
1567
+ await connection.send("test syslog message from Node TCP");
1568
+ connection.close();
1449
1569
 
1450
- const address = server.address() as { port: number };
1570
+ // Wait a bit for server to receive data
1571
+ await new Promise((resolve) => setTimeout(resolve, 100));
1451
1572
 
1452
- try {
1453
- // Connect and send message
1573
+ // Verify message was received
1574
+ assertEquals(
1575
+ receivedData.includes("test syslog message from Node TCP"),
1576
+ true,
1577
+ );
1578
+ } finally {
1579
+ server.close();
1580
+ }
1581
+ });
1582
+
1583
+ test("NodeTcpSyslogConnection secure connection attempt (TLS)", async () => {
1584
+ // Attempt to connect to a port where no TLS server is listening
1454
1585
  const connection = new NodeTcpSyslogConnection(
1455
1586
  "127.0.0.1",
1456
- address.port,
1457
- 5000,
1458
- );
1587
+ 1515,
1588
+ 100,
1589
+ true,
1590
+ ); // secure: true
1591
+ try {
1592
+ await assertRejects(
1593
+ () => connection.connect(),
1594
+ Error,
1595
+ // Expected error message for TLS connection failure (e.g., handshake error)
1596
+ // Node.js TLS errors can be quite specific like "ECONNREFUSED" or "ERR_TLS_CERT_ALTNAME_INVALID" etc.
1597
+ // The key is that it should NOT connect successfully if unsecured
1598
+ );
1599
+ } finally {
1600
+ connection.close();
1601
+ }
1602
+ });
1459
1603
 
1460
- await connection.connect();
1461
- await connection.send("test syslog message from Node TCP");
1462
- connection.close();
1604
+ test("NodeTcpSyslogSink secure connection (TLS) with getSyslogSink", async () => {
1605
+ // Similar to Deno, this requires a mock TLS server for full verification.
1606
+ // For now, we verify that it attempts a secure connection and rejects if no TLS server.
1607
+ const sink = getSyslogSink({
1608
+ hostname: "127.0.0.1",
1609
+ port: 1516, // Different port for TLS test
1610
+ protocol: "tcp",
1611
+ secure: true,
1612
+ timeout: 100,
1613
+ });
1614
+ const sinkWithPromise = sink as TestSink;
1463
1615
 
1464
- // Wait a bit for server to receive data
1465
- await new Promise((resolve) => setTimeout(resolve, 100));
1616
+ try {
1617
+ await assertRejects(
1618
+ async () => {
1619
+ sink(createMockLogRecord("info", ["Test secure sink connection"]));
1620
+ await sinkWithPromise._internal_lastPromise;
1621
+ },
1622
+ Error,
1623
+ // Error messages might vary, but should indicate a connection or TLS issue.
1624
+ );
1625
+ } finally {
1626
+ await sink[Symbol.asyncDispose]();
1627
+ }
1628
+ });
1629
+ }
1466
1630
 
1467
- // Verify message was received
1468
- assertEquals(
1469
- receivedData.includes("test syslog message from Node TCP"),
1470
- true,
1471
- );
1472
- } finally {
1473
- server.close();
1474
- }
1631
+ // TLS options configuration tests
1632
+ test("getSyslogSink() with TLS options", () => {
1633
+ const sink = getSyslogSink({
1634
+ protocol: "tcp",
1635
+ secure: true,
1636
+ tlsOptions: {
1637
+ rejectUnauthorized: false,
1638
+ ca: "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----",
1639
+ },
1640
+ });
1641
+
1642
+ assertEquals(typeof sink, "function");
1643
+ assertEquals(typeof sink[Symbol.asyncDispose], "function");
1644
+ });
1645
+
1646
+ test("getSyslogSink() with TLS options and multiple CA certs", () => {
1647
+ const sink = getSyslogSink({
1648
+ protocol: "tcp",
1649
+ secure: true,
1650
+ tlsOptions: {
1651
+ rejectUnauthorized: true,
1652
+ ca: [
1653
+ "-----BEGIN CERTIFICATE-----\ncert1\n-----END CERTIFICATE-----",
1654
+ "-----BEGIN CERTIFICATE-----\ncert2\n-----END CERTIFICATE-----",
1655
+ ],
1656
+ },
1657
+ });
1658
+
1659
+ assertEquals(typeof sink, "function");
1660
+ assertEquals(typeof sink[Symbol.asyncDispose], "function");
1661
+ });
1662
+
1663
+ test("getSyslogSink() TLS options ignored for UDP", () => {
1664
+ // TLS options should be ignored for UDP connections
1665
+ const sink = getSyslogSink({
1666
+ protocol: "udp",
1667
+ secure: true, // This will be ignored for UDP
1668
+ tlsOptions: {
1669
+ rejectUnauthorized: false,
1670
+ },
1671
+ });
1672
+
1673
+ assertEquals(typeof sink, "function");
1674
+ assertEquals(typeof sink[Symbol.asyncDispose], "function");
1475
1675
  });