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

Adds tests for HTTP device sample #534

Merged
merged 7 commits into from
Dec 19, 2017
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,32 @@ function publishAsync (messageCount, numMessages) {
}
// [END iot_http_publish]

// [START iot_http_getconfig]
function getConfig (version) {
console.log('Getting config:');
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: combine these into one console.log call? e.g:

console.log(`Getting config from URL: ${urlBase}`);

console.log(urlBase);
const options = {
url: urlBase + '/config?local_version=' + version,
headers: {
'authorization': 'Bearer ' + authToken,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: use template strings instead of concatenation? e.g:

`Bearer ${authToken}`

If you decide to make this change, please update the rest of your PR as well.

'content-type': 'application/json',
'cache-control': 'no-cache'

},
json: true
};
request.get(options, function (error, response, body) {
if (error) {
console.error('Received error: ', error);
} else if (response.body.error) {
console.error('Received error: ' + JSON.stringify(response.body.error));
} else {
console.log('Received config', JSON.stringify(body));
}
});
}
// [END iot_http_getconfig]

// [START iot_run_http]
// A unique string that identifies this device. For Google Cloud IoT Core, it
// must be in the format below.
Expand All @@ -174,10 +200,14 @@ const devicePath = `projects/${argv.project_id}/locations/${argv.cloud_region}/r
// The request path, set accordingly depending on the message type.
const pathSuffix = argv.message_type === 'events'
? ':publishEvent' : ':setState';
const url = `https://${argv.http_bridge_address}/v1beta1/${devicePath}${pathSuffix}`;
const urlBase = `https://${argv.http_bridge_address}/v1beta1/${devicePath}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

Move this to the top of the file, or use a let and take advantage of hoisting? Seeing this declared after the functions that use it may confuse people who are new to JS (and don't understand that global statements get executed first).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It uses the args, so at a minimum it needs to be after the argument parser... I have moved the variables up.

const url = `${urlBase}${pathSuffix}`;
let iatTime = parseInt(Date.now() / 1000);
let authToken = createJwt(argv.project_id, argv.private_key_file, argv.algorithm);

// Print latest configuration
getConfig(0);

// Publish messages.
publishAsync(1, argv.num_messages);
// [END iot_run_http]
13 changes: 12 additions & 1 deletion iot/http_example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@
"license": "Apache-2.0",
"author": "Google Inc.",
"main": "cloudiot_http_example_nodejs.js",
"scripts": {
"lint": "samples lint",
"pretest": "npm run lint",
"test": "samples test run --cmd ava -- -T 3m --verbose system-test/*.test.js"
},
"dependencies": {
"@google-cloud/pubsub": "0.13.2",
"@google-cloud/nodejs-repo-tools": "1.4.17",
"ava": "0.22.0",
"yargs": "8.0.2",
"jsonwebtoken": "7.4.1",
"request": "2.82.0"
"request": "2.82.0",
"uuid": "3.1.0"
},
"testDependencies": {
},
"devDependencies": {}
}
4 changes: 4 additions & 0 deletions iot/http_example/resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Test public certificate files

The public certificates in this folder are only provided for testing and should
not be used for registering your devices.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we use these in our CI tests - if so, I assume they are sufficiently secure?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, these certificates are used in our CI tests. The authorization credentials are revoked when the tests tear down.

18 changes: 18 additions & 0 deletions iot/http_example/resources/rsa_cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC9TCCAd2gAwIBAgIJALM44e3ivEWkMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV
BAMMBnVudXNlZDAeFw0xNzEyMDcwMDQ1MjdaFw0yNzEyMDUwMDQ1MjdaMBExDzAN
BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL4w
BxHuEyYdbiwKiD8yXY7vYpcygeOQ4/ZdEg3wCB2OuYcaFRcCuqLcTLMnuzdcL+y3
HBjWkrRW658cg3NG93Vj0iwSrga6u24CGBNYV+h8MBvwaDxk+uubnd5M/Q2OyL1J
GiMxQ1blR/71Hr5hhqaQZ2+qOF6kuf1m9rLUtMUJwOKp/PjPDmy654ZGsFWFSZmy
eRpNzmGU+KJg0o+Qf+sm75a8gQZ8AsrqveW0S/8o+zAjD0SkPcd01QBmYzQhjbi/
LGGITrzbaB3ld9umJBIcXfnYPYisJfwSsT/jFwiXhrhpxNNaIaKlTzlQIt5l8bSs
HXzJBbuIg5Jb/SyIEpkCAwEAAaNQME4wHQYDVR0OBBYEFOfaQTUVAoNb6fc7qzzl
uKyHGrCYMB8GA1UdIwQYMBaAFOfaQTUVAoNb6fc7qzzluKyHGrCYMAwGA1UdEwQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBALKKDtiV1YV8k0YsNdiIXRlS3jsuoGuI
VVBrvDGz5Hel0rH9YmmfPS/Yn08kk3DF8Uynr4Xo1Zt9hmhgoq3ZoWm7MIP1+a9s
WyACyEMhVQSCzQrexRvG5ElpHx/vNjbcwiBkE5urlIvMBVt+BRRNKMNWq6F9ae63
FxRp7CtNFSbibtLJuPgCs6qoNs0nlt2FPsNvs7jpPipj69o+egVckvQjAyppirWO
+jO5hCLy7EahLz2wCn90z0Xf9lhOZni9meaV1Vy3CHHg6jwIB8/XlRaHFrOGMGXg
h8eQqsmpk9/3o8pv00yj6Hkq+swVg7Rg9FZaUiOv/HO/J7stWU7qPbI=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions iot/http_example/resources/rsa_private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+MAcR7hMmHW4s
Cog/Ml2O72KXMoHjkOP2XRIN8AgdjrmHGhUXArqi3EyzJ7s3XC/stxwY1pK0Vuuf
HINzRvd1Y9IsEq4GurtuAhgTWFfofDAb8Gg8ZPrrm53eTP0Njsi9SRojMUNW5Uf+
9R6+YYamkGdvqjhepLn9Zvay1LTFCcDiqfz4zw5suueGRrBVhUmZsnkaTc5hlPii
YNKPkH/rJu+WvIEGfALK6r3ltEv/KPswIw9EpD3HdNUAZmM0IY24vyxhiE6822gd
5XfbpiQSHF352D2IrCX8ErE/4xcIl4a4acTTWiGipU85UCLeZfG0rB18yQW7iIOS
W/0siBKZAgMBAAECggEAfwLmBdRfl2m6JNFX0hSZpJY72kuRsN8XTnUzVHmDgfHJ
9u61POvGpnLHCjIzdjIrk0NqETBjQup1aooJQ1gWdKAYQPSsobPc7geZ+nlaI9mj
61Su1/58EBKZ6Faz/HTpnHeQbAY/OW3fmeYrBOtumBgB6/HauWH7D77Oa/lfS+Ij
4f6OVAxevsi6PUtNmNtBwk5S0lZl9SFcKeHurVindquX9vWZjBEEFtNXazJttIJS
z9KX29VYwoLfflIKaUKckn8X+wYc+3u3BvH8zJpd60yQ6MSo7Sb1XkxT9549m+JW
Cb+i1K7MC/yQo4mvDtAQIVBh8p8qpd4VjpBwMuUbgQKBgQDexuAaLO3adSYFXGwW
nom6Mz/ImYcpxYo0ouAR1talbmF5/oKl9Tcwh7l1eDHfe70gfeP+g4uwAcc1hx3a
ZtXusrJFBktFezlFQnZXaE5ppryrFWeu0he0RYLAVxnL6IlP9dYQhVsTZm+7uX5d
UP7aZtmOU9ZTEsAoqvjJQXvaCQKBgQDajPebXOxIUj8ffGTeiPZczTwXux04caDC
eFKSCbAlHWgG7mR4P3fQONfEGWNHF0CxBSrew9CHmKdPyiISaExCfUaUWDDCPQCp
UE5VAHPdjSlb4lqi+cyNVlJxBJGONtyYkbQNd6N9GHMnBS8jZi7zf8VzIXpeExA4
n79Aml/YEQKBgDFrGId19AWD+z0xNWEHJjJB8CJFvHANvAzVHLOYXuEvzTvMs5qw
/N8tHHzsftO+lUPB6XOqJrCSlGhRYtPx//8FcPpS3Ru6rAerKKlXIB3buPqSsv9a
55s72DdmmvhayysLs8LSclOpY5vXGCsHLqGwMw6Zlm+zNyFOXAX5GspRAoGAaJMx
W68ABK8OM0OzhGQm9kriKTzIg5yjXspyQBzQo0HJ6B8kBgHgk8rPO68mOPsgYlPl
qogp/OgHjv9ahFJRwzLslckJM7g628loYfYAew+zrZrG4dsDjNG0Sw3zlAgeUAbQ
D+2iVhZf61josFiRuMP3t9paEi+vAFk4C3KSz/ECgYBpi1akpIzsYehW5uOL7Jhw
Hay5eshQ4vmHYuhDnn3gtT3h6J7TMwWs9pOygBG1I1b7GJ+tp4BZWJ2PmI7P8s45
jdI99WODHwv03lAzjLwigoqDUDduaYqXcGghcGht5Sknkl2uYDChwLtI5JdBZ9/x
8h9dE9oAiH/KTzhPmK1E1Q==
-----END PRIVATE KEY-----
118 changes: 118 additions & 0 deletions iot/http_example/system-test/cloudiot_http_example_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* Copyright 2017, Google, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const path = require(`path`);
const PubSub = require(`@google-cloud/pubsub`);
const test = require(`ava`);
const tools = require(`@google-cloud/nodejs-repo-tools`);
const uuid = require(`uuid`);

const deviceId = `test-node-device`;
const topicName = `nodejs-docs-samples-test-iot-${uuid.v4()}`;
const registryName = `nodejs-test-registry-iot-${uuid.v4()}`;
const helper = `node ../manager/manager.js`;
const cmd = `node cloudiot_http_example.js --registry_id="${registryName}" --device_id="${deviceId}" `;
const cwd = path.join(__dirname, `..`);

test.before(tools.checkCredentials);
test.before(async () => {
const pubsub = PubSub();
return pubsub.createTopic(topicName)
.then((results) => {
const topic = results[0];
console.log(`Topic ${topic.name} created.`);
return topic;
});
});

test.after.always(async () => {
const pubsub = PubSub();
const topic = pubsub.topic(topicName);
return topic.delete()
.then(() => {
console.log(`Topic ${topic.name} deleted.`);
});
});

test(`should receive configuration message`, async (t) => {
const localDevice = `test-rsa-device`;
const localRegName = `${registryName}-rsa256`;
let output = await tools.runAsync(`${helper} setupIotTopic ${topicName}`, cwd);
output = await tools.runAsync(
`${helper} createRegistry ${localRegName} ${topicName}`, cwd);
output = await tools.runAsync(
`${helper} createRsa256Device ${localDevice} ${localRegName} resources/rsa_cert.pem`, cwd);
t.regex(output, new RegExp(`Created device`));

output = await tools.runAsync(
`${cmd} --message_type=events --num_messages=1 --private_key_file=resources/rsa_private.pem --algorithm=RS256`, cwd);

t.regex(output, new RegExp(`Getting config`));
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: can this be t.regex(output, /Getting config/)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


// Check / cleanup
output = await tools.runAsync(
`${helper} getDeviceState ${localDevice} ${localRegName}`, cwd);
t.regex(output, new RegExp(`State`));
output = await tools.runAsync(
`${helper} deleteDevice ${localDevice} ${localRegName}`, cwd);
t.regex(output, new RegExp(`Successfully deleted device`));
output = await tools.runAsync(`${helper} deleteRegistry ${localRegName}`, cwd);
});

test(`should send event message`, async (t) => {
const localDevice = `test-rsa-device`;
const localRegName = `${registryName}-rsa256`;
let output = await tools.runAsync(`${helper} setupIotTopic ${topicName}`, cwd);
output = await tools.runAsync(
`${helper} createRegistry ${localRegName} ${topicName}`, cwd);
output = await tools.runAsync(
`${helper} createRsa256Device ${localDevice} ${localRegName} resources/rsa_cert.pem`, cwd);

output = await tools.runAsync(
`${cmd} --message_type=events --num_messages=1 --private_key_file=resources/rsa_private.pem --algorithm=RS256`, cwd);

t.regex(output, new RegExp(`Publishing message`));

// Check / cleanup
output = await tools.runAsync(
`${helper} getDeviceState ${localDevice} ${localRegName}`, cwd);
output = await tools.runAsync(
`${helper} deleteDevice ${localDevice} ${localRegName}`, cwd);
output = await tools.runAsync(`${helper} deleteRegistry ${localRegName}`, cwd);
});

test(`should send event message`, async (t) => {
const localDevice = `test-rsa-device`;
const localRegName = `${registryName}-rsa256`;
let output = await tools.runAsync(`${helper} setupIotTopic ${topicName}`, cwd);
output = await tools.runAsync(
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the output = part required if you're not planning to use the output?

If not, please fix this throughout your PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

`${helper} createRegistry ${localRegName} ${topicName}`, cwd);
output = await tools.runAsync(
`${helper} createRsa256Device ${localDevice} ${localRegName} resources/rsa_cert.pem`, cwd);

output = await tools.runAsync(
`${cmd} --message_type=state --num_messages=1 --private_key_file=resources/rsa_private.pem --algorithm=RS256`, cwd);

t.regex(output, new RegExp(`Publishing message`));

// Check / cleanup
output = await tools.runAsync(
`${helper} getDeviceState ${localDevice} ${localRegName}`, cwd);
output = await tools.runAsync(
`${helper} deleteDevice ${localDevice} ${localRegName}`, cwd);
output = await tools.runAsync(`${helper} deleteRegistry ${localRegName}`, cwd);
});