diff --git a/doc/7/controllers/security/m-get-profiles/snippets/m-get-profiles.test.yml b/doc/7/controllers/security/m-get-profiles/snippets/m-get-profiles.test.yml index d20ca0ba1..35652db1e 100644 --- a/doc/7/controllers/security/m-get-profiles/snippets/m-get-profiles.test.yml +++ b/doc/7/controllers/security/m-get-profiles/snippets/m-get-profiles.test.yml @@ -12,4 +12,4 @@ hooks: curl -XDELETE kuzzle:7512/profiles/profile${i} done template: default -expected: '^ policies: \[ \[Object\] \] } \]$' +expected: '.*Profile.*_id.*rateLimit.*policies.*' diff --git a/doc/7/controllers/security/m-get-roles/snippets/m-get-roles.test.yml b/doc/7/controllers/security/m-get-roles/snippets/m-get-roles.test.yml index ea2870d33..6f2dc043b 100644 --- a/doc/7/controllers/security/m-get-roles/snippets/m-get-roles.test.yml +++ b/doc/7/controllers/security/m-get-roles/snippets/m-get-roles.test.yml @@ -18,4 +18,4 @@ hooks: curl -XDELETE kuzzle:7512/roles/role${i} done template: default -expected: '^ _id: ''role3'',$' +expected: '.*Role.*_id.*controllers.*' diff --git a/doc/7/controllers/security/m-get-users/snippets/m-get-users.test.yml b/doc/7/controllers/security/m-get-users/snippets/m-get-users.test.yml index b482c7fc0..58bcc9ee9 100644 --- a/doc/7/controllers/security/m-get-users/snippets/m-get-users.test.yml +++ b/doc/7/controllers/security/m-get-users/snippets/m-get-users.test.yml @@ -21,4 +21,4 @@ hooks: curl -XDELETE kuzzle:7512/users/user${i} done template: default -expected: '^ _id: ''user3'',$' +expected: '.*User.*' diff --git a/src/controllers/Base.js b/src/controllers/Base.js index 33ca42450..9aa3a8f0e 100644 --- a/src/controllers/Base.js +++ b/src/controllers/Base.js @@ -5,7 +5,10 @@ class BaseController { * @param {string} name - Controller full name for API request. */ constructor (kuzzle, name) { - this._kuzzle = kuzzle; + Reflect.defineProperty(this, '_kuzzle', { + value: kuzzle + }); + this._name = name; } diff --git a/src/controllers/MemoryStorage.js b/src/controllers/MemoryStorage.js index 73713be11..896177094 100644 --- a/src/controllers/MemoryStorage.js +++ b/src/controllers/MemoryStorage.js @@ -237,7 +237,6 @@ for (const action of Object.keys(commands)) { for (const opt of command.opts) { if (options[opt] !== null && options[opt] !== undefined) { assignParameter(request, command.getter, opt, options[opt]); - delete options[opt]; } } } @@ -296,7 +295,6 @@ function assignGeoRadiusOptions(data, options) { .forEach(function (opt) { if (opt === 'withcoord' || opt === 'withdist') { parsed.push(opt); - delete options[opt]; } else if (opt === 'count' || opt === 'sort') { if (opt === 'count') { @@ -305,8 +303,6 @@ function assignGeoRadiusOptions(data, options) { parsed.push(options[opt]); } - - delete options[opt]; }); if (parsed.length > 0) { @@ -327,7 +323,6 @@ function assignZrangeOptions (data, options) { if (options.limit) { data.limit = options.limit; - delete options.limit; } } diff --git a/src/controllers/Realtime.js b/src/controllers/Realtime.js index aca778320..e2847e01b 100644 --- a/src/controllers/Realtime.js +++ b/src/controllers/Realtime.js @@ -9,8 +9,8 @@ class RealTimeController extends BaseController { constructor (kuzzle) { super(kuzzle, 'realtime'); - this.subscriptions = {}; - this.subscriptionsOff = {}; + this.subscriptions = new Map(); + this.subscriptionsOff = new Map(); this.kuzzle.on('tokenExpired', () => this.tokenExpired()); } @@ -28,7 +28,8 @@ class RealTimeController extends BaseController { index, collection, body: message, - action: 'publish' + action: 'publish', + _id: options._id }; return this.query(request, options) @@ -40,50 +41,51 @@ class RealTimeController extends BaseController { return room.subscribe() .then(() => { - if (!this.subscriptions[room.id]) { - this.subscriptions[room.id] = []; + if (!this.subscriptions.has(room.id)) { + this.subscriptions.set(room.id, []); } - this.subscriptions[room.id].push(room); + this.subscriptions.get(room.id).push(room); return room.id; }); } unsubscribe (roomId, options = {}) { - const rooms = this.subscriptions[roomId]; + const request = { + action: 'unsubscribe', + body: { roomId } + }; - if (!rooms) { - return Promise.reject(new Error(`not subscribed to ${roomId}`)); - } + return this.query(request, options) + .then(response => { + const rooms = this.subscriptions.get(roomId); - for (const room of rooms) { - room.removeListeners(); - } - delete this.subscriptions[roomId]; + if (rooms) { + for (const room of rooms) { + room.removeListeners(); + } + + this.subscriptions.delete(roomId); + } - return this.query({ - action: 'unsubscribe', - body: {roomId} - }, options) - .then(response => { return response.result; }); } // called on network error or disconnection disconnected () { - for (const roomId of Object.keys(this.subscriptions)) { - for (const room of this.subscriptions[roomId]) { + for (const roomId of this.subscriptions.keys()) { + for (const room of this.subscriptions.get(roomId)) { room.removeListeners(); if (room.autoResubscribe) { - if (!this.subscriptionsOff[roomId]) { - this.subscriptionsOff[roomId] = []; + if (!this.subscriptionsOff.has(roomId)) { + this.subscriptionsOff.set(roomId, []); } - this.subscriptionsOff[roomId].push(room); + this.subscriptionsOff.get(roomId).push(room); } } - delete this.subscriptions[roomId]; + this.subscriptions.delete(roomId); } } @@ -92,18 +94,18 @@ class RealTimeController extends BaseController { * Resubscribe to eligible disabled rooms. */ reconnected () { - for (const roomId of Object.keys(this.subscriptionsOff)) { - for (const room of this.subscriptionsOff[roomId]) { - if (!this.subscriptions[roomId]) { - this.subscriptions[roomId] = []; + for (const roomId of this.subscriptionsOff.keys()) { + for (const room of this.subscriptionsOff.get(roomId)) { + if (!this.subscriptions.has(roomId)) { + this.subscriptions.set(roomId, []); } - this.subscriptions[roomId].push(room); + this.subscriptions.get(roomId).push(room); room.subscribe() .catch(() => this.kuzzle.emit('discarded', {request: room.request})); } - delete this.subscriptionsOff[roomId]; + this.subscriptionsOff.delete(roomId); } } @@ -111,12 +113,14 @@ class RealTimeController extends BaseController { * Removes all subscriptions. */ tokenExpired() { - for (const roomId of Object.keys(this.subscriptions)) { - this.subscriptions[roomId].forEach(room => room.removeListeners()); + for (const roomId of this.subscriptions.keys()) { + for (const room of this.subscriptions.get(roomId)) { + room.removeListeners(); + } } - this.subscriptions = {}; - this.subscriptionsOff = {}; + this.subscriptions = new Map(); + this.subscriptionsOff = new Map(); } } diff --git a/src/controllers/Security.js b/src/controllers/Security.js index f4f959a7d..a04f3ed8d 100644 --- a/src/controllers/Security.js +++ b/src/controllers/Security.js @@ -99,7 +99,6 @@ class SecurityController extends BaseController { action: 'createFirstAdmin', reset: options.reset }; - delete options.reset; return this.query(request, options) .then(response => new User(this.kuzzle, response.result._id, response.result._source)); diff --git a/src/core/KuzzleEventEmitter.js b/src/core/KuzzleEventEmitter.js index 981d26f86..d4dd8205d 100644 --- a/src/core/KuzzleEventEmitter.js +++ b/src/core/KuzzleEventEmitter.js @@ -7,7 +7,7 @@ class Listener { class KuzzleEventEmitter { constructor() { - this._events = {}; + this._events = new Map(); } _exists (listeners, fn) { @@ -15,11 +15,11 @@ class KuzzleEventEmitter { } listeners (eventName) { - if (this._events[eventName] === undefined) { + if (! this._events.has(eventName)) { return []; } - return this._events[eventName].map(listener => listener.fn); + return this._events.get(eventName).map(listener => listener.fn); } addListener (eventName, listener, once = false) { @@ -33,12 +33,12 @@ class KuzzleEventEmitter { throw new Error(`Invalid listener type: expected a function, got a ${listenerType}`); } - if (this._events[eventName] === undefined) { - this._events[eventName] = []; + if (! this._events.has(eventName)) { + this._events.set(eventName, []); } - if (!this._exists(this._events[eventName], listener)) { - this._events[eventName].push(new Listener(listener, once)); + if (! this._exists(this._events.get(eventName), listener)) { + this._events.get(eventName).push(new Listener(listener, once)); } return this; @@ -53,12 +53,14 @@ class KuzzleEventEmitter { return this; } - if (this._events[eventName] === undefined) { - this._events[eventName] = []; + if (! this._events.has(eventName)) { + this._events.set(eventName, []); } - if (!this._exists(this._events[eventName], listener)) { - this._events[eventName] = [new Listener(listener, once)].concat(this._events[eventName]); + if (!this._exists(this._events.get(eventName), listener)) { + const listeners = [new Listener(listener, once)].concat(this._events.get(eventName)); + + this._events.set(eventName, listeners); } return this; @@ -77,7 +79,7 @@ class KuzzleEventEmitter { } removeListener (eventName, listener) { - const listeners = this._events[eventName]; + const listeners = this._events.get(eventName); if (!listeners || !listeners.length) { return this; @@ -90,7 +92,7 @@ class KuzzleEventEmitter { } if (listeners.length === 0) { - delete this._events[eventName]; + this._events.delete(eventName); } return this; @@ -98,16 +100,17 @@ class KuzzleEventEmitter { removeAllListeners (eventName) { if (eventName) { - delete this._events[eventName]; - } else { - this._events = {}; + this._events.delete(eventName); + } + else { + this._events = new Map(); } return this; } emit (eventName, ...payload) { - const listeners = this._events[eventName]; + const listeners = this._events.get(eventName); if (listeners === undefined) { return false; @@ -131,11 +134,11 @@ class KuzzleEventEmitter { } eventNames () { - return Object.keys(this._events); + return Array.from(this._events.keys()); } listenerCount (eventName) { - return this._events[eventName] && this._events[eventName].length || 0; + return this._events.has(eventName) && this._events.get(eventName).length || 0; } } diff --git a/src/core/Room.js b/src/core/Room.js index 3cfaf90f4..7f6b30937 100644 --- a/src/core/Room.js +++ b/src/core/Room.js @@ -9,8 +9,10 @@ class Room { * @param {object} options */ constructor (controller, index, collection, body, callback, options = {}) { + Reflect.defineProperty(this, '_kuzzle', { + value: controller.kuzzle + }); this.controller = controller; - this.kuzzle = controller.kuzzle; this.index = index; this.collection = collection; this.callback = callback; @@ -25,12 +27,12 @@ class Room { collection, body, controller: 'realtime', - action: 'subscribe' + action: 'subscribe', + state: this.options.state, + scope: this.options.scope, + users: this.options.users, + volatile: this.options.volatile }; - for (const opt of ['state', 'scope', 'users', 'volatile']) { - this.request[opt] = this.options[opt]; - delete this.options[opt]; - } this.autoResubscribe = typeof options.autoResubscribe === 'boolean' ? options.autoResubscribe @@ -39,14 +41,14 @@ class Room { ? options.subscribeToSelf : true; - for (const opt of ['autoResubscribe', 'subscribeToSelf']) { - delete this.options[opt]; - } - // force bind for further event listener calls this._channelListener = this._channelListener.bind(this); } + get kuzzle () { + return this._kuzzle; + } + subscribe () { return this.kuzzle.query(this.request, this.options) .then(response => { diff --git a/src/core/searchResult/SearchResultBase.js b/src/core/searchResult/SearchResultBase.js index 0949a76ec..fca170b93 100644 --- a/src/core/searchResult/SearchResultBase.js +++ b/src/core/searchResult/SearchResultBase.js @@ -8,10 +8,18 @@ class SearchResultBase { * @param {object} response */ constructor (kuzzle, request = {}, options = {}, response = {}) { - this._kuzzle = kuzzle; - this._request = request; - this._response = response; - this._options = options; + Reflect.defineProperty(this, '_kuzzle', { + value: kuzzle + }); + Reflect.defineProperty(this, '_request', { + value: request + }); + Reflect.defineProperty(this, '_options', { + value: options + }); + Reflect.defineProperty(this, '_response', { + value: response + }); this._controller = request.controller; this._searchAction = 'search'; diff --git a/src/core/security/Profile.js b/src/core/security/Profile.js index ca68a6d38..4cf2de8f5 100644 --- a/src/core/security/Profile.js +++ b/src/core/security/Profile.js @@ -5,7 +5,10 @@ class Profile { * @param {Object} data */ constructor (kuzzle, _id = null, content = null) { - this._kuzzle = kuzzle; + Reflect.defineProperty(this, '_kuzzle', { + value: kuzzle + }); + this._id = _id; this.rateLimit = content && content.rateLimit ? content.rateLimit : 0; this.policies = content && content.policies ? content.policies : []; diff --git a/src/core/security/Role.js b/src/core/security/Role.js index 640d5bfde..d372cba4c 100644 --- a/src/core/security/Role.js +++ b/src/core/security/Role.js @@ -5,7 +5,10 @@ class Role { * @param {Object} data */ constructor (kuzzle, _id = null, controllers = {}) { - this._kuzzle = kuzzle; + Reflect.defineProperty(this, '_kuzzle', { + value: kuzzle + }); + this._id = _id; this.controllers = controllers; } diff --git a/src/core/security/User.js b/src/core/security/User.js index eb9cdc191..75e19014c 100644 --- a/src/core/security/User.js +++ b/src/core/security/User.js @@ -5,7 +5,10 @@ class User { * @param {Object} data */ constructor (kuzzle, _id = null, content = {}) { - this._kuzzle = kuzzle; + Reflect.defineProperty(this, '_kuzzle', { + value: kuzzle + }); + this._id = _id; this.content = content; } diff --git a/test/controllers/realtime.test.js b/test/controllers/realtime.test.js index 5aa4ebcb8..549cd1b89 100644 --- a/test/controllers/realtime.test.js +++ b/test/controllers/realtime.test.js @@ -60,6 +60,7 @@ describe('Realtime Controller', () => { describe('#publish', () => { it('should call realtime/publish query with the index, collection and body and return a Promise which resolves an acknowledgement', () => { kuzzle.query.resolves({result: {published: true}}); + options._id = 'doc-id'; return kuzzle.realtime.publish('index', 'collection', {foo: 'bar'}, options) .then(published => { @@ -70,7 +71,8 @@ describe('Realtime Controller', () => { action: 'publish', index: 'index', collection: 'collection', - body: {foo: 'bar'} + body: {foo: 'bar'}, + _id: 'doc-id' }, options); should(published).be.a.Boolean().and.be.true(); @@ -131,22 +133,22 @@ describe('Realtime Controller', () => { }); }); - it('should store the room subsciption locally', () => { + it('should store the room subscription locally', () => { const body = {foo: 'bar'}, cb = sinon.stub(); - kuzzle.realtime.subscriptions = {}; + kuzzle.realtime.subscriptions = new Map(); return kuzzle.realtime.subscribe('index', 'collection', body, cb, options) .then(() => { - const subscriptions = kuzzle.realtime.subscriptions[roomId]; + const subscriptions = kuzzle.realtime.subscriptions.get(roomId); should(subscriptions).be.an.Array(); should(subscriptions.length).be.exactly(1); should(subscriptions[0]).be.exactly(room); return kuzzle.realtime.subscribe('index', 'collection', body, cb, options); }).then(() => { - const subscriptions = kuzzle.realtime.subscriptions[roomId]; + const subscriptions = kuzzle.realtime.subscriptions.get(roomId); should(subscriptions).be.an.Array(); should(subscriptions.length).be.exactly(2); @@ -172,22 +174,12 @@ describe('Realtime Controller', () => { room1.removeListeners.reset(); room2.removeListeners.reset(); - kuzzle.realtime.subscriptions[roomId] = [room1, room2]; - kuzzle.realtime.subscriptions.foo = [room3]; + kuzzle.realtime.subscriptions.set(roomId, [room1, room2]); + kuzzle.realtime.subscriptions.set('foo', [room3]); kuzzle.query.resolves({result: roomId}); }); - it('should reject the promise if the room is not found', () => { - return kuzzle.realtime.unsubscribe('bar') - .then(() => { - throw new Error('Expected Function unsubscribe() to reject'); - }) - .catch(err => { - should(err.message).be.equal('not subscribed to bar'); - }); - }); - it('should call removeListeners for each room', () => { return kuzzle.realtime.unsubscribe(roomId) .then(() => { @@ -200,12 +192,12 @@ describe('Realtime Controller', () => { it('should delete rooms from local storage', () => { return kuzzle.realtime.unsubscribe(roomId) .then(() => { - should(kuzzle.realtime.subscriptions[roomId]).be.undefined(); + should(kuzzle.realtime.subscriptions.get(roomId)).be.undefined(); // Check we do not remove other registered rooms: - should(kuzzle.realtime.subscriptions.foo).be.an.Array(); - should(kuzzle.realtime.subscriptions.foo.length).be.equal(1); - should(kuzzle.realtime.subscriptions.foo[0]).be.equal(room3); + should(kuzzle.realtime.subscriptions.get('foo')).be.an.Array(); + should(kuzzle.realtime.subscriptions.get('foo').length).be.equal(1); + should(kuzzle.realtime.subscriptions.get('foo')[0]).be.equal(room3); }); }); @@ -240,17 +232,17 @@ describe('Realtime Controller', () => { removeListeners: sinon.stub() }; - kuzzle.realtime.subscriptions = { - foo: [roomA, roomB], - bar: [roomC] - }; + kuzzle.realtime.subscriptions = new Map([ + ['foo', [roomA, roomB]], + ['bar', [roomC]] + ]); kuzzle.realtime.disconnected(); should(kuzzle.realtime.subscriptions).be.empty(); - should(kuzzle.realtime.subscriptionsOff).eql({ - foo: [roomA] - }); + should(kuzzle.realtime.subscriptionsOff).eql(new Map([ + ['foo', [roomA]] + ])); for (const room of [roomA, roomB, roomC]) { should(room.removeListeners).be.calledOnce(); } @@ -263,18 +255,18 @@ describe('Realtime Controller', () => { const roomB = { subscribe: sinon.stub().resolves() }; const roomC = { subscribe: sinon.stub().resolves() }; - kuzzle.realtime.subscriptionsOff = { - foo: [roomA, roomB], - bar: [roomC] - }; + kuzzle.realtime.subscriptionsOff = new Map([ + ['foo', [roomA, roomB]], + ['bar', [roomC]] + ]); kuzzle.realtime.reconnected(); should(kuzzle.realtime.subscriptionsOff).be.empty(); - should(kuzzle.realtime.subscriptions).eql({ - foo: [roomA, roomB], - bar: [roomC] - }); + should(kuzzle.realtime.subscriptions).eql(new Map([ + ['foo', [roomA, roomB]], + ['bar', [roomC]] + ])); for (const room of [roomA, roomB, roomC]) { should(room.subscribe).be.calledOnce(); @@ -290,7 +282,7 @@ describe('Realtime Controller', () => { kuzzle.jwt = 'foobar'; for (let i = 0; i < 10; i++) { - kuzzle.realtime.subscriptions[uuidv4()] = [{removeListeners: stub}]; + kuzzle.realtime.subscriptions.set(uuidv4(), [{removeListeners: stub}]); } kuzzle.realtime.tokenExpired(); diff --git a/test/controllers/security.test.js b/test/controllers/security.test.js index dd497d8d6..e19f576bc 100644 --- a/test/controllers/security.test.js +++ b/test/controllers/security.test.js @@ -165,7 +165,7 @@ describe('Security Controller', () => { controller: 'security', action: 'createFirstAdmin', reset: true - }, {}); + }, {reset: true}); should(user).be.an.instanceOf(User); should(user._id).be.eql('id'); diff --git a/test/core/room.test.js b/test/core/room.test.js index 2cddfe977..1b79153b2 100644 --- a/test/core/room.test.js +++ b/test/core/room.test.js @@ -67,20 +67,17 @@ describe('Room', () => { }); it('should handle scope/state/users/volatile options', () => { - const - opts = { - scope: 'scope', - state: 'state', - users: 'users', - volatile: 'volatile' - }, - body = {foo: 'bar'}, - cb = sinon.stub(); + const opts = { + scope: 'scope', + state: 'state', + users: 'users', + volatile: 'volatile' + }; + const body = {foo: 'bar'}; + const cb = sinon.stub(); const room = new Room(controller, 'index', 'collection', body, cb, opts); - should(room.options).be.empty(); - should(room.request.scope).be.equal('scope'); should(room.request.state).be.equal('state'); should(room.request.users).be.equal('users'); @@ -104,10 +101,6 @@ describe('Room', () => { controller, 'index', 'collection', body, cb, {autoResubscribe: 'foobar'}); - should(room1.options).be.empty(); - should(room2.options).be.empty(); - should(room3.options).be.empty(); - should(room1.autoResubscribe).be.a.Boolean().and.be.True(); should(room2.autoResubscribe).be.a.Boolean().and.be.False(); should(room3.autoResubscribe).be.equal('default'); @@ -128,10 +121,6 @@ describe('Room', () => { controller, 'index', 'collection', body, cb, {subscribeToSelf: 'foobar'}); - should(room1.options).be.empty(); - should(room2.options).be.empty(); - should(room3.options).be.empty(); - should(room1.subscribeToSelf).be.a.Boolean().and.be.True(); should(room2.subscribeToSelf).be.a.Boolean().and.be.False(); should(room3.subscribeToSelf).be.a.Boolean().and.be.True(); @@ -177,7 +166,7 @@ describe('Room', () => { state: 'done', users: 'all', volatile: {bar: 'foo'} - }, options); + }, opts); should(res).be.equal(response); });