diff --git a/lib/search/document.js b/lib/search/document.js index 29aea20e398..9abdc731d64 100644 --- a/lib/search/document.js +++ b/lib/search/document.js @@ -21,6 +21,7 @@ 'use strict'; var is = require('is'); +var nodeutil = require('util'); /** * @type {module:search/field} @@ -28,6 +29,12 @@ var is = require('is'); */ var Field = require('./field.js'); +/** + * @type {module:common/serviceObject} + * @private + */ +var ServiceObject = require('../common/service-object.js'); + /** * @type {module:common/util} * @private @@ -52,13 +59,59 @@ var util = require('../common/util.js'); * var document = search.index('records').document('stephen'); */ function Document(index, id) { - this.search_ = index.search_; - this.index_ = index; + var methods = { + /** + * Delete this document. + * + * @resource [Documents: delete API Documentation]{@link https://cloud.google.com/search/reference/rest/v1/projects/indexes/documents/delete} + * + * @param {function=} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * document.delete(function(err, apiResponse) {}); + */ + delete: true, + + /** + * Check if the document exists. + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this + * request. + * @param {boolean} callback.exists - Whether the zone exists or not. + * + * @example + * document.exists(function(err, exists) {}); + */ + exists: true, + + /** + * Get a document if it exists. + * + * @example + * document.get(function(err, document, apiResponse) { + * // `document.fields` has been populated. + * }); + */ + get: true + }; + + ServiceObject.call(this, { + parent: index, + baseUrl: '/documents', + id: id, + methods: methods + }); this.id = id; this.fields = {}; } +nodeutil.inherits(Document, ServiceObject); + /** * Add a field to this document. * @@ -82,21 +135,17 @@ Document.prototype.addField = function(name) { }; /** - * Delete this document. - * - * @resource [Documents: delete API Documentation]{@link https://cloud.google.com/search/reference/rest/v1/projects/indexes/documents/delete} - * - * @param {function=} callback - The callback function. - * @param {?error} callback.err - An error returned while making this request - * @param {object} callback.apiResponse - The full API response. + * Create a document. * * @example - * document.delete(function(err, apiResponse) {}); + * document.create(function(err, document, apiResponse) { + * if (!err) { + * // The document was created successfully. + * } + * }); */ -Document.prototype.delete = function(callback) { - this.makeReq_('DELETE', '', null, null, function(err, resp) { - (callback || util.noop)(err, resp); - }); +Document.prototype.create = function(callback) { + this.parent.createDocument(this, callback); }; /** @@ -129,7 +178,7 @@ Document.prototype.getMetadata = function(callback) { callback = callback || util.noop; - this.makeReq_('GET', '/', null, null, function(err, resp) { + ServiceObject.prototype.getMetadata.call(this, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -203,22 +252,4 @@ Document.prototype.toJSON = function() { return documentObject; }; -/** - * Make a new request object from the provided arguments and wrap the callback - * to intercept non-successful responses. - * - * @private - * - * @param {string} method - Action. - * @param {string} path - Request path. - * @param {*} query - Request query object. - * @param {*} body - Request body contents. - * @param {function} callback - The callback function. - */ -Document.prototype.makeReq_ = function(method, path, query, body, callback) { - path = '/documents/' + this.id + path; - - this.index_.makeReq_(method, path, query, body, callback); -}; - module.exports = Document; diff --git a/lib/search/index-class.js b/lib/search/index-class.js index 07db1bcf83a..c05af9a2516 100644 --- a/lib/search/index-class.js +++ b/lib/search/index-class.js @@ -20,8 +20,10 @@ 'use strict'; +var arrify = require('arrify'); var extend = require('extend'); var is = require('is'); +var nodeutil = require('util'); /** * @type {module:search/document} @@ -29,6 +31,12 @@ var is = require('is'); */ var Document = require('./document.js'); +/** + * @type {module:common/serviceObject} + * @private + */ +var ServiceObject = require('../common/service-object.js'); + /** * @type {module:common/streamrouter} * @private @@ -53,14 +61,20 @@ var streamRouter = require('../common/stream-router.js'); * var index = search.index('records'); */ function Index(search, id) { - this.search_ = search; - this.id = id; + ServiceObject.call(this, { + parent: search, + baseUrl: '/indexes', + id: id, + methods: { + // Nothing needed other than the `request` method. + } + }); - if (!this.id) { - throw new Error('An ID is needed to access a Google Cloud Search index.'); - } + this.id = id; } +nodeutil.inherits(Index, ServiceObject); + /** * Create a document in the index. * @@ -121,7 +135,11 @@ Index.prototype.createDocument = function(documentObj, callback) { document = this.documentFromObject_(documentObj); } - this.makeReq_('POST', '/documents', null, documentObj, function(err, resp) { + this.request({ + method: 'POST', + uri: '/documents', + json: documentObj + }, function(err, resp) { if (err) { callback(err, null, resp); return; @@ -139,8 +157,29 @@ Index.prototype.createDocument = function(documentObj, callback) { * * @example * var myDocument = index.document('my-document'); + * + * //- + * // Documents can also be created from objects. + * //- + * var myDocument = index.document({ + * docId: 'my-document', + * fields: { + * person: { + * values: [ + * { + * stringFormat: 'TEXT', + * stringValue: 'Stephen' + * } + * ] + * } + * } + * }); */ Index.prototype.document = function(id) { + if (is.object(id)) { + return this.documentFromObject_(id); + } + return new Document(this, id); }; @@ -222,7 +261,10 @@ Index.prototype.getDocuments = function(query, callback) { query = {}; } - this.makeReq_('GET', '/documents', query, null, function(err, resp) { + this.request({ + uri: '/documents', + qs: query + }, function(err, resp) { if (err) { callback(err, null, null, resp); return; @@ -236,7 +278,7 @@ Index.prototype.getDocuments = function(query, callback) { }); } - var documents = (resp.documents || []) + var documents = arrify(resp.documents) .map(self.documentFromObject_.bind(self)); callback(null, documents, nextQuery, resp); @@ -322,7 +364,10 @@ Index.prototype.search = function(query, callback) { throw new Error('A query must be either a string or object.'); } - this.makeReq_('GET', '/search', query, null, function(err, resp) { + this.request({ + uri: '/search', + qs: query + }, function(err, resp) { if (err) { callback(err, null, null, resp); return; @@ -336,7 +381,7 @@ Index.prototype.search = function(query, callback) { }); } - var documents = (resp.results || []) + var documents = arrify(resp.results) .map(self.documentFromObject_.bind(self)); callback(null, documents, nextQuery, resp); @@ -385,24 +430,6 @@ Index.prototype.documentFromObject_ = function(documentObj) { return document; }; -/** - * Make a new request object from the provided arguments and wrap the callback - * to intercept non-successful responses. - * - * @private - * - * @param {string} method - Action. - * @param {string} path - Request path. - * @param {*} query - Request query object. - * @param {*} body - Request body contents. - * @param {function} callback - The callback function. - */ -Index.prototype.makeReq_ = function(method, path, query, body, callback) { - path = '/indexes/' + this.id + path; - - this.search_.makeReq_(method, path, query, body, callback); -}; - /*! Developer Documentation * * {module:search/index#getDocuments} and {module:search/index#search} can be diff --git a/lib/search/index.js b/lib/search/index.js index 20ea50212eb..358b0402aaa 100644 --- a/lib/search/index.js +++ b/lib/search/index.js @@ -21,8 +21,8 @@ 'use strict'; var extend = require('extend'); -var format = require('string-format-obj'); var is = require('is'); +var nodeutil = require('util'); /** * @type {module:search/index} @@ -31,32 +31,22 @@ var is = require('is'); var Index = require('./index-class.js'); /** - * @type {module:common/streamrouter} - * @private - */ -var streamRouter = require('../common/stream-router.js'); - -/** - * @type {module:common/util} + * @type {module:common/service} * @private */ -var util = require('../common/util.js'); +var Service = require('../common/service.js'); /** - * @const {array} Required scopes for the Search API. + * @type {module:common/streamrouter} * @private */ -var SCOPES = [ - 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/cloudsearch', - 'https://www.googleapis.com/auth/userinfo.email' -]; +var streamRouter = require('../common/stream-router.js'); /** - * @const {string} Base URL for the Search API. + * @type {module:common/util} * @private */ -var SEARCH_BASE_URL = 'https://cloudsearch.googleapis.com/v1/'; +var util = require('../common/util.js'); /** * Create a Search object to Interact with the Cloud Search API. Using this @@ -85,16 +75,20 @@ function Search(options) { return new Search(options); } - this.makeAuthenticatedRequest_ = util.makeAuthenticatedRequestFactory({ - credentials: options.credentials, - email: options.email, - keyFile: options.keyFilename, - scopes: SCOPES - }); + var config = { + baseUrl: 'https://cloudsearch.googleapis.com/v1', + scopes: [ + 'https://www.googleapis.com/auth/cloud-platform', + 'https://www.googleapis.com/auth/cloudsearch', + 'https://www.googleapis.com/auth/userinfo.email' + ] + }; - this.projectId_ = options.projectId; + Service.call(this, config, options); } +nodeutil.inherits(Search, Service); + /** * Get {module:search/index} objects for all of the indexes in your project. * @@ -180,7 +174,10 @@ Search.prototype.getIndexes = function(query, callback) { delete query.prefix; } - this.makeReq_('GET', '/indexes', query, null, function(err, resp) { + this.request({ + uri: '/indexes', + qs: query + }, function(err, resp) { if (err) { callback(err, null, null, resp); return; @@ -215,37 +212,11 @@ Search.prototype.getIndexes = function(query, callback) { * @return {module:search/index} */ Search.prototype.index = function(id) { - return new Index(this, id); -}; - -/** - * Make a new request object from the provided arguments and wrap the callback - * to intercept non-successful responses. - * - * @private - * - * @param {string} method - Action. - * @param {string} path - Request path. - * @param {*} query - Request query object. - * @param {*} body - Request body contents. - * @param {function} callback - The callback function. - */ -Search.prototype.makeReq_ = function(method, path, query, body, callback) { - var reqOpts = { - method: method, - qs: query, - uri: format('{base}projects/{projectId}{path}', { - base: SEARCH_BASE_URL, - projectId: this.projectId_, - path: path - }) - }; - - if (body) { - reqOpts.json = body; + if (!id) { + throw new Error('An ID is needed to access a Google Cloud Search index.'); } - this.makeAuthenticatedRequest_(reqOpts, callback); + return new Index(this, id); }; /*! Developer Documentation diff --git a/system-test/search.js b/system-test/search.js index 74fa42731d8..7a2035f113a 100644 --- a/system-test/search.js +++ b/system-test/search.js @@ -65,7 +65,9 @@ describe('Search', function() { var newIndexName = generateIndexName(); var newIndex = search.index(newIndexName); - newIndex.createDocument(TEST_DOCUMENT_JSON, function(err, document) { + var document = newIndex.document(TEST_DOCUMENT_JSON); + + document.create(function(err) { assert.ifError(err); document.delete(done); }); @@ -80,7 +82,9 @@ describe('Search', function() { var newIndexName = generateIndexName(); var newIndex = search.index(newIndexName); - newIndex.createDocument(TEST_DOCUMENT_JSON, function(err, document) { + var document = newIndex.document(TEST_DOCUMENT_JSON); + + document.create(function(err) { if (err) { done(err); return; @@ -114,18 +118,10 @@ describe('Search', function() { }); describe('listing documents', function() { - var document; + var document = index.document(TEST_DOCUMENT_JSON); before(function(done) { - index.createDocument(TEST_DOCUMENT_JSON, function(err, doc) { - if (err) { - done(err); - return; - } - - document = doc; - done(); - }); + document.create(done); }); after(function(done) { @@ -186,25 +182,31 @@ describe('Search', function() { }); }); - index.createDocument(newDocument, function(err, document) { + newDocument.create(function(err) { assert.ifError(err); - document.getMetadata(function(err) { + + newDocument.getMetadata(function(err) { assert.ifError(err); - assert.deepEqual(document.toJSON(), TEST_DOCUMENT_JSON); - document.delete(done); + assert.deepEqual(newDocument.toJSON(), TEST_DOCUMENT_JSON); + + newDocument.delete(done); }); }); }); it('should create a document from JSON', function(done) { - index.createDocument(TEST_DOCUMENT_JSON, function(err, document) { + var newDocument = index.document(TEST_DOCUMENT_JSON); + + newDocument.create(function(err) { assert.ifError(err); - document.getMetadata(function(err) { + + newDocument.getMetadata(function(err) { assert.ifError(err); - assert.deepEqual(document.toJSON(), TEST_DOCUMENT_JSON); - document.delete(done); + assert.deepEqual(newDocument.toJSON(), TEST_DOCUMENT_JSON); + + newDocument.delete(done); }); }); }); @@ -213,16 +215,15 @@ describe('Search', function() { describe('search', function() { var query = 'ryan'; var DOCUMENT_NAME = generateDocumentName(); - var document; + var document = index.document(DOCUMENT_NAME); before(function(done) { - document = index.document(DOCUMENT_NAME); - var questions = document.addField('question'); + questions.addTextValue('Where did Ryan go?'); questions.addTextValue('Where did Silvano go?'); - index.createDocument(document, done); + document.create(done); }); after(function(done) { diff --git a/test/search/document.js b/test/search/document.js index c5c937e24c8..7ef166dc79f 100644 --- a/test/search/document.js +++ b/test/search/document.js @@ -17,40 +17,70 @@ 'use strict'; var assert = require('assert'); +var mockery = require('mockery'); +var nodeutil = require('util'); -var Document = require('../../lib/search/document.js'); -var Field = require('../../lib/search/field.js'); +var ServiceObject = require('../../lib/common/service-object.js'); var DOCUMENT_JSON = require('../testdata/search-document.json'); +function FakeServiceObject() { + this.calledWith_ = arguments; + ServiceObject.apply(this, arguments); +} + +nodeutil.inherits(FakeServiceObject, ServiceObject); + describe('Document', function() { + var Document; var document; - var SEARCH_INSTANCE = { - projectId: 'project-id' - }; - - var INDEX_INSTANCE = { - search_: SEARCH_INSTANCE - }; + var INDEX_INSTANCE = {}; var ID = 'document-id'; + before(function() { + mockery.registerMock('../common/service-object.js', FakeServiceObject); + + mockery.enable({ + useCleanCache: true, + warnOnUnregistered: false + }); + + Document = require('../../lib/search/document.js'); + }); + + after(function() { + mockery.deregisterAll(); + mockery.disable(); + }); + beforeEach(function() { document = new Document(INDEX_INSTANCE, ID); }); describe('instantiation', function() { - it('should localize the Search instance', function() { - assert.deepEqual(document.search_, SEARCH_INSTANCE); + it('should localize the id', function() { + assert.equal(document.id, ID); }); - it('should localize the Index instance', function() { - assert.deepEqual(document.index_, INDEX_INSTANCE); + it('should create an empty fields object', function() { + assert.deepEqual(document.fields, {}); }); - it('should localize the id', function() { - assert.equal(document.id, ID); + it('should inherit from ServiceObject', function() { + assert(document instanceof ServiceObject); + + var calledWith = document.calledWith_[0]; + + assert.strictEqual(calledWith.parent, INDEX_INSTANCE); + assert.strictEqual(calledWith.baseUrl, '/documents'); + assert.strictEqual(calledWith.id, ID); + assert.deepEqual(calledWith.methods, { + delete: true, + exists: true, + get: true + }); }); }); @@ -66,7 +96,7 @@ describe('Document', function() { it('should return a Field instance', function() { var field = document.addField(FIELD_NAME); - assert(field instanceof Field); + assert.strictEqual(field.constructor.name, 'Field'); }); it('should localize the Field instance', function() { @@ -76,56 +106,21 @@ describe('Document', function() { }); }); - describe('delete', function() { - it('should delete the document', function(done) { - document.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'DELETE'); - assert.equal(path, ''); - assert.strictEqual(query, null); - assert.strictEqual(body, null); - done(); - }; - - document.delete(assert.ifError); - }); - - it('should pass an error if one occurred', function(done) { - var error = new Error('Error.'); - var apiResponse = { a: 'b', c: 'd' }; - - document.makeReq_ = function(method, path, query, body, callback) { - callback(error, apiResponse); - }; - - document.delete(function(err, apiResponse_) { - assert.deepEqual(err, error); - assert.deepEqual(apiResponse_, apiResponse); - done(); - }); - }); - - it('should pass the API response to the callback', function(done) { - var apiResponse = { a: 'b', c: 'd' }; - - document.makeReq_ = function(method, path, query, body, callback) { - callback(null, apiResponse); + describe('create', function() { + it('should call Index.createDocument', function(done) { + document.parent.createDocument = function(document_, callback) { + assert.strictEqual(document_, document); + callback(); }; - document.delete(function(err, apiResponse_) { - assert.ifError(err); - assert.deepEqual(apiResponse_, apiResponse); - done(); - }); + document.create(done); }); }); describe('getMetadata', function() { - it('should get the document from the API', function(done) { - document.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/'); - assert.strictEqual(query, null); - assert.strictEqual(body, null); + it('should call ServiceObject.delete', function(done) { + FakeServiceObject.prototype.getMetadata = function() { + assert.strictEqual(this, document); done(); }; @@ -136,7 +131,7 @@ describe('Document', function() { var error = new Error('Error.'); var apiResponse = { a: 'b', c: 'd' }; - document.makeReq_ = function(method, path, query, body, callback) { + FakeServiceObject.prototype.getMetadata = function(callback) { callback(error, apiResponse); }; @@ -148,7 +143,7 @@ describe('Document', function() { }); it('should reset the localized fields', function(done) { - document.makeReq_ = function(method, path, query, body, callback) { + FakeServiceObject.prototype.getMetadata = function(callback) { callback(null, {}); }; @@ -164,7 +159,7 @@ describe('Document', function() { }); it('should create and localize Field instances', function(done) { - document.makeReq_ = function(method, path, query, body, callback) { + FakeServiceObject.prototype.getMetadata = function(callback) { callback(null, DOCUMENT_JSON); }; @@ -194,7 +189,7 @@ describe('Document', function() { }); it('should reset the localized rank', function(done) { - document.makeReq_ = function(method, path, query, body, callback) { + FakeServiceObject.prototype.getMetadata = function(callback) { callback(null, {}); }; @@ -208,7 +203,7 @@ describe('Document', function() { }); it('should localize a new rank', function(done) { - document.makeReq_ = function(method, path, query, body, callback) { + FakeServiceObject.prototype.getMetadata = function(callback) { callback(null, DOCUMENT_JSON); }; @@ -220,7 +215,7 @@ describe('Document', function() { }); it('should execute the callback with Document & api resp', function(done) { - document.makeReq_ = function(method, path, query, body, callback) { + FakeServiceObject.prototype.getMetadata = function(callback) { callback(null, DOCUMENT_JSON); }; @@ -280,25 +275,4 @@ describe('Document', function() { assert.equal(documentJson.rank, 8); }); }); - - describe('makeReq_', function() { - it('should call index instance makeReq_', function(done) { - var method = 'POST'; - var path = '/'; - var query = 'query'; - var body = 'body'; - var callback = 'callback'; - - document.index_.makeReq_ = function(m, p, q, b, c) { - assert.equal(m, method); - assert.equal(p, '/documents/' + ID + path); - assert.equal(q, query); - assert.equal(b, body); - assert.equal(c, callback); - done(); - }; - - document.makeReq_(method, path, query, body, callback); - }); - }); }); diff --git a/test/search/index-class.js b/test/search/index-class.js index 0273e1d599f..aad0a7aa4d7 100644 --- a/test/search/index-class.js +++ b/test/search/index-class.js @@ -20,6 +20,9 @@ var arrify = require('arrify'); var assert = require('assert'); var extend = require('extend'); var mockery = require('mockery'); +var nodeutil = require('util'); + +var ServiceObject = require('../../lib/common/service-object.js'); var util = require('../../lib/common/util.js'); function FakeDocument() { @@ -27,6 +30,13 @@ function FakeDocument() { } FakeDocument.prototype.toJSON = util.noop; +function FakeServiceObject() { + this.calledWith_ = arguments; + ServiceObject.apply(this, arguments); +} + +nodeutil.inherits(FakeServiceObject, ServiceObject); + var extended = false; var fakeStreamRouter = { extend: function(Class, methods) { @@ -48,8 +58,10 @@ describe('Index', function() { var ID = 'index-id'; before(function() { - mockery.registerMock('./document.js', FakeDocument); + mockery.registerMock('../common/service-object.js', FakeServiceObject); mockery.registerMock('../common/stream-router.js', fakeStreamRouter); + mockery.registerMock('./document.js', FakeDocument); + mockery.enable({ useCleanCache: true, warnOnUnregistered: false @@ -72,24 +84,21 @@ describe('Index', function() { assert(extended); // See `fakeStreamRouter.extend` }); - it('should localize the Search instance', function() { - assert.deepEqual(index.search_, SEARCH_INSTANCE); - }); + it('should inherit from ServiceObject', function() { + assert(index instanceof ServiceObject); - it('should localize the id', function() { - assert.equal(index.id, ID); - }); + var calledWith = index.calledWith_[0]; - it('should throw if an ID is not provided', function() { - assert.throws(function() { - new Index(SEARCH_INSTANCE); - }, /An ID is needed/); + assert.strictEqual(calledWith.parent, SEARCH_INSTANCE); + assert.strictEqual(calledWith.baseUrl, '/indexes'); + assert.strictEqual(calledWith.id, ID); + assert.deepEqual(calledWith.methods, {}); }); }); describe('createDocument', function() { beforeEach(function() { - index.makeReq_ = util.noop; + index.request = util.noop; }); it('should accept a Document object', function(done) { @@ -116,11 +125,10 @@ describe('Index', function() { var document = new FakeDocument(); document.toJSON = function() { return expectedDocumentJson; }; - index.makeReq_ = function(method, path, query, body) { - assert.equal(method, 'POST'); - assert.equal(path, '/documents'); - assert.strictEqual(query, null); - assert.deepEqual(body, expectedDocumentJson); + index.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'POST'); + assert.strictEqual(reqOpts.uri, '/documents'); + assert.deepEqual(reqOpts.json, expectedDocumentJson); done(); }; @@ -131,7 +139,7 @@ describe('Index', function() { var error = new Error('Error.'); var apiResponse = { a: 'b', c: 'd' }; - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -148,7 +156,7 @@ describe('Index', function() { it('should execute callback with Document object', function(done) { var apiResponse = { a: 'b', c: 'd' }; - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -176,11 +184,9 @@ describe('Index', function() { it('should get document from the API', function(done) { var query = { a: 'b', c: 'd' }; - index.makeReq_ = function(method, path, q, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/documents'); - assert.deepEqual(q, query); - assert.strictEqual(body, null); + index.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/documents'); + assert.deepEqual(reqOpts.qs, query); done(); }; @@ -188,8 +194,8 @@ describe('Index', function() { }); it('should send empty query if only a callback is given', function(done) { - index.makeReq_ = function(method, path, query) { - assert.deepEqual(query, {}); + index.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, {}); done(); }; @@ -200,7 +206,7 @@ describe('Index', function() { var error = new Error('Error.'); var apiResponse = { a: 'b', c: 'd' }; - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -225,7 +231,7 @@ describe('Index', function() { return true; }; - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -251,7 +257,7 @@ describe('Index', function() { pageToken: apiResponse.nextPageToken }); - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -280,11 +286,9 @@ describe('Index', function() { query: 'completed=true' }; - index.makeReq_ = function(method, path, q, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/search'); - assert.deepEqual(q, query); - assert.strictEqual(body, null); + index.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/search'); + assert.deepEqual(reqOpts.qs, query); done(); }; @@ -294,8 +298,8 @@ describe('Index', function() { it('should build a query object from a string', function(done) { var query = 'completed=true'; - index.makeReq_ = function(method, path, q) { - assert.deepEqual(q, { query: query }); + index.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, { query: query }); done(); }; @@ -306,7 +310,7 @@ describe('Index', function() { var apiResponse = { a: 'b', c: 'd' }; var error = new Error('Error.'); - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -330,7 +334,7 @@ describe('Index', function() { return true; }; - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -356,7 +360,7 @@ describe('Index', function() { pageToken: apiResponse.nextPageToken }); - index.makeReq_ = function(method, path, query, body, callback) { + index.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -407,25 +411,4 @@ describe('Index', function() { assert.equal(document.rank, documentObject.rank); }); }); - - describe('makeReq_', function() { - it('should call search instance makeReq_', function(done) { - var method = 'POST'; - var path = '/'; - var query = 'query'; - var body = 'body'; - var callback = 'callback'; - - index.search_.makeReq_ = function(m, p, q, b, c) { - assert.equal(m, method); - assert.equal(p, '/indexes/' + ID + path); - assert.equal(q, query); - assert.equal(b, body); - assert.equal(c, callback); - done(); - }; - - index.makeReq_(method, path, query, body, callback); - }); - }); }); diff --git a/test/search/index.js b/test/search/index.js index 1e0cc9f7d1b..cd0819bbc33 100644 --- a/test/search/index.js +++ b/test/search/index.js @@ -20,7 +20,10 @@ var arrify = require('arrify'); var assert = require('assert'); var extend = require('extend'); var mockery = require('mockery'); +var nodeutil = require('util'); var prop = require('propprop'); + +var Service = require('../../lib/common/service.js'); var util = require('../../lib/common/util.js'); function FakeIndex() { @@ -52,6 +55,13 @@ var fakeUtil = extend({}, util, { } }); +function FakeService() { + this.calledWith_ = arguments; + Service.apply(this, arguments); +} + +nodeutil.inherits(FakeService, Service); + describe('Search', function() { var Search; var search; @@ -59,9 +69,11 @@ describe('Search', function() { var PROJECT_ID = 'project-id'; before(function() { - mockery.registerMock('./index-class.js', FakeIndex); + mockery.registerMock('../common/service.js', FakeService); mockery.registerMock('../common/stream-router.js', fakeStreamRouter); mockery.registerMock('../common/util.js', fakeUtil); + mockery.registerMock('./index-class.js', FakeIndex); + mockery.enable({ useCleanCache: true, warnOnUnregistered: false @@ -76,8 +88,6 @@ describe('Search', function() { }); beforeEach(function() { - makeAuthenticatedRequestFactoryOverride = null; - search = new Search({ projectId: PROJECT_ID }); @@ -107,34 +117,18 @@ describe('Search', function() { fakeUtil.normalizeArguments = normalizeArguments; }); - it('should create an authenticated request function', function(done) { - var options = { - projectId: 'projectId', - credentials: 'credentials', - email: 'email', - keyFilename: 'keyFile' - }; - - makeAuthenticatedRequestFactoryOverride = function(options_) { - assert.deepEqual(options_, { - credentials: options.credentials, - email: options.email, - keyFile: options.keyFilename, - scopes: [ - 'https://www.googleapis.com/auth/cloud-platform', - 'https://www.googleapis.com/auth/cloudsearch', - 'https://www.googleapis.com/auth/userinfo.email' - ] - }); - return done; - }; + it('should inherit from Service', function() { + assert(search instanceof Service); - var search = new Search(options); - search.makeAuthenticatedRequest_(); - }); + var calledWith = search.calledWith_[0]; - it('should localize the projectId', function() { - assert.equal(search.projectId_, PROJECT_ID); + var baseUrl = 'https://cloudsearch.googleapis.com/v1'; + assert.strictEqual(calledWith.baseUrl, baseUrl); + assert.deepEqual(calledWith.scopes, [ + 'https://www.googleapis.com/auth/cloud-platform', + 'https://www.googleapis.com/auth/cloudsearch', + 'https://www.googleapis.com/auth/userinfo.email' + ]); }); }); @@ -142,11 +136,9 @@ describe('Search', function() { it('should get indexes from the API', function(done) { var query = { a: 'b', c: 'd' }; - search.makeReq_ = function(method, path, q, body) { - assert.equal(method, 'GET'); - assert.equal(path, '/indexes'); - assert.deepEqual(q, query); - assert.strictEqual(body, null); + search.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/indexes'); + assert.deepEqual(reqOpts.qs, query); done(); }; @@ -156,9 +148,9 @@ describe('Search', function() { it('should rename query.prefix to indexNamePrefix', function(done) { var query = { prefix: 'prefix' }; - search.makeReq_ = function(method, path, q) { - assert.equal(typeof q.prefix, 'undefined'); - assert.equal(q.indexNamePrefix, query.prefix); + search.request = function(reqOpts) { + assert.strictEqual(typeof reqOpts.qs.prefix, 'undefined'); + assert.strictEqual(reqOpts.qs.indexNamePrefix, query.prefix); done(); }; @@ -166,8 +158,8 @@ describe('Search', function() { }); it('should send empty query if only a callback is given', function(done) { - search.makeReq_ = function(method, path, query) { - assert.deepEqual(query, {}); + search.request = function(reqOpts) { + assert.deepEqual(reqOpts.qs, {}); done(); }; @@ -178,7 +170,7 @@ describe('Search', function() { var error = new Error('Error.'); var apiResponse = { a: 'b', c: 'd' }; - search.makeReq_ = function(method, path, query, body, callback) { + search.request = function(reqOpts, callback) { callback(error, apiResponse); }; @@ -205,7 +197,7 @@ describe('Search', function() { return true; }; - search.makeReq_ = function(method, path, query, body, callback) { + search.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -236,7 +228,7 @@ describe('Search', function() { return {}; }; - search.makeReq_ = function(method, path, query, body, callback) { + search.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -256,7 +248,7 @@ describe('Search', function() { pageToken: apiResponse.nextPageToken }); - search.makeReq_ = function(method, path, query, body, callback) { + search.request = function(reqOpts, callback) { callback(null, apiResponse); }; @@ -270,6 +262,12 @@ describe('Search', function() { }); describe('index', function() { + it('should throw if an ID is not provided', function() { + assert.throws(function() { + search.index(); + }, /An ID is needed/); + }); + it('should return a new Index object', function() { var indexId = 'index-id'; var index = search.index(indexId); @@ -277,27 +275,4 @@ describe('Search', function() { assert.deepEqual(index.calledWith_, [search, indexId]); }); }); - - describe('makeReq_', function() { - it('should make correct authenticated request', function(done) { - var method = 'POST'; - var path = '/'; - var query = 'query'; - var body = 'body'; - - search.makeAuthenticatedRequest_ = function(reqOpts, callback) { - assert.equal(reqOpts.method, method); - assert.equal(reqOpts.qs, query); - - var baseUri = 'https://cloudsearch.googleapis.com/v1/'; - assert.equal(reqOpts.uri, baseUri + 'projects/' + PROJECT_ID + path); - - assert.equal(reqOpts.json, body); - - callback(); - }; - - search.makeReq_(method, path, query, body, done); - }); - }); });