Repository: nodejs/node
Pull request: test: update tests for OpenSSL 3.0.14

Starting from OpenSSL 3.0.14, 3.1.6, 3.2.2, and 3.3.1, OpenSSL was fixed to return an error reason string for bad/unknown application protocols.

Update tests to handle both the old `ECONNRESET` error on older versions of OpenSSL and the new `ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL` on newer versions of OpenSSL.

Refs: https://github.com/openssl/openssl/pull/24338

---

Addresses these failures (Node.js dynamically linked against OpenSSL 3.0.14 -- I first noticed these (and other failures) with OpenSSL 3.2.2):
```console
not ok 1779 parallel/test-http2-https-fallback
  ---
  duration_ms: 164.14700
  severity: fail
  exitcode: 1
  stack: |-
    node:assert:126
      throw new AssertionError(obj);
      ^

    AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
    + actual - expected

    + 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'
    - 'ECONNRESET'
        at TLSSocket.<anonymous> (/home/nodejs/node/test/parallel/test-http2-https-fallback.js:154:11)
        at TLSSocket.<anonymous> (/home/nodejs/node/test/common/index.js:466:15)
        at TLSSocket.emit (node:events:520:28)
        at emitErrorNT (node:internal/streams/destroy:170:8)
        at emitErrorCloseNT (node:internal/streams/destroy:129:3)
        at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
      generatedMessage: true,
      code: 'ERR_ASSERTION',
      actual: 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL',
      expected: 'ECONNRESET',
      operator: 'strictEqual'
    }

    Node.js v23.0.0-pre
  ...
--
not ok 1873 parallel/test-http2-server-unknown-protocol
  ---
  duration_ms: 132.88000
  severity: fail
  exitcode: 1
  stack: |-
    node:assert:126
      throw new AssertionError(obj);
      ^

    AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
    + actual - expected

    + 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'
    - 'ECONNRESET'
        at TLSSocket.<anonymous> (/home/nodejs/node/test/parallel/test-http2-server-unknown-protocol.js:45:12)
        at TLSSocket.<anonymous> (/home/nodejs/node/test/common/index.js:466:15)
        at TLSSocket.emit (node:events:520:28)
        at emitErrorNT (node:internal/streams/destroy:170:8)
        at emitErrorCloseNT (node:internal/streams/destroy:129:3)
        at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
      generatedMessage: true,
      code: 'ERR_ASSERTION',
      actual: 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL',
      expected: 'ECONNRESET',
      operator: 'strictEqual'
    }

    Node.js v23.0.0-pre
  ...
--
not ok 3010 parallel/test-tls-alpn-server-client
  ---
  duration_ms: 156.74900
  severity: fail
  exitcode: 1
  stack: |-
    node:assert:126
      throw new AssertionError(obj);
      ^

    AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
    + actual - expected

    + 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'
    - 'ECONNRESET'
        at TLSSocket.<anonymous> (/home/nodejs/node/test/parallel/test-tls-alpn-server-client.js:195:14)
        at TLSSocket.<anonymous> (/home/nodejs/node/test/common/index.js:466:15)
        at TLSSocket.emit (node:events:520:28)
        at emitErrorNT (node:internal/streams/destroy:170:8)
        at emitErrorCloseNT (node:internal/streams/destroy:129:3)
        at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
      generatedMessage: true,
      code: 'ERR_ASSERTION',
      actual: 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL',
      expected: 'ECONNRESET',
      operator: 'strictEqual'
    }

    Node.js v23.0.0-pre
  ...
```

cc @nodejs/crypto 

<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


Changed files:
filename: test/parallel/test-http2-https-fallback.js
patch: @@ -151,7 +151,8 @@ function onSession(session, next) {
       // Incompatible ALPN TLS client
       tls(Object.assign({ port, ALPNProtocols: ['fake'] }, clientOptions))
         .on('error', common.mustCall((err) => {
-          strictEqual(err.code, 'ECONNRESET');
+          const allowedErrors = ['ECONNRESET', 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'];
+          ok(allowedErrors.includes(err.code), `'${err.code}' was not one of ${allowedErrors}.`);
           cleanup();
           testNoALPN();
         }));

filename: test/parallel/test-http2-server-unknown-protocol.js
patch: @@ -42,6 +42,7 @@ server.listen(0, function() {
     rejectUnauthorized: false,
     ALPNProtocols: ['bogus']
   }).on('error', common.mustCall((err) => {
-    assert.strictEqual(err.code, 'ECONNRESET');
+    const allowedErrors = ['ECONNRESET', 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'];
+    assert.ok(allowedErrors.includes(err.code), `'${err.code}' was not one of ${allowedErrors}.`);
   }));
 });

filename: test/parallel/test-tls-alpn-server-client.js
patch: @@ -184,15 +184,17 @@ function TestFatalAlert() {
   server.listen(0, serverIP, common.mustCall(() => {
     const { port } = server.address();
 
-    // The Node.js client will just report ECONNRESET because the connection
+    // The Node.js client will just report ECONNRESET (older OpenSSL) or
+    // ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL because the connection
     // is severed before the TLS handshake completes.
     tls.connect({
       host: serverIP,
       port,
       rejectUnauthorized: false,
       ALPNProtocols: ['bar']
     }, common.mustNotCall()).on('error', common.mustCall((err) => {
-      assert.strictEqual(err.code, 'ECONNRESET');
+      const allowedErrors = ['ECONNRESET', 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'];
+      assert.ok(allowedErrors.includes(err.code), `'${err.code}' was not one of ${allowedErrors}.`);
 
       // OpenSSL's s_client should output the TLS alert number, which is 120
       // for the 'no_application_protocol' alert.
@@ -240,7 +242,8 @@ function TestALPNCallback() {
 
     // Callback picks 2nd preference => undefined => ALPN rejected:
     assert.strictEqual(results[1].server, undefined);
-    assert.strictEqual(results[1].client.error.code, 'ECONNRESET');
+    const allowedErrors = ['ECONNRESET', 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'];
+    assert.ok(allowedErrors.includes(results[1].client.error.code), `'${results[1].client.error.code}' was not one of ${allowedErrors}.`);
 
     TestBadALPNCallback();
   });
@@ -263,7 +266,8 @@ function TestBadALPNCallback() {
   runTest(clientsOptions, serverOptions, function(results) {
     // Callback returns 'http/5' => doesn't match client ALPN => error & reset
     assert.strictEqual(results[0].server, undefined);
-    assert.strictEqual(results[0].client.error.code, 'ECONNRESET');
+    const allowedErrors = ['ECONNRESET', 'ERR_SSL_TLSV1_ALERT_NO_APPLICATION_PROTOCOL'];
+    assert.ok(allowedErrors.includes(results[0].client.error.code), `'${results[0].client.error.code}' was not one of ${allowedErrors}.`);
 
     TestALPNOptionsCallback();
   });