it("when the client send too many publish requests that the server can queue, the server returns a Service result of BadTooManyPublishRequests",function(){

        var publish_server = new ServerSidePublishEngine({
            maxPublishRequestInQueue: 5
        });
        var send_response_for_request_spy = sinon.spy(publish_server,"send_response_for_request");

        var subscription=new Subscription({
            id: 1,
            //
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);

        // simulate client sending PublishRequest ,and server doing nothing
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());

        //en: the straw that broke the camel's back.
        //fr: la goutte qui fait d├ęborder le vase.
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());

        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].responseHeader.serviceResult.should.eql(StatusCodes.BadTooManyPublishRequests);
        send_response_for_request_spy.getCall(0).args[1].results.should.eql([]);


        subscription.terminate();
        publish_server.remove_subscription(subscription);
        publish_server.shutdown();
    });
Example #2
0
    it("a subscription that have only some notification ready before max_keepalive_count expired shall send notifications and no keepalive", function () {

        fake_publish_engine.pendingPublishRequestCount.should.eql(0);

        // pretend we have received 10 PublishRequest from client
        fake_publish_engine.pendingPublishRequestCount = 10;

        var subscription = new Subscription({
            publishingInterval: 1000,   // 1 second interval
            lifeTimeCount: 100000, // very long lifeTimeCount not to be bother by client not pinging us
            maxKeepAliveCount: 20,
            //
            publishEngine: fake_publish_engine
        });

        subscription.on("perform_update", function () {
            /* pretend that we do not have a notification ready */
        });

        var notification_event_spy = sinon.spy();
        var keepalive_event_spy = sinon.spy();
        var expire_event_spy = sinon.spy();

        subscription.on("notification", notification_event_spy);
        //subscription.on("notification", function(){
        //    subscription.popNotificationToSend();
        //});
        subscription.on("keepalive", keepalive_event_spy);
        subscription.on("expired", expire_event_spy);

        // no notification ready, during 7 seconds
        this.clock.tick(subscription.publishingInterval * 7);

        notification_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(1);
        expire_event_spy.callCount.should.equal(0);

        // a notification finally arrived !
        subscription.addNotificationMessage(fakeNotificationData);
        subscription.hasPendingNotifications.should.eql(true);

        this.clock.tick(subscription.publishingInterval * 4);

        notification_event_spy.callCount.should.equal(1);
        keepalive_event_spy.callCount.should.equal(1);
        expire_event_spy.callCount.should.equal(0);

        // a other notification finally arrived !
        subscription.addNotificationMessage(fakeNotificationData);

        this.clock.tick(subscription.publishingInterval * 4);
        notification_event_spy.callCount.should.equal(2);
        keepalive_event_spy.callCount.should.equal(1);
        expire_event_spy.callCount.should.equal(0);

        subscription.terminate();

    });
    it("a server should feed the availableSequenceNumbers in PublishResponse with sequence numbers that have not been acknowledged by the client", function () {

        var publish_server = new ServerSidePublishEngine();
        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: publish_server
        });

        publish_server.add_subscription(subscription);
        var send_response_for_request_spy = sinon.spy(publish_server,"send_response_for_request");

        // client sends a PublishRequest to the server
        var fake_request1 = new subscription_service.PublishRequest({ subscriptionAcknowledgements: [] });
        publish_server._on_PublishRequest(fake_request1);
        send_response_for_request_spy.callCount.should.equal(0);


        // server send a notification to the client
        subscription.addNotificationMessage([{}]);

        this.clock.tick(subscription.publishingInterval*1.2);

        // server should send a response for the first publish request with the above notification
        // in this response, there should be  one element in the availableSequenceNumbers.
        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].subscriptionId.should.eql(1234);
        send_response_for_request_spy.getCall(0).args[1].availableSequenceNumbers.should.eql([1]);

        // client sends a PublishRequest to the server ( with no acknowledgement)
        var fake_request2 = new subscription_service.PublishRequest({ subscriptionAcknowledgements: [] });
        publish_server._on_PublishRequest(fake_request2);


        // server has now some notification ready and send them to the client
        subscription.addNotificationMessage([{}]);
        send_response_for_request_spy.callCount.should.equal(1);

        this.clock.tick(subscription.publishingInterval);

        // server should send an response for the second publish request with a notification
        send_response_for_request_spy.callCount.should.equal(2);
        send_response_for_request_spy.getCall(1).args[1]._schema.name.should.equal("PublishResponse");
        send_response_for_request_spy.getCall(1).args[1].subscriptionId.should.eql(1234);
        send_response_for_request_spy.getCall(1).args[1].availableSequenceNumbers.should.eql([1,2]);


        // send_response_for_request_spy.
        publish_server.remove_subscription(subscription);
        subscription.terminate();
        publish_server.shutdown();
    });
Example #4
0
    it("should return BadMonitorItemInvalid when trying to remove a monitored item that doesn't exist",function(){

        var subscription = new Subscription({
            publishEngine: fake_publish_engine
        });
        subscription.removeMonitoredItem(26).should.eql(StatusCodes.BadMonitoredItemIdInvalid);

        subscription.terminate();

    });
    it("a server should send keep alive notifications", function () {

        var test = this;

        function pulse(nbInterval) {
            for (var i = 0; i < nbInterval; i++) {
                test.clock.tick(subscription.publishingInterval);
            }
        }

        var publish_server = new ServerSidePublishEngine();

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: publish_server
        });

        publish_server.add_subscription(subscription);
        subscription.state.should.equal(SubscriptionState.CREATING);

        this.clock.tick(subscription.publishingInterval);
        subscription.state.should.equal(SubscriptionState.LATE);

        // client sends a PublishRequest to the server
        var fake_request1 = new subscription_service.PublishRequest({subscriptionAcknowledgements: []});
        publish_server._on_PublishRequest(fake_request1);

        // publish request should be consumed immediately as subscription is late.
        publish_server.pendingPublishRequestCount.should.equal(0);
        subscription.state.should.equal(SubscriptionState.KEEPALIVE);

        var fake_request2 = new subscription_service.PublishRequest({subscriptionAcknowledgements: []});
        publish_server._on_PublishRequest(fake_request2);
        publish_server.pendingPublishRequestCount.should.equal(1);

        pulse(19);
        publish_server.pendingPublishRequestCount.should.equal(1);
        subscription.state.should.equal(SubscriptionState.KEEPALIVE);

        pulse(5);
        publish_server.pendingPublishRequestCount.should.equal(0);
        subscription.state.should.equal(SubscriptionState.KEEPALIVE);

        pulse(20);
        publish_server.pendingPublishRequestCount.should.equal(0);
        subscription.state.should.equal(SubscriptionState.LATE);

        subscription.terminate();
        publish_server.shutdown();
    });
    it("XX a subscription should collect monitored item notification with collectNotificationData", function (done) {

        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            publishEngine: fake_publish_engine
        });

        subscription.on("monitoredItem", function (monitoredItem) {
            monitoredItem.samplingFunc = install_spying_samplingFunc();
        });


        var monitoredItemCreateRequest = new MonitoredItemCreateRequest({
            itemToMonitor: {nodeId: someVariableNode},
            monitoringMode: subscription_service.MonitoringMode.Reporting,
            requestedParameters: {
                queueSize: 10,
                samplingInterval: 100
            }
        });

        var monitoredItemCreateResult = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest);
        monitoredItemCreateResult.statusCode.should.eql(StatusCodes.Good);
        monitoredItemCreateResult.revisedSamplingInterval.should.eql(100);

        var monitoredItem = subscription.getMonitoredItem(monitoredItemCreateResult.monitoredItemId);

        // at first, collectNotificationData  should has 1 notification with current dataItem value
        var notifications = subscription.collectNotificationData();
        should(notifications.length).equal(1);

        // now simulate some data change
        this.clock.tick(500);

        monitoredItem.queue.length.should.eql(5);

        // then, collectNotificationData  should collect at least 2 values
        notifications = subscription.collectNotificationData();
        notifications.length.should.eql(1);

        notifications = notifications[0];
        notifications.length.should.eql(1);

        notifications[0].monitoredItems.length.should.eql(5);
        notifications[0].monitoredItems[0].clientHandle.should.eql(monitoredItem.clientHandle);

        subscription.on("terminated", function () {
            done();
        });
        subscription.terminate();

    });
    it("a subscription shall send a keep-alive message at the end of the first publishing interval, if there are no Notifications ready.", function () {

        var publish_server = new ServerSidePublishEngine();


        var send_keep_alive_response_spy = sinon.spy(publish_server, "send_keep_alive_response");
        var send_response_for_request_spy = sinon.spy(publish_server, "send_response_for_request");

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 4,
            maxKeepAliveCount: 20,
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);

        // make sure we have at least 5 PublishRequest in queue
        publish_server.maxPublishRequestInQueue.should.be.greaterThan(5);
        subscription.maxKeepAliveCount.should.eql(20);
        subscription.state.should.eql(SubscriptionState.CREATING);

        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());

        this.clock.tick(subscription.publishingInterval);

        // Immediately  a keep Alive message shall be send
        subscription.state.should.eql(SubscriptionState.KEEPALIVE);
        subscription.publishIntervalCount.should.eql(1);
        send_keep_alive_response_spy.callCount.should.equal(1);
        send_response_for_request_spy.callCount.should.eql(1);

        this.clock.tick(subscription.publishingInterval);
        subscription.state.should.eql(SubscriptionState.KEEPALIVE);
        subscription.publishIntervalCount.should.eql(2);
        send_keep_alive_response_spy.callCount.should.equal(1);
        send_response_for_request_spy.callCount.should.eql(1);

        // after maxKeepAliveCount * publishingCycle a second keep Alive message shall be send
        this.clock.tick(subscription.publishingInterval * 20);

        subscription.state.should.eql(SubscriptionState.KEEPALIVE);
        subscription.publishIntervalCount.should.eql(22);
        send_keep_alive_response_spy.callCount.should.equal(2);
        send_response_for_request_spy.callCount.should.eql(2);

        subscription.terminate();
        publish_server.shutdown();
    });
Example #8
0
    it("the first Notification Message sent on a Subscription has a sequence number of 1.",function(){
        var subscription = new Subscription({
            publishEngine: fake_publish_engine
        });
        subscription._get_future_sequence_number().should.equal(1);
        subscription._get_next_sequence_number().should.equal(1);
        subscription._get_next_sequence_number().should.equal(2);
        subscription._get_next_sequence_number().should.equal(3);
        subscription._get_future_sequence_number().should.equal(4);

        subscription.terminate();
    });
    it("should have a proper maxNotificationsPerPublish default value", function (done) {
        var subscription = new Subscription({
            publishEngine: publishEngine
        });
        subscription.id = 1;
        publishEngine.add_subscription(subscription);
        subscription.maxNotificationsPerPublish.should.eql(0);

        publishEngine.remove_subscription(subscription);
        subscription.terminate();

        done();
    });
Example #10
0
    it("a subscription send a first message at the end of the first publishing cycle without waiting for the maximum  count to be reached",function(){
        // pretend the client has sent many pending PublishRequests
        fake_publish_engine.pendingPublishRequestCount = 1000;

        /**
         * When a Subscription is created, the first Message is sent at the end of the first publishing cycle to
         * inform the Client that the Subscription is operational. A Notification Message is sent if there are
         * Notifications ready to be reported. If there are none, a keep-alive Message is sent instead that
         * contains a sequence number of 1, indicating that the first Notification Message has not yet been
         * sent. This is the only time a keep-alive Message is sent without waiting for the maximum keep-alive
         * count to be reached, as specified in (f) above.
         *
         */
        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: fake_publish_engine
        });

        // pretend that we already have notification messages
        // a notification finally arrived !
        subscription.addNotificationMessage({});

        var notification_event_spy = sinon.spy();
        var keepalive_event_spy = sinon.spy();
        var expire_event_spy = sinon.spy();

        subscription.on("notification", notification_event_spy);
        subscription.on("keepalive", keepalive_event_spy);
        subscription.on("expired", expire_event_spy);

        this.clock.tick(200);
        keepalive_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.eql(0);

        this.clock.tick(1000);
        keepalive_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.eql(1);

        this.clock.tick(1000);
        keepalive_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.eql(1);

        this.clock.tick(30000);
        keepalive_event_spy.callCount.should.equal(1);
        notification_event_spy.callCount.should.eql(1);

        subscription.terminate();

    });
Example #11
0
    it("a publishing subscription can be disabled and re-enabled", function (done) {
        // pretend the client has sent many pending PublishRequests
        fake_publish_engine.pendingPublishRequestCount = 1000;

        var subscription = new Subscription({
            publishingInterval: 100,
            maxKeepAliveCount: 5,
            lifeTimeCount: 10,
            publishingEnabled: true,              //  PUBLISHING IS ENABLED !!!
            publishEngine: fake_publish_engine
        });

        // pretend that we already have notification messages
        function push_some_notification() {
            subscription.addNotificationMessage(fakeNotificationData);
        }

        var t = setInterval(push_some_notification, 50);

        var notification_event_spy = sinon.spy();
        var keepalive_event_spy = sinon.spy();
        var expire_event_spy = sinon.spy();

        subscription.on("notification", notification_event_spy);
        subscription.on("keepalive", keepalive_event_spy);
        subscription.on("expired", expire_event_spy);

        this.clock.tick(2000);
        keepalive_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.be.greaterThan(20);


        // now disable
        subscription.setPublishingMode(false);
        this.clock.tick(2000);
        keepalive_event_spy.callCount.should.equal(4);
        notification_event_spy.callCount.should.be.greaterThan(20);

        subscription.setPublishingMode(true);
        this.clock.tick(2000);
        keepalive_event_spy.callCount.should.equal(4);
        notification_event_spy.callCount.should.be.greaterThan(40);

        clearInterval(t);

        subscription.terminate();
        done();


    });
Example #12
0
    it("a subscription that has no notification within maxKeepAliveCount shall send a keepalive signal ", function () {

        // pretend the client has sent many pending PublishRequests
        fake_publish_engine.pendingPublishRequestCount = 1000;

        var subscription = new Subscription({
            publishingInterval: 1000,
            lifeTimeCount: 100000, // very large lifetime not to be bother by client not pinging us
            maxKeepAliveCount: 20,
            //
            publishEngine: fake_publish_engine
        });
        subscription.on("perform_update", function () {
            // pretend there is no notification ready
        });

        var expire_event_spy = sinon.spy();
        var notification_event_spy = sinon.spy();
        var keepalive_event_spy = sinon.spy();
        subscription.on("expired", expire_event_spy);
        subscription.on("notification", notification_event_spy);
        subscription.on("keepalive", keepalive_event_spy);

        var terminate_spy = sinon.spy(subscription, "terminate");

        this.clock.tick(subscription.publishingInterval * (subscription.maxKeepAliveCount - 5));

        terminate_spy.callCount.should.equal(0);
        expire_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(1);

        this.clock.tick(subscription.publishingInterval * 10);

        terminate_spy.callCount.should.equal(0);
        expire_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(2);

        this.clock.tick(subscription.publishingInterval * (subscription.maxKeepAliveCount + 3));

        terminate_spy.callCount.should.equal(0);
        expire_event_spy.callCount.should.equal(0);
        notification_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(3);

        subscription.terminate();

    });
    it("should have a proper maxNotificationsPerPublish default value", function (done) {
        var subscription = new Subscription({
            publishEngine: publishEngine
        });
        subscription.on("monitoredItem", function (monitoredItem) {
            monitoredItem.samplingFunc = install_spying_samplingFunc();
        });

        subscription.id = 1;
        publishEngine.add_subscription(subscription);
        subscription.maxNotificationsPerPublish.should.eql(0);

        subscription.terminate();

        done();
    });
    it("a Normal subscription that receives a notification shall wait for the next publish interval to send a PublishResponse ", function () {

        var publish_server = new ServerSidePublishEngine();

        var send_keep_alive_response_spy = sinon.spy(publish_server, "send_keep_alive_response");
        var send_notification_message_spy = sinon.spy(publish_server, "send_notification_message");

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 4,
            maxKeepAliveCount: 20,
            publishEngine: publish_server,
            maxNotificationsPerPublish: 0 // no limits
        });
        publish_server.add_subscription(subscription);
        var monitoredItem  =add_mock_monitored_item(subscription);

        monitoredItem.simulateMonitoredItemAddingNotification();

        // make sure we have at least 5 PublishRequest in queue
        publish_server.maxPublishRequestInQueue.should.be.greaterThan(5);
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());
        publish_server._on_PublishRequest(new subscription_service.PublishRequest());


        this.clock.tick(2);
        publish_server.pendingPublishRequestCount.should.eql(5);


        this.clock.tick(subscription.publishingInterval);
        subscription.state.should.eql(SubscriptionState.NORMAL);
        subscription.publishIntervalCount.should.eql(1);

        this.clock.tick(subscription.publishingInterval);
        subscription.publishIntervalCount.should.eql(2);
        subscription.state.should.eql(SubscriptionState.NORMAL);

        send_keep_alive_response_spy.callCount.should.eql(0);
        send_notification_message_spy.callCount.should.eql(1);

        subscription.terminate();
        publish_server.shutdown();
    });
    it("should return an error when filter is DataChangeFilter deadband is out of bound", function (done) {

        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            publishEngine: fake_publish_engine
        });
        subscription.on("monitoredItem", function (monitoredItem) {
            monitoredItem.samplingFunc = install_spying_samplingFunc();
        });


        function _create_MonitoredItemCreateRequest_with_deadbandValue(value) {
            return new MonitoredItemCreateRequest({
                itemToMonitor: {
                    nodeId: someVariableNode,
                    attributeId: AttributeIds.Value
                },
                monitoringMode: subscription_service.MonitoringMode.Reporting,
                requestedParameters: {
                    queueSize: 10,
                    samplingInterval: 100,
                    filter: new subscription_service.DataChangeFilter({
                        trigger: subscription_service.DataChangeTrigger.Status,
                        deadbandType: subscription_service.DeadbandType.Percent,
                        deadbandValue: value
                    })
                }
            });

        }

        var monitoredItemCreateRequest1 = _create_MonitoredItemCreateRequest_with_deadbandValue(-10);
        var monitoredItemCreateResult1 = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest1);
        monitoredItemCreateResult1.statusCode.should.eql(StatusCodes.BadDeadbandFilterInvalid);

        var monitoredItemCreateRequest2 = _create_MonitoredItemCreateRequest_with_deadbandValue(110);
        var monitoredItemCreateResult2 = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest2);
        monitoredItemCreateResult2.statusCode.should.eql(StatusCodes.BadDeadbandFilterInvalid);

        var monitoredItemCreateRequest3 = _create_MonitoredItemCreateRequest_with_deadbandValue(90);
        var monitoredItemCreateResult3 = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest3);
        monitoredItemCreateResult3.statusCode.should.eql(StatusCodes.Good);

        subscription.terminate();
        done();
    });
    it("a subscription should collect monitored item notification with collectDataChangeNotification", function (done) {

        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            publishEngine: fake_publish_engine
        });


        var monitoredItemCreateRequest = new MonitoredItemCreateRequest({
            itemToMonitor: {},
            monitoringMode: subscription_service.MonitoringMode.Reporting,
            requestedParameters: {
                queueSize: 10,
                samplingInterval: 100
            }
        });

        var monitoredItemCreateResult = subscription.createMonitoredItem(TimestampsToReturn.Both, monitoredItemCreateRequest);

        var monitoredItem = subscription.getMonitoredItem(monitoredItemCreateResult.monitoredItemId);

        // at first, collectDataChangeNotification  should collect nothing
        var notifications = subscription.collectDataChangeNotification();
        should(notifications.length).equal(0);

        // now simulate some data change
        this.clock.tick(100);
        monitoredItem.recordValue({value: {dataType: DataType.UInt32, value: 1000}});

        this.clock.tick(100);
        monitoredItem.recordValue({value: {dataType: DataType.UInt32, value: 1001}});
        monitoredItem.queue.length.should.eql(2);

        // then, collectDataChangeNotification  should collect at least 2 values
        notifications = subscription.collectDataChangeNotification();
        notifications.length.should.eql(1);
        notifications[0].monitoredItems.length.should.eql(2);
        notifications[0].monitoredItems[0].clientHandle.should.eql(monitoredItem.clientHandle);

        subscription.on("terminated", function () {
            done();
        });
        subscription.terminate();

    });
    it("PublishRequest timeout, the publish engine shall return a publish response with serviceResult = BadTimeout when Publish requests have timed out", function () {
        var publish_server = new ServerSidePublishEngine();

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 4,
            maxKeepAliveCount: 20,
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);

        subscription.maxKeepAliveCount.should.eql(20);
        subscription.state.should.eql(SubscriptionState.CREATING);
        var send_response_for_request_spy = sinon.spy(publish_server, "send_response_for_request");

        publish_server._on_PublishRequest(new subscription_service.PublishRequest({requestHeader: {timeoutHint: 1200}}));
        publish_server._on_PublishRequest(new subscription_service.PublishRequest({requestHeader: {timeoutHint: 1200}}));
        publish_server._on_PublishRequest(new subscription_service.PublishRequest({requestHeader: {timeoutHint: 1200}}));
        publish_server._on_PublishRequest(new subscription_service.PublishRequest({requestHeader: {timeoutHint: 1200}}));
        publish_server._on_PublishRequest(new subscription_service.PublishRequest({requestHeader: {timeoutHint: 1200}}));

        this.clock.tick(20);
        publish_server.pendingPublishRequestCount.should.eql(5); // one should have been consumed by subscription

        this.clock.tick(1000);

        send_response_for_request_spy.callCount.should.equal(1);
        publish_server.pendingPublishRequestCount.should.eql(4);
        send_response_for_request_spy.firstCall.args[1].responseHeader.serviceResult.should.eql(StatusCodes.Good);
        publish_server._on_PublishRequest(new subscription_service.PublishRequest({requestHeader: {timeoutHint: 1200}}));

        this.clock.tick(1000);
        // all remaining 4 publish request must have been detected as timedout now and answered as such.
        send_response_for_request_spy.callCount.should.equal(5);
        publish_server.pendingPublishRequestCount.should.eql(1);
        send_response_for_request_spy.getCall(1).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadTimeout);
        send_response_for_request_spy.getCall(2).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadTimeout);
        send_response_for_request_spy.getCall(3).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadTimeout);
        send_response_for_request_spy.getCall(4).args[1].responseHeader.serviceResult.should.eql(StatusCodes.BadTimeout);

        subscription.terminate();
        publish_server.shutdown();

    });
    it("the server shall return BadSequenceNumberInvalid if the client attempts to acknowledge a notification that is not in the queue", function () {

        var publish_server = new ServerSidePublishEngine();
        var send_response_for_request_spy = sinon.spy(publish_server, "send_response_for_request");

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);
        var monitoredItem  =add_mock_monitored_item(subscription);

        // simulate a client sending a PublishRequest to the server
        // that acknowledge on a wrong sequenceNumber
        publish_server._on_PublishRequest(new subscription_service.PublishRequest({
                subscriptionAcknowledgements: [
                    {
                        subscriptionId: 1234,
                        sequenceNumber: 36   // <<< INVALID SEQUENCE NUMBER
                    }
                ]
            }
        ));


        // server send a notification to the client
        monitoredItem.simulateMonitoredItemAddingNotification();


        this.clock.tick(subscription.publishingInterval * 1.2);

        subscription.getAvailableSequenceNumbers().should.eql([1]);

        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].responseHeader.serviceResult.should.eql(StatusCodes.Good);
        send_response_for_request_spy.getCall(0).args[1].results.should.eql([StatusCodes.BadSequenceNumberUnknown]);

        subscription.terminate();
        publish_server.shutdown();
    });
    it("should return BadFilterNotAllowed if a DataChangeFilter is specified on a non-Value Attribute monitored item", function () {

        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            publishEngine: fake_publish_engine
        });
        subscription.on("monitoredItem", function (monitoredItem) {
            monitoredItem.samplingFunc = install_spying_samplingFunc();
        });

        function test_with_attributeId(attributeId, statusCode) {
            var monitoredItemCreateRequest = new MonitoredItemCreateRequest({
                itemToMonitor: {
                    nodeId: someVariableNode,
                    attributeId: attributeId
                },
                monitoringMode: subscription_service.MonitoringMode.Reporting,
                requestedParameters: {
                    queueSize: 10,
                    samplingInterval: 100,
                    filter: new subscription_service.DataChangeFilter({
                        trigger: subscription_service.DataChangeTrigger.Status,
                        deadbandType: subscription_service.DeadbandType.Percent,
                        deadbandValue: 10
                    })
                }
            });
            var monitoredItemCreateResult = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest);
            return monitoredItemCreateResult.statusCode;
        }


        test_with_attributeId(AttributeIds.BrowseName).should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_attributeId(AttributeIds.AccessLevel).should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_attributeId(AttributeIds.ArrayDimensions).should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_attributeId(AttributeIds.DataType).should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_attributeId(AttributeIds.DisplayName).should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_attributeId(AttributeIds.EventNotifier).should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_attributeId(AttributeIds.Historizing).should.eql(StatusCodes.BadFilterNotAllowed);

        test_with_attributeId(AttributeIds.Value).should.eql(StatusCodes.Good);
        subscription.terminate();

    });
    it("a subscription should accept monitored item", function (done) {

        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            publishEngine: fake_publish_engine
        });
        subscription.on("monitoredItem", function (monitoredItem) {
            monitoredItem.samplingFunc = install_spying_samplingFunc();
        });


        var monitoredItemCreateRequest = new MonitoredItemCreateRequest({
            itemToMonitor: {nodeId: someVariableNode},
            monitoringMode: subscription_service.MonitoringMode.Reporting,

            requestedParameters: {
                queueSize: 10,
                samplingInterval: 100
            }
        });

        subscription.monitoredItemCount.should.eql(0);

        var monitoredItemCreateResult = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest);
        monitoredItemCreateResult.statusCode.should.eql(StatusCodes.Good);

        //xx require("lib/utils").dump(monitoredItemCreateResult);
        subscription.monitoredItemCount.should.eql(1);

        monitoredItemCreateResult.should.be.instanceOf(subscription_service.MonitoredItemCreateResult);

        monitoredItemCreateResult.monitoredItemId.should.eql(1);
        monitoredItemCreateResult.revisedSamplingInterval.should.eql(100);

        subscription.on("terminated", function () {
            // monitored Item shall be deleted at this stage
            subscription.monitoredItemCount.should.eql(0);
            done();
        });
        subscription.terminate();

    });
Example #21
0
    it("a subscription shall maintain a retransmission queue of pending NotificationMessages.",function(){

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: fake_publish_engine
        });

        subscription.pendingNotificationsCount.should.equal(0);
        subscription.addNotificationMessage({});
        subscription.pendingNotificationsCount.should.equal(1);

        subscription.terminate();


    });
    it("LifeTimeCount, the server shall terminated the subscription if it has not received any PublishRequest after LifeTimeCount cycles", function () {

        var publish_server = new ServerSidePublishEngine();

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 4,
            maxKeepAliveCount: 20,
            publishEngine: publish_server
        });
        subscription.maxKeepAliveCount.should.eql(20);
        subscription.state.should.eql(SubscriptionState.CREATING);
        publish_server.add_subscription(subscription);
        var monitoredItem  =add_mock_monitored_item(subscription);

        publish_server._on_PublishRequest(new subscription_service.PublishRequest());

        this.clock.tick(subscription.publishingInterval);
        subscription.state.should.eql(SubscriptionState.KEEPALIVE);
        subscription.publishIntervalCount.should.eql(1);


        // server send a notification to the client
        monitoredItem.simulateMonitoredItemAddingNotification();
        subscription.state.should.eql(SubscriptionState.KEEPALIVE);

        // server send a notification to the client
        monitoredItem.simulateMonitoredItemAddingNotification();
        subscription.state.should.eql(SubscriptionState.KEEPALIVE);

        this.clock.tick(subscription.publishingInterval);
        subscription.publishIntervalCount.should.eql(2);
        subscription.state.should.eql(SubscriptionState.LATE);

        this.clock.tick(subscription.publishingInterval * subscription.lifeTimeCount + 20);
        subscription.publishIntervalCount.should.eql(subscription.lifeTimeCount+1);
        subscription.state.should.eql(SubscriptionState.CLOSED);

        subscription.terminate();
        publish_server.shutdown();
    });
    it("LifeTimeCount, the server shall terminated the subscription if it has not received any PublishRequest after LifeTimeCount cycles",function(){

        var publish_server = new ServerSidePublishEngine();

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount:   4,
            maxKeepAliveCount: 20,
            publishEngine: publish_server
        });
        subscription.maxKeepAliveCount.should.eql(20);
        subscription.state.should.eql(SubscriptionState.NORMAL);

        this.clock.tick(2);
        subscription.state.should.eql(SubscriptionState.NORMAL);
        subscription.publishIntervalCount.should.eql(0);

        publish_server.add_subscription(subscription);

        // server send a notification to the client
        subscription.addNotificationMessage([{}]);
        subscription.pendingNotificationsCount.should.eql(1);
        subscription.state.should.eql(SubscriptionState.NORMAL);

        // server send a notification to the client
        subscription.addNotificationMessage([{}]);
        subscription.pendingNotificationsCount.should.eql(2);
        subscription.state.should.eql(SubscriptionState.NORMAL);

        this.clock.tick(subscription.publishingInterval);
        subscription.publishIntervalCount.should.eql(1);
        subscription.state.should.eql(SubscriptionState.LATE);

        this.clock.tick(subscription.publishingInterval * subscription.lifeTimeCount + 20);
        subscription.publishIntervalCount.should.eql(subscription.lifeTimeCount);
        subscription.state.should.eql(SubscriptionState.CLOSED);

        subscription.terminate();
        publish_server.remove_subscription(subscription);
        publish_server.shutdown();
    });
Example #24
0
    it("a subscription created with publishingEnabled=false shall not emit notification (but keepalive)",function(done) {

        // pretend the client has sent many pending PublishRequests
        fake_publish_engine.pendingPublishRequestCount = 1000;

        var subscription = new Subscription({
            publishingInterval: 100,
            maxKeepAliveCount:    5,
            lifeTimeCount:    10,
            publishingEnabled:   false,              //  PUBLISHING IS DISABLED !!!
            publishEngine: fake_publish_engine

        });


        // pretend that we already have notification messages
        // a notification finally arrived !
        subscription.addNotificationMessage({});
        // a notification finally arrived !
        subscription.addNotificationMessage({});
        // a notification finally arrived !
        subscription.addNotificationMessage({});
        // a notification finally arrived !
        subscription.addNotificationMessage({});
        // a notification finally arrived !
        subscription.addNotificationMessage({});

        var notification_event_spy = sinon.spy();
        var keepalive_event_spy = sinon.spy();
        var expire_event_spy = sinon.spy();

        subscription.on("notification", notification_event_spy);
        subscription.on("keepalive", keepalive_event_spy);
        subscription.on("expired", expire_event_spy);

        this.clock.tick(2000);
        keepalive_event_spy.callCount.should.equal(4);
        notification_event_spy.callCount.should.eql(0);

        subscription.terminate();
        done();
    });
Example #25
0
    it("a subscription that have no monitored items shall not terminate if client has sent enough PublishRequest", function () {

        // pretend there is plenty of PublishRequest in publish engine
        fake_publish_engine.pendingPublishRequestCount = 1000;

        var subscription = new Subscription({
            publishingInterval: 100,
            maxKeepAliveCount:    5,
            lifeTimeCount:    10,
            publishEngine: fake_publish_engine
        });

        var notification_event_spy = sinon.spy();
        var keepalive_event_spy = sinon.spy();
        var expire_event_spy = sinon.spy();

        subscription.on("notification", notification_event_spy);
        subscription.on("keepalive", keepalive_event_spy);
        subscription.on("expired", expire_event_spy);

        this.clock.tick(3000);

        subscription.publishIntervalCount.should.equal(30,
            " 3000 ms with a publishingInterval: 100 ms means publishIntervalCount = 30");


        expire_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(6);
        notification_event_spy.callCount.should.equal(0);

        this.clock.tick(3000);
        expire_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(12);
        notification_event_spy.callCount.should.equal(0);

        this.clock.tick(3000);
        expire_event_spy.callCount.should.equal(0);
        keepalive_event_spy.callCount.should.equal(18);
        notification_event_spy.callCount.should.equal(0);

        subscription.terminate();
    });
    it("should be possible to remove a subscription from a publish_server", function () {
        var publish_server = new ServerSidePublishEngine({});
        publish_server.subscriptionCount.should.equal(0);

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);
        publish_server.subscriptionCount.should.equal(1);


        subscription.terminate();
        publish_server.shutdown();
        publish_server.subscriptionCount.should.equal(0);

    });
    it("should return BadFilterNotAllowed if DeadBandFilter is specified on non-Numeric value monitored item", function () {


        var subscription = new Subscription({
            publishingInterval: 1000,
            maxKeepAliveCount: 20,
            publishEngine: fake_publish_engine
        });
        subscription.on("monitoredItem", function (monitoredItem) {
            monitoredItem.samplingFunc = install_spying_samplingFunc();
        });

        function test_with_nodeId(nodeId, statusCode) {
            var monitoredItemCreateRequest = new MonitoredItemCreateRequest({
                itemToMonitor: {
                    nodeId: nodeId,
                    attributeId: AttributeIds.Value
                },
                monitoringMode: subscription_service.MonitoringMode.Reporting,
                requestedParameters: {
                    queueSize: 10,
                    samplingInterval: 100,
                    filter: new subscription_service.DataChangeFilter({
                        trigger: subscription_service.DataChangeTrigger.Status,
                        deadbandType: subscription_service.DeadbandType.Percent,
                        deadbandValue: 10
                    })
                }
            });
            var monitoredItemCreateResult = subscription.createMonitoredItem(addressSpace, TimestampsToReturn.Both, monitoredItemCreateRequest);
            return monitoredItemCreateResult.statusCode;
        }


        test_with_nodeId("ns=100;s=Static_ByteString").should.eql(StatusCodes.BadFilterNotAllowed);
        test_with_nodeId("ns=100;s=Static_LocalizedText").should.eql(StatusCodes.BadFilterNotAllowed);

        subscription.terminate();

    });
    it("should be possible to find a subscription by id on a publish_server", function () {
        var publish_server = new ServerSidePublishEngine({});
        publish_server.subscriptionCount.should.equal(0);

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000, // 1 second
            lifeTimeCount: 100,
            maxKeepAliveCount: 20,
            //
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);
        publish_server.subscriptionCount.should.equal(1);
        publish_server.getSubscriptionById(1234).should.equal(subscription);

        subscription.terminate();

        publish_server.shutdown();
        publish_server.subscriptionCount.should.equal(0);

    });
    it("a server should send keep alive notifications", function () {

        var publish_server = new ServerSidePublishEngine();

        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 1000,
            maxKeepAliveCount: 20,
            //
            publishEngine: publish_server
        });

        publish_server.add_subscription(subscription);
        subscription.state.should.equal(SubscriptionState.NORMAL);

        // client sends a PublishRequest to the server
        var fake_request1 = new subscription_service.PublishRequest({
            subscriptionAcknowledgements: []
        });
        publish_server._on_PublishRequest(fake_request1);
        publish_server.pendingPublishRequestCount.should.equal(1);

        var fake_request2 = new subscription_service.PublishRequest({
            subscriptionAcknowledgements: []
        });
        publish_server._on_PublishRequest(fake_request2);
        publish_server.pendingPublishRequestCount.should.equal(2);

        this.clock.tick(subscription.publishingInterval * 19);
        publish_server.pendingPublishRequestCount.should.equal(1);

        this.clock.tick(subscription.publishingInterval * 5);
        publish_server.pendingPublishRequestCount.should.equal(0);

        publish_server.remove_subscription(subscription);
        subscription.terminate();
        publish_server.shutdown();
    });
    it("a subscription should provide its time to expiration so that publish engine could sort late subscriptions by order of priority", function () {

        var publish_server = new ServerSidePublishEngine();
        var subscription = new Subscription({
            id: 1234,
            publishingInterval: 1000,
            lifeTimeCount: 10,
            maxKeepAliveCount: 2,
            publishEngine: publish_server
        });
        publish_server.add_subscription(subscription);

        subscription.lifeTimeCount.should.eql(10);
        subscription.timeToExpiration.should.eql(1000 * 10);

        this.clock.tick(subscription.publishingInterval * 1.2);
        subscription.timeToExpiration.should.eql(1000 * 9);

        this.clock.tick(subscription.publishingInterval * 1.2);
        subscription.timeToExpiration.should.eql(1000 * 8);

        subscription.terminate();
        publish_server.shutdown();
    });