Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 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
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ functions @ace-n @grant
run @GoogleCloudPlatform/cdpe-cbr-containers

# Other functions samples
functions/bigtable @billyjacobson
functions/composer-storage-trigger @leahecole
functions/scheduleinstance @djmailhot
functions/speech-to-speech @ricalo
Expand Down
1 change: 1 addition & 0 deletions functions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ environment.
* [Hello World](helloworld/)
* [Background](background/)
* [Callbacks](messages/)
* [Cloud Bigtable](bigtable/)
* [Cloud Pub/Sub](pubsub/)
* [Cloud Spanner](spanner/)
* [Dependencies](uuid/)
Expand Down
67 changes: 67 additions & 0 deletions functions/bigtable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2020 Google LLC
//
// 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';

// [START bigtable_functions_quickstart]
// Imports the Google Cloud client library
const {Bigtable} = require('@google-cloud/bigtable');

// Instantiates a client
const bigtable = new Bigtable();

// Your Cloud Bigtable instance ID
const instanceId = 'your-instance';

// Your Cloud Bigtable table ID
const tableId = 'mobile-time-series';

/**
* HTTP Cloud Function.
*
* @param {Object} req Cloud Function request context.
* @param {Object} res Cloud Function response context.
*/
exports.get = async (req, res) => {
// Gets a reference to a Cloud Bigtable instance and database
const instance = bigtable.instance(instanceId);
const table = instance.table(tableId);

// Execute the query
try {
const prefix = 'phone#';
let rows = [];
await table
.createReadStream({
prefix,
})
.on('error', err => {
res.send(`Error querying Bigtable: ${err}`);
res.status(500).end();
})
.on('data', row => {
rows.push(
`rowkey: ${row.id}, ` +
`os_build: ${row.data["stats_summary"]["os_build"][0].value}\n`
)
}).on('end', () => {
rows.forEach(r => res.write(r));
res.status(200).end();
});
} catch (err) {
res.send(`Error querying Bigtable: ${err}`);
res.status(500).end();
}
};
// [END bigtable_functions_quickstart]
31 changes: 31 additions & 0 deletions functions/bigtable/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "nodejs-docs-samples-functions-bigtable",
"version": "0.0.1",
"private": true,
"license": "Apache-2.0",
"author": "Google Inc.",
"repository": {
"type": "git",
"url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
},
"engines": {
"node": ">=8.0.0"
},
"scripts": {
"test": "mocha test/*.test.js --timeout=20000",
"start": "functions-framework --target=get"
},
"dependencies": {
"@google-cloud/bigtable": "^2.3.2",
"@google-cloud/functions-framework": "^1.5.1"
},
"devDependencies": {
"mocha": "^7.0.0",
"proxyquire": "^2.1.0",
"sinon": "^9.0.0"
},
"cloud-repo-tools": {
"requiresKeyFile": true,
"requiresProjectId": true
}
}
109 changes: 109 additions & 0 deletions functions/bigtable/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2020 Google LLC
//
// 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 proxyquire = require('proxyquire').noCallThru();
const sinon = require('sinon');
const assert = require('assert');
const {PassThrough} = require('stream');

let mockedStream;
const rows = [
{
id: "phone#4c410523#20190501",
data: {
stats_summary: {
os_build: [{
value: "PQ2A.190405.003"
}]
}
},
},
{
id: "phone#5c10102#20190501",
data: {
stats_summary: {
os_build: [{
value: "PQ2A.190406.000"
}]
}
},
},
];

const query = {
prefix: "phone#"
};

const getSample = () => {
mockedStream = require('stream').Readable.from(rows);

const tableMock = {
createReadStream: sinon.stub().returns(mockedStream),
};
const instanceMock = {
table: sinon.stub().returns(tableMock),
};
const bigtableMock = {
instance: sinon.stub().returns(instanceMock),
};

const BigtableMock = sinon.stub().returns(bigtableMock);

return {
program: proxyquire('../', {
'@google-cloud/bigtable': {Bigtable: BigtableMock},
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth testing this directly instead of using a mocked client library?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't have a strong opinion about this, I'm just following what every other sample has done.

}),
mocks: {
bigtable: bigtableMock,
table: tableMock,
instance: instanceMock,
res: {
status: sinon.stub().returnsThis(),
send: sinon.stub().returnsThis(),
end: sinon.stub().returnsThis(),
write: sinon.stub().returnsThis(),
},
},
};
};

describe('bigtable_functions_quickstart', () => {
it('get: Gets rows', async () => {
const sample = getSample();
const {mocks} = sample;
await sample.program.get(mocks.req, mocks.res);
rows.forEach((row) => {
mockedStream.emit('data', row);
});
mockedStream.emit("end");
assert.strictEqual(mocks.bigtable.instance.called, true);
assert.strictEqual(mocks.instance.table.called, true);
assert.strictEqual(mocks.table.createReadStream.calledWith(query), true);
assert.strictEqual(
mocks.res.write.calledWith(
'rowkey: phone#4c410523#20190501, os_build: PQ2A.190405.003\n'
),
true
);
assert.strictEqual(
mocks.res.write.calledWith(
'rowkey: phone#5c10102#20190501, os_build: PQ2A.190406.000\n'
),
true
);
assert.strictEqual(mocks.res.end.called, true);
});
});