This is an automated email from the ASF dual-hosted git repository.

maciej pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new ae29f6c31 feat(js): add TCP/TLS integration tests and examples (#2822)
ae29f6c31 is described below

commit ae29f6c3154a12cec17c92217bb88897c744058a
Author: Atharva Lade <[email protected]>
AuthorDate: Mon Mar 9 14:24:19 2026 -0500

    feat(js): add TCP/TLS integration tests and examples (#2822)
    
    Closes #2808
---
 .github/actions/node-npm/pre-merge/action.yml |  31 +++++-
 examples/node/README.md                       |  22 ++++
 examples/node/package.json                    |   4 +-
 examples/node/src/tcp-tls/consumer.ts         | 135 ++++++++++++++++++++++++
 examples/node/src/tcp-tls/producer.ts         | 126 +++++++++++++++++++++++
 examples/node/test-examples.sh                |   9 ++
 foreign/node/src/e2e/tls.system.e2e.ts        | 142 ++++++++++++++++++++++++++
 scripts/run-node-examples-from-readme.sh      |  86 +++++++++++++++-
 8 files changed, 549 insertions(+), 6 deletions(-)

diff --git a/.github/actions/node-npm/pre-merge/action.yml 
b/.github/actions/node-npm/pre-merge/action.yml
index 3700e2fa4..06213dfce 100644
--- a/.github/actions/node-npm/pre-merge/action.yml
+++ b/.github/actions/node-npm/pre-merge/action.yml
@@ -106,9 +106,38 @@ runs:
         IGGY_SERVER_TCP_PORT: 8090
       shell: bash
 
-    - name: Stop Iggy server
+    - name: Stop Iggy server (plain)
       if: always() && inputs.task == 'e2e'
       uses: ./.github/actions/utils/server-stop
       with:
         pid-file: ${{ steps.iggy.outputs.pid_file }}
         log-file: ${{ steps.iggy.outputs.log_file }}
+
+    - name: Start Iggy server (TLS)
+      id: iggy-tls
+      if: inputs.task == 'e2e'
+      uses: ./.github/actions/utils/server-start
+      with:
+        pid-file: ${{ runner.temp }}/iggy-server-tls.pid
+        log-file: ${{ runner.temp }}/iggy-server-tls.log
+      env:
+        IGGY_TCP_TLS_ENABLED: "true"
+        IGGY_TCP_TLS_CERT_FILE: core/certs/iggy_cert.pem
+        IGGY_TCP_TLS_KEY_FILE: core/certs/iggy_key.pem
+
+    - name: TLS E2E tests
+      if: inputs.task == 'e2e'
+      run: |
+        cd foreign/node
+        node --import @swc-node/register/esm-register --test 
src/e2e/tls.system.e2e.ts
+      env:
+        IGGY_TCP_TLS_ENABLED: "true"
+        IGGY_TCP_ADDRESS: 127.0.0.1:8090
+      shell: bash
+
+    - name: Stop Iggy server (TLS)
+      if: always() && inputs.task == 'e2e'
+      uses: ./.github/actions/utils/server-stop
+      with:
+        pid-file: ${{ steps.iggy-tls.outputs.pid_file }}
+        log-file: ${{ steps.iggy-tls.outputs.log_file }}
diff --git a/examples/node/README.md b/examples/node/README.md
index 413156b91..e25098bba 100644
--- a/examples/node/README.md
+++ b/examples/node/README.md
@@ -107,3 +107,25 @@ npm run test:sink-data-producer
 ```
 
 Demonstrates how to produce data that can be consumed by external sinks for 
integration with other systems.
+
+## TLS Examples
+
+### TCP/TLS
+
+Producer and consumer examples using TLS-encrypted TCP connections with custom 
CA certificates:
+
+```bash
+npm run test:tcp-tls:producer
+npm run test:tcp-tls:consumer
+```
+
+These examples require a TLS-enabled Iggy server. Start the server with:
+
+```bash
+IGGY_TCP_TLS_ENABLED=true \
+IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \
+IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \
+cargo r --bin iggy-server
+```
+
+Demonstrates how to configure the client with `transport: 'TLS'` and a custom 
CA certificate for secure communication.
diff --git a/examples/node/package.json b/examples/node/package.json
index 3d6b2b550..a4160d50b 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -19,7 +19,9 @@
     "test:multi-tenant:producer": "tsx src/multi-tenant/producer.ts",
     "test:multi-tenant:consumer": "tsx src/multi-tenant/consumer.ts",
     "test:stream-builder": "tsx src/stream-builder/example.ts",
-    "test:sink-data-producer": "tsx src/sink-data-producer/producer.ts"
+    "test:sink-data-producer": "tsx src/sink-data-producer/producer.ts",
+    "test:tcp-tls:producer": "tsx src/tcp-tls/producer.ts",
+    "test:tcp-tls:consumer": "tsx src/tcp-tls/consumer.ts"
   },
   "keywords": [
     "iggy",
diff --git a/examples/node/src/tcp-tls/consumer.ts 
b/examples/node/src/tcp-tls/consumer.ts
new file mode 100644
index 000000000..f1772c1a7
--- /dev/null
+++ b/examples/node/src/tcp-tls/consumer.ts
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// TCP/TLS Consumer Example
+//
+// Demonstrates consuming messages over a TLS-encrypted TCP connection
+// using custom certificates from core/certs/.
+//
+// Prerequisites:
+//   Start the Iggy server with TLS enabled:
+//     IGGY_TCP_TLS_ENABLED=true \
+//     IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \
+//     IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \
+//     cargo r --bin iggy-server
+//
+// Run this example (from examples/node/):
+//   DEBUG=iggy:* npx tsx src/tcp-tls/consumer.ts
+
+import { readFileSync } from 'node:fs';
+import { Client, PollingStrategy, Consumer } from 'apache-iggy';
+import { log, PARTITION_ID, STREAM_ID, TOPIC_ID } from '../utils';
+
+const BATCHES_LIMIT = 5;
+const MESSAGES_PER_BATCH = 10;
+
+async function consumeMessages(
+  client: Client,
+  streamId: number | string,
+  topicId: number | string,
+  partitionId: number,
+) {
+  const interval = 500;
+  log(
+    'Messages will be consumed from stream: %s, topic: %s, partition: %d with 
interval %d ms.',
+    streamId,
+    topicId,
+    partitionId,
+    interval,
+  );
+
+  let offset = 0;
+  let consumedBatches = 0;
+
+  while (consumedBatches < BATCHES_LIMIT) {
+    try {
+      log('Polling for messages...');
+      const polledMessages = await client.message.poll({
+        streamId,
+        topicId,
+        consumer: Consumer.Single,
+        partitionId,
+        pollingStrategy: PollingStrategy.Offset(BigInt(offset)),
+        count: MESSAGES_PER_BATCH,
+        autocommit: false,
+      });
+
+      if (!polledMessages || polledMessages.messages.length === 0) {
+        log('No messages found.');
+        consumedBatches++;
+        await new Promise(resolve => setTimeout(resolve, interval));
+        continue;
+      }
+
+      offset += polledMessages.messages.length;
+
+      for (const message of polledMessages.messages) {
+        const payload = message.payload.toString('utf8');
+        const { offset: msgOffset, timestamp } = message.headers;
+        log('Received message: %s (offset: %d, timestamp: %d)', payload, 
msgOffset, timestamp);
+      }
+
+      consumedBatches++;
+      log('Consumed %d message(s) in batch %d.', 
polledMessages.messages.length, consumedBatches);
+
+      await new Promise(resolve => setTimeout(resolve, interval));
+    } catch (error) {
+      log('Error consuming messages: %o', error);
+      throw error;
+    }
+  }
+
+  log('Consumed %d batches of messages, exiting.', consumedBatches);
+}
+
+async function main() {
+  // Configure the client with TLS transport.
+  // transport: 'TLS'  activates TLS on the TCP connection
+  // ca: readFileSync(...)  provides the CA certificate to verify the server 
cert
+  // host: 'localhost'  must match the server certificate CN/SAN
+  const client = new Client({
+    transport: 'TLS',
+    options: {
+      port: 8090,
+      host: 'localhost',
+      ca: readFileSync('../../core/certs/iggy_ca_cert.pem'),
+    },
+    credentials: { username: 'iggy', password: 'iggy' },
+  });
+
+  try {
+    log('TLS consumer has started, selected transport: TLS');
+    log('Connecting to Iggy server over TLS...');
+
+    await consumeMessages(client, STREAM_ID, TOPIC_ID, PARTITION_ID);
+  } catch (error) {
+    log('Error in main: %o', error);
+    process.exitCode = 1;
+  } finally {
+    await client.destroy();
+    log('Disconnected from server.');
+  }
+}
+
+process.on('unhandledRejection', (reason, promise) => {
+  log('Unhandled Rejection at: %o, reason: %o', promise, reason);
+  process.exitCode = 1;
+});
+
+main();
diff --git a/examples/node/src/tcp-tls/producer.ts 
b/examples/node/src/tcp-tls/producer.ts
new file mode 100644
index 000000000..4fd3f5c93
--- /dev/null
+++ b/examples/node/src/tcp-tls/producer.ts
@@ -0,0 +1,126 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// TCP/TLS Producer Example
+//
+// Demonstrates producing messages over a TLS-encrypted TCP connection
+// using custom certificates from core/certs/.
+//
+// Prerequisites:
+//   Start the Iggy server with TLS enabled:
+//     IGGY_TCP_TLS_ENABLED=true \
+//     IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \
+//     IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \
+//     cargo r --bin iggy-server
+//
+// Run this example (from examples/node/):
+//   DEBUG=iggy:* npx tsx src/tcp-tls/producer.ts
+
+import { readFileSync } from 'node:fs';
+import { Client, Partitioning } from 'apache-iggy';
+import { BATCHES_LIMIT, cleanup, initSystem, log, MESSAGES_PER_BATCH, sleep } 
from '../utils';
+
+async function produceMessages(
+  client: Client,
+  streamId: number | string,
+  topicId: number | string,
+) {
+  const interval = 500;
+  log(
+    'Messages will be sent to stream: %s, topic: %s with interval %d ms.',
+    streamId,
+    topicId,
+    interval,
+  );
+
+  let currentId = 0;
+  let sentBatches = 0;
+
+  for (; sentBatches < BATCHES_LIMIT;) {
+    const messages = Array.from({ length: MESSAGES_PER_BATCH }).map(() => {
+      currentId++;
+      return {
+        id: currentId,
+        headers: [],
+        payload: `message-${currentId}`,
+      };
+    });
+
+    try {
+      await client.message.send({
+        streamId,
+        topicId,
+        messages,
+        partition: Partitioning.Balanced,
+      });
+    } catch (error) {
+      log('Error sending messages: %o', error);
+    } finally {
+      sentBatches++;
+      log('Sent messages: %o', messages);
+      await sleep(interval);
+    }
+  }
+
+  log('Sent %d batches of messages, exiting.', sentBatches);
+}
+
+async function main() {
+  // Configure the client with TLS transport.
+  // transport: 'TLS'  activates TLS on the TCP connection
+  // ca: readFileSync(...)  provides the CA certificate to verify the server 
cert
+  // host: 'localhost'  must match the server certificate CN/SAN
+  const client = new Client({
+    transport: 'TLS',
+    options: {
+      port: 8090,
+      host: 'localhost',
+      ca: readFileSync('../../core/certs/iggy_ca_cert.pem'),
+    },
+    credentials: { username: 'iggy', password: 'iggy' },
+  });
+
+  let streamId: number | null = null;
+  let topicId = 0;
+  try {
+    log('TLS producer has started, selected transport: TLS');
+    log('Connecting to Iggy server over TLS...');
+
+    const { stream, topic } = await initSystem(client);
+    streamId = stream.id;
+    topicId = topic.id;
+
+    const pong = await client.system.ping();
+    log('Ping successful.', pong);
+
+    log('Stream ID: %s, Topic ID: %s', streamId, topicId);
+    await produceMessages(client, streamId, topicId);
+  } catch (error) {
+    log('Error in main: %o', error);
+    process.exitCode = 1;
+  } finally {
+    if (streamId) {
+      await cleanup(client, streamId, topicId);
+    }
+    await client.destroy();
+    log('Disconnected from server.');
+  }
+}
+
+await main();
diff --git a/examples/node/test-examples.sh b/examples/node/test-examples.sh
index 6fb579d40..b2a5b5984 100755
--- a/examples/node/test-examples.sh
+++ b/examples/node/test-examples.sh
@@ -133,4 +133,13 @@ test_example "Stream Builder" "npm run 
test:stream-builder" 8
 echo -e "\n${YELLOW}Testing Sink Data Producer${NC}"
 test_example "Sink Data Producer" "npm run test:sink-data-producer" 8
 
+# TCP/TLS examples (require a TLS-enabled server)
+if [ "$IGGY_TCP_TLS_ENABLED" = "true" ]; then
+    echo -e "\n${YELLOW}Testing TCP/TLS Examples${NC}"
+    test_example "TCP/TLS Producer" "npm run test:tcp-tls:producer" 10
+    test_example "TCP/TLS Consumer" "npm run test:tcp-tls:consumer" 8
+else
+    echo -e "\n${YELLOW}Skipping TCP/TLS examples (set 
IGGY_TCP_TLS_ENABLED=true to run)${NC}"
+fi
+
 echo -e "\n${GREEN}🎉 All tests completed!${NC}"
diff --git a/foreign/node/src/e2e/tls.system.e2e.ts 
b/foreign/node/src/e2e/tls.system.e2e.ts
new file mode 100644
index 000000000..d6006ef31
--- /dev/null
+++ b/foreign/node/src/e2e/tls.system.e2e.ts
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// TLS integration tests for the Node.js SDK.
+//
+// These tests require a TLS-enabled Iggy server and are skipped by default.
+// To run them locally:
+//
+//   1. Start the server with TLS:
+//        IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \
+//        IGGY_TCP_TLS_ENABLED=true \
+//        IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \
+//        IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \
+//        cargo r --bin iggy-server
+//
+//   2. Run the tests:
+//        cd foreign/node
+//        IGGY_TCP_TLS_ENABLED=true IGGY_TCP_ADDRESS=127.0.0.1:8090 \
+//        node --import @swc-node/register/esm-register --test 
src/e2e/tls.system.e2e.ts
+
+import { readFileSync } from 'node:fs';
+import { resolve } from 'node:path';
+import { after, describe, it } from 'node:test';
+import assert from 'node:assert/strict';
+import { Client } from '../client/client.js';
+import { Partitioning, Consumer, PollingStrategy } from '../wire/index.js';
+import { getIggyAddress } from '../tcp.sm.utils.js';
+
+const tlsEnabled = process.env.IGGY_TCP_TLS_ENABLED === 'true';
+
+// Path to the CA certificate. Override with E2E_ROOT_CA_CERT env var,
+// otherwise fall back to the default relative path from the repo root.
+const caCertPath = process.env.E2E_ROOT_CA_CERT
+  || resolve(process.cwd(), '../../core/certs/iggy_ca_cert.pem');
+
+const getTlsClient = () => {
+  const [host, port] = getIggyAddress();
+  const caCert = readFileSync(caCertPath);
+
+  // The server certificate is issued for 'localhost'. When IGGY_TCP_ADDRESS 
uses
+  // an IP (e.g. 127.0.0.1), the default TLS hostname check would fail because
+  // the cert CN/SAN does not match an IP literal. Providing a custom
+  // checkServerIdentity that always succeeds works around this for local 
testing.
+  return new Client({
+    transport: 'TLS',
+    options: {
+      port,
+      host,
+      ca: caCert,
+      checkServerIdentity: () => undefined,
+    },
+    credentials: { username: 'iggy', password: 'iggy' },
+  });
+};
+
+describe('e2e -> tls', { skip: !tlsEnabled && 'IGGY_TCP_TLS_ENABLED is not 
set' }, async () => {
+
+  const c = getTlsClient();
+  const credentials = { username: 'iggy', password: 'iggy' };
+
+  it('e2e -> tls::ping', async () => {
+    assert.ok(await c.system.ping());
+  });
+
+  it('e2e -> tls::login', async () => {
+    assert.deepEqual(
+      await c.session.login(credentials),
+      { userId: 0 }
+    );
+  });
+
+  it('e2e -> tls::getStats', async () => {
+    const stats = await c.system.getStats();
+    assert.ok(stats);
+    assert.ok('processId' in stats);
+    assert.ok('hostname' in stats);
+  });
+
+  it('e2e -> tls::send and poll messages', async () => {
+    const streamName = 'tls-e2e-stream';
+    const topicName = 'tls-e2e-topic';
+
+    await c.stream.create({ name: streamName });
+    await c.topic.create({
+      streamId: streamName,
+      name: topicName,
+      partitionCount: 1,
+      compressionAlgorithm: 1,
+    });
+
+    const messages = [
+      { id: 1, headers: [], payload: 'tls-message-1' },
+      { id: 2, headers: [], payload: 'tls-message-2' },
+      { id: 3, headers: [], payload: 'tls-message-3' },
+    ];
+
+    await c.message.send({
+      streamId: streamName,
+      topicId: topicName,
+      messages,
+      partition: Partitioning.PartitionId(0),
+    });
+
+    const polled = await c.message.poll({
+      streamId: streamName,
+      topicId: topicName,
+      consumer: Consumer.Single,
+      partitionId: 0,
+      pollingStrategy: PollingStrategy.First,
+      count: 10,
+      autocommit: false,
+    });
+
+    assert.equal(polled.messages.length, 3);
+
+    await c.stream.delete({ streamId: streamName });
+  });
+
+  it('e2e -> tls::logout', async () => {
+    assert.ok(await c.session.logout());
+  });
+
+  after(() => {
+    c.destroy();
+  });
+});
diff --git a/scripts/run-node-examples-from-readme.sh 
b/scripts/run-node-examples-from-readme.sh
index 443c08636..449f44d59 100755
--- a/scripts/run-node-examples-from-readme.sh
+++ b/scripts/run-node-examples-from-readme.sh
@@ -131,7 +131,7 @@ done < <(grep -E "^\`cargo r --bin iggy -- " README.md)
 
 cd examples/node
 
-# Execute all example commands from README.md and examples/node/README.md and 
check if they pass or fail
+# Execute all non-TLS example commands from README.md and 
examples/node/README.md
 for readme_file in README.md examples/node/README.md; do
     if [ ! -f "${readme_file}" ]; then
         continue
@@ -163,13 +163,91 @@ for readme_file in README.md examples/node/README.md; do
         # Add a small delay between examples to avoid potential race conditions
         sleep 2
 
-    done < <(grep -E "^(npm run|tsx)" "${readme_file}")
+    done < <(grep -E "^(npm run|tsx)" "${readme_file}" | grep -v "tcp-tls")
 done
 
 cd "${ROOT_WORKDIR}"
 
-# Terminate server
-kill -TERM "$(cat ${PID_FILE})"
+# Stop the plain server before starting TLS server
+kill -TERM "$(cat ${PID_FILE})" 2>/dev/null || true
+sleep 2
+test -e ${PID_FILE} && rm ${PID_FILE}
+test -e ${LOG_FILE} && rm ${LOG_FILE}
+
+# Check if there are any TLS examples to run
+TLS_COMMANDS=""
+if [ -f "examples/node/README.md" ]; then
+    TLS_COMMANDS=$(grep -E "^(npm run|tsx)" "examples/node/README.md" | grep 
"tcp-tls" || true)
+fi
+
+if [ -n "${TLS_COMMANDS}" ] && [ "${exit_code}" -eq 0 ]; then
+    echo ""
+    echo "=== Starting TLS server for TLS examples ==="
+
+    # Remove old server data for clean TLS test
+    test -d local_data && rm -fr local_data
+
+    # Start TLS-enabled server
+    IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy \
+    IGGY_TCP_TLS_ENABLED=true \
+    IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \
+    IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \
+    ${SERVER_BIN} &>${LOG_FILE} &
+    echo $! >${PID_FILE}
+
+    # Wait for TLS server to start
+    SERVER_START_TIME=0
+    while ! grep -q "has started" ${LOG_FILE}; do
+        if [ ${SERVER_START_TIME} -gt ${TIMEOUT} ]; then
+            echo "TLS server did not start within ${TIMEOUT} seconds."
+            cat ${LOG_FILE}
+            exit 1
+        fi
+        echo "Waiting for TLS Iggy server to start... ${SERVER_START_TIME}"
+        sleep 1
+        ((SERVER_START_TIME += 1))
+    done
+
+    cd examples/node
+
+    # Run only TLS examples
+    for readme_file in README.md examples/node/README.md; do
+        if [ ! -f "${readme_file}" ]; then
+            continue
+        fi
+
+        while IFS= read -r command; do
+            command=$(echo "${command}" | tr -d '`' | sed 's/^#.*//')
+            if [ -z "${command}" ]; then
+                continue
+            fi
+
+            echo -e "\e[33mChecking TLS example command from 
${readme_file}:\e[0m ${command}"
+            echo ""
+
+            set +e
+            eval "${command}"
+            exit_code=$?
+            set -e
+
+            if [ ${exit_code} -ne 0 ]; then
+                echo ""
+                echo -e "\e[31mTLS example command failed:\e[0m ${command}"
+                echo ""
+                break 2
+            fi
+            sleep 2
+
+        done < <(grep -E "^(npm run|tsx)" "${readme_file}" | grep "tcp-tls")
+    done
+
+    cd "${ROOT_WORKDIR}"
+
+    # Terminate TLS server
+    kill -TERM "$(cat ${PID_FILE})" 2>/dev/null || true
+fi
+
+# Cleanup
 test -e ${PID_FILE} && rm ${PID_FILE}
 
 # If everything is ok remove log and pid files otherwise cat server log

Reply via email to