CVE-2022-24375: Uncontrolled Resource Consumption (CWE-400)
value: The package node-opcua before 2.74.0 are vulnerable to Denial of Service (DoS) when bypassing the limitations for excessive memory consumption by sending multiple CloseSession requests with the deleteSubscription parameter equal to False.
CWE description: The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
CVSS v3 base score: 7.5
Published: 2022-08-24T05:15Z
Repository: https://github.com/node-opcua/node-opcua
Language: JavaScript
Files changed: packages/node-opcua-client/source/private/client_session_impl.ts, packages/node-opcua-client/source/private/client_subscription_impl.ts, packages/node-opcua-end2end-test/test/discovery/u_test_discovery_server.ts, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_BrowseRequest.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionUseCase.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_Subscription_Transfer.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_browse_read.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_registerNodes.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_set_triggering.ts, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_test_accessing_service_before_session_is_activated.js, packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_transfer_session.js, packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts, packages/node-opcua-server-discovery/source/opcua_discovery_server.ts, packages/node-opcua-server/source/opcua_server.ts, packages/node-opcua-server/source/server_publish_engine.ts, packages/node-opcua-server/test/test_server_engine_subscription.js, packages/node-opcua-server/test/test_server_publish_engine.ts, packages/parallel_test.js
Commit date: 2022-08-13 11:38:40 +0200
Commit message: server: use ServiceFault on request error

Diff: diff --git a/packages/node-opcua-client/source/private/client_session_impl.ts b/packages/node-opcua-client/source/private/client_session_impl.ts
index 6a7d67eab..67e133d90 100644
--- a/packages/node-opcua-client/source/private/client_session_impl.ts
+++ b/packages/node-opcua-client/source/private/client_session_impl.ts
@@ -8,11 +8,11 @@ import { AggregateFunction } from "node-opcua-constants";
 import { DateTime } from "node-opcua-basic-types";
 import {
     ExtraDataTypeManager,
     getExtensionObjectConstructor,
     getExtraDataTypeManager,
-    promoteOpaqueStructure,
+    promoteOpaqueStructure
 } from "node-opcua-client-dynamic-extension-object";
 import { Certificate, Nonce } from "node-opcua-crypto";
 import { attributeNameById, BrowseDirection, LocalizedTextLike } from "node-opcua-data-model";
 import { DataValue } from "node-opcua-data-value";
 import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
@@ -80,11 +80,17 @@ import {
     TranslateBrowsePathsToNodeIdsResponse
 } from "node-opcua-service-translate-browse-path";
 import { WriteRequest, WriteResponse, WriteValue } from "node-opcua-service-write";
 import { StatusCode, StatusCodes, Callback, CallbackT } from "node-opcua-status-code";
 import { ErrorCallback } from "node-opcua-status-code";
-import { BrowseNextRequest, BrowseNextResponse, HistoryReadValueIdOptions, WriteValueOptions } from "node-opcua-types";
+import {
+    BrowseNextRequest,
+    BrowseNextResponse,
+    HistoryReadValueIdOptions,
+    ServiceFault,
+    WriteValueOptions
+} from "node-opcua-types";
 import { buffer_ellipsis, getFunctionParameterNames, isNullOrUndefined, lowerFirstLetter } from "node-opcua-utils";
 import { DataType, Variant, VariantLike } from "node-opcua-variant";
 
 import {
     ArgumentDefinition,
@@ -1538,10 +1544,11 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
             this._reconnecting.pendingTransactionsCount--;
 
             if (err && err.message.match(/BadSessionIdInvalid/) && request.constructor.name !== "ActivateSessionRequest") {
                 debugLog("Transaction on Invalid Session ", request.constructor.name);
                 request.requestHeader.requestHandle = requestHandleNotSetValue;
+                warningLog("client is now attempting to recreate a session");
                 this.recreate_session_and_reperform_transaction(request, callback);
                 return;
             }
             callback(err, response);
             const length = this._reconnecting.pendingTransactions.length; // record length before callback is called !
@@ -1593,10 +1600,11 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
                 if (response && (response as any).diagnosticInfos) {
                     (err as any).diagnosticsInfo = (response as any).diagnosticInfos;
                 }
                 return callback(err);
             }
+
             /* istanbul ignore next */
             if (!response) {
                 return callback(new Error("internal Error"));
             }
 
diff --git a/packages/node-opcua-client/source/private/client_subscription_impl.ts b/packages/node-opcua-client/source/private/client_subscription_impl.ts
index ec41ac017..ccf678f68 100644
--- a/packages/node-opcua-client/source/private/client_subscription_impl.ts
+++ b/packages/node-opcua-client/source/private/client_subscription_impl.ts
@@ -469,12 +469,16 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
             subscriptionId,
             triggeringItemId
         });
         session.setTriggering(setTriggeringRequest, (err: Error | null, response?: SetTriggeringResponse) => {
             if (err) {
-                // use soft error, no exceptions
-                return callback(null, response);
+                if (response) {
+                    // use soft error, no exceptions
+                    return callback(null, response);
+                } else {
+                    return callback(err);
+                }
             }
             // istanbul ignore next
             if (!response) {
                 return callback(new Error("Internal Error"));
             }
diff --git a/packages/node-opcua-end2end-test/test/discovery/u_test_discovery_server.ts b/packages/node-opcua-end2end-test/test/discovery/u_test_discovery_server.ts
index a944bb7cc..3e1b48439 100644
--- a/packages/node-opcua-end2end-test/test/discovery/u_test_discovery_server.ts
+++ b/packages/node-opcua-end2end-test/test/discovery/u_test_discovery_server.ts
@@ -16,11 +16,12 @@ import {
     RegisterServerResponse,
     RegisterServerRequest,
     StatusCodes,
     RegisterServerMethod,
     makeApplicationUrn,
-    OPCUADiscoveryServer
+    OPCUADiscoveryServer,
+    ServiceFault
 } from "node-opcua";
 import { readCertificate, exploreCertificate } from "node-opcua-crypto";
 import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
 
 import { createServerCertificateManager } from "../../test_helpers/createServerCertificateManager";
@@ -130,17 +131,19 @@ export function t(test: any) {
                     semaphoreFilePath: null,
                     isOnline: false
                 }
             });
 
-            function check_response(err: Error | null, response: any): void {
-                should.not.exist(err);
+            function check_error_response(err: Error | null, response: any): void {
+                should.exist(err);
+                should.not.exist(response);
+                (err as any).response.should.be.instanceOf(ServiceFault);
                 //xx console.log(response.toString());
-                response.responseHeader.serviceResult.should.eql(StatusCodes.BadDiscoveryUrlMissing);
+                (err as any).response.responseHeader.serviceResult.should.eql(StatusCodes.BadDiscoveryUrlMissing);
             }
 
-            await send_registered_server_request(discoveryServerEndpointUrl, request, check_response);
+            await send_registered_server_request(discoveryServerEndpointUrl, request, check_error_response);
         });
 
         it("DISCO1-2 should fail to register server to the discover server if server type is Client (BadInvalidArgument)", async () => {
             const request = new RegisterServerRequest({
                 server: {
@@ -159,17 +162,19 @@ export function t(test: any) {
                     semaphoreFilePath: null,
                     isOnline: false
                 }
             });
 
-            function check_response(err: Error | null, response: any) {
-                should.not.exist(err);
+            function check_error_response(err: Error | null, response: any) {
+                should.exist(err);
+                should.not.exist(response);
                 //xx debugLog(response.toString());
-                response.responseHeader.serviceResult.should.eql(StatusCodes.BadInvalidArgument);
+                (err as any).response.should.be.instanceOf(ServiceFault);
+                (err as any).response.responseHeader.serviceResult.should.eql(StatusCodes.BadInvalidArgument);
             }
 
-            await send_registered_server_request(discoveryServerEndpointUrl, request, check_response);
+            await send_registered_server_request(discoveryServerEndpointUrl, request, check_error_response);
         });
 
         it("DISCO1-3 should fail to register server to the discover server if server name array is empty (BadServerNameMissing)", async () => {
             const request = new RegisterServerRequest({
                 server: {
@@ -188,16 +193,18 @@ export function t(test: any) {
                     semaphoreFilePath: null,
                     isOnline: false
                 }
             });
 
-            function check_response(err: Error | null, response: any) {
-                should.not.exist(err);
-                response.responseHeader.serviceResult.should.eql(StatusCodes.BadServerNameMissing);
+            function check_error_response(err: Error | null, response: any) {
+                should.exist(err);
+                should.not.exist(response);
+                (err as any).response.should.be.instanceOf(ServiceFault);
+                (err as any).response.responseHeader.serviceResult.should.eql(StatusCodes.BadServerNameMissing);
             }
 
-            await send_registered_server_request(discoveryServerEndpointUrl, request, check_response);
+            await send_registered_server_request(discoveryServerEndpointUrl, request, check_error_response);
         });
     });
 
     describe("DISCO2 - DiscoveryServer2", function (this: any) {
         this.timeout(Math.max(40 * 1000, this.timeout()));
@@ -205,11 +212,12 @@ export function t(test: any) {
         let discoveryServer: OPCUADiscoveryServer;
         let discoveryServerEndpointUrl: string;
         let server: OPCUAServer;
 
         before(() => {
-            OPCUAServer.registry.count().should.eql(0);1162
+            OPCUAServer.registry.count().should.eql(0);
+            1162;
         });
 
         after(() => {
             OPCUAServer.registry.count().should.eql(0);
         });
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_BrowseRequest.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_BrowseRequest.js
index 6bfe035e1..483dcf638 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_BrowseRequest.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_BrowseRequest.js
@@ -162,14 +162,14 @@ module.exports = function(test) {
 
                 function(callback) {
                     const browseNextRequest = new BrowseNextRequest({
                         continuationPoints: null
                     });
-                    g_session.performMessageTransaction(browseNextRequest, function(err, response) {
+                    g_session.performMessageTransaction(browseNextRequest, function(err, _response) {
                         err.message.should.match(/BadNothingToDo/);
                         // console.log(response.toString());
-                        response.responseHeader.serviceResult.should.equal(StatusCodes.BadNothingToDo);
+                        err.response.responseHeader.serviceResult.should.equal(StatusCodes.BadNothingToDo);
                         callback();
                     });
                 }
             ], done);
         });
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionUseCase.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionUseCase.js
index d85b2c17c..5d6348a43 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionUseCase.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_SubscriptionUseCase.js
@@ -37,14 +37,14 @@ const {
     RepublishResponse,
     VariableIds,
     Variant,
     Subscription,
     SubscriptionState,
-    installSessionLogging
+    installSessionLogging,
+    ServiceFault
 } = require("node-opcua");
 
-
 const { make_debugLog, checkDebugFlag } = require("node-opcua-debug");
 
 const {
     perform_operation_on_client_session,
     perform_operation_on_subscription,
@@ -724,11 +724,12 @@ module.exports = function (test) {
                                         callback(err);
                                     });
                                 },
                                 function (callback) {
                                     function publish_callback(err, response) {
-                                        should.exist(response);
+                                        should.not.exist(response);
+                                        err.response.should.be.instanceOf(ServiceFault);
                                         should(err.message).match(/BadNoSubscription/);
                                     }
 
                                     // send many publish requests, in one go
                                     session.publish({}, publish_callback);
@@ -823,11 +824,12 @@ module.exports = function (test) {
                                 session.deleteSubscriptions(
                                     {
                                         subscriptionIds: []
                                     },
                                     function (err, response) {
-                                        should.exist(response);
+                                        should.not.exist(response);
+                                        should.exist(err);
                                         err.message.should.match(/BadNothingToDo/);
                                         callback();
                                     }
                                 );
                             }
@@ -1516,11 +1518,12 @@ module.exports = function (test) {
                         timestampsToReturn: TimestampsToReturn.Neither,
                         itemsToCreate: []
                     });
                     session.createMonitoredItems(createMonitoredItemsRequest, function (err, createMonitoredItemsResponse) {
                         should(err.message).match(/BadNothingToDo/);
-                        createMonitoredItemsResponse.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                        should.not.exist(createMonitoredItemsResponse);
+                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                         callback();
                     });
                 },
                 done
             );
@@ -1579,11 +1582,12 @@ module.exports = function (test) {
                         timestampsToReturn: TimestampsToReturn.Neither,
                         itemsToModify: []
                     });
                     session.modifyMonitoredItems(modifyMonitoredItemsRequest, function (err, modifyMonitoredItemsResponse) {
                         should(err.message).match(/BadNothingToDo/);
-                        modifyMonitoredItemsResponse.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                        should.not.exist(modifyMonitoredItemsResponse);
                         callback();
                     });
                 },
                 done
             );
@@ -1598,11 +1602,12 @@ module.exports = function (test) {
                         subscriptionId: subscription.subscriptionId,
                         monitoredItemIds: []
                     });
                     session.deleteMonitoredItems(deleteMonitoredItemsRequest, function (err, deleteMonitoredItemsResponse) {
                         should(err.message).match(/BadNothingToDo/);
-                        deleteMonitoredItemsResponse.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                        should.not.exist(deleteMonitoredItemsResponse);
                         callback();
                     });
                 },
                 done
             );
@@ -1791,10 +1796,11 @@ module.exports = function (test) {
                     session.createSubscription(
                         {
                             requestedPublishingInterval: -1
                         },
                         function (err, createSubscriptionResponse) {
+                            should.not.exist(err);
                             createSubscriptionResponse.revisedPublishingInterval.should.be.greaterThan(10);
 
                             inner_done(err);
                         }
                     );
@@ -1901,11 +1907,10 @@ module.exports = function (test) {
         before(function (done) {
             server = test.server;
 
             installSessionLogging(server);
 
-
             endpointUrl = test.endpointUrl;
             temperatureVariableId = server.temperatureVariableId;
 
             const namespace = server.engine.addressSpace.getOwnNamespace();
 
@@ -2137,17 +2142,17 @@ module.exports = function (test) {
                                     setImmediate(callback);
                                 });
                             })
                         ],
                         (err) => {
-                            tracelog("inner", err ? err.message: "");
+                            tracelog("inner", err ? err.message : "");
                             inner_done(err);
                         }
                     );
                 },
                 (err) => {
-                    tracelog("done", err ? err.message: "");
+                    tracelog("done", err ? err.message : "");
                     done(err);
                 }
             );
         });
 
@@ -4062,12 +4067,13 @@ module.exports = function (test) {
                         subscriptionId: VALID_SUBSCRIPTION,
                         retransmitSequenceNumber: INVALID_RETRANSMIT_SEQNUM
                     });
                     g_session.republish(request, function (err, response) {
                         should.exist(err);
-                        response.should.be.instanceof(RepublishResponse);
-                        response.responseHeader.serviceResult.should.eql(StatusCodes.BadMessageNotAvailable);
+                        should.not.exist(response);
+                        err.response.should.be.instanceof(ServiceFault);
+                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadMessageNotAvailable);
                         done();
                     });
                 }, done);
             });
 
@@ -4079,12 +4085,13 @@ module.exports = function (test) {
                         subscriptionId: INVALID_SUBSCRIPTION,
                         retransmitSequenceNumber: VALID_RETRANSMIT_SEQNUM
                     });
                     g_session.republish(request, function (err, response) {
                         should.exist(err);
-                        response.should.be.instanceof(RepublishResponse);
-                        response.responseHeader.serviceResult.should.eql(StatusCodes.BadSubscriptionIdInvalid);
+                        should.not.exist(response);
+                        err.response.should.be.instanceof(ServiceFault);
+                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSubscriptionIdInvalid);
                         done();
                     });
                 }, done);
             });
 
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_Subscription_Transfer.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_Subscription_Transfer.js
index 431fa1777..a440ca723 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_Subscription_Transfer.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_Subscription_Transfer.js
@@ -454,14 +454,21 @@ module.exports = function (test) {
                         spy_publish_session2.callCount.should.eql(4);
 
                         const response1 = spy_publish_session2.getCall(1).args[1];
                         const response2 = spy_publish_session2.getCall(2).args[1];
                         const response3 = spy_publish_session2.getCall(3).args[1];
-
-                        response1.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
-                        response2.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
-                        response3.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
+                        should.not.exist(response1);
+                        should.not.exist(response2);
+                        should.not.exist(response3);
+
+                        const err1 = spy_publish_session2.getCall(1).args[0];
+                        const err2 = spy_publish_session2.getCall(2).args[0];
+                        const err3 = spy_publish_session2.getCall(3).args[0];
+                        
+                        err1.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
+                        err2.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
+                        err3.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
                         //xx console.log(response1.toString())
                         //xx console.log(response2.toString())
                         //xx console.log(response3.toString())
                         callback();
                     }
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_browse_read.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_browse_read.js
index 4b2ba9863..9906d0f44 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_browse_read.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_browse_read.js
@@ -27,10 +27,12 @@ const fail_fast_connectivity_strategy = {
 };
 
 const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
 module.exports = function (test) {
     describe("Browse-Read-Write Services", function () {
+
+        /** @type {ClientSession} */
         let g_session = null;
 
         // use fail fast connectionStrategy
         const options = { connectionStrategy: fail_fast_connectivity_strategy };
 
@@ -168,11 +170,11 @@ module.exports = function (test) {
         it("T8-15 - #read should return BadNothingToDo when reading an empty nodeToRead array", function (done) {
             const nodesToRead = [];
 
             g_session.read(nodesToRead, function (err, dataValues) {
                 if (err) {
-                    const response = dataValues;
+                    const response = err.response;
                     //dataValues.length.should.be(1);
                     response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                     done();
                 } else {
                     done(new Error("Expecting an error here"));
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_registerNodes.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_registerNodes.js
index 9df1eef57..8d887c3fe 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_registerNodes.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_registerNodes.js
@@ -1,23 +1,14 @@
 "use strict";
 const should = require("should");
 const async = require("async");
 
+const { OPCUAClient, StatusCodes, UnregisterNodesRequest, RegisterNodesRequest, DataType, AttributeIds, ServiceFault } = require("node-opcua");
 const { perform_operation_on_client_session } = require("../../test_helpers/perform_operation_on_client_session");
 
-const opcua = require("node-opcua");
-const StatusCodes = opcua.StatusCodes;
-const OPCUAClient = opcua.OPCUAClient;
-const UnregisterNodesRequest = opcua.UnregisterNodesRequest;
-const RegisterNodesRequest = opcua.RegisterNodesRequest;
-const AttributeIds = opcua.AttributeIds;
-const DataType = opcua.DataType;
-
 module.exports = function (test) {
-
     describe("end-to-end testing registerNodes", function () {
-
         let client, endpointUrl;
 
         beforeEach(function (done) {
             client = OPCUAClient.create({});
             endpointUrl = test.endpointUrl;
@@ -28,137 +19,149 @@ module.exports = function (test) {
             client = null;
             done();
         });
 
         it("should register nodes - BadNothingToDo", function (done) {
-
-            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {
-
-                const request = new RegisterNodesRequest({
-                    nodesToRegister: []
-                });
-                session.performMessageTransaction(request, function (err/*, response*/) {
-                    err.message.should.match(/BadNothingToDo/);
-                    inner_done();
-                });
-
-            }, done);
+            perform_operation_on_client_session(
+                client,
+                endpointUrl,
+                function (session, inner_done) {
+                    const request = new RegisterNodesRequest({
+                        nodesToRegister: []
+                    });
+                    session.performMessageTransaction(request, function (err /*, response*/) {
+                        err.message.should.match(/BadNothingToDo/);
+                        inner_done();
+                    });
+                },
+                done
+            );
         });
 
         it("should register nodes - Good", function (done) {
-
-            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {
-
-                const request = new RegisterNodesRequest({
-                    nodesToRegister: [
-                        "ns=0;i=1"
-                    ]
-                });
-                session.performMessageTransaction(request, function (err, response) {
-                    should.not.exist(err);
-                    response.registeredNodeIds.length.should.eql(1);
-                    inner_done();
-                });
-
-            }, done);
+            perform_operation_on_client_session(
+                client,
+                endpointUrl,
+                function (session, inner_done) {
+                    const request = new RegisterNodesRequest({
+                        nodesToRegister: ["ns=0;i=1"]
+                    });
+                    session.performMessageTransaction(request, function (err, response) {
+                        should.not.exist(err);
+                        response.registeredNodeIds.length.should.eql(1);
+                        inner_done();
+                    });
+                },
+                done
+            );
         });
 
         it("should unregister nodes - BadNothingToDo", function (done) {
-            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {
-
-                const request = new UnregisterNodesRequest({
-                    nodesToUnregister: []
-                });
-                session.performMessageTransaction(request, function (err, response) {
-                    should.exist(response);
-                    err.message.should.match(/BadNothingToDo/);
-                    inner_done();
-                });
-
-            }, done);
+            perform_operation_on_client_session(
+                client,
+                endpointUrl,
+                function (session, inner_done) {
+                    const request = new UnregisterNodesRequest({
+                        nodesToUnregister: []
+                    });
+                    session.performMessageTransaction(request, function (err, response) {
+                        should.not.exist(response);
+                        should.exist(err);
+                        err.response.should.be.instanceOf(ServiceFault);
+                        err.message.should.match(/BadNothingToDo/);
+                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                        inner_done();
+                    });
+                },
+                done
+            );
         });
 
         it("should unregister nodes - Good", function (done) {
-            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {
-
-                const request = new UnregisterNodesRequest({
-                    nodesToUnregister: [
-                        "ns=0;i=1"
-                    ]
-                });
-                session.performMessageTransaction(request, function (err, response) {
-                    should.exist(response);
-                    should.not.exist(err);
-                    inner_done();
-                });
-
-            }, done);
+            perform_operation_on_client_session(
+                client,
+                endpointUrl,
+                function (session, inner_done) {
+                    const request = new UnregisterNodesRequest({
+                        nodesToUnregister: ["ns=0;i=1"]
+                    });
+                    session.performMessageTransaction(request, function (err, response) {
+                        should.exist(response);
+                        should.not.exist(err);
+                        inner_done();
+                    });
+                },
+                done
+            );
         });
 
-
         it("should register nodes and provide a alias that can be used on all operations", function (done) {
-            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {
-
-                const nodesToRegister = ["ns=2;s=Static_Scalar_Double"];
-                let registeredNodeIds = [];
-                let dataValue1, dataValue2;
-                async.series([
-                    function register_some_node(callback) {
-
-                        session.registerNodes(nodesToRegister, function (err, _registeredNodeIds) {
-                            if (err) {
-                                return callback(err);
+            perform_operation_on_client_session(
+                client,
+                endpointUrl,
+                function (session, inner_done) {
+                    const nodesToRegister = ["ns=2;s=Static_Scalar_Double"];
+                    let registeredNodeIds = [];
+                    let dataValue1, dataValue2;
+                    async.series(
+                        [
+                            function register_some_node(callback) {
+                                session.registerNodes(nodesToRegister, function (err, _registeredNodeIds) {
+                                    if (err) {
+                                        return callback(err);
+                                    }
+                                    registeredNodeIds = _registeredNodeIds;
+                                    callback();
+                                });
+                            },
+                            function (callback) {
+                                const nodeToWrite = {
+                                    nodeId: registeredNodeIds[0],
+                                    attributeId: AttributeIds.Value,
+                                    value: { value: { dataType: DataType.Double, value: 1000 } }
+                                };
+                                session.write(nodeToWrite, function (err, statusCode) {
+                                    statusCode.should.eql(StatusCodes.Good);
+                                    callback(err);
+                                });
+                            },
+                            function (callback) {
+                                const nodeToRead = { nodeId: nodesToRegister[0], attributeId: 13 };
+                                session.read(nodeToRead, function (err, dataValue) {
+                                    if (err) {
+                                        return callback(err);
+                                    }
+                                    dataValue.statusCode.should.eql(StatusCodes.Good);
+                                    dataValue1 = dataValue;
+                                    callback();
+                                });
+                            },
+                            function (callback) {
+                                const nodeToRead = { nodeId: registeredNodeIds[0], attributeId: 13 };
+                                session.read(nodeToRead, function (err, dataValue) {
+                                    if (err) {
+                                        return callback(err);
+                                    }
+                                    dataValue.statusCode.should.eql(StatusCodes.Good);
+                                    dataValue2 = dataValue;
+                                    callback();
+                                });
+                            },
+                            function (callback) {
+                                registeredNodeIds[0].toString().should.not.eql(nodesToRegister[0].toString());
+                                dataValue1.statusCode.toString().should.eql(dataValue2.statusCode.toString());
+
+                                //xx console.log(dataValue1.toString());
+                                //xx console.log(dataValue2.toString());
+
+                                dataValue1.value.toString().should.eql(dataValue2.value.toString());
+                                callback();
                             }
-                            registeredNodeIds = _registeredNodeIds;
-                            callback();
-                        });
-                    },
-                    function (callback) {
-
-                        const nodeToWrite = {
-                            nodeId: registeredNodeIds[0],
-                            attributeId: AttributeIds.Value,
-                            value: {value: {dataType: DataType.Double, value: 1000}}
-                        };
-                        session.write(nodeToWrite, function (err, statusCode) {
-                            statusCode.should.eql(StatusCodes.Good);
-                            callback(err);
-                        });
-                    },
-                    function (callback) {
-                        const nodeToRead = {nodeId: nodesToRegister[0], attributeId: 13};
-                        session.read(nodeToRead, function (err, dataValue) {
-                            if (err) {
-                                return callback(err);
-                            }
-                            dataValue.statusCode.should.eql(StatusCodes.Good);
-                            dataValue1 = dataValue;
-                            callback();
-                        });
-                    },
-                    function (callback) {
-                        const nodeToRead = {nodeId: registeredNodeIds[0], attributeId: 13};
-                        session.read(nodeToRead, function (err, dataValue) {
-                            if (err) {
-                                return callback(err);
-                            }
-                            dataValue.statusCode.should.eql(StatusCodes.Good);
-                            dataValue2 = dataValue;
-                            callback();
-                        });
-                    },
-                    function (callback) {
-                        registeredNodeIds[0].toString().should.not.eql(nodesToRegister[0].toString());
-                        dataValue1.statusCode.toString().should.eql(dataValue2.statusCode.toString());
-
-                        //xx console.log(dataValue1.toString());
-                        //xx console.log(dataValue2.toString());
-
-                        dataValue1.value.toString().should.eql(dataValue2.value.toString());
-                        callback();
-                    }
-                ], inner_done);
-
-            }, done);
+                        ],
+                        inner_done
+                    );
+                },
+                done
+            );
         });
     });
 };
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_set_triggering.ts b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_set_triggering.ts
index ddb819f9a..6192356e7 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_set_triggering.ts
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_set_triggering.ts
@@ -1,5 +1,6 @@
+/* eslint-disable max-statements */
 // tslint:disable: no-shadowed-variable
 // tslint:disable: no-console
 import {
     AddressSpace,
     assert,
@@ -27,10 +28,11 @@ import {
     NodeIdLike,
     NotificationMessage,
     OPCUAClient,
     Range,
     ServerSidePublishEngine,
+    ServiceFault,
     SetTriggeringRequestOptions,
     StatusCode,
     StatusCodes,
     TimestampsToReturn,
     UAVariable
@@ -239,20 +241,18 @@ export function t(test: any) {
 
             let _err!: Error;
 
             try {
                 const result = await subscription.setTriggering(t, [], []);
-
-                //  console.log(result.toString());
-
-                result.removeResults?.length.should.eql(0);
-                result.addResults?.length.should.eql(0);
-                result.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
+                console.log(result.toString());
             } catch (err) {
                 _err = err as Error;
             }
-            should.not.exist(_err, "not expecting any exception");
+            should.exist(_err, "expecting a ServiceFault exception");
+            const response = (_err as any).response as ServiceFault;
+            response.should.be.instanceOf(ServiceFault);
+            response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
 
             /*
              */
         });
         it("SetTriggering-2 it should return BadNothingToDo if both linksToAdd and linksToRemove are empty", async () => {
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_test_accessing_service_before_session_is_activated.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_test_accessing_service_before_session_is_activated.js
index dbbb0d8fb..62a0cb410 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_test_accessing_service_before_session_is_activated.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_test_accessing_service_before_session_is_activated.js
@@ -27,10 +27,11 @@ module.exports = function(test) {
 
         it("SNAC1- should return BadSessionNotActivated when service is called before session is activated", (done) => {
 
             let session1;
             let last_response;
+            let last_response_err;
             let activate_error;
             async.series([
 
                 function(callback) {
                     client.connect(test.endpointUrl, callback);
@@ -56,10 +57,11 @@ module.exports = function(test) {
 
                     client.performMessageTransaction(request, function(err, response) {
                         console.log(err ? err.toString() : "null");
                         console.log(response ? response.toString() : "null");
                         last_response = response;
+                        last_response_err = err;
                         callback();
                     });
                 },
                 // verify the session can no longer be used
                 function(callback) {
@@ -79,11 +81,11 @@ module.exports = function(test) {
                 }
             ], (err) => {
                 if (err) {
                     return done(err);
                 }
-                last_response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionNotActivated);
+                last_response_err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionNotActivated);
                 should.exist(activate_error, 
                     "Activate Session should return an error if there has been an attempt to use it before being activated");
                 activate_error.message.should.match(/BadSessionIdInvalid|BadSessionClosed/);
                 done();
             });
diff --git a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_transfer_session.js b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_transfer_session.js
index 21e3f06f6..60170476c 100644
--- a/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_transfer_session.js
+++ b/packages/node-opcua-end2end-test/test/end_to_end/u_test_e2e_transfer_session.js
@@ -1,724 +1,712 @@
 "use strict";
+const path = require("path");
+const fs = require("fs");
 const should = require("should");
 const async = require("async");
 const _ = require("underscore");
-const path = require("path");
-const fs = require("fs");
 
-const { 
-  OPCUAClient, 
-  StatusCodes, 
-  PublishRequest,
-  CreateSubscriptionRequest,
-  CloseSessionRequest,
-  ReadRequest,
-  TimestampsToReturn, 
-  MessageSecurityMode,
-  SecurityPolicy,
-  UserNameIdentityToken
-} = require("node-opcua");
 const {
-  readCertificate,
-  readCertificateRevocationList
-} = require("node-opcua-crypto");
+    OPCUAClient,
+    StatusCodes,
+    PublishRequest,
+    CreateSubscriptionRequest,
+    CloseSessionRequest,
+    ReadRequest,
+    TimestampsToReturn,
+    MessageSecurityMode,
+    SecurityPolicy,
+    UserNameIdentityToken,
+    ServiceFault,
+    ReadResponse
+} = require("node-opcua");
+const { readCertificate, readCertificateRevocationList } = require("node-opcua-crypto");
 
 const certificateFolder = path.join(__dirname, "../../../node-opcua-samples/certificates");
 fs.existsSync(certificateFolder).should.eql(true, "expecting certificate store at " + certificateFolder);
 
 function sendPublishRequest(session, callback) {
-  const publishRequest = new PublishRequest({});
-  session.performMessageTransaction(publishRequest, function(err, response) {
-    callback(err, response);
-  });
+    const publishRequest = new PublishRequest({});
+    session.performMessageTransaction(publishRequest, function (err, response) {
+        callback(err, response);
+    });
 }
 
 function createSubscription(session, callback) {
-  const publishingInterval = 1000;
-  const createSubscriptionRequest = new CreateSubscriptionRequest({
-    requestedPublishingInterval: publishingInterval,
-    requestedLifetimeCount: 60,
-    requestedMaxKeepAliveCount: 10,
-    maxNotificationsPerPublish: 10,
-    publishingEnabled: true,
-    priority: 6
-  });
-
-  session.performMessageTransaction(createSubscriptionRequest, function(err/*, response*/) {
-    callback(err);
-  });
-}
-
-const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
-
-module.exports = function(test) {
-
-  describe("testing session  transfer to different channel", function() {
-
-    it("RQC1 - It should be possible to close a session that has not be activated yet", function(done) {
-      let client1;
-      let session1;
-      async.series([
-
-        function(callback) {
-          client1 = OPCUAClient.create({});
-          client1.connect(test.endpointUrl, callback);
-        },
-
-        // create a session using client1, without activating it
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          client1._createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            callback();
-          });
-        },
-
-        function(callback) {
-
-          // Question: ? Should a unactivated session be accounted for
-          //             in the currentSessionCount ?
-          test.server.engine.currentSessionCount.should.eql(1);
-
-          // however client shall not record session yet
-          client1._sessions.length.should.eql(0);
-
-          // in fact, let make sure that close Session is not harmfull
-          client1.closeSession(session1, /* deleteSubscriptions =*/true, function(err) {
-            client1._sessions.length.should.eql(0);
-            if (err) {
-              // if treated as a Failure , close session expected to return BadSessionNotActivated
-              err.message.match(/BadSessionNotActivated/);
-            }
-            callback();
-          });
-
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        }
-      ], done);
-
+    const publishingInterval = 1000;
+    const createSubscriptionRequest = new CreateSubscriptionRequest({
+        requestedPublishingInterval: publishingInterval,
+        requestedLifetimeCount: 60,
+        requestedMaxKeepAliveCount: 10,
+        maxNotificationsPerPublish: 10,
+        publishingEnabled: true,
+        priority: 6
     });
 
-    it("RQB1 - calling CreateSession and CloseSession &  CloseSession again should return BadSessionIdInvalid", function(done) {
-      let client1;
-      let session1;
-      async.series([
-
-        function(callback) {
-          client1 = OPCUAClient.create();
-          client1.connect(test.endpointUrl, callback);
-        },
-        // create a session using client1
-        function(callback) {
-          client1._createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            callback();
-          });
-        },
-
-        function(callback) {
-          session1.close(function() {
-            callback();
-          });
-        },
-        function(callback) {
-          session1.close(function(err) {
-            // now session close do not return error if session in invalid
-            // err.message.should.match(/SessionIdInvalid/);
-            should.not.exist(err);
-            callback();
-          });
-        },
-        //
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          client1.disconnect(callback);
-        }
-
-      ], done);
-
-    });
-
-    it("RQB2 - calling CloseSession without calling CreateSession first", function(done) {
-      let client1;
-
-      async.series([
-
-        function(callback) {
-          client1 = OPCUAClient.create({});
-          client1.connect(test.endpointUrl, callback);
-        },
-        function(callback) {
-          const request = new CloseSessionRequest({
-            deleteSubscriptions: true
-          });
-          client1.performMessageTransaction(request, function(err, response) {
-            should.not.exist(err);
-            //err.message.should.match(/BadSessionIdInvalid/);
-            response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
-            callback();
-          });
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        }
-      ], done);
-
+    session.performMessageTransaction(createSubscriptionRequest, function (err /*, response*/) {
+        callback(err);
     });
+}
 
-    it("RQB3 - calling CreateSession,  CloseSession  and CloseSession again", function(done) {
-      let client1;
-      let session1;
-      async.series([
-
-        function(callback) {
-          client1 = OPCUAClient.create();
-          client1.connect(test.endpointUrl, callback);
-        },
-        // create a session using client1
-        function(callback) {
-          client1.createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            callback();
-          });
-        },
-
-        // first call to close session should be OK
-        function(callback) {
-          client1.closeSession(session1, /* deleteSubscriptions =*/true, function(err) {
-            callback(err);
-          });
-        },
-
-        // second call to close session should raise an error
-        function(callback) {
-          const request = new CloseSessionRequest({
-            deleteSubscriptions: true
-          });
-          client1.performMessageTransaction(request, function(err, response) {
-            should.not.exist(err);
-            //err.message.should.match(/BadSessionIdInvalid/);
-            response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
-            callback();
-          });
-        },
-
-        function(callback) {
-          client1.disconnect(callback);
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        }
+const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
 
-      ], function final(err) {
-        client1.disconnect(function() {
-          done(err);
+module.exports = function (test) {
+    describe("testing session  transfer to different channel", function () {
+        it("RQC1 - It should be possible to close a session that has not be activated yet", function (done) {
+            let client1;
+            let session1;
+            async.series(
+                [
+                    function (callback) {
+                        client1 = OPCUAClient.create({});
+                        client1.connect(test.endpointUrl, callback);
+                    },
+
+                    // create a session using client1, without activating it
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        client1._createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+
+                    function (callback) {
+                        // Question: ? Should a unactivated session be accounted for
+                        //             in the currentSessionCount ?
+                        test.server.engine.currentSessionCount.should.eql(1);
+
+                        // however client shall not record session yet
+                        client1._sessions.length.should.eql(0);
+
+                        // in fact, let make sure that close Session is not harmfull
+                        client1.closeSession(session1, /* deleteSubscriptions =*/ true, function (err) {
+                            client1._sessions.length.should.eql(0);
+                            if (err) {
+                                // if treated as a Failure , close session expected to return BadSessionNotActivated
+                                err.message.match(/BadSessionNotActivated/);
+                            }
+                            callback();
+                        });
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    }
+                ],
+                done
+            );
         });
-      });
 
-    });
-
-    it("RQ0 - call ActiveSession on a session that has been transferred to a different channel", function(done) {
-
-      // this test verifies that the following requirement can be met
-      // OpcUA 1.02 part 3 $5.5 Secure Channel Set page 20
-      // Once a  Client  has established a  Session  it may wish to access the  Session  from a different
-      // SecureChannel. The Client can do this by validating the new  SecureChannel  with the
-      // ActivateSession  Service  described in 5.6.3.
-      let client1, client2;
-      let session1;
-      async.series([
-
-        // create a first channel (client1)
-        function(callback) {
-          client1 = OPCUAClient.create();
-          client1.connect(test.endpointUrl, callback);
-        },
-        // create a session using client1
-        function(callback) {
-          client1._createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            callback();
-          });
-        },
-        // activate the session as expected on same channel used to create it
-        function(callback) {
-          client1._activateSession(session1, function(err) {
-            callback(err);
-          });
-        },
-        // let verify that it is now possible to send a request on client1's session
-        function(callback) {
-          // coerce nodeIds
-          const request = new ReadRequest({
-            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
-            maxAge: 0,
-            timestampsToReturn: TimestampsToReturn.Both
-          });
-          request.requestHeader.authenticationToken = session1.authenticationToken;
-          client1.performMessageTransaction(request, function(err, response) {
-            should.not.exist(err);
-            response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
-            callback();
-          });
-        },
-
-        // create a second channel (client2)
-        function(callback) {
-          client2 = OPCUAClient.create();
-          client2.connect(test.endpointUrl, callback);
-        },
-
-        // reactivate session on second channel
-        function(callback) {
-          client2.reactivateSession(session1, function(err) {
-            callback(err);
-          });
-        },
-
-        // now that session has been assigned to client 1,
-        // server shall refuse any requests on channel1
-        function(callback) {
-          // coerce nodeIds
-          const request = new ReadRequest({
-            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
-            maxAge: 0,
-            timestampsToReturn: TimestampsToReturn.Both
-          });
-          request.requestHeader.authenticationToken = session1.authenticationToken;
-          client1.performMessageTransaction(request, function(err, response) {
-            if (!err) {
-              response.responseHeader.serviceResult.should.eql(StatusCodes.BadSecureChannelIdInvalid);
-            }
-            callback(err);
-          });
-        },
-        // but server shall access request on new channel
-        function(callback) {
-          // coerce nodeIds
-          const request = new ReadRequest({
-            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
-            maxAge: 0,
-            timestampsToReturn: TimestampsToReturn.Both
-          });
-          request.requestHeader.authenticationToken = session1.authenticationToken;
-          client2.performMessageTransaction(request, function(err, response) {
-            if (!err) {
-              response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
-            }
-            callback(err);
-          });
-        },
-
-
-        // terminate
-        function(callback) {
-          client2.disconnect(callback);
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        }
-
-      ], done);
-    });
-
-    // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
-    // When the ActivateSession  Service  is called f or the first time then the Server shall reject the request
-    // if the  SecureChannel  is not same as the one associated with the CreateSession  request.
-    it("RQ1 - should reject if the channel used to activate the session for the first time is not the same as the channel used to create the session", function(done) {
-
-      let client1, client2;
-      let session1;
-
-      let initialChannelCount = 0;
-      async.series([
-
-        // create a first channel (client1)
-        function(callback) {
-          initialChannelCount = test.server.getChannels().length;
-          test.server.getChannels().length.should.equal(initialChannelCount);
-          client1 = OPCUAClient.create();
-          client1.connect(test.endpointUrl, callback);
-        },
-
-        // create a session using client1
-        //   ( without activating it)
-        function(callback) {
-          client1._createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            test.server.getChannels().length.should.equal(initialChannelCount + 1);
-            callback();
-          });
-        },
-        // create a second channel (client2)
-        function(callback) {
-          client2 = OPCUAClient.create();
-          client2.connect(test.endpointUrl, callback);
-        },
-
-        // activate the session created with client1 using client2 !!
-        // this should be detected by server and server shall return an error
-        function(callback) {
-          test.server.getChannels().length.should.equal(initialChannelCount + 2);
-          //xx console.log(" ID1 =", client1._secureChannel.channelId);
-          //xx console.log(" ID2 =", client2._secureChannel.channelId);
-
-          client2.reactivateSession(session1, function(err) {
-
-            if (!err) {
-              callback(new Error("_activateSession shall return an error "));
-            }
-            err.message.should.match(/BadSessionNotActivated/);
-            callback();
-          });
-        },
-
-        // terminate
-        function(callback) {
-          client2.disconnect(callback);
-        },
-        // activate the session as expected on same channel used to create it
-        // so we can close it properly
-        function(callback) {
-          client1._activateSession(session1, function(err) {
-            should.not.exist(err);
-            session1.close(callback);
-          });
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        }
-
-      ], done);
-    });
+        it("RQB1 - calling CreateSession and CloseSession &  CloseSession again should return BadSessionIdInvalid", function (done) {
+            let client1;
+            let session1;
+            async.series(
+                [
+                    function (callback) {
+                        client1 = OPCUAClient.create();
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    // create a session using client1
+                    function (callback) {
+                        client1._createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+
+                    function (callback) {
+                        session1.close(function () {
+                            callback();
+                        });
+                    },
+                    function (callback) {
+                        session1.close(function (err) {
+                            // now session close do not return error if session in invalid
+                            // err.message.should.match(/SessionIdInvalid/);
+                            should.not.exist(err);
+                            callback();
+                        });
+                    },
+                    //
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        client1.disconnect(callback);
+                    }
+                ],
+                done
+            );
+        });
 
+        it("RQB2 - calling CloseSession without calling CreateSession first", function (done) {
+            let client1;
+
+            async.series(
+                [
+                    function (callback) {
+                        client1 = OPCUAClient.create({});
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    function (callback) {
+                        const request = new CloseSessionRequest({
+                            deleteSubscriptions: true
+                        });
+                        client1.performMessageTransaction(request, function (err, response) {
+                            should.exist(err);
+                            should.not.exist(response);
+                            err.response.should.be.instanceOf(ServiceFault);
+                            err.message.should.match(/BadSessionIdInvalid/);
+                            err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
+                            callback();
+                        });
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                done
+            );
+        });
 
-    function m(file) {
-      const p = path.join(certificateFolder, file);
-      if (!fs.existsSync(p)) {
-        console.error(" cannot find ", p);
-      }
-      return p;
-    }
-
-    // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
-    // Subsequent calls to  ActivateSession  may be associated with different  SecureChannels.  If this is the
-    // case then  the  Server  shall verify that the  Certificate  the  Client  used to create the new
-    // SecureChannel  is the same as the  Certificate  used to create the original  SecureChannel.
-    it("RQ2 -server should raise an error if a existing session is reactivated from a channel that have different certificate than the original channel", function(done) {
-
-      const serverCertificate = test.server.getCertificateChain();
-
-      let client1, client2;
-      let session1;
-      async.series([
-
-        // create a first channel (client1) with
-        function(callback) {
-          //xx console.log(" creating initial channel with some certificate");
-          const certificateFile1 = m("client_cert_2048.pem");
-          const privateKeyFile1 = m("client_key_2048.pem");
-          console.log(certificateFile1);
-
-          client1 = OPCUAClient.create({
-            certificateFile: certificateFile1,
-            privateKeyFile: privateKeyFile1,
-            securityMode: MessageSecurityMode.Sign,
-            securityPolicy: SecurityPolicy.Basic128Rsa15,
-            serverCertificate: serverCertificate
-          });
-
-   
-          const certificate = readCertificate(certificateFile1);
-
-          async function doIt() {
-            await test.server.serverCertificateManager.trustCertificate(certificate);
-            const issuerCertificateFile = m("CA/public/cacert.pem");
-            const issuerCertificateRevocationListFile = m("CA/crl/revocation_list.der");
-            const issuerCertificate = readCertificate(issuerCertificateFile);
-            const issuerCrl = await readCertificateRevocationList(issuerCertificateRevocationListFile);
-            await test.server.serverCertificateManager.addIssuer(issuerCertificate);
-            await test.server.serverCertificateManager.addRevocationList(issuerCrl);
-            callback();
-          }
-          doIt();
-        },
-        function(callback) {
-          client1.connect(test.endpointUrl, callback);
-        },
-        // create a session using client1
-        function(callback) {
-          //xx console.log(" create session");
-          client1._createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            callback();
-          });
-        },
-        // activate the session as expected on same channel used to create it
-        function(callback) {
-          //xx console.log(" activate session");
-          client1._activateSession(session1, function(err) {
-            callback(err);
-          });
-        },
-
-        // create a second channel (client2)
-        // with a different certificate ....
-        function(callback) {
-
-          // creating second channel with different credential
-          console.log(" creating second channel with different certificate");
-          const certificateFile2 = m("client_cert_3072.pem");
-          const privateKeyFile2 = m("client_key_3072.pem");
-          client2 = OPCUAClient.create({
-            certificateFile: certificateFile2,
-            privateKeyFile: privateKeyFile2,
-            securityMode: MessageSecurityMode.Sign,
-            securityPolicy: SecurityPolicy.Basic256,
-            serverCertificate: serverCertificate
-          });
-          const certificate = readCertificate(certificateFile2);
-          test.server.serverCertificateManager.trustCertificate(certificate, callback);
-
-        },
-        function(callback) {
-          client2.connect(test.endpointUrl, callback);
-        },
-        function(callback) {
-          // reactivate session on second channel
-          // Reactivate should fail because certificate is not the same as the original one
-          client2.reactivateSession(session1, function(err) {
-            if (err) {
-              err.message.should.match(/BadNoValidCertificates/);
-              callback();
-            } else {
-              callback(new Error("expecting reactivateSession to fail"));
-            }
-          });
-        },
-        // terminate
-        function(callback) {
-          client2.disconnect(callback);
-        },
-        function(callback) {
-          session1.close(callback);
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        },
-
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        }
+        it("RQB3 - calling CreateSession,  CloseSession  and CloseSession again", function (done) {
+            let client1;
+            let session1;
+            async.series(
+                [
+                    function (callback) {
+                        client1 = OPCUAClient.create();
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    // create a session using client1
+                    function (callback) {
+                        client1.createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+
+                    // first call to close session should be OK
+                    function (callback) {
+                        client1.closeSession(session1, /* deleteSubscriptions =*/ true, function (err) {
+                            callback(err);
+                        });
+                    },
+
+                    // second call to close session should raise an error
+                    function (callback) {
+                        const request = new CloseSessionRequest({
+                            deleteSubscriptions: true
+                        });
+                        client1.performMessageTransaction(request, function (err, response) {
+                            should.exist(err);
+                            should.not.exist(response);
+                            err.message.should.match(/BadSessionIdInvalid/);
+                            err.response.should.be.instanceOf(ServiceFault);
+                            err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
+                            callback();
+                        });
+                    },
+
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                function final(err) {
+                    client1.disconnect(function () {
+                        done(err);
+                    });
+                }
+            );
+        });
 
-      ], done);
+        it("RQ0 - call ActiveSession on a session that has been transferred to a different channel", function (done) {
+            // this test verifies that the following requirement can be met
+            // OpcUA 1.02 part 3 $5.5 Secure Channel Set page 20
+            // Once a  Client  has established a  Session  it may wish to access the  Session  from a different
+            // SecureChannel. The Client can do this by validating the new  SecureChannel  with the
+            // ActivateSession  Service  described in 5.6.3.
+            let client1, client2;
+            let session1;
+            async.series(
+                [
+                    // create a first channel (client1)
+                    function (callback) {
+                        client1 = OPCUAClient.create();
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    // create a session using client1
+                    function (callback) {
+                        client1._createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+                    // activate the session as expected on same channel used to create it
+                    function (callback) {
+                        client1._activateSession(session1, function (err) {
+                            callback(err);
+                        });
+                    },
+                    // let verify that it is now possible to send a request on client1's session
+                    function (callback) {
+                        // coerce nodeIds
+                        const request = new ReadRequest({
+                            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
+                            maxAge: 0,
+                            timestampsToReturn: TimestampsToReturn.Both
+                        });
+                        request.requestHeader.authenticationToken = session1.authenticationToken;
+                        client1.performMessageTransaction(request, function (err, response) {
+                            should.not.exist(err);
+                            response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
+                            callback();
+                        });
+                    },
+
+                    // create a second channel (client2)
+                    function (callback) {
+                        client2 = OPCUAClient.create();
+                        client2.connect(test.endpointUrl, callback);
+                    },
+
+                    // reactivate session on second channel
+                    function (callback) {
+                        client2.reactivateSession(session1, function (err) {
+                            callback(err);
+                        });
+                    },
+
+                    // now that session has been assigned to client 1,
+                    // server shall refuse any requests on channel1
+                    function (callback) {
+                        // coerce nodeIds
+                        const request = new ReadRequest({
+                            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
+                            maxAge: 0,
+                            timestampsToReturn: TimestampsToReturn.Both
+                        });
+                        request.requestHeader.authenticationToken = session1.authenticationToken;
+                        client1.performMessageTransaction(request, function (err, response) {
+                            should.not.exist(err);
+                            should.exist(response);
+                            response.should.be.instanceOf(ReadResponse);
+                            response.responseHeader.serviceResult.should.eql(StatusCodes.BadSecureChannelIdInvalid);
+                            callback();
+                        });
+                    },
+                    // but server shall access request on new channel
+                    function (callback) {
+                        // coerce nodeIds
+                        const request = new ReadRequest({
+                            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
+                            maxAge: 0,
+                            timestampsToReturn: TimestampsToReturn.Both
+                        });
+                        request.requestHeader.authenticationToken = session1.authenticationToken;
+                        client2.performMessageTransaction(request, function (err, response) {
+                            if (!err) {
+                                response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
+                            }
+                            callback(err);
+                        });
+                    },
+
+                    // terminate
+                    function (callback) {
+                        client2.disconnect(callback);
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                done
+            );
+        });
 
-    });
+        // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
+        // When the ActivateSession  Service  is called f or the first time then the Server shall reject the request
+        // if the  SecureChannel  is not same as the one associated with the CreateSession  request.
+        it("RQ1 - should reject if the channel used to activate the session for the first time is not the same as the channel used to create the session", function (done) {
+            let client1, client2;
+            let session1;
+
+            let initialChannelCount = 0;
+            async.series(
+                [
+                    // create a first channel (client1)
+                    function (callback) {
+                        initialChannelCount = test.server.getChannels().length;
+                        test.server.getChannels().length.should.equal(initialChannelCount);
+                        client1 = OPCUAClient.create();
+                        client1.connect(test.endpointUrl, callback);
+                    },
+
+                    // create a session using client1
+                    //   ( without activating it)
+                    function (callback) {
+                        client1._createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            test.server.getChannels().length.should.equal(initialChannelCount + 1);
+                            callback();
+                        });
+                    },
+                    // create a second channel (client2)
+                    function (callback) {
+                        client2 = OPCUAClient.create();
+                        client2.connect(test.endpointUrl, callback);
+                    },
+
+                    // activate the session created with client1 using client2 !!
+                    // this should be detected by server and server shall return an error
+                    function (callback) {
+                        test.server.getChannels().length.should.equal(initialChannelCount + 2);
+                        //xx console.log(" ID1 =", client1._secureChannel.channelId);
+                        //xx console.log(" ID2 =", client2._secureChannel.channelId);
+
+                        client2.reactivateSession(session1, function (err) {
+                            if (!err) {
+                                callback(new Error("_activateSession shall return an error "));
+                            }
+                            err.message.should.match(/BadSessionNotActivated/);
+                            callback();
+                        });
+                    },
+
+                    // terminate
+                    function (callback) {
+                        client2.disconnect(callback);
+                    },
+                    // activate the session as expected on same channel used to create it
+                    // so we can close it properly
+                    function (callback) {
+                        client1._activateSession(session1, function (err) {
+                            should.not.exist(err);
+                            session1.close(callback);
+                        });
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                done
+            );
+        });
 
-    // In addition,the Server shall verify that the  Client  supplied a  UserIdentityToken  that is   identical to the token
-    // currently associated with the  Session.
-    it("RQ3 - server should raise an error if a session is reactivated with different user identity tokens", function(done) {
-      let client1, client2;
-      let session1;
-
-      const user1 = {
-        userName: "user1", password: "password1"
-      };
-      const user2 = new UserNameIdentityToken({
-        userName: "user1", password: "password1"
-      });
-      //xx console.log(" user1 ", user1.toString());
-      async.series([
-
-        // given a established session with a subscription and some publish request
-
-        function(callback) {
-          client1 = OPCUAClient.create();
-          client1.connect(test.endpointUrl, callback);
-        },
-        // create a session using client1
-        function(callback) {
-
-          client1.createSession(user1, function(err, session) {
-            if (err) {
-              return callback(err);
+        function m(file) {
+            const p = path.join(certificateFolder, file);
+            if (!fs.existsSync(p)) {
+                console.error(" cannot find ", p);
             }
-            session1 = session;
-            callback();
-          });
-        },
-        // when the session is transferred to a different channel
-        // create a second channel (client2)
-        function(callback) {
-          client2 = OPCUAClient.create();
-          client2.connect(test.endpointUrl, callback);
-        },
-        function(callback) {
-          // reactivate session on second channel
-          // alter session1.userIdentityInfo
-          session1.userIdentityInfo = user2;
-          session1.userIdentityInfo.userName.should.eql("user1");
-
-          client2.reactivateSession(session1, function(err) {
-            err.message.should.match(/BadIdentityChangeNotSupported/);
-            _.contains(client1._sessions, session1).should.eql(true);// should have failed
-            callback();
-          });
-        },
-        // terminate
-        function(callback) {
-          client2.disconnect(callback);
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
+            return p;
         }
 
-      ], done);
-
-    });
-    // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel.
-    xit("RQ4 - server should reject request send via old channel when session has been transferred to new channel", function(done) {
-      async.series([], done);
-    });
-
-    // unprocessed pending Requests such as PublishRequest shall be be denied by the server
-    // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel
-    it("RQ5 - server should reject pending requests send to old channel when session has been transferred to new channel", function(done) {
-
-      const sinon = require("sinon");
-
-      const collectPublishResponse = sinon.spy();
-
-      let client1, client2;
-      let session1;
-      async.series([
-
-        // given a established session with a subscription and some publish request
-
-        function(callback) {
-          client1 = OPCUAClient.create();
-          client1.connect(test.endpointUrl, callback);
-        },
-        // create a session using client1
-        function(callback) {
-          client1._createSession(function(err, session) {
-            if (err) {
-              return callback(err);
-            }
-            session1 = session;
-            callback();
-          });
-        },
-        // activate the session as expected on same channel used to create it
-        function(callback) {
-          client1._activateSession(session1, function(err) {
-            callback(err);
-          });
-        },
-
-        // creaet a subscription,
-        function(callback) {
-          createSubscription(session1, callback);
-        },
-
-
-        // when the session is transferred to a different channel
-        // create a second channel (client2)
-        function(callback) {
-          client2 = OPCUAClient.create();
-          client2.connect(test.endpointUrl, callback);
-          collectPublishResponse.callCount.should.eql(0);
-        },
-
-        // provision 3 publish requests and wait for the first keep alive
-        function(callback) {
-
-          sendPublishRequest(session1, function(err) {
-            should.not.exist(err);
-            collectPublishResponse.callCount.should.eql(0);
-            callback();
-          });
-          sendPublishRequest(session1, collectPublishResponse);
-          sendPublishRequest(session1, collectPublishResponse);
-        },
-
-
-        function(callback) {
-          // reactivate session on second channel
-          client2.reactivateSession(session1, function(err) {
-            callback(err);
-          });
-        },
-        function(callback) {
-          setTimeout(callback, 100);
-        },
-
-        function(callback) {
-
-          collectPublishResponse.callCount.should.eql(2);
-          collectPublishResponse.getCall(0).args[0].message.should.match(/BadSecureChannelClosed/);
-          collectPublishResponse.getCall(1).args[0].message.should.match(/BadSecureChannelClosed/);
-          callback();
-        },
-
-
-        // terminate
-        function(callback) {
-          client2.disconnect(callback);
-        },
-        function(callback) {
-          client1.disconnect(callback);
-        },
-        function(callback) {
-          test.server.engine.currentSessionCount.should.eql(0);
-          callback();
-        }
+        // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
+        // Subsequent calls to  ActivateSession  may be associated with different  SecureChannels.  If this is the
+        // case then  the  Server  shall verify that the  Certificate  the  Client  used to create the new
+        // SecureChannel  is the same as the  Certificate  used to create the original  SecureChannel.
+        it("RQ2 -server should raise an error if a existing session is reactivated from a channel that have different certificate than the original channel", function (done) {
+            const serverCertificate = test.server.getCertificateChain();
+
+            let client1, client2;
+            let session1;
+            async.series(
+                [
+                    // create a first channel (client1) with
+                    function (callback) {
+                        //xx console.log(" creating initial channel with some certificate");
+                        const certificateFile1 = m("client_cert_2048.pem");
+                        const privateKeyFile1 = m("client_key_2048.pem");
+                        console.log(certificateFile1);
+
+                        client1 = OPCUAClient.create({
+                            certificateFile: certificateFile1,
+                            privateKeyFile: privateKeyFile1,
+                            securityMode: MessageSecurityMode.Sign,
+                            securityPolicy: SecurityPolicy.Basic128Rsa15,
+                            serverCertificate: serverCertificate
+                        });
+
+                        const certificate = readCertificate(certificateFile1);
+
+                        async function doIt() {
+                            await test.server.serverCertificateManager.trustCertificate(certificate);
+                            const issuerCertificateFile = m("CA/public/cacert.pem");
+                            const issuerCertificateRevocationListFile = m("CA/crl/revocation_list.der");
+                            const issuerCertificate = readCertificate(issuerCertificateFile);
+                            const issuerCrl = await readCertificateRevocationList(issuerCertificateRevocationListFile);
+                            await test.server.serverCertificateManager.addIssuer(issuerCertificate);
+                            await test.server.serverCertificateManager.addRevocationList(issuerCrl);
+                            callback();
+                        }
+                        doIt();
+                    },
+                    function (callback) {
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    // create a session using client1
+                    function (callback) {
+                        //xx console.log(" create session");
+                        client1._createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+                    // activate the session as expected on same channel used to create it
+                    function (callback) {
+                        //xx console.log(" activate session");
+                        client1._activateSession(session1, function (err) {
+                            callback(err);
+                        });
+                    },
+
+                    // create a second channel (client2)
+                    // with a different certificate ....
+                    function (callback) {
+                        // creating second channel with different credential
+                        console.log(" creating second channel with different certificate");
+                        const certificateFile2 = m("client_cert_3072.pem");
+                        const privateKeyFile2 = m("client_key_3072.pem");
+                        client2 = OPCUAClient.create({
+                            certificateFile: certificateFile2,
+                            privateKeyFile: privateKeyFile2,
+                            securityMode: MessageSecurityMode.Sign,
+                            securityPolicy: SecurityPolicy.Basic256,
+                            serverCertificate: serverCertificate
+                        });
+                        const certificate = readCertificate(certificateFile2);
+                        test.server.serverCertificateManager.trustCertificate(certificate, callback);
+                    },
+                    function (callback) {
+                        client2.connect(test.endpointUrl, callback);
+                    },
+                    function (callback) {
+                        // reactivate session on second channel
+                        // Reactivate should fail because certificate is not the same as the original one
+                        client2.reactivateSession(session1, function (err) {
+                            if (err) {
+                                err.message.should.match(/BadNoValidCertificates/);
+                                callback();
+                            } else {
+                                callback(new Error("expecting reactivateSession to fail"));
+                            }
+                        });
+                    },
+                    // terminate
+                    function (callback) {
+                        client2.disconnect(callback);
+                    },
+                    function (callback) {
+                        session1.close(callback);
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                done
+            );
+        });
 
-      ], done);
+        // In addition,the Server shall verify that the  Client  supplied a  UserIdentityToken  that is   identical to the token
+        // currently associated with the  Session.
+        it("RQ3 - server should raise an error if a session is reactivated with different user identity tokens", function (done) {
+            let client1, client2;
+            let session1;
+
+            const user1 = {
+                userName: "user1",
+                password: "password1"
+            };
+            const user2 = new UserNameIdentityToken({
+                userName: "user1",
+                password: "password1"
+            });
+            //xx console.log(" user1 ", user1.toString());
+            async.series(
+                [
+                    // given a established session with a subscription and some publish request
+
+                    function (callback) {
+                        client1 = OPCUAClient.create();
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    // create a session using client1
+                    function (callback) {
+                        client1.createSession(user1, function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+                    // when the session is transferred to a different channel
+                    // create a second channel (client2)
+                    function (callback) {
+                        client2 = OPCUAClient.create();
+                        client2.connect(test.endpointUrl, callback);
+                    },
+                    function (callback) {
+                        // reactivate session on second channel
+                        // alter session1.userIdentityInfo
+                        session1.userIdentityInfo = user2;
+                        session1.userIdentityInfo.userName.should.eql("user1");
+
+                        client2.reactivateSession(session1, function (err) {
+                            err.message.should.match(/BadIdentityChangeNotSupported/);
+                            _.contains(client1._sessions, session1).should.eql(true); // should have failed
+                            callback();
+                        });
+                    },
+                    // terminate
+                    function (callback) {
+                        client2.disconnect(callback);
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                done
+            );
+        });
+        // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel.
+        xit("RQ4 - server should reject request send via old channel when session has been transferred to new channel", function (done) {
+            async.series([], done);
+        });
 
+        // unprocessed pending Requests such as PublishRequest shall be be denied by the server
+        // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel
+        it("RQ5 - server should reject pending requests send to old channel when session has been transferred to new channel", function (done) {
+            const sinon = require("sinon");
+
+            const collectPublishResponse = sinon.spy();
+
+            let client1, client2;
+            let session1;
+            async.series(
+                [
+                    // given a established session with a subscription and some publish request
+
+                    function (callback) {
+                        client1 = OPCUAClient.create();
+                        client1.connect(test.endpointUrl, callback);
+                    },
+                    // create a session using client1
+                    function (callback) {
+                        client1._createSession(function (err, session) {
+                            if (err) {
+                                return callback(err);
+                            }
+                            session1 = session;
+                            callback();
+                        });
+                    },
+                    // activate the session as expected on same channel used to create it
+                    function (callback) {
+                        client1._activateSession(session1, function (err) {
+                            callback(err);
+                        });
+                    },
+
+                    // creaet a subscription,
+                    function (callback) {
+                        createSubscription(session1, callback);
+                    },
+
+                    // when the session is transferred to a different channel
+                    // create a second channel (client2)
+                    function (callback) {
+                        client2 = OPCUAClient.create();
+                        client2.connect(test.endpointUrl, callback);
+                        collectPublishResponse.callCount.should.eql(0);
+                    },
+
+                    // provision 3 publish requests and wait for the first keep alive
+                    function (callback) {
+                        sendPublishRequest(session1, function (err) {
+                            should.not.exist(err);
+                            collectPublishResponse.callCount.should.eql(0);
+                            callback();
+                        });
+                        sendPublishRequest(session1, collectPublishResponse);
+                        sendPublishRequest(session1, collectPublishResponse);
+                    },
+
+                    function (callback) {
+                        // reactivate session on second channel
+                        client2.reactivateSession(session1, function (err) {
+                            callback(err);
+                        });
+                    },
+                    function (callback) {
+                        setTimeout(callback, 100);
+                    },
+
+                    function (callback) {
+                        collectPublishResponse.callCount.should.eql(2);
+                        collectPublishResponse.getCall(0).args[0].message.should.match(/BadSecureChannelClosed/);
+                        collectPublishResponse.getCall(1).args[0].message.should.match(/BadSecureChannelClosed/);
+                        callback();
+                    },
+
+                    // terminate
+                    function (callback) {
+                        client2.disconnect(callback);
+                    },
+                    function (callback) {
+                        client1.disconnect(callback);
+                    },
+                    function (callback) {
+                        test.server.engine.currentSessionCount.should.eql(0);
+                        callback();
+                    }
+                ],
+                done
+            );
+        });
     });
-
-  });
-
 };
diff --git a/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts b/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts
index 710acfd19..7db1dcd1b 100644
--- a/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts
+++ b/packages/node-opcua-secure-channel/source/client/client_secure_channel_layer.ts
@@ -117,11 +117,12 @@ function process_request_callback(requestData: RequestData, err?: Error | null,
     if (response && response instanceof ServiceFault) {
         response.responseHeader.stringTable = [...(response.responseHeader.stringTable || [])];
         err = new Error(" serviceResult = " + response.responseHeader.serviceResult.toString());
         //  "  returned by server \n response:" + response.toString() + "\n  request: " + request.toString());
         (err as any).response = response;
-        ((err as any).request = request), (response = undefined);
+        (err as any).request = request;
+        response = undefined;
     }
 
     const theCallbackFunction = requestData.callback;
     /* istanbul ignore next */
     if (!theCallbackFunction) {
@@ -1719,11 +1720,11 @@ export class ClientSecureChannelLayer extends EventEmitter {
         }
 
         // istanbul ignore next
         if (!this.derivedKeys || !this.derivedKeys.derivedClientKeys) {
             errorLog("derivedKeys not set but security mode = ", MessageSecurityMode[this.securityMode]);
-            return null; // 
+            return null; //
             // throw new Error("internal error expecting valid derivedKeys while security mode is " + MessageSecurityMode[this.securityMode]);
         }
 
         const derivedClientKeys = this.derivedKeys.derivedClientKeys;
         assert(derivedClientKeys, "expecting valid derivedClientKeys");
diff --git a/packages/node-opcua-server-discovery/source/opcua_discovery_server.ts b/packages/node-opcua-server-discovery/source/opcua_discovery_server.ts
index cfdf334db..fb11970ba 100644
--- a/packages/node-opcua-server-discovery/source/opcua_discovery_server.ts
+++ b/packages/node-opcua-server-discovery/source/opcua_discovery_server.ts
@@ -13,11 +13,11 @@ import envPaths = require("env-paths");
 import { assert } from "node-opcua-assert";
 import { UAString } from "node-opcua-basic-types";
 import { makeApplicationUrn } from "node-opcua-common";
 import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
 import { extractFullyQualifiedDomainName, resolveFullyQualifiedDomainName } from "node-opcua-hostname";
-import { Message, Response, ServerSecureChannelLayer } from "node-opcua-secure-channel";
+import { Message, Response, ServerSecureChannelLayer, ServiceFault } from "node-opcua-secure-channel";
 import { OPCUABaseServer, OPCUABaseServerOptions, OPCUAServerEndPoint } from "node-opcua-server";
 
 import {
     Announcement,
     BonjourHolder,
@@ -388,11 +388,11 @@ export class OPCUADiscoveryServer extends OPCUABaseServer {
             ];
         }
 
         function sendError(statusCode: StatusCode): Response {
             debugLog(chalk.red("_on_RegisterServer(2)Request error"), statusCode.toString());
-            const response1 = new RegisterServerXResponse({
+            const response1 = new ServiceFault({
                 responseHeader: { serviceResult: statusCode }
             });
             return response1;
         }
 
diff --git a/packages/node-opcua-server/source/opcua_server.ts b/packages/node-opcua-server/source/opcua_server.ts
index 5d5ebccf6..df4a872c8 100644
--- a/packages/node-opcua-server/source/opcua_server.ts
+++ b/packages/node-opcua-server/source/opcua_server.ts
@@ -143,11 +143,12 @@ import {
     UserIdentityToken,
     UserTokenPolicy,
     BuildInfoOptions,
     MonitoredItemCreateResult,
     IssuedIdentityToken,
-    BrowseResultOptions
+    BrowseResultOptions,
+    ServiceFault
 } from "node-opcua-types";
 import { DataType } from "node-opcua-variant";
 import { VariantArrayType } from "node-opcua-variant";
 import { matchUri } from "node-opcua-utils";
 
@@ -182,11 +183,11 @@ const errorLog = make_errorLog(__filename);
 const warningLog = make_warningLog(__filename);
 
 const default_maxConnectionsPerEndpoint = 10;
 
 function g_sendError(channel: ServerSecureChannelLayer, message: Message, ResponseClass: any, statusCode: StatusCode): void {
-    const response = new ResponseClass({
+    const response = new ServiceFault({
         responseHeader: { serviceResult: statusCode }
     });
     return channel.send_response("MSG", response, message);
 }
 
@@ -2231,11 +2232,11 @@ export class OPCUAServer extends OPCUABaseServer {
     ): Promise<void> {
         assert(typeof actionToPerform === "function");
 
         function sendResponse(response1: Response) {
             try {
-                assert(response1 instanceof ResponseClass);
+                assert(response1 instanceof ResponseClass || response1 instanceof ServiceFault);
                 if (message.session) {
                     const counterName = ResponseClass.name.replace("Response", "");
                     message.session.incrementRequestTotalCounter(counterName);
                 }
                 return channel.send_response("MSG", response1, message);
@@ -3069,11 +3070,11 @@ export class OPCUAServer extends OPCUABaseServer {
             message,
             channel,
             (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
                 assert(session);
                 assert(session.publishEngine); // server.publishEngine doesn't exists, OPCUAServer has probably shut down already
-                session.publishEngine._on_PublishRequest(request, (request1: PublishRequest, response: PublishResponse) => {
+                session.publishEngine._on_PublishRequest(request, (_request1, response) => {
                     sendResponse(response);
                 });
             }
         );
     }
@@ -3178,20 +3179,24 @@ export class OPCUAServer extends OPCUABaseServer {
                 const { addResults, removeResults, statusCode } = subscription.setTriggering(
                     triggeringItemId,
                     linksToAdd,
                     linksToRemove
                 );
-                const response = new SetTriggeringResponse({
-                    responseHeader: { serviceResult: statusCode },
-
-                    addResults,
-                    removeResults,
-                    addDiagnosticInfos: null,
-                    removeDiagnosticInfos: null
-                });
+                if (statusCode !== StatusCodes.Good) {
+                    const response = new ServiceFault({ responseHeader: { serviceResult: statusCode } });
+                    sendResponse(response);
+                } else {
+                    const response = new SetTriggeringResponse({
+                        responseHeader: { serviceResult: statusCode },
 
-                sendResponse(response);
+                        addResults,
+                        removeResults,
+                        addDiagnosticInfos: null,
+                        removeDiagnosticInfos: null
+                    });
+                    sendResponse(response);
+                }
             }
         );
     }
 
     protected async _beforeDeleteSubscription(subscription: Subscription): Promise<void> {
@@ -3388,15 +3393,12 @@ export class OPCUAServer extends OPCUABaseServer {
         this._apply_on_SessionObject(
             RegisterNodesResponse,
             message,
             channel,
             (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
-                let response;
-
                 if (!request.nodesToRegister || request.nodesToRegister.length === 0) {
-                    response = new RegisterNodesResponse({ responseHeader: { serviceResult: StatusCodes.BadNothingToDo } });
-                    return sendResponse(response);
+                    return sendError(StatusCodes.BadNothingToDo);
                 }
                 if (this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes > 0) {
                     if (request.nodesToRegister.length > this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes) {
                         return sendError(StatusCodes.BadTooManyOperations);
                     }
@@ -3408,11 +3410,11 @@ export class OPCUAServer extends OPCUABaseServer {
                 // is recommended that the Server return a numeric NodeIds for aliasing.
                 // In case no optimization is supported for a Node, the Server shall return the
                 // NodeId from the request.
                 const registeredNodeIds = request.nodesToRegister.map((nodeId) => session.registerNode(nodeId));
 
-                response = new RegisterNodesResponse({
+                const response = new RegisterNodesResponse({
                     registeredNodeIds
                 });
                 sendResponse(response);
             }
         );
@@ -3425,17 +3427,14 @@ export class OPCUAServer extends OPCUABaseServer {
         this._apply_on_SessionObject(
             UnregisterNodesResponse,
             message,
             channel,
             (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
-                let response;
-
                 request.nodesToUnregister = request.nodesToUnregister || [];
 
                 if (!request.nodesToUnregister || request.nodesToUnregister.length === 0) {
-                    response = new UnregisterNodesResponse({ responseHeader: { serviceResult: StatusCodes.BadNothingToDo } });
-                    return sendResponse(response);
+                    return sendError(StatusCodes.BadNothingToDo);
                 }
 
                 if (this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes > 0) {
                     if (
                         request.nodesToUnregister.length > this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes
@@ -3444,11 +3443,11 @@ export class OPCUAServer extends OPCUABaseServer {
                     }
                 }
 
                 request.nodesToUnregister.map((nodeId: NodeId) => session.unRegisterNode(nodeId));
 
-                response = new UnregisterNodesResponse({});
+                const response = new UnregisterNodesResponse({});
                 sendResponse(response);
             }
         );
     }
 
diff --git a/packages/node-opcua-server/source/server_publish_engine.ts b/packages/node-opcua-server/source/server_publish_engine.ts
index 0c87ba452..f9a6211b7 100644
--- a/packages/node-opcua-server/source/server_publish_engine.ts
+++ b/packages/node-opcua-server/source/server_publish_engine.ts
@@ -9,11 +9,11 @@ import { partition, sortBy } from "lodash";
 import { assert } from "node-opcua-assert";
 import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
 import { ObjectRegistry } from "node-opcua-object-registry";
 import { StatusCode, StatusCodes } from "node-opcua-status-code";
 
-import { PublishRequest, PublishResponse, SubscriptionAcknowledgement } from "node-opcua-types";
+import { PublishRequest, PublishResponse, ServiceFault, SubscriptionAcknowledgement } from "node-opcua-types";
 import { Subscription } from "./server_subscription";
 import { SubscriptionState } from "./server_subscription";
 import { IServerSidePublishEngine, INotifMsg, IClosedOrTransferredSubscription } from "./i_server_side_publish_engine";
 
 const debugLog = make_debugLog(__filename);
@@ -34,11 +34,11 @@ export interface ServerSidePublishEngineOptions {
 
 interface PublishData {
     request: PublishRequest;
     serverTimeWhenReceived: number;
     results: StatusCode[];
-    callback: (request: PublishRequest, response: PublishResponse) => void;
+    callback: (request: PublishRequest, response: PublishResponse | ServiceFault) => void;
 }
 
 function _assertValidPublishData(publishData: PublishData) {
     assert(publishData.request instanceof PublishRequest);
     assert(typeof publishData.serverTimeWhenReceived === "number");
@@ -135,11 +135,11 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
         //  to the old Session.
         subscription.notifyTransfer();
 
         const tmp = srcPublishEngine.detach_subscription(subscription);
         destPublishEngine.add_subscription(tmp);
-        
+
         subscription.resetLifeTimeCounter();
         if (sendInitialValues) {
             /*  A Boolean parameter with the following values:
                 TRUE  the first Publish response(s) after the TransferSubscriptions call
                       shall contain the current values of all Monitored Items in the
@@ -325,15 +325,16 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
     }
 
     public on_close_subscription(subscription: IClosedOrTransferredSubscription): void {
         doDebug && debugLog("ServerSidePublishEngine#on_close_subscription", subscription.id);
         if (subscription.hasPendingNotifications) {
-            doDebug && debugLog(
-                "ServerSidePublishEngine#on_close_subscription storing subscription",
-                subscription.id,
-                " to _closed_subscriptions because it has pending notification"
-            );
+            doDebug &&
+                debugLog(
+                    "ServerSidePublishEngine#on_close_subscription storing subscription",
+                    subscription.id,
+                    " to _closed_subscriptions because it has pending notification"
+                );
             this._closed_subscriptions.push(subscription);
         } else {
             doDebug && debugLog("ServerSidePublishEngine#on_close_subscription disposing subscription", subscription.id);
             // subscription is no longer needed
             subscription.dispose();
@@ -400,11 +401,11 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
      * @private
      * @internal
      */
     public _on_PublishRequest(
         request: PublishRequest,
-        callback?: (request1: PublishRequest, response: PublishResponse) => void
+        callback?: (request1: PublishRequest, response: PublishResponse| ServiceFault) => void
     ): void {
         callback = callback || dummy_function;
         assert(typeof callback === "function");
 
         // istanbul ignore next
@@ -481,13 +482,14 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
                                 s.timeToExpiration +
                                 " ka=" +
                                 s.timeToKeepAlive +
                                 " m?=" +
                                 s.hasUncollectedMonitoredItemNotifications +
-                                " " + 
+                                " " +
                                 SubscriptionState[s.state] +
-                                " " + s.messageSent + 
+                                " " +
+                                s.messageSent +
                                 "]"
                         )
                         .join(" \n")
                 );
             }
@@ -506,11 +508,12 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
             if (!this.pendingPublishRequestCount) {
                 return;
             }
             const starving_subscription = this._find_starving_subscription();
             if (starving_subscription) {
-                doDebug && debugLog(chalk.bgWhite.red("feeding most late subscription subscriptionId  = "), starving_subscription.id);
+                doDebug &&
+                    debugLog(chalk.bgWhite.red("feeding most late subscription subscriptionId  = "), starving_subscription.id);
                 starving_subscription.process_subscription();
             }
         });
     }
 
@@ -535,14 +538,14 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
         return true;
     }
 
     private _send_error_for_request(publishData: PublishData, statusCode: StatusCode): void {
         _assertValidPublishData(publishData);
-        const publishResponse = new PublishResponse({
+        const response = new ServiceFault({
             responseHeader: { serviceResult: statusCode }
         });
-        this._send_response_for_request(publishData, publishResponse);
+        this._send_response_for_request(publishData, response);
     }
 
     private _cancelPendingPublishRequest(statusCode: StatusCode): void {
         if (this._publish_request_queue) {
             debugLog(
@@ -627,11 +630,11 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
     }
     public _send_response(subscription: Subscription, response: PublishResponse): void {
         assert(this.pendingPublishRequestCount > 0);
         assert(response.subscriptionId !== 0xffffff);
         const publishData = this._publish_request_queue.shift()!;
-        this._send_response_for_request(publishData, response);
+        this._send_valid_response_for_request(publishData, response);
     }
 
     public _on_tick(): void {
         this._cancelTimeoutRequests();
     }
@@ -652,17 +655,19 @@ export class ServerSidePublishEngine extends EventEmitter implements IServerSide
                 debugLog(chalk.cyan(" CANCELING TIMEOUT PUBLISH REQUEST "));
             }
             this._send_error_for_request(publishData, StatusCodes.BadTimeout);
         }
     }
-
-    public _send_response_for_request(publishData: PublishData, response: PublishResponse): void {
+    public _send_response_for_request(publishData: PublishData, response: PublishResponse | ServiceFault): void {
+        response.responseHeader.requestHandle = publishData.request.requestHeader.requestHandle;
+        publishData.callback(publishData.request, response);
+    }
+    public _send_valid_response_for_request(publishData: PublishData, response: PublishResponse): void {
         if (doDebug) {
             debugLog("_send_response_for_request ", response.toString());
         }
         _assertValidPublishData(publishData);
         // xx assert(response.responseHeader.requestHandle !== 0,"expecting a valid requestHandle");
         response.results = publishData.results;
-        response.responseHeader.requestHandle = publishData.request.requestHeader.requestHandle;
-        publishData.callback(publishData.request, response);
+        this._send_response_for_request(publishData, response);
     }
 }
diff --git a/packages/node-opcua-server/test/test_server_engine_subscription.js b/packages/node-opcua-server/test/test_server_engine_subscription.js
index a3796a6e2..cb992eb16 100644
--- a/packages/node-opcua-server/test/test_server_engine_subscription.js
+++ b/packages/node-opcua-server/test/test_server_engine_subscription.js
@@ -4,10 +4,11 @@ const sinon = require("sinon");
 
 const { MonitoringMode, PublishRequest } = require("node-opcua-service-subscription");
 const { StatusCodes, StatusCode } = require("node-opcua-status-code");
 const { TimestampsToReturn } = require("node-opcua-service-read");
 const { MonitoredItemCreateRequest } = require("node-opcua-service-subscription");
+const { ServiceFault } = require("node-opcua-types");
 
 const { get_mini_nodeset_filename } = require("node-opcua-address-space/testHelpers");
 
 const { ServerEngine, SubscriptionState } = require("..");
 const { with_fake_timer } = require("./helper_with_fake_timer");
@@ -400,23 +401,26 @@ describe("ServerEngine Subscriptions service", function () {
             publishSpy.getCall(0).args[1].notificationMessage.notificationData[0].status.should.eql(StatusCodes.BadTimeout);
 
             publishSpy.callCount.should.eql(4);
 
             publishSpy.getCall(1).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
-            publishSpy.getCall(1).args[1].subscriptionId.should.eql(0xffffffff);
-            publishSpy.getCall(1).args[1].notificationMessage.sequenceNumber.should.eql(0);
-            publishSpy.getCall(1).args[1].notificationMessage.notificationData.length.should.eql(0);
+            publishSpy.getCall(1).args[1].should.be.instanceOf(ServiceFault);
+            // publishSpy.getCall(1).args[1].subscriptionId.should.eql(0xffffffff);
+            // publishSpy.getCall(1).args[1].notificationMessage.sequenceNumber.should.eql(0);
+            // publishSpy.getCall(1).args[1].notificationMessage.notificationData.length.should.eql(0);
 
             publishSpy.getCall(2).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
-            publishSpy.getCall(2).args[1].subscriptionId.should.eql(0xffffffff);
-            publishSpy.getCall(2).args[1].notificationMessage.sequenceNumber.should.eql(0);
-            publishSpy.getCall(2).args[1].notificationMessage.notificationData.length.should.eql(0);
+            publishSpy.getCall(2).args[1].should.be.instanceOf(ServiceFault);
+            // publishSpy.getCall(2).args[1].subscriptionId.should.eql(0xffffffff);
+            // publishSpy.getCall(2).args[1].notificationMessage.sequenceNumber.should.eql(0);
+            // publishSpy.getCall(2).args[1].notificationMessage.notificationData.length.should.eql(0);
 
             publishSpy.getCall(3).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
-            publishSpy.getCall(3).args[1].subscriptionId.should.eql(0xffffffff);
-            publishSpy.getCall(3).args[1].notificationMessage.sequenceNumber.should.eql(0);
-            publishSpy.getCall(3).args[1].notificationMessage.notificationData.length.should.eql(0);
+            publishSpy.getCall(3).args[1].should.be.instanceOf(ServiceFault);
+            // publishSpy.getCall(3).args[1].subscriptionId.should.eql(0xffffffff);
+            // publishSpy.getCall(3).args[1].notificationMessage.sequenceNumber.should.eql(0);
+            // publishSpy.getCall(3).args[1].notificationMessage.notificationData.length.should.eql(0);
 
             await engine.closeSession(session.authenticationToken, true, "CloseSession");
         });
     });
 
diff --git a/packages/node-opcua-server/test/test_server_publish_engine.ts b/packages/node-opcua-server/test/test_server_publish_engine.ts
index 4e6af18fc..91ba99de2 100644
--- a/packages/node-opcua-server/test/test_server_publish_engine.ts
+++ b/packages/node-opcua-server/test/test_server_publish_engine.ts
@@ -183,11 +183,11 @@ describe("Testing the server publish engine", function (this: any) {
         subscription.dispose();
         serverSidePublishEngine.shutdown();
         serverSidePublishEngine.dispose();
     });
 
-    it("ZDZ-5 a server should return BadNoSubscription as a response for a publish Request if there is no subscription available for this session. ", () => {
+    it("ZDZ-5 a server should return ServiceFault(BadNoSubscription) as a response for a publish Request if there is no subscription available for this session. ", () => {
         // create a server - server has no subscription
         const publish_server = new ServerSidePublishEngine();
 
         const send_response_for_request_spy = sinon.spy(publish_server, "_send_response_for_request");
 
@@ -197,11 +197,11 @@ describe("Testing the server publish engine", function (this: any) {
         });
         publish_server._on_PublishRequest(fakeRequest1);
         flushPending();
 
         send_response_for_request_spy.callCount.should.equal(1);
-        send_response_for_request_spy.getCall(0).args[1].schema.name.should.equal("PublishResponse");
+        send_response_for_request_spy.getCall(0).args[1].schema.name.should.equal("ServiceFault");
         send_response_for_request_spy.getCall(0).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
 
         publish_server.shutdown();
         publish_server.dispose();
     });
@@ -307,29 +307,27 @@ describe("Testing the server publish engine", function (this: any) {
         send_response_for_request_spy.callCount.should.be.equal(2);
 
         // xx console.log(send_response_for_request_spy.getCall(0).args[1].responseHeader.toString());
         // xx console.log(send_response_for_request_spy.getCall(1).args[1].responseHeader.toString());
 
-        send_response_for_request_spy.getCall(1).args[1].schema.name.should.equal("PublishResponse");
+        send_response_for_request_spy.getCall(1).args[1].schema.name.should.equal("ServiceFault");
         send_response_for_request_spy
             .getCall(1)
             .args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadTooManyPublishRequests);
         send_response_for_request_spy.getCall(1).args[1].responseHeader.requestHandle.should.eql(2);
-        send_response_for_request_spy.getCall(1).args[1].results!.should.eql([]);
-
+       
         publish_server._on_PublishRequest(new PublishRequest({ requestHeader: { requestHandle: 8 } }));
         flushPending();
 
         send_response_for_request_spy.callCount.should.be.equal(3);
         // xx console.log(send_response_for_request_spy.getCall(2).args[1].responseHeader.toString());
-        send_response_for_request_spy.getCall(2).args[1].schema.name.should.equal("PublishResponse");
+        send_response_for_request_spy.getCall(2).args[1].schema.name.should.equal("ServiceFault");
         send_response_for_request_spy
             .getCall(2)
             .args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadTooManyPublishRequests);
         send_response_for_request_spy.getCall(2).args[1].responseHeader.requestHandle.should.eql(3);
-        send_response_for_request_spy.getCall(2).args[1].results!.should.eql([]);
-
+    
         subscription.terminate();
         subscription.dispose();
         publish_server.shutdown();
         publish_server.dispose();
     });
diff --git a/packages/parallel_test.js b/packages/parallel_test.js
index c81cc550b..78b975ed3 100644
--- a/packages/parallel_test.js
+++ b/packages/parallel_test.js
@@ -300,10 +300,14 @@ if (isMainThread) {
                     process.exit(0);
                 }
                 if (key.name === "l") {
                     dumpRunningTests();
                 }
+                if (key.name === "i") {
+                    dumpRunningTests();
+                    dumpRunningTestsLogs();
+                }
             });
         }
 
         const data = {
             index: 0,
@@ -313,18 +317,11 @@ if (isMainThread) {
         };
 
         const infoTimer = setInterval(() => {
             console.log("----------------------------------------------- RUNNING TESTS ");
             dumpRunningTests();
-            const runningTests = [...runningPages].map((i) => testFiles[i]);
-            for (let file of runningTests) {
-                const outputs = outputFor[file];
-                if (outputs && outputs.length) {
-                    console.log(chalk.green("log for", file));
-                    console.log(outputs.join("\n"));
-                }
-            }
+            dumpRunningTestsLogs();
         }, testWatchDogTimeout);
 
         fileMax = testFiles.length;
         const promises = [];
         const cpuCount = Math.max(CPU || os.cpus().length * 0.7, 2);
@@ -340,5 +337,15 @@ if (isMainThread) {
     })();
 } else {
     const { workerThread } = require("./parallel_test_worker");
     workerThread();
 }
+function dumpRunningTestsLogs() {
+    const runningTests = [...runningPages].map((i) => testFiles[i]);
+    for (let file of runningTests) {
+        const outputs = outputFor[file];
+        if (outputs && outputs.length) {
+            console.log(chalk.green("log for", file));
+            console.log(outputs.join("\n"));
+        }
+    }
+}

Vulnerable code:     promoteOpaqueStructure,
import { BrowseNextRequest, BrowseNextResponse, HistoryReadValueIdOptions, WriteValueOptions } from "node-opcua-types";
                // use soft error, no exceptions
                return callback(null, response);
    OPCUADiscoveryServer
            function check_response(err: Error | null, response: any): void {
                should.not.exist(err);
                response.responseHeader.serviceResult.should.eql(StatusCodes.BadDiscoveryUrlMissing);
            await send_registered_server_request(discoveryServerEndpointUrl, request, check_response);
            function check_response(err: Error | null, response: any) {
                should.not.exist(err);
                response.responseHeader.serviceResult.should.eql(StatusCodes.BadInvalidArgument);
            await send_registered_server_request(discoveryServerEndpointUrl, request, check_response);
            function check_response(err: Error | null, response: any) {
                should.not.exist(err);
                response.responseHeader.serviceResult.should.eql(StatusCodes.BadServerNameMissing);
            await send_registered_server_request(discoveryServerEndpointUrl, request, check_response);
            OPCUAServer.registry.count().should.eql(0);1162
                    g_session.performMessageTransaction(browseNextRequest, function(err, response) {
                        response.responseHeader.serviceResult.should.equal(StatusCodes.BadNothingToDo);
    installSessionLogging

                                        should.exist(response);
                                        should.exist(response);
                        createMonitoredItemsResponse.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                        modifyMonitoredItemsResponse.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                        deleteMonitoredItemsResponse.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);

                            tracelog("inner", err ? err.message: "");
                    tracelog("done", err ? err.message: "");
                        response.should.be.instanceof(RepublishResponse);
                        response.responseHeader.serviceResult.should.eql(StatusCodes.BadMessageNotAvailable);
                        response.should.be.instanceof(RepublishResponse);
                        response.responseHeader.serviceResult.should.eql(StatusCodes.BadSubscriptionIdInvalid);

                        response1.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
                        response2.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
                        response3.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
                    const response = dataValues;
const opcua = require("node-opcua");
const StatusCodes = opcua.StatusCodes;
const OPCUAClient = opcua.OPCUAClient;
const UnregisterNodesRequest = opcua.UnregisterNodesRequest;
const RegisterNodesRequest = opcua.RegisterNodesRequest;
const AttributeIds = opcua.AttributeIds;
const DataType = opcua.DataType;




            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {

                const request = new RegisterNodesRequest({
                    nodesToRegister: []
                });
                session.performMessageTransaction(request, function (err/*, response*/) {
                    err.message.should.match(/BadNothingToDo/);
                    inner_done();
                });

            }, done);

            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {

                const request = new RegisterNodesRequest({
                    nodesToRegister: [
                        "ns=0;i=1"
                    ]
                });
                session.performMessageTransaction(request, function (err, response) {
                    should.not.exist(err);
                    response.registeredNodeIds.length.should.eql(1);
                    inner_done();
                });

            }, done);
            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {

                const request = new UnregisterNodesRequest({
                    nodesToUnregister: []
                });
                session.performMessageTransaction(request, function (err, response) {
                    should.exist(response);
                    err.message.should.match(/BadNothingToDo/);
                    inner_done();
                });

            }, done);
            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {

                const request = new UnregisterNodesRequest({
                    nodesToUnregister: [
                        "ns=0;i=1"
                    ]
                });
                session.performMessageTransaction(request, function (err, response) {
                    should.exist(response);
                    should.not.exist(err);
                    inner_done();
                });

            }, done);

            perform_operation_on_client_session(client, endpointUrl, function (session, inner_done) {

                const nodesToRegister = ["ns=2;s=Static_Scalar_Double"];
                let registeredNodeIds = [];
                let dataValue1, dataValue2;
                async.series([
                    function register_some_node(callback) {

                        session.registerNodes(nodesToRegister, function (err, _registeredNodeIds) {
                            if (err) {
                                return callback(err);
                            registeredNodeIds = _registeredNodeIds;
                            callback();
                        });
                    },
                    function (callback) {

                        const nodeToWrite = {
                            nodeId: registeredNodeIds[0],
                            attributeId: AttributeIds.Value,
                            value: {value: {dataType: DataType.Double, value: 1000}}
                        };
                        session.write(nodeToWrite, function (err, statusCode) {
                            statusCode.should.eql(StatusCodes.Good);
                            callback(err);
                        });
                    },
                    function (callback) {
                        const nodeToRead = {nodeId: nodesToRegister[0], attributeId: 13};
                        session.read(nodeToRead, function (err, dataValue) {
                            if (err) {
                                return callback(err);
                            }
                            dataValue.statusCode.should.eql(StatusCodes.Good);
                            dataValue1 = dataValue;
                            callback();
                        });
                    },
                    function (callback) {
                        const nodeToRead = {nodeId: registeredNodeIds[0], attributeId: 13};
                        session.read(nodeToRead, function (err, dataValue) {
                            if (err) {
                                return callback(err);
                            }
                            dataValue.statusCode.should.eql(StatusCodes.Good);
                            dataValue2 = dataValue;
                            callback();
                        });
                    },
                    function (callback) {
                        registeredNodeIds[0].toString().should.not.eql(nodesToRegister[0].toString());
                        dataValue1.statusCode.toString().should.eql(dataValue2.statusCode.toString());

                        //xx console.log(dataValue1.toString());
                        //xx console.log(dataValue2.toString());

                        dataValue1.value.toString().should.eql(dataValue2.value.toString());
                        callback();
                    }
                ], inner_done);

            }, done);

                //  console.log(result.toString());

                result.removeResults?.length.should.eql(0);
                result.addResults?.length.should.eql(0);
                result.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
            should.not.exist(_err, "not expecting any exception");
                last_response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionNotActivated);
const path = require("path");
const fs = require("fs");
const { 
  OPCUAClient, 
  StatusCodes, 
  PublishRequest,
  CreateSubscriptionRequest,
  CloseSessionRequest,
  ReadRequest,
  TimestampsToReturn, 
  MessageSecurityMode,
  SecurityPolicy,
  UserNameIdentityToken
} = require("node-opcua");
  readCertificate,
  readCertificateRevocationList
} = require("node-opcua-crypto");
  const publishRequest = new PublishRequest({});
  session.performMessageTransaction(publishRequest, function(err, response) {
    callback(err, response);
  });
  const publishingInterval = 1000;
  const createSubscriptionRequest = new CreateSubscriptionRequest({
    requestedPublishingInterval: publishingInterval,
    requestedLifetimeCount: 60,
    requestedMaxKeepAliveCount: 10,
    maxNotificationsPerPublish: 10,
    publishingEnabled: true,
    priority: 6
  });

  session.performMessageTransaction(createSubscriptionRequest, function(err/*, response*/) {
    callback(err);
  });
}

const describe = require("node-opcua-leak-detector").describeWithLeakDetector;

module.exports = function(test) {

  describe("testing session  transfer to different channel", function() {

    it("RQC1 - It should be possible to close a session that has not be activated yet", function(done) {
      let client1;
      let session1;
      async.series([

        function(callback) {
          client1 = OPCUAClient.create({});
          client1.connect(test.endpointUrl, callback);
        },

        // create a session using client1, without activating it
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          client1._createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            callback();
          });
        },

        function(callback) {

          // Question: ? Should a unactivated session be accounted for
          //             in the currentSessionCount ?
          test.server.engine.currentSessionCount.should.eql(1);

          // however client shall not record session yet
          client1._sessions.length.should.eql(0);

          // in fact, let make sure that close Session is not harmfull
          client1.closeSession(session1, /* deleteSubscriptions =*/true, function(err) {
            client1._sessions.length.should.eql(0);
            if (err) {
              // if treated as a Failure , close session expected to return BadSessionNotActivated
              err.message.match(/BadSessionNotActivated/);
            }
            callback();
          });

        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        },
        function(callback) {
          client1.disconnect(callback);
        }
      ], done);

    it("RQB1 - calling CreateSession and CloseSession &  CloseSession again should return BadSessionIdInvalid", function(done) {
      let client1;
      let session1;
      async.series([

        function(callback) {
          client1 = OPCUAClient.create();
          client1.connect(test.endpointUrl, callback);
        },
        // create a session using client1
        function(callback) {
          client1._createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            callback();
          });
        },

        function(callback) {
          session1.close(function() {
            callback();
          });
        },
        function(callback) {
          session1.close(function(err) {
            // now session close do not return error if session in invalid
            // err.message.should.match(/SessionIdInvalid/);
            should.not.exist(err);
            callback();
          });
        },
        //
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          client1.disconnect(callback);
        }

      ], done);

    });

    it("RQB2 - calling CloseSession without calling CreateSession first", function(done) {
      let client1;

      async.series([

        function(callback) {
          client1 = OPCUAClient.create({});
          client1.connect(test.endpointUrl, callback);
        },
        function(callback) {
          const request = new CloseSessionRequest({
            deleteSubscriptions: true
          });
          client1.performMessageTransaction(request, function(err, response) {
            should.not.exist(err);
            //err.message.should.match(/BadSessionIdInvalid/);
            response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
            callback();
          });
        },
        function(callback) {
          client1.disconnect(callback);
        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        }
      ], done);

    it("RQB3 - calling CreateSession,  CloseSession  and CloseSession again", function(done) {
      let client1;
      let session1;
      async.series([

        function(callback) {
          client1 = OPCUAClient.create();
          client1.connect(test.endpointUrl, callback);
        },
        // create a session using client1
        function(callback) {
          client1.createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            callback();
          });
        },

        // first call to close session should be OK
        function(callback) {
          client1.closeSession(session1, /* deleteSubscriptions =*/true, function(err) {
            callback(err);
          });
        },

        // second call to close session should raise an error
        function(callback) {
          const request = new CloseSessionRequest({
            deleteSubscriptions: true
          });
          client1.performMessageTransaction(request, function(err, response) {
            should.not.exist(err);
            //err.message.should.match(/BadSessionIdInvalid/);
            response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
            callback();
          });
        },

        function(callback) {
          client1.disconnect(callback);
        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        }
      ], function final(err) {
        client1.disconnect(function() {
          done(err);
      });
    });

    it("RQ0 - call ActiveSession on a session that has been transferred to a different channel", function(done) {

      // this test verifies that the following requirement can be met
      // OpcUA 1.02 part 3 $5.5 Secure Channel Set page 20
      // Once a  Client  has established a  Session  it may wish to access the  Session  from a different
      // SecureChannel. The Client can do this by validating the new  SecureChannel  with the
      // ActivateSession  Service  described in 5.6.3.
      let client1, client2;
      let session1;
      async.series([

        // create a first channel (client1)
        function(callback) {
          client1 = OPCUAClient.create();
          client1.connect(test.endpointUrl, callback);
        },
        // create a session using client1
        function(callback) {
          client1._createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            callback();
          });
        },
        // activate the session as expected on same channel used to create it
        function(callback) {
          client1._activateSession(session1, function(err) {
            callback(err);
          });
        },
        // let verify that it is now possible to send a request on client1's session
        function(callback) {
          // coerce nodeIds
          const request = new ReadRequest({
            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
            maxAge: 0,
            timestampsToReturn: TimestampsToReturn.Both
          });
          request.requestHeader.authenticationToken = session1.authenticationToken;
          client1.performMessageTransaction(request, function(err, response) {
            should.not.exist(err);
            response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
            callback();
          });
        },

        // create a second channel (client2)
        function(callback) {
          client2 = OPCUAClient.create();
          client2.connect(test.endpointUrl, callback);
        },

        // reactivate session on second channel
        function(callback) {
          client2.reactivateSession(session1, function(err) {
            callback(err);
          });
        },

        // now that session has been assigned to client 1,
        // server shall refuse any requests on channel1
        function(callback) {
          // coerce nodeIds
          const request = new ReadRequest({
            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
            maxAge: 0,
            timestampsToReturn: TimestampsToReturn.Both
          });
          request.requestHeader.authenticationToken = session1.authenticationToken;
          client1.performMessageTransaction(request, function(err, response) {
            if (!err) {
              response.responseHeader.serviceResult.should.eql(StatusCodes.BadSecureChannelIdInvalid);
            }
            callback(err);
          });
        },
        // but server shall access request on new channel
        function(callback) {
          // coerce nodeIds
          const request = new ReadRequest({
            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
            maxAge: 0,
            timestampsToReturn: TimestampsToReturn.Both
          });
          request.requestHeader.authenticationToken = session1.authenticationToken;
          client2.performMessageTransaction(request, function(err, response) {
            if (!err) {
              response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
            }
            callback(err);
          });
        },


        // terminate
        function(callback) {
          client2.disconnect(callback);
        },
        function(callback) {
          client1.disconnect(callback);
        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        }

      ], done);
    });

    // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
    // When the ActivateSession  Service  is called f or the first time then the Server shall reject the request
    // if the  SecureChannel  is not same as the one associated with the CreateSession  request.
    it("RQ1 - should reject if the channel used to activate the session for the first time is not the same as the channel used to create the session", function(done) {

      let client1, client2;
      let session1;

      let initialChannelCount = 0;
      async.series([

        // create a first channel (client1)
        function(callback) {
          initialChannelCount = test.server.getChannels().length;
          test.server.getChannels().length.should.equal(initialChannelCount);
          client1 = OPCUAClient.create();
          client1.connect(test.endpointUrl, callback);
        },

        // create a session using client1
        //   ( without activating it)
        function(callback) {
          client1._createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            test.server.getChannels().length.should.equal(initialChannelCount + 1);
            callback();
          });
        },
        // create a second channel (client2)
        function(callback) {
          client2 = OPCUAClient.create();
          client2.connect(test.endpointUrl, callback);
        },

        // activate the session created with client1 using client2 !!
        // this should be detected by server and server shall return an error
        function(callback) {
          test.server.getChannels().length.should.equal(initialChannelCount + 2);
          //xx console.log(" ID1 =", client1._secureChannel.channelId);
          //xx console.log(" ID2 =", client2._secureChannel.channelId);

          client2.reactivateSession(session1, function(err) {

            if (!err) {
              callback(new Error("_activateSession shall return an error "));
            }
            err.message.should.match(/BadSessionNotActivated/);
            callback();
          });
        },

        // terminate
        function(callback) {
          client2.disconnect(callback);
        },
        // activate the session as expected on same channel used to create it
        // so we can close it properly
        function(callback) {
          client1._activateSession(session1, function(err) {
            should.not.exist(err);
            session1.close(callback);
          });
        },
        function(callback) {
          client1.disconnect(callback);
        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        }

      ], done);
    });
    function m(file) {
      const p = path.join(certificateFolder, file);
      if (!fs.existsSync(p)) {
        console.error(" cannot find ", p);
      }
      return p;
    }

    // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
    // Subsequent calls to  ActivateSession  may be associated with different  SecureChannels.  If this is the
    // case then  the  Server  shall verify that the  Certificate  the  Client  used to create the new
    // SecureChannel  is the same as the  Certificate  used to create the original  SecureChannel.
    it("RQ2 -server should raise an error if a existing session is reactivated from a channel that have different certificate than the original channel", function(done) {

      const serverCertificate = test.server.getCertificateChain();

      let client1, client2;
      let session1;
      async.series([

        // create a first channel (client1) with
        function(callback) {
          //xx console.log(" creating initial channel with some certificate");
          const certificateFile1 = m("client_cert_2048.pem");
          const privateKeyFile1 = m("client_key_2048.pem");
          console.log(certificateFile1);

          client1 = OPCUAClient.create({
            certificateFile: certificateFile1,
            privateKeyFile: privateKeyFile1,
            securityMode: MessageSecurityMode.Sign,
            securityPolicy: SecurityPolicy.Basic128Rsa15,
            serverCertificate: serverCertificate
          });

   
          const certificate = readCertificate(certificateFile1);

          async function doIt() {
            await test.server.serverCertificateManager.trustCertificate(certificate);
            const issuerCertificateFile = m("CA/public/cacert.pem");
            const issuerCertificateRevocationListFile = m("CA/crl/revocation_list.der");
            const issuerCertificate = readCertificate(issuerCertificateFile);
            const issuerCrl = await readCertificateRevocationList(issuerCertificateRevocationListFile);
            await test.server.serverCertificateManager.addIssuer(issuerCertificate);
            await test.server.serverCertificateManager.addRevocationList(issuerCrl);
            callback();
          }
          doIt();
        },
        function(callback) {
          client1.connect(test.endpointUrl, callback);
        },
        // create a session using client1
        function(callback) {
          //xx console.log(" create session");
          client1._createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            callback();
          });
        },
        // activate the session as expected on same channel used to create it
        function(callback) {
          //xx console.log(" activate session");
          client1._activateSession(session1, function(err) {
            callback(err);
          });
        },

        // create a second channel (client2)
        // with a different certificate ....
        function(callback) {

          // creating second channel with different credential
          console.log(" creating second channel with different certificate");
          const certificateFile2 = m("client_cert_3072.pem");
          const privateKeyFile2 = m("client_key_3072.pem");
          client2 = OPCUAClient.create({
            certificateFile: certificateFile2,
            privateKeyFile: privateKeyFile2,
            securityMode: MessageSecurityMode.Sign,
            securityPolicy: SecurityPolicy.Basic256,
            serverCertificate: serverCertificate
          });
          const certificate = readCertificate(certificateFile2);
          test.server.serverCertificateManager.trustCertificate(certificate, callback);

        },
        function(callback) {
          client2.connect(test.endpointUrl, callback);
        },
        function(callback) {
          // reactivate session on second channel
          // Reactivate should fail because certificate is not the same as the original one
          client2.reactivateSession(session1, function(err) {
            if (err) {
              err.message.should.match(/BadNoValidCertificates/);
              callback();
            } else {
              callback(new Error("expecting reactivateSession to fail"));
            }
          });
        },
        // terminate
        function(callback) {
          client2.disconnect(callback);
        },
        function(callback) {
          session1.close(callback);
        },
        function(callback) {
          client1.disconnect(callback);
        },

        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        }
      ], done);
    });
    // In addition,the Server shall verify that the  Client  supplied a  UserIdentityToken  that is   identical to the token
    // currently associated with the  Session.
    it("RQ3 - server should raise an error if a session is reactivated with different user identity tokens", function(done) {
      let client1, client2;
      let session1;

      const user1 = {
        userName: "user1", password: "password1"
      };
      const user2 = new UserNameIdentityToken({
        userName: "user1", password: "password1"
      });
      //xx console.log(" user1 ", user1.toString());
      async.series([

        // given a established session with a subscription and some publish request

        function(callback) {
          client1 = OPCUAClient.create();
          client1.connect(test.endpointUrl, callback);
        },
        // create a session using client1
        function(callback) {

          client1.createSession(user1, function(err, session) {
            if (err) {
              return callback(err);
            session1 = session;
            callback();
          });
        },
        // when the session is transferred to a different channel
        // create a second channel (client2)
        function(callback) {
          client2 = OPCUAClient.create();
          client2.connect(test.endpointUrl, callback);
        },
        function(callback) {
          // reactivate session on second channel
          // alter session1.userIdentityInfo
          session1.userIdentityInfo = user2;
          session1.userIdentityInfo.userName.should.eql("user1");

          client2.reactivateSession(session1, function(err) {
            err.message.should.match(/BadIdentityChangeNotSupported/);
            _.contains(client1._sessions, session1).should.eql(true);// should have failed
            callback();
          });
        },
        // terminate
        function(callback) {
          client2.disconnect(callback);
        },
        function(callback) {
          client1.disconnect(callback);
        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
      ], done);

    });
    // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel.
    xit("RQ4 - server should reject request send via old channel when session has been transferred to new channel", function(done) {
      async.series([], done);
    });

    // unprocessed pending Requests such as PublishRequest shall be be denied by the server
    // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel
    it("RQ5 - server should reject pending requests send to old channel when session has been transferred to new channel", function(done) {

      const sinon = require("sinon");

      const collectPublishResponse = sinon.spy();

      let client1, client2;
      let session1;
      async.series([

        // given a established session with a subscription and some publish request

        function(callback) {
          client1 = OPCUAClient.create();
          client1.connect(test.endpointUrl, callback);
        },
        // create a session using client1
        function(callback) {
          client1._createSession(function(err, session) {
            if (err) {
              return callback(err);
            }
            session1 = session;
            callback();
          });
        },
        // activate the session as expected on same channel used to create it
        function(callback) {
          client1._activateSession(session1, function(err) {
            callback(err);
          });
        },

        // creaet a subscription,
        function(callback) {
          createSubscription(session1, callback);
        },


        // when the session is transferred to a different channel
        // create a second channel (client2)
        function(callback) {
          client2 = OPCUAClient.create();
          client2.connect(test.endpointUrl, callback);
          collectPublishResponse.callCount.should.eql(0);
        },

        // provision 3 publish requests and wait for the first keep alive
        function(callback) {

          sendPublishRequest(session1, function(err) {
            should.not.exist(err);
            collectPublishResponse.callCount.should.eql(0);
            callback();
          });
          sendPublishRequest(session1, collectPublishResponse);
          sendPublishRequest(session1, collectPublishResponse);
        },


        function(callback) {
          // reactivate session on second channel
          client2.reactivateSession(session1, function(err) {
            callback(err);
          });
        },
        function(callback) {
          setTimeout(callback, 100);
        },

        function(callback) {

          collectPublishResponse.callCount.should.eql(2);
          collectPublishResponse.getCall(0).args[0].message.should.match(/BadSecureChannelClosed/);
          collectPublishResponse.getCall(1).args[0].message.should.match(/BadSecureChannelClosed/);
          callback();
        },


        // terminate
        function(callback) {
          client2.disconnect(callback);
        },
        function(callback) {
          client1.disconnect(callback);
        },
        function(callback) {
          test.server.engine.currentSessionCount.should.eql(0);
          callback();
        }
      ], done);

  });

        ((err as any).request = request), (response = undefined);
            return null; // 
import { Message, Response, ServerSecureChannelLayer } from "node-opcua-secure-channel";
            const response1 = new RegisterServerXResponse({
    BrowseResultOptions
    const response = new ResponseClass({
                assert(response1 instanceof ResponseClass);
                session.publishEngine._on_PublishRequest(request, (request1: PublishRequest, response: PublishResponse) => {
                const response = new SetTriggeringResponse({
                    responseHeader: { serviceResult: statusCode },

                    addResults,
                    removeResults,
                    addDiagnosticInfos: null,
                    removeDiagnosticInfos: null
                });
                sendResponse(response);
                let response;

                    response = new RegisterNodesResponse({ responseHeader: { serviceResult: StatusCodes.BadNothingToDo } });
                    return sendResponse(response);
                response = new RegisterNodesResponse({
                let response;

                    response = new UnregisterNodesResponse({ responseHeader: { serviceResult: StatusCodes.BadNothingToDo } });
                    return sendResponse(response);
                response = new UnregisterNodesResponse({});
import { PublishRequest, PublishResponse, SubscriptionAcknowledgement } from "node-opcua-types";
    callback: (request: PublishRequest, response: PublishResponse) => void;
        
            doDebug && debugLog(
                "ServerSidePublishEngine#on_close_subscription storing subscription",
                subscription.id,
                " to _closed_subscriptions because it has pending notification"
            );
        callback?: (request1: PublishRequest, response: PublishResponse) => void
                                " " + 
                                " " + s.messageSent + 
                doDebug && debugLog(chalk.bgWhite.red("feeding most late subscription subscriptionId  = "), starving_subscription.id);
        const publishResponse = new PublishResponse({
        this._send_response_for_request(publishData, publishResponse);
        this._send_response_for_request(publishData, response);

    public _send_response_for_request(publishData: PublishData, response: PublishResponse): void {
        response.responseHeader.requestHandle = publishData.request.requestHeader.requestHandle;
        publishData.callback(publishData.request, response);
            publishSpy.getCall(1).args[1].subscriptionId.should.eql(0xffffffff);
            publishSpy.getCall(1).args[1].notificationMessage.sequenceNumber.should.eql(0);
            publishSpy.getCall(1).args[1].notificationMessage.notificationData.length.should.eql(0);
            publishSpy.getCall(2).args[1].subscriptionId.should.eql(0xffffffff);
            publishSpy.getCall(2).args[1].notificationMessage.sequenceNumber.should.eql(0);
            publishSpy.getCall(2).args[1].notificationMessage.notificationData.length.should.eql(0);
            publishSpy.getCall(3).args[1].subscriptionId.should.eql(0xffffffff);
            publishSpy.getCall(3).args[1].notificationMessage.sequenceNumber.should.eql(0);
            publishSpy.getCall(3).args[1].notificationMessage.notificationData.length.should.eql(0);
    it("ZDZ-5 a server should return BadNoSubscription as a response for a publish Request if there is no subscription available for this session. ", () => {
        send_response_for_request_spy.getCall(0).args[1].schema.name.should.equal("PublishResponse");
        send_response_for_request_spy.getCall(1).args[1].schema.name.should.equal("PublishResponse");
        send_response_for_request_spy.getCall(1).args[1].results!.should.eql([]);

        send_response_for_request_spy.getCall(2).args[1].schema.name.should.equal("PublishResponse");
        send_response_for_request_spy.getCall(2).args[1].results!.should.eql([]);

            const runningTests = [...runningPages].map((i) => testFiles[i]);
            for (let file of runningTests) {
                const outputs = outputFor[file];
                if (outputs && outputs.length) {
                    console.log(chalk.green("log for", file));
                    console.log(outputs.join("\n"));
                }
            }
Fixed code:     promoteOpaqueStructure
import {
    BrowseNextRequest,
    BrowseNextResponse,
    HistoryReadValueIdOptions,
    ServiceFault,
    WriteValueOptions
} from "node-opcua-types";
                warningLog("client is now attempting to recreate a session");

                if (response) {
                    // use soft error, no exceptions
                    return callback(null, response);
                } else {
                    return callback(err);
                }
    OPCUADiscoveryServer,
    ServiceFault
            function check_error_response(err: Error | null, response: any): void {
                should.exist(err);
                should.not.exist(response);
                (err as any).response.should.be.instanceOf(ServiceFault);
                (err as any).response.responseHeader.serviceResult.should.eql(StatusCodes.BadDiscoveryUrlMissing);
            await send_registered_server_request(discoveryServerEndpointUrl, request, check_error_response);
            function check_error_response(err: Error | null, response: any) {
                should.exist(err);
                should.not.exist(response);
                (err as any).response.should.be.instanceOf(ServiceFault);
                (err as any).response.responseHeader.serviceResult.should.eql(StatusCodes.BadInvalidArgument);
            await send_registered_server_request(discoveryServerEndpointUrl, request, check_error_response);
            function check_error_response(err: Error | null, response: any) {
                should.exist(err);
                should.not.exist(response);
                (err as any).response.should.be.instanceOf(ServiceFault);
                (err as any).response.responseHeader.serviceResult.should.eql(StatusCodes.BadServerNameMissing);
            await send_registered_server_request(discoveryServerEndpointUrl, request, check_error_response);
            OPCUAServer.registry.count().should.eql(0);
            1162;
                    g_session.performMessageTransaction(browseNextRequest, function(err, _response) {
                        err.response.responseHeader.serviceResult.should.equal(StatusCodes.BadNothingToDo);
    installSessionLogging,
    ServiceFault
                                        should.not.exist(response);
                                        err.response.should.be.instanceOf(ServiceFault);
                                        should.not.exist(response);
                                        should.exist(err);
                        should.not.exist(createMonitoredItemsResponse);
                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                        should.not.exist(modifyMonitoredItemsResponse);
                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                        should.not.exist(deleteMonitoredItemsResponse);
                            should.not.exist(err);
                            tracelog("inner", err ? err.message : "");
                    tracelog("done", err ? err.message : "");
                        should.not.exist(response);
                        err.response.should.be.instanceof(ServiceFault);
                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadMessageNotAvailable);
                        should.not.exist(response);
                        err.response.should.be.instanceof(ServiceFault);
                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSubscriptionIdInvalid);
                        should.not.exist(response1);
                        should.not.exist(response2);
                        should.not.exist(response3);

                        const err1 = spy_publish_session2.getCall(1).args[0];
                        const err2 = spy_publish_session2.getCall(2).args[0];
                        const err3 = spy_publish_session2.getCall(3).args[0];
                        
                        err1.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
                        err2.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);
                        err3.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNoSubscription);

        /** @type {ClientSession} */
                    const response = err.response;
const { OPCUAClient, StatusCodes, UnregisterNodesRequest, RegisterNodesRequest, DataType, AttributeIds, ServiceFault } = require("node-opcua");
            perform_operation_on_client_session(
                client,
                endpointUrl,
                function (session, inner_done) {
                    const request = new RegisterNodesRequest({
                        nodesToRegister: []
                    });
                    session.performMessageTransaction(request, function (err /*, response*/) {
                        err.message.should.match(/BadNothingToDo/);
                        inner_done();
                    });
                },
                done
            );
            perform_operation_on_client_session(
                client,
                endpointUrl,
                function (session, inner_done) {
                    const request = new RegisterNodesRequest({
                        nodesToRegister: ["ns=0;i=1"]
                    });
                    session.performMessageTransaction(request, function (err, response) {
                        should.not.exist(err);
                        response.registeredNodeIds.length.should.eql(1);
                        inner_done();
                    });
                },
                done
            );
            perform_operation_on_client_session(
                client,
                endpointUrl,
                function (session, inner_done) {
                    const request = new UnregisterNodesRequest({
                        nodesToUnregister: []
                    });
                    session.performMessageTransaction(request, function (err, response) {
                        should.not.exist(response);
                        should.exist(err);
                        err.response.should.be.instanceOf(ServiceFault);
                        err.message.should.match(/BadNothingToDo/);
                        err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
                        inner_done();
                    });
                },
                done
            );
            perform_operation_on_client_session(
                client,
                endpointUrl,
                function (session, inner_done) {
                    const request = new UnregisterNodesRequest({
                        nodesToUnregister: ["ns=0;i=1"]
                    });
                    session.performMessageTransaction(request, function (err, response) {
                        should.exist(response);
                        should.not.exist(err);
                        inner_done();
                    });
                },
                done
            );
            perform_operation_on_client_session(
                client,
                endpointUrl,
                function (session, inner_done) {
                    const nodesToRegister = ["ns=2;s=Static_Scalar_Double"];
                    let registeredNodeIds = [];
                    let dataValue1, dataValue2;
                    async.series(
                        [
                            function register_some_node(callback) {
                                session.registerNodes(nodesToRegister, function (err, _registeredNodeIds) {
                                    if (err) {
                                        return callback(err);
                                    }
                                    registeredNodeIds = _registeredNodeIds;
                                    callback();
                                });
                            },
                            function (callback) {
                                const nodeToWrite = {
                                    nodeId: registeredNodeIds[0],
                                    attributeId: AttributeIds.Value,
                                    value: { value: { dataType: DataType.Double, value: 1000 } }
                                };
                                session.write(nodeToWrite, function (err, statusCode) {
                                    statusCode.should.eql(StatusCodes.Good);
                                    callback(err);
                                });
                            },
                            function (callback) {
                                const nodeToRead = { nodeId: nodesToRegister[0], attributeId: 13 };
                                session.read(nodeToRead, function (err, dataValue) {
                                    if (err) {
                                        return callback(err);
                                    }
                                    dataValue.statusCode.should.eql(StatusCodes.Good);
                                    dataValue1 = dataValue;
                                    callback();
                                });
                            },
                            function (callback) {
                                const nodeToRead = { nodeId: registeredNodeIds[0], attributeId: 13 };
                                session.read(nodeToRead, function (err, dataValue) {
                                    if (err) {
                                        return callback(err);
                                    }
                                    dataValue.statusCode.should.eql(StatusCodes.Good);
                                    dataValue2 = dataValue;
                                    callback();
                                });
                            },
                            function (callback) {
                                registeredNodeIds[0].toString().should.not.eql(nodesToRegister[0].toString());
                                dataValue1.statusCode.toString().should.eql(dataValue2.statusCode.toString());

                                //xx console.log(dataValue1.toString());
                                //xx console.log(dataValue2.toString());

                                dataValue1.value.toString().should.eql(dataValue2.value.toString());
                                callback();
                        ],
                        inner_done
                    );
                },
                done
            );
/* eslint-disable max-statements */
    ServiceFault,
                console.log(result.toString());
            should.exist(_err, "expecting a ServiceFault exception");
            const response = (_err as any).response as ServiceFault;
            response.should.be.instanceOf(ServiceFault);
            response.responseHeader.serviceResult.should.eql(StatusCodes.BadNothingToDo);
            let last_response_err;
                        last_response_err = err;
                last_response_err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionNotActivated);
const path = require("path");
const fs = require("fs");
    OPCUAClient,
    StatusCodes,
    PublishRequest,
    CreateSubscriptionRequest,
    CloseSessionRequest,
    ReadRequest,
    TimestampsToReturn,
    MessageSecurityMode,
    SecurityPolicy,
    UserNameIdentityToken,
    ServiceFault,
    ReadResponse
} = require("node-opcua");
const { readCertificate, readCertificateRevocationList } = require("node-opcua-crypto");
    const publishRequest = new PublishRequest({});
    session.performMessageTransaction(publishRequest, function (err, response) {
        callback(err, response);
    });
    const publishingInterval = 1000;
    const createSubscriptionRequest = new CreateSubscriptionRequest({
        requestedPublishingInterval: publishingInterval,
        requestedLifetimeCount: 60,
        requestedMaxKeepAliveCount: 10,
        maxNotificationsPerPublish: 10,
        publishingEnabled: true,
        priority: 6
    session.performMessageTransaction(createSubscriptionRequest, function (err /*, response*/) {
        callback(err);
}
const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
module.exports = function (test) {
    describe("testing session  transfer to different channel", function () {
        it("RQC1 - It should be possible to close a session that has not be activated yet", function (done) {
            let client1;
            let session1;
            async.series(
                [
                    function (callback) {
                        client1 = OPCUAClient.create({});
                        client1.connect(test.endpointUrl, callback);
                    },

                    // create a session using client1, without activating it
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        client1._createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },

                    function (callback) {
                        // Question: ? Should a unactivated session be accounted for
                        //             in the currentSessionCount ?
                        test.server.engine.currentSessionCount.should.eql(1);

                        // however client shall not record session yet
                        client1._sessions.length.should.eql(0);

                        // in fact, let make sure that close Session is not harmfull
                        client1.closeSession(session1, /* deleteSubscriptions =*/ true, function (err) {
                            client1._sessions.length.should.eql(0);
                            if (err) {
                                // if treated as a Failure , close session expected to return BadSessionNotActivated
                                err.message.match(/BadSessionNotActivated/);
                            }
                            callback();
                        });
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    }
                ],
                done
            );
        it("RQB1 - calling CreateSession and CloseSession &  CloseSession again should return BadSessionIdInvalid", function (done) {
            let client1;
            let session1;
            async.series(
                [
                    function (callback) {
                        client1 = OPCUAClient.create();
                        client1.connect(test.endpointUrl, callback);
                    },
                    // create a session using client1
                    function (callback) {
                        client1._createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },

                    function (callback) {
                        session1.close(function () {
                            callback();
                        });
                    },
                    function (callback) {
                        session1.close(function (err) {
                            // now session close do not return error if session in invalid
                            // err.message.should.match(/SessionIdInvalid/);
                            should.not.exist(err);
                            callback();
                        });
                    },
                    //
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        client1.disconnect(callback);
                    }
                ],
                done
            );
        });
        it("RQB2 - calling CloseSession without calling CreateSession first", function (done) {
            let client1;

            async.series(
                [
                    function (callback) {
                        client1 = OPCUAClient.create({});
                        client1.connect(test.endpointUrl, callback);
                    },
                    function (callback) {
                        const request = new CloseSessionRequest({
                            deleteSubscriptions: true
                        });
                        client1.performMessageTransaction(request, function (err, response) {
                            should.exist(err);
                            should.not.exist(response);
                            err.response.should.be.instanceOf(ServiceFault);
                            err.message.should.match(/BadSessionIdInvalid/);
                            err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
                            callback();
                        });
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                done
            );
        });
        it("RQB3 - calling CreateSession,  CloseSession  and CloseSession again", function (done) {
            let client1;
            let session1;
            async.series(
                [
                    function (callback) {
                        client1 = OPCUAClient.create();
                        client1.connect(test.endpointUrl, callback);
                    },
                    // create a session using client1
                    function (callback) {
                        client1.createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },

                    // first call to close session should be OK
                    function (callback) {
                        client1.closeSession(session1, /* deleteSubscriptions =*/ true, function (err) {
                            callback(err);
                        });
                    },

                    // second call to close session should raise an error
                    function (callback) {
                        const request = new CloseSessionRequest({
                            deleteSubscriptions: true
                        });
                        client1.performMessageTransaction(request, function (err, response) {
                            should.exist(err);
                            should.not.exist(response);
                            err.message.should.match(/BadSessionIdInvalid/);
                            err.response.should.be.instanceOf(ServiceFault);
                            err.response.responseHeader.serviceResult.should.eql(StatusCodes.BadSessionIdInvalid);
                            callback();
                        });
                    },

                    function (callback) {
                        client1.disconnect(callback);
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                function final(err) {
                    client1.disconnect(function () {
                        done(err);
                    });
                }
            );
        });
        it("RQ0 - call ActiveSession on a session that has been transferred to a different channel", function (done) {
            // this test verifies that the following requirement can be met
            // OpcUA 1.02 part 3 $5.5 Secure Channel Set page 20
            // Once a  Client  has established a  Session  it may wish to access the  Session  from a different
            // SecureChannel. The Client can do this by validating the new  SecureChannel  with the
            // ActivateSession  Service  described in 5.6.3.
            let client1, client2;
            let session1;
            async.series(
                [
                    // create a first channel (client1)
                    function (callback) {
                        client1 = OPCUAClient.create();
                        client1.connect(test.endpointUrl, callback);
                    },
                    // create a session using client1
                    function (callback) {
                        client1._createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },
                    // activate the session as expected on same channel used to create it
                    function (callback) {
                        client1._activateSession(session1, function (err) {
                            callback(err);
                        });
                    },
                    // let verify that it is now possible to send a request on client1's session
                    function (callback) {
                        // coerce nodeIds
                        const request = new ReadRequest({
                            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
                            maxAge: 0,
                            timestampsToReturn: TimestampsToReturn.Both
                        });
                        request.requestHeader.authenticationToken = session1.authenticationToken;
                        client1.performMessageTransaction(request, function (err, response) {
                            should.not.exist(err);
                            response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
                            callback();
                        });
                    },

                    // create a second channel (client2)
                    function (callback) {
                        client2 = OPCUAClient.create();
                        client2.connect(test.endpointUrl, callback);
                    },

                    // reactivate session on second channel
                    function (callback) {
                        client2.reactivateSession(session1, function (err) {
                            callback(err);
                        });
                    },

                    // now that session has been assigned to client 1,
                    // server shall refuse any requests on channel1
                    function (callback) {
                        // coerce nodeIds
                        const request = new ReadRequest({
                            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
                            maxAge: 0,
                            timestampsToReturn: TimestampsToReturn.Both
                        });
                        request.requestHeader.authenticationToken = session1.authenticationToken;
                        client1.performMessageTransaction(request, function (err, response) {
                            should.not.exist(err);
                            should.exist(response);
                            response.should.be.instanceOf(ReadResponse);
                            response.responseHeader.serviceResult.should.eql(StatusCodes.BadSecureChannelIdInvalid);
                            callback();
                        });
                    },
                    // but server shall access request on new channel
                    function (callback) {
                        // coerce nodeIds
                        const request = new ReadRequest({
                            nodesToRead: [{ nodeId: "i=2255", attributeId: 13 }],
                            maxAge: 0,
                            timestampsToReturn: TimestampsToReturn.Both
                        });
                        request.requestHeader.authenticationToken = session1.authenticationToken;
                        client2.performMessageTransaction(request, function (err, response) {
                            if (!err) {
                                response.responseHeader.serviceResult.should.eql(StatusCodes.Good);
                            }
                            callback(err);
                        });
                    },

                    // terminate
                    function (callback) {
                        client2.disconnect(callback);
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                done
            );
        });
        // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
        // When the ActivateSession  Service  is called f or the first time then the Server shall reject the request
        // if the  SecureChannel  is not same as the one associated with the CreateSession  request.
        it("RQ1 - should reject if the channel used to activate the session for the first time is not the same as the channel used to create the session", function (done) {
            let client1, client2;
            let session1;

            let initialChannelCount = 0;
            async.series(
                [
                    // create a first channel (client1)
                    function (callback) {
                        initialChannelCount = test.server.getChannels().length;
                        test.server.getChannels().length.should.equal(initialChannelCount);
                        client1 = OPCUAClient.create();
                        client1.connect(test.endpointUrl, callback);
                    },

                    // create a session using client1
                    //   ( without activating it)
                    function (callback) {
                        client1._createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            test.server.getChannels().length.should.equal(initialChannelCount + 1);
                            callback();
                        });
                    },
                    // create a second channel (client2)
                    function (callback) {
                        client2 = OPCUAClient.create();
                        client2.connect(test.endpointUrl, callback);
                    },

                    // activate the session created with client1 using client2 !!
                    // this should be detected by server and server shall return an error
                    function (callback) {
                        test.server.getChannels().length.should.equal(initialChannelCount + 2);
                        //xx console.log(" ID1 =", client1._secureChannel.channelId);
                        //xx console.log(" ID2 =", client2._secureChannel.channelId);

                        client2.reactivateSession(session1, function (err) {
                            if (!err) {
                                callback(new Error("_activateSession shall return an error "));
                            }
                            err.message.should.match(/BadSessionNotActivated/);
                            callback();
                        });
                    },

                    // terminate
                    function (callback) {
                        client2.disconnect(callback);
                    },
                    // activate the session as expected on same channel used to create it
                    // so we can close it properly
                    function (callback) {
                        client1._activateSession(session1, function (err) {
                            should.not.exist(err);
                            session1.close(callback);
                        });
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                done
            );
        });
        function m(file) {
            const p = path.join(certificateFolder, file);
            if (!fs.existsSync(p)) {
                console.error(" cannot find ", p);
            return p;
        // OpcUA 1.02 part 3 $5.6.3.1 ActiveSession Set page 29
        // Subsequent calls to  ActivateSession  may be associated with different  SecureChannels.  If this is the
        // case then  the  Server  shall verify that the  Certificate  the  Client  used to create the new
        // SecureChannel  is the same as the  Certificate  used to create the original  SecureChannel.
        it("RQ2 -server should raise an error if a existing session is reactivated from a channel that have different certificate than the original channel", function (done) {
            const serverCertificate = test.server.getCertificateChain();

            let client1, client2;
            let session1;
            async.series(
                [
                    // create a first channel (client1) with
                    function (callback) {
                        //xx console.log(" creating initial channel with some certificate");
                        const certificateFile1 = m("client_cert_2048.pem");
                        const privateKeyFile1 = m("client_key_2048.pem");
                        console.log(certificateFile1);

                        client1 = OPCUAClient.create({
                            certificateFile: certificateFile1,
                            privateKeyFile: privateKeyFile1,
                            securityMode: MessageSecurityMode.Sign,
                            securityPolicy: SecurityPolicy.Basic128Rsa15,
                            serverCertificate: serverCertificate
                        });

                        const certificate = readCertificate(certificateFile1);

                        async function doIt() {
                            await test.server.serverCertificateManager.trustCertificate(certificate);
                            const issuerCertificateFile = m("CA/public/cacert.pem");
                            const issuerCertificateRevocationListFile = m("CA/crl/revocation_list.der");
                            const issuerCertificate = readCertificate(issuerCertificateFile);
                            const issuerCrl = await readCertificateRevocationList(issuerCertificateRevocationListFile);
                            await test.server.serverCertificateManager.addIssuer(issuerCertificate);
                            await test.server.serverCertificateManager.addRevocationList(issuerCrl);
                            callback();
                        }
                        doIt();
                    },
                    function (callback) {
                        client1.connect(test.endpointUrl, callback);
                    },
                    // create a session using client1
                    function (callback) {
                        //xx console.log(" create session");
                        client1._createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },
                    // activate the session as expected on same channel used to create it
                    function (callback) {
                        //xx console.log(" activate session");
                        client1._activateSession(session1, function (err) {
                            callback(err);
                        });
                    },

                    // create a second channel (client2)
                    // with a different certificate ....
                    function (callback) {
                        // creating second channel with different credential
                        console.log(" creating second channel with different certificate");
                        const certificateFile2 = m("client_cert_3072.pem");
                        const privateKeyFile2 = m("client_key_3072.pem");
                        client2 = OPCUAClient.create({
                            certificateFile: certificateFile2,
                            privateKeyFile: privateKeyFile2,
                            securityMode: MessageSecurityMode.Sign,
                            securityPolicy: SecurityPolicy.Basic256,
                            serverCertificate: serverCertificate
                        });
                        const certificate = readCertificate(certificateFile2);
                        test.server.serverCertificateManager.trustCertificate(certificate, callback);
                    },
                    function (callback) {
                        client2.connect(test.endpointUrl, callback);
                    },
                    function (callback) {
                        // reactivate session on second channel
                        // Reactivate should fail because certificate is not the same as the original one
                        client2.reactivateSession(session1, function (err) {
                            if (err) {
                                err.message.should.match(/BadNoValidCertificates/);
                                callback();
                            } else {
                                callback(new Error("expecting reactivateSession to fail"));
                            }
                        });
                    },
                    // terminate
                    function (callback) {
                        client2.disconnect(callback);
                    },
                    function (callback) {
                        session1.close(callback);
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    },

                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                done
            );
        });
        // In addition,the Server shall verify that the  Client  supplied a  UserIdentityToken  that is   identical to the token
        // currently associated with the  Session.
        it("RQ3 - server should raise an error if a session is reactivated with different user identity tokens", function (done) {
            let client1, client2;
            let session1;

            const user1 = {
                userName: "user1",
                password: "password1"
            };
            const user2 = new UserNameIdentityToken({
                userName: "user1",
                password: "password1"
            });
            //xx console.log(" user1 ", user1.toString());
            async.series(
                [
                    // given a established session with a subscription and some publish request

                    function (callback) {
                        client1 = OPCUAClient.create();
                        client1.connect(test.endpointUrl, callback);
                    },
                    // create a session using client1
                    function (callback) {
                        client1.createSession(user1, function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },
                    // when the session is transferred to a different channel
                    // create a second channel (client2)
                    function (callback) {
                        client2 = OPCUAClient.create();
                        client2.connect(test.endpointUrl, callback);
                    },
                    function (callback) {
                        // reactivate session on second channel
                        // alter session1.userIdentityInfo
                        session1.userIdentityInfo = user2;
                        session1.userIdentityInfo.userName.should.eql("user1");

                        client2.reactivateSession(session1, function (err) {
                            err.message.should.match(/BadIdentityChangeNotSupported/);
                            _.contains(client1._sessions, session1).should.eql(true); // should have failed
                            callback();
                        });
                    },
                    // terminate
                    function (callback) {
                        client2.disconnect(callback);
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                done
            );
        });
        // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel.
        xit("RQ4 - server should reject request send via old channel when session has been transferred to new channel", function (done) {
            async.series([], done);
        });
        // unprocessed pending Requests such as PublishRequest shall be be denied by the server
        // Once the Server accepts the new  SecureChannel  it shall reject requests sent via the old  SecureChannel
        it("RQ5 - server should reject pending requests send to old channel when session has been transferred to new channel", function (done) {
            const sinon = require("sinon");

            const collectPublishResponse = sinon.spy();

            let client1, client2;
            let session1;
            async.series(
                [
                    // given a established session with a subscription and some publish request

                    function (callback) {
                        client1 = OPCUAClient.create();
                        client1.connect(test.endpointUrl, callback);
                    },
                    // create a session using client1
                    function (callback) {
                        client1._createSession(function (err, session) {
                            if (err) {
                                return callback(err);
                            }
                            session1 = session;
                            callback();
                        });
                    },
                    // activate the session as expected on same channel used to create it
                    function (callback) {
                        client1._activateSession(session1, function (err) {
                            callback(err);
                        });
                    },

                    // creaet a subscription,
                    function (callback) {
                        createSubscription(session1, callback);
                    },

                    // when the session is transferred to a different channel
                    // create a second channel (client2)
                    function (callback) {
                        client2 = OPCUAClient.create();
                        client2.connect(test.endpointUrl, callback);
                        collectPublishResponse.callCount.should.eql(0);
                    },

                    // provision 3 publish requests and wait for the first keep alive
                    function (callback) {
                        sendPublishRequest(session1, function (err) {
                            should.not.exist(err);
                            collectPublishResponse.callCount.should.eql(0);
                            callback();
                        });
                        sendPublishRequest(session1, collectPublishResponse);
                        sendPublishRequest(session1, collectPublishResponse);
                    },

                    function (callback) {
                        // reactivate session on second channel
                        client2.reactivateSession(session1, function (err) {
                            callback(err);
                        });
                    },
                    function (callback) {
                        setTimeout(callback, 100);
                    },

                    function (callback) {
                        collectPublishResponse.callCount.should.eql(2);
                        collectPublishResponse.getCall(0).args[0].message.should.match(/BadSecureChannelClosed/);
                        collectPublishResponse.getCall(1).args[0].message.should.match(/BadSecureChannelClosed/);
                        callback();
                    },

                    // terminate
                    function (callback) {
                        client2.disconnect(callback);
                    },
                    function (callback) {
                        client1.disconnect(callback);
                    },
                    function (callback) {
                        test.server.engine.currentSessionCount.should.eql(0);
                        callback();
                    }
                ],
                done
            );
        });
        (err as any).request = request;
        response = undefined;
            return null; //
import { Message, Response, ServerSecureChannelLayer, ServiceFault } from "node-opcua-secure-channel";
            const response1 = new ServiceFault({
    BrowseResultOptions,
    ServiceFault
    const response = new ServiceFault({
                assert(response1 instanceof ResponseClass || response1 instanceof ServiceFault);
                session.publishEngine._on_PublishRequest(request, (_request1, response) => {
                if (statusCode !== StatusCodes.Good) {
                    const response = new ServiceFault({ responseHeader: { serviceResult: statusCode } });
                    sendResponse(response);
                } else {
                    const response = new SetTriggeringResponse({
                        responseHeader: { serviceResult: statusCode },
                        addResults,
                        removeResults,
                        addDiagnosticInfos: null,
                        removeDiagnosticInfos: null
                    });
                    sendResponse(response);
                }
                    return sendError(StatusCodes.BadNothingToDo);
                const response = new RegisterNodesResponse({
                    return sendError(StatusCodes.BadNothingToDo);
                const response = new UnregisterNodesResponse({});
import { PublishRequest, PublishResponse, ServiceFault, SubscriptionAcknowledgement } from "node-opcua-types";
    callback: (request: PublishRequest, response: PublishResponse | ServiceFault) => void;

            doDebug &&
                debugLog(
                    "ServerSidePublishEngine#on_close_subscription storing subscription",
                    subscription.id,
                    " to _closed_subscriptions because it has pending notification"
                );
        callback?: (request1: PublishRequest, response: PublishResponse| ServiceFault) => void
                                " " +
                                " " +
                                s.messageSent +
                doDebug &&
                    debugLog(chalk.bgWhite.red("feeding most late subscription subscriptionId  = "), starving_subscription.id);
        const response = new ServiceFault({
        this._send_response_for_request(publishData, response);
        this._send_valid_response_for_request(publishData, response);
    public _send_response_for_request(publishData: PublishData, response: PublishResponse | ServiceFault): void {
        response.responseHeader.requestHandle = publishData.request.requestHeader.requestHandle;
        publishData.callback(publishData.request, response);
    }
    public _send_valid_response_for_request(publishData: PublishData, response: PublishResponse): void {
        this._send_response_for_request(publishData, response);
const { ServiceFault } = require("node-opcua-types");
            publishSpy.getCall(1).args[1].should.be.instanceOf(ServiceFault);
            // publishSpy.getCall(1).args[1].subscriptionId.should.eql(0xffffffff);
            // publishSpy.getCall(1).args[1].notificationMessage.sequenceNumber.should.eql(0);
            // publishSpy.getCall(1).args[1].notificationMessage.notificationData.length.should.eql(0);
            publishSpy.getCall(2).args[1].should.be.instanceOf(ServiceFault);
            // publishSpy.getCall(2).args[1].subscriptionId.should.eql(0xffffffff);
            // publishSpy.getCall(2).args[1].notificationMessage.sequenceNumber.should.eql(0);
            // publishSpy.getCall(2).args[1].notificationMessage.notificationData.length.should.eql(0);
            publishSpy.getCall(3).args[1].should.be.instanceOf(ServiceFault);
            // publishSpy.getCall(3).args[1].subscriptionId.should.eql(0xffffffff);
            // publishSpy.getCall(3).args[1].notificationMessage.sequenceNumber.should.eql(0);
            // publishSpy.getCall(3).args[1].notificationMessage.notificationData.length.should.eql(0);
    it("ZDZ-5 a server should return ServiceFault(BadNoSubscription) as a response for a publish Request if there is no subscription available for this session. ", () => {
        send_response_for_request_spy.getCall(0).args[1].schema.name.should.equal("ServiceFault");
        send_response_for_request_spy.getCall(1).args[1].schema.name.should.equal("ServiceFault");
       
        send_response_for_request_spy.getCall(2).args[1].schema.name.should.equal("ServiceFault");
    
                if (key.name === "i") {
                    dumpRunningTests();
                    dumpRunningTestsLogs();
                }
            dumpRunningTestsLogs();
function dumpRunningTestsLogs() {
    const runningTests = [...runningPages].map((i) => testFiles[i]);
    for (let file of runningTests) {
        const outputs = outputFor[file];
        if (outputs && outputs.length) {
            console.log(chalk.green("log for", file));
            console.log(outputs.join("\n"));
        }
    }
}