Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding callback to thingShadow.register #83

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,12 @@ thingShadows.on('connect', function() {
// After connecting to the AWS IoT platform, register interest in the
// Thing Shadow named 'RGBLedLamp'.
//
thingShadows.register( 'RGBLedLamp' );
//
// 5 seconds after registering, update the Thing Shadow named
thingShadows.register( 'RGBLedLamp', function() {

// When the Thing Shadow is ready, update the Thing Shadow named
// 'RGBLedLamp' with the latest device state and save the clientToken
// so that we can correlate it with status or timeout events.
//
// Note that the delay is not required for subsequent updates; only
// the first update after a Thing Shadow registration using default
// parameters requires a delay. See API documentation for the update
// method for more details.
//
setTimeout( function() {
//
// Thing shadow state
//
var rgbLedLampState = {"state":{"desired":{"red":rval,"green":gval,"blue":bval}}};
Expand All @@ -160,7 +153,6 @@ thingShadows.on('connect', function() {
{
console.log('update shadow failed, operation still in progress');
}
}, 5000 );
});

thingShadows.on('status',
Expand Down Expand Up @@ -333,7 +325,7 @@ from each operation.

-------------------------------------------------------
<a name="register"></a>
### awsIot.thingShadow#register(thingName, [options] )
### awsIot.thingShadow#register(thingName, [options], [callback] )

Register interest in the Thing Shadow named `thingName`. The thingShadow class will
subscribe to any applicable topics, and will fire events for the Thing Shadow
Expand Down Expand Up @@ -364,6 +356,10 @@ AWS IoT maintains version numbers for each shadow, and will reject operations wh
contain the incorrect version; in applications where multiple clients update the same
shadow, clients can use versioning to avoid overwriting each other's changes.

The `callback` parameter are optional and will be called when the thingShadow is read for use.
*Ready for use* means when we have received subscription ACK on all needed topics.
The callback should be used when delete/get/update operations is needed right after the thingShadow is ready.

-------------------------------------------------------
<a name="unregister"></a>
### awsIot.thingShadow#unregister(thingName)
Expand Down
22 changes: 21 additions & 1 deletion test/mock/mockMQTTClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,37 @@ function mockMQTTClient( wrapper, options ) {
callback = callback || '';
this.commandCalled['subscribe'] += 1;

var granted = [];
if ( Object.prototype.toString.call(topic) === '[object Array]' ) {
topic.forEach( function( item, index, array ) {
var grantedTopic = {topic: item, qos: 0}
that.subscriptions.push( item );
if (!isUndefined( options.qos )) {
that.subscribeQosValues.push( options.qos );
grantedTopic.qos = options.qos;
}

if (mockMQTTClient.triggerError()) {
grantedTopic.qos = 128;
}

granted.push(grantedTopic);
});
}
else {
var grantedTopic = {topic: topic, qos: 0}
this.subscriptions.push( topic );
if (!isUndefined( options.qos )) {
that.subscribeQosValues.push( options.qos );
grantedTopic.qos = options.qos;
}
if (mockMQTTClient.triggerError()) {
grantedTopic.qos = 128;
}
granted.push(grantedTopic);
}
if(callback !== '') {
callback(null); // call callback
callback(null, granted); // call callback
}
};

Expand All @@ -107,4 +122,9 @@ function mockMQTTClient( wrapper, options ) {
}

util.inherits(mockMQTTClient, EventEmitter);

mockMQTTClient.triggerError = function() {
return false;
};

module.exports = mockMQTTClient;
70 changes: 67 additions & 3 deletions test/thing-unit-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,70 @@ describe( "thing shadow class unit tests", function() {
});
});

describe( "register a thing shadow name", function() {
//
// Verify that the thing shadow invokes the register callback when subscription to all
// topics are finished. The callback is invoked based on the callback from the mqtt library.
//

var thingShadowsConfig = {
keyPath: 'test/data/private.pem.key',
certPath: 'test/data/certificate.pem.crt',
caPath: 'test/data/root-CA.crt',
clientId: 'dummy-client-1',
region: 'us-east-1'
};

it("should trigger error when a subscription fails", function () {

var stubTriggerError = sinon.stub(mockMQTTClient, 'triggerError', function(){return true;});
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't used sinon that much before, so don't know if I did it the correct way :)


var thingShadows = thingShadow(thingShadowsConfig);
thingShadows.register('testShadow1', { ignoreDeltas: true, persistentSubscribe: true }, function (err, granted) {
assert.notEqual(err, null);
for (var k = 0, grantedLen = granted.length; k < grantedLen; k++) {
//
// 128 is 0x80 - Failure from the MQTT lib.
//
assert.equal(granted[k].qos, 128);
stubTriggerError.restore();
}
});
});

it("should trigger callback when ignoreDeltas is true and persistentSubscribe is true", function() {
var thingShadows = thingShadow( thingShadowsConfig );
var fakeCallback = sinon.spy();
thingShadows.register( 'testShadow1', {ignoreDeltas:true, persistentSubscribe:true}, fakeCallback);

assert(fakeCallback.calledOnce);
});

it("should trigger callback when ignoreDeltas is false and persistentSubscribe is false", function() {
var thingShadows = thingShadow( thingShadowsConfig );
var fakeCallback = sinon.spy();
thingShadows.register( 'testShadow1', {ignoreDeltas:false, persistentSubscribe:false}, fakeCallback);

assert(fakeCallback.calledOnce);
});

it("should trigger callback when ignoreDeltas is true and persistentSubscribe is false", function() {
var thingShadows = thingShadow( thingShadowsConfig );
var fakeCallback = sinon.spy();
thingShadows.register( 'testShadow1', {ignoreDeltas:true, persistentSubscribe:false}, fakeCallback);

assert(fakeCallback.calledOnce);
});

it("should trigger callback when ignoreDeltas is false and persistentSubscribe is true", function() {
var thingShadows = thingShadow( thingShadowsConfig );
var fakeCallback = sinon.spy();
thingShadows.register( 'testShadow1', {ignoreDeltas:false, persistentSubscribe:true}, fakeCallback);

assert(fakeCallback.calledOnce);
});
});

describe( "subscribe to/unsubscribe from a non-thing topic", function() {
//
// Verify that the thing shadow module does not throw an exception
Expand Down Expand Up @@ -211,10 +275,10 @@ describe( "thing shadow class unit tests", function() {
} );
// Register a thing, using default delta settings
thingShadows.register('testShadow1');
assert.equal(mockMQTTClientObject.commandCalled['subscribe'], 2); // Called twice, one for delta, one for GUD
assert.equal(mockMQTTClientObject.commandCalled['subscribe'], 1); // Called twice, one for delta, one for GUD
mockMQTTClientObject.reInitCommandCalled();
thingShadows.unregister('testShadow1');
assert.equal(mockMQTTClientObject.commandCalled['unsubscribe'], 2);
assert.equal(mockMQTTClientObject.commandCalled['unsubscribe'], 1);
});
});

Expand Down Expand Up @@ -244,7 +308,7 @@ describe( "thing shadow class unit tests", function() {
assert.equal(mockMQTTClientObject.commandCalled['subscribe'], 1); // Called once, for GUD
mockMQTTClientObject.reInitCommandCalled();
thingShadows.unregister('testShadow1');
assert.equal(mockMQTTClientObject.commandCalled['unsubscribe'], 2); // Called twice, unsub from ALL
assert.equal(mockMQTTClientObject.commandCalled['unsubscribe'], 1); // Called twice, unsub from ALL
});
});

Expand Down
Loading