diff --git a/lib/api_resources/root.js b/lib/api_resources/root.js index cbafa00..f6252f0 100644 --- a/lib/api_resources/root.js +++ b/lib/api_resources/root.js @@ -40,28 +40,64 @@ RootResource.prototype.list = function(env, next) { return next(env); } + // Filter only peers connecting to this server + peers = peers.filter(function(peer) { + return peer.direction === 'acceptor'; + }); + var href = '/servers/{{peerName}}'; var qs ='?' + querystring.stringify({ql: params.ql}); env.request.templateUrl = href + qs; var httpServer = self.server.httpServer; - self.server.runtime.registry.find(params.ql, function(err, results) { - if (err) { - env.response.statusCode = 400; - env.response.body = { - class: ['query-error'], - properties: { - message: err.message - }, - links: [ - { rel: ['self'], href: env.helpers.url.current() } - ] - }; - return next(env); + var results = []; + var query = self.server.runtime.ql(params.ql); + var keys = Object.keys(self.server.runtime._jsDevices); + var maxIndex = keys.length - 1; + var hasError = false; + + if (maxIndex === -1) { + return done(); + } + + // Return all devices from local server + keys.forEach(function(key, i) { + var device = self.server.runtime._jsDevices[key]; + + if (hasError) { + return; } + + self.server.runtime.registry.match(query, device, function(err, match) { + if (err) { + env.response.statusCode = 400; + hasError = true; + env.response.body = { + class: ['query-error'], + properties: { + message: err.message + }, + links: [ + { rel: ['self'], href: env.helpers.url.current() } + ] + }; + return next(env); + } + + if (match) { + results.push(match); + } + + if (i === maxIndex) { + done(); + } + }); + }); + + function done() { var localEntities = (!!err || !results) ? [] : results.map(function(device){ - var deviceOnRuntime = self.server.runtime._jsDevices[device.id]; + var deviceOnRuntime = device; if (deviceOnRuntime) { var model = deviceOnRuntime; var loader = {path: '/servers/' + encodeURI(self.server.id)} @@ -76,7 +112,7 @@ RootResource.prototype.list = function(env, next) { }; return entity; } - }).filter(function(entity) { return entity !== null }); + }).filter(function(entity) { return entity !== null || entity !== undefined; }); httpServer.proxyToPeers(peers, env, function(err, results, messageId) { var entities = results.map(function(obj) { @@ -128,7 +164,8 @@ RootResource.prototype.list = function(env, next) { delete httpServer.clients[messageId]; next(env); }); - }); + }// done + }); } else if (this.shouldProxy(server)) { this.server.peerRegistry.get(server, function(err, peer) { diff --git a/test/test_query_api.js b/test/test_query_api.js index 95246fa..92e1bf3 100644 --- a/test/test_query_api.js +++ b/test/test_query_api.js @@ -1,5 +1,6 @@ var assert = require('assert'); var os = require('os'); +var util = require('util'); var request = require('supertest'); var zetta = require('../'); var Query = require('calypso').Query; @@ -10,6 +11,25 @@ var HttpDriver = require('./fixture/example_http_driver'); var Registry = require('./fixture/mem_registry'); var PeerRegistry = require('./fixture/mem_peer_registry'); var zettacluster = require('zetta-cluster'); +var Scientist = require('zetta-scientist'); +var Runtime = require('../zetta_runtime'); +var Device = Runtime.Device; + +function TestDriver() { + Device.call(this); + this.foo = 'fooData'; + this.bar = 'barData'; + this.id = '123456789'; +} +util.inherits(TestDriver, Device); + +TestDriver.prototype.init = function(config) { + config + .name('Test') + .type('testdriver') + .state('ready'); +}; + function getHttpServer(app) { return app.httpServer.server; @@ -308,9 +328,73 @@ describe('Zetta Query Api', function() { hasLinkRel(body.links, 'http://rels.zettajs.io/query'); })) .end(done); - }); }); + + describe('Non provisioned devices', function() { + beforeEach(function(done) { + machine = Scientist.create(TestDriver); + Scientist.init(machine); + reg.save(machine, function(err) { + assert.ok(!err); + app = zetta({ registry: reg, peerRegistry: peerRegistry }) + .silent() + .use(Scout) + .name('local') + .expose('*') + ._run(); + done(); + }); + }); + + it('queries on /servers/ should return no results', function(done) { + request(getHttpServer(app)) + .get('/servers/local?ql=where%20type%20=%20"testdriver"') + .expect(getBody(function(res, body) { + assert.equal(body.entities.length, 1); + body.entities.forEach(function(entity) { + assert(entity.links); + }) + })) + .end(done); + }) + + it('queries on /?server= should return no results', function(done) { + request(getHttpServer(app)) + .get('/?ql=where%20type%20=%20"testdriver"&server=local') + .expect(getBody(function(res, body) { + assert.equal(body.entities.length, 1); + body.entities.forEach(function(entity) { + assert(entity.links); + }) + })) + .end(done); + }) + + it('queries on /?server=* should return no results', function(done) { + request(getHttpServer(app)) + .get('/?ql=where%20type%20=%20"testdriver"&server=*') + .expect(getBody(function(res, body) { + assert.equal(body.entities.length, 1); + body.entities.forEach(function(entity) { + assert(entity.links); + }) + })) + .end(done); + }) + + it('queries on / should return no results', function(done) { + request(getHttpServer(app)) + .get('/?ql=where%20type%20=%20"testdriver"') + .expect(getBody(function(res, body) { + assert.equal(body.entities.length, 1); + body.entities.forEach(function(entity) { + assert(entity.links); + }) + })) + .end(done); + }) + }) describe('queries on /servers/', function() { var app = null;