From c7c3688e389ddebb1676e873663be5086474bf44 Mon Sep 17 00:00:00 2001 From: Silvano Luciani Date: Thu, 24 Jul 2014 11:54:48 -0700 Subject: [PATCH 1/2] Adding regression tests. * Coverage for datastore. --- package.json | 1 + regression/datastore.js | 403 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 404 insertions(+) create mode 100644 regression/datastore.js diff --git a/package.json b/package.json index 0d39d93b504..ddb8061dbef 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "scripts": { "test": "node_modules/mocha/bin/_mocha --reporter spec", + "regression-test": "node_modules/mocha/bin/_mocha --reporter spec --timeout 4000 regression/*", "cover": "node_modules/istanbul/lib/cli.js cover node_modules/mocha/bin/_mocha" }, "license": "Apache 2" diff --git a/regression/datastore.js b/regression/datastore.js new file mode 100644 index 00000000000..e6af6530a13 --- /dev/null +++ b/regression/datastore.js @@ -0,0 +1,403 @@ +/** + * Copyright 2014 Google Inc. All Rights Reserved. + * + * 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. + */ + +if (!process.env.GCLOUD_TESTS_PROJECT_ID && + !process.env.GCLOUD_TESTS_SERVICE_ACCOUNT && + !process.env.GCLOUD_TESTS_PEM_KEY) { + var error = ['To run the regression tests, you need to set the value of some environment variables.', + 'Please check the README for instructions.' + ].join('\n'); + throw error; +} +var projectId = process.env.GCLOUD_TESTS_PROJECT_ID, + email = process.env.GCLOUD_TESTS_SERVICE_ACCOUNT, + pemFilePath = process.env.GCLOUD_TESTS_PEM_KEY; + +var assert = require('assert'), + datastore = require('../lib/datastore'), + ds = new datastore.Dataset({ + projectId: projectId, + email: email, + pemFilePath: pemFilePath + }); + +describe('datastore', function() { + + describe.only('create, retrieve and delete using the datastore service', function() { + + it('should save/get/delete with a key name', function(done) { + var post = { + title: "How to make the perfect pizza in your grill", + tags: ['pizza', 'grill'], + publishedAt: Date("2001-01-01T00:00:00.000Z"), + author: "Silvano", + isDraft: false, + wordCount: 400, + rating: 5.0, + }; + var postKeyName = 'post1'; + + ds.save(['Post', postKeyName], post, function(err, key) { + if (err) return done(err); + assert.equal(key[1], postKeyName); + ds.get(['Post', postKeyName], function(err, key, obj) { + if (err) return done(err); + assert.deepEqual(obj, post); + ds.del(['Post', postKeyName], function(err) { + if (err) return done(err); + done(); + }); + }); + }); + }); + + it('should save/get/delete with a numeric key id', function(done) { + var post = { + title: "How to make the perfect pizza in your grill", + tags: ['pizza', 'grill'], + publishedAt: Date("2001-01-01T00:00:00.000Z"), + author: "Silvano", + isDraft: false, + wordCount: 400, + rating: 5.0, + }; + var postKeyId = '123456789'; + + ds.save(['Post', postKeyId], post, function(err, key) { + if (err) return done(err); + assert.equal(key[1], postKeyId); + ds.get(['Post', postKeyId], function(err, key, obj) { + if (err) return done(err); + assert.deepEqual(obj, post); + ds.del(['Post', postKeyId], function(err) { + if (err) return done(err); + done(); + }); + }); + }); + }); + + it('should save/get/delete with an automatically generated key id', function(done) { + var post = { + title: "How to make the perfect pizza in your grill", + tags: ['pizza', 'grill'], + publishedAt: Date("2001-01-01T00:00:00.000Z"), + author: "Silvano", + isDraft: false, + wordCount: 400, + rating: 5.0, + }; + ds.save(['Post', null], post, function(err, key) { + if (err) return done(err); + assert(key[1]); + var assignedId = key[1]; + ds.get(['Post', assignedId], function(err, key, obj) { + if (err) return done(err); + assert.deepEqual(obj, post); + ds.del(['Post', assignedId], function(err) { + if (err) return done(err); + done(); + }); + }); + }); + }); + + it('should save/get/delete multiple entities at once', function(done) { + var post1 = { + title: "How to make the perfect pizza in your grill", + tags: ['pizza', 'grill'], + publishedAt: Date("2001-01-01T00:00:00.000Z"), + author: "Silvano", + isDraft: false, + wordCount: 400, + rating: 5.0, + }; + var post2 = { + title: "How to make the perfect homemade pasta", + tags: ['pasta', 'homemade'], + publishedAt: Date("2001-01-01T00:00:00.000Z"), + author: "Silvano", + isDraft: false, + wordCount: 450, + rating: 4.5, + }; + var key = ['Post', null], + saveAllAssignedIds = [], + saveAllMap = {}; + ds.saveAll([key, key], [post1, post2], function(err, keys) { + if (err) return done(err); + assert(keys[0][1]); + saveAllAssignedIds.push(keys[0][1]) + saveAllMap[keys[0][1]] = post1; + assert(keys[1][1]); + saveAllAssignedIds.push(keys[1][1]) + saveAllMap[keys[1][1]] = post2; + var firstKey = ['Post', saveAllAssignedIds[0]], + secondKey = ['Post', saveAllAssignedIds[1]]; + ds.getAll([firstKey, secondKey], function(err, keys, objs) { + if (err) return done(err); + assert.deepEqual(objs[0], saveAllMap[keys[0][1]]); + assert.deepEqual(objs[1], saveAllMap[keys[1][1]]); + ds.delAll([firstKey, secondKey], function(err) { + if (err) return done(err); + done(); + }); + }); + }) + }); + + }); + + describe('querying the datastore', function() { + + var keys = [ + ['Character', 'Rickard'], + ['Character', 'Rickard', 'Character', 'Eddard'], + ['Character', 'Catelyn'], + ['Character', 'Eddard', 'Character', 'Arya'], + ['Character', 'Eddard', 'Character', 'Sansa'], + ['Character', 'Eddard', 'Character', 'Robb'], + ['Character', 'Eddard', 'Character', 'Bran'], + ['Character', 'Eddard', 'Character', 'Jon Snow'] + ]; + + var characters = [{ + name: 'Rickard', + family: 'Stark', + appearances: 0, + alive: false + }, { + name: 'Eddard', + family: 'Stark', + appearances: 9, + alive: false + }, { + name: 'Catelyn', + family: ['Stark', 'Tully'], + appearances: 26, + alive: false + }, { + name: 'Arya', + family: 'Stark', + appearances: 33, + alive: true + }, { + name: 'Sansa', + family: 'Stark', + appearances: 31, + alive: true + }, { + name: 'Robb', + family: 'Stark', + appearances: 22, + alive: false + }, { + name: 'Bran', + family: 'Stark', + appearances: 25, + alive: true + }, { + name: 'Jon Snow', + family: 'Stark', + appearances: 32, + alive: true + }]; + + before(function(done) { + + ds.saveAll(keys, characters, function(err, keys) { + if (err) return done(err); + done(); + }); + + }); + + it('should limit queries', function(done) { + var q = ds.createQuery('Character').limit(5); + ds.runQuery(q, function(err, keys, objs, secondQuery) { + if (err) return done(err); + assert.equal(objs.length, 5); + assert(secondQuery); + ds.runQuery(secondQuery, function(err, keys, objs, thirdQuery) { + if (err) return done(err); + assert.equal(objs.length, 3); + // TODO(silvano): it currently requires an additional request that brings + // an empty page and a null query + //assert.equal(thirdQuery, null) + ds.runQuery(thirdQuery, function(err, keys, objs, fourthQuery) { + if (err) return done(err); + assert.equal(fourthQuery, null); + done(); + }); + }); + }); + }); + + it('should filter queries with simple indexes', function(done) { + var q = ds.createQuery('Character') + .filter('appearances >=', 20); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.equal(objs.length, 6); + done(); + }); + }); + + it('should filter queries with defined indexes', function(done) { + var q = ds.createQuery('Character') + .filter('family =', 'Stark') + .filter('appearances >=', 20); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.equal(objs.length, 6); + done(); + }); + }); + + it('should filter by ancestor', function(done) { + var q = ds.createQuery('Character').hasAncestor(['Character', 'Eddard']); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.equal(objs.length, 5); + done(); + }); + }); + + it('should order queries', function(done) { + var q = ds.createQuery('Character').order('+appearances'); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.equal(objs[0].name, characters[0].name); + assert.equal(objs[7].name, characters[3].name); + done(); + }); + }); + + it('should select projections', function(done) { + var q = ds.createQuery('Character') + .select(['name', 'family']); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.deepEqual(objs[0], { + name: 'Arya', + family: 'Stark' + }); + assert.deepEqual(objs[8], { + name: 'Sansa', + family: 'Stark' + }); + done(); + }); + }); + + it('should paginate with offset and limit', function(done) { + var q = ds.createQuery('Character') + .offset(2) + .limit(3) + .order('+appearances'); + ds.runQuery(q, function(err, keys, objs, secondQuery) { + if (err) return done(err); + assert.equal(objs.length, 3); + assert.equal(objs[0].name, 'Robb'); + assert.equal(objs[2].name, 'Catelyn'); + ds.runQuery(secondQuery, function(err, keys, objs, thirdQuery) { + assert.equal(objs.length, 3); + assert.equal(objs[0].name, 'Sansa'); + assert.equal(objs[2].name, 'Arya'); + done(); + }); + }); + }); + + it('should resume from a start cursor', function(done) { + var q = ds.createQuery('Character') + .offset(2) + .limit(2) + .order('+appearances'); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + var startCursor = nextQuery.startVal; + var cursorQuery = ds.createQuery('Character') + .order('+appearances') + .start(startCursor); + ds.runQuery(cursorQuery, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.equal(objs.length, 4); + assert.equal(objs[0].name, 'Catelyn'); + assert.equal(objs[3].name, 'Arya'); + done(); + }); + }); + }); + + it('should group queries', function(done) { + var q = ds.createQuery('Character') + .groupBy('alive'); + ds.runQuery(q, function(err, keys, objs, nextQuery) { + if (err) return done(err); + assert.equal(objs.length, 2); + done(); + }); + }) + + after(function(done) { + + ds.delAll(keys, function(err) { + if (err) return done(err); + done(); + }); + + }); + + }); + + describe('transactions', function() { + + it('should run in a transaction', function(done) { + var key = ['Company', 'Google'], + obj = { + 'url': 'www.google.com' + }; + ds.runInTransaction(function(t, tDone) { + ds.get(key, function(err, keyRes, objRes) { + if (err) return done(err); + if (objRes) { + tDone(); + return; + } else { + ds.save(key, obj, function(err, keyRes) { + if (err) console.log(err); + tDone(); + return; + }); + } + }); + }, function(err) { + if (err) throw (err); + ds.get(key, function(err, keyRes, objRes) { + if (err) return done(err); + assert.deepEqual(objRes, obj); + ds.del(keyRes, function(err) { + if (err) return done(err); + done(); + }) + }); + }); + }); + + }); + +}); From e7225a3ea9a72687df43520b5a233d6338ebe6ea Mon Sep 17 00:00:00 2001 From: Silvano Luciani Date: Thu, 24 Jul 2014 14:16:38 -0700 Subject: [PATCH 2/2] Simplified test for multiple entities --- regression/datastore.js | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/regression/datastore.js b/regression/datastore.js index e6af6530a13..6ec90b84dd5 100644 --- a/regression/datastore.js +++ b/regression/datastore.js @@ -36,7 +36,7 @@ var assert = require('assert'), describe('datastore', function() { - describe.only('create, retrieve and delete using the datastore service', function() { + describe('create, retrieve and delete using the datastore service', function() { it('should save/get/delete with a key name', function(done) { var post = { @@ -134,23 +134,16 @@ describe('datastore', function() { wordCount: 450, rating: 4.5, }; - var key = ['Post', null], - saveAllAssignedIds = [], - saveAllMap = {}; + var key = ['Post', null]; ds.saveAll([key, key], [post1, post2], function(err, keys) { if (err) return done(err); - assert(keys[0][1]); - saveAllAssignedIds.push(keys[0][1]) - saveAllMap[keys[0][1]] = post1; - assert(keys[1][1]); - saveAllAssignedIds.push(keys[1][1]) - saveAllMap[keys[1][1]] = post2; - var firstKey = ['Post', saveAllAssignedIds[0]], - secondKey = ['Post', saveAllAssignedIds[1]]; + assert.equal(keys.length,2); + var firstKey = ['Post', keys[0][1]], + secondKey = ['Post', keys[1][1]]; ds.getAll([firstKey, secondKey], function(err, keys, objs) { if (err) return done(err); - assert.deepEqual(objs[0], saveAllMap[keys[0][1]]); - assert.deepEqual(objs[1], saveAllMap[keys[1][1]]); + assert.deepEqual(objs[0], post1); + assert.deepEqual(objs[1], post2); ds.delAll([firstKey, secondKey], function(err) { if (err) return done(err); done();