diff --git a/.kuzzlerc b/.kuzzlerc
index bbb7064384..3a839058eb 100644
--- a/.kuzzlerc
+++ b/.kuzzlerc
@@ -1,6 +1,6 @@
{
// Kuzzle server listening port
- "port": 7512,
+ "port": 7511,
// Host and port for ipBroker service that handle internal communication
"ipcBroker": {
"host": "localhost",
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 35f9f43a4b..00e0660f5b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -31,7 +31,8 @@ docker-compose -f docker-compose/debug.yml up
You can now access to:
-* http://localhost:7512/api for standard Kuzzle API
+* http://localhost:7511/api for the standard Kuzzle REST API
+* ws://localhost:7512 for the Socket.io API (needs the [Socket.io](https://github.com/kuzzleio/kuzzle-plugin-socketio) plugin installed)
* http://127.0.0.1:8080/debug?port=7000 to debug the server
* http://127.0.0.1:8081/debug?port=7001 to debug the worker
diff --git a/app-start.js b/app-start.js
index e191ddd74f..cf2ebcfbd9 100644
--- a/app-start.js
+++ b/app-start.js
@@ -35,14 +35,32 @@ if (process.env.FEATURE_COVERAGE == 1) {
rc = require('rc');
kuzzle.start(rc('kuzzle'))
- .then(function () {
- return kuzzle.cleanDb();
- })
- .then(function () {
- return kuzzle.prepareDb();
+ .then(() => { return kuzzle.cleanDb(); })
+ .then(() => { return kuzzle.prepareDb(); })
+ .then(() => {
+ console.log(
+ `
+ ▄▄▄▄▄ ▄███▄ ▄▄▄▄
+ ▄█████████▄▄█████████▄▄████████▄
+ ██████████████████████████████████
+ ▀██████████████████████████████▀
+ ▄███████████████████████████▄
+ ▄███████████████████████████████▄
+ ▀█████████████████████████████████▀
+ ▀██▀ ▀██████▀ ▀██▀
+ ██ ████ ██
+ ▄████▄
+ ▀████▀
+ ▀▀`
+ );
+
+ console.log(`
+████████████████████████████████████
+██ KUZZLE ` + (kuzzle.isServer ? 'SERVER' : 'WORKER') + ` STARTED ██
+████████████████████████████████████`);
})
- .catch(function (error) {
- kuzzle.log.error(error);
+ .catch(error => {
+ console.error(error);
+ process.exit(1);
});
-
})();
diff --git a/bin/kuzzle-start.js b/bin/kuzzle-start.js
index 921dadd90f..1bfe5fe6b4 100644
--- a/bin/kuzzle-start.js
+++ b/bin/kuzzle-start.js
@@ -1,22 +1,39 @@
#!/usr/bin/env node
var
rc = require('rc'),
- winston = require('winston'),
kuzzle = require('../lib');
module.exports = function () {
- var log = winston;
- log.info('Starting Kuzzle');
+ console.log('Starting Kuzzle');
kuzzle.start(rc('kuzzle'))
- .then(function () {
- return kuzzle.cleanDb();
- })
- .then(function () {
- return kuzzle.prepareDb();
+ .then(() => { return kuzzle.cleanDb(); })
+ .then(() => { return kuzzle.prepareDb(); })
+ .then(() => {
+ console.log(
+ `
+ ▄▄▄▄▄ ▄███▄ ▄▄▄▄
+ ▄█████████▄▄█████████▄▄████████▄
+ ██████████████████████████████████
+ ▀██████████████████████████████▀
+ ▄███████████████████████████▄
+ ▄███████████████████████████████▄
+ ▀█████████████████████████████████▀
+ ▀██▀ ▀██████▀ ▀██▀
+ ██ ████ ██
+ ▄████▄
+ ▀████▀
+ ▀▀`
+ );
+
+ console.log(`
+████████████████████████████████████
+██ KUZZLE ` + (kuzzle.isServer ? 'SERVER' : 'WORKER') + ` STARTED ██
+████████████████████████████████████`);
})
- .catch(function (error) {
- kuzzle.log.error(error);
+ .catch(error => {
+ console.error(error);
+ process.exit(1);
});
};
\ No newline at end of file
diff --git a/config/defaultPlugins.json b/config/defaultPlugins.json
index dab075973d..9e084c193e 100644
--- a/config/defaultPlugins.json
+++ b/config/defaultPlugins.json
@@ -1,16 +1,29 @@
{
"kuzzle-plugin-logger": {
- "version": "1.0.4",
+ "version": "1.0.6",
"activated": true,
+ "name": "kuzzle-plugin-logger",
"defaultConfig": {
"service": "winston",
"level": "info",
- "addDate": true
+ "addDate": true,
+ "loadedBy": "all"
+ }
+ },
+ "kuzzle-plugin-socketio": {
+ "version": "1.0.3",
+ "activated": true,
+ "name": "kuzzle-plugin-socketio",
+ "defaultConfig": {
+ "port": 7512,
+ "room": "kuzzle",
+ "loadedBy": "server"
}
},
"kuzzle-plugin-auth-passport-local": {
"url": "git+https://github.com/kuzzleio/kuzzle-plugin-auth-passport-local.git",
"activated": true,
+ "name": "kuzzle-plugin-auth-passport-local",
"defaultConfig": {}
}
}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index d62fb474e9..ccd997c8f2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,7 @@
kuzzle:
image: kuzzleio/kuzzle
ports:
+ - "7511:7511"
- "7512:7512"
links:
- elasticsearch
diff --git a/docker-compose/debug.yml b/docker-compose/debug.yml
index b87c681329..5ec67dd842 100644
--- a/docker-compose/debug.yml
+++ b/docker-compose/debug.yml
@@ -4,6 +4,7 @@ kuzzle:
volumes:
- "..:/var/app"
ports:
+ - "7511:7511"
- "7512:7512"
- "8080:8080"
- "8081:8081"
@@ -14,7 +15,7 @@ kuzzle:
environment:
- MQ_BROKER_ENABLED=1
- LIKE_A_VIRGIN
- - FIXTURES
+ - FIXTURES=/var/app/features/fixtures/functionalTestsFixtures.json
- FEATURE_COVERAGE
rabbit:
diff --git a/docker-compose/perf.yml b/docker-compose/perf.yml
index abee0fcfe9..06f3a1604f 100644
--- a/docker-compose/perf.yml
+++ b/docker-compose/perf.yml
@@ -4,6 +4,7 @@ kuzzle:
- "..:/var/app"
- "/var/log"
ports:
+ - "7511:7511"
- "7512:7512"
command: /run-perf.sh
links:
diff --git a/docker-compose/test-travis.yml b/docker-compose/test-travis.yml
index ebf198ba49..0dcda99982 100644
--- a/docker-compose/test-travis.yml
+++ b/docker-compose/test-travis.yml
@@ -4,6 +4,7 @@ kuzzle:
volumes:
- "..:/var/app"
ports:
+ - "7511:7511"
- "7512:7512"
links:
- rabbit
@@ -11,7 +12,7 @@ kuzzle:
- redis
environment:
- LIKE_A_VIRGIN=1
- - FIXTURES
+ - FIXTURES=/var/app/features/fixtures/functionalTestsFixtures.json
- MQ_BROKER_ENABLED=1
- FEATURE_COVERAGE=1
# Travis env var must be propagated into the container
diff --git a/docker-compose/test.yml b/docker-compose/test.yml
index 8d74142a98..11f7cae6ec 100644
--- a/docker-compose/test.yml
+++ b/docker-compose/test.yml
@@ -4,6 +4,7 @@ kuzzle:
volumes:
- "..:/var/app"
ports:
+ - "7511:7511"
- "7512:7512"
links:
- rabbit
@@ -11,7 +12,7 @@ kuzzle:
- redis
environment:
- LIKE_A_VIRGIN=1
- - FIXTURES
+ - FIXTURES=/var/app/features/fixtures/functionalTestsFixtures.json
- MQ_BROKER_ENABLED=1
- FEATURE_COVERAGE=1
diff --git a/docs/MQ-broker.md b/docs/MQ-broker.md
index b585e3951a..13c0d657c8 100644
--- a/docs/MQ-broker.md
+++ b/docs/MQ-broker.md
@@ -22,6 +22,7 @@ And add an environment variable and link in the main Kuzzle container:
kuzzle:
image: kuzzleio/kuzzle
ports:
+ - "7511:7511"
- "7512:7512"
links:
- rabbit
diff --git a/docs/installation.md b/docs/installation.md
index 82af31584e..b80153244d 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -1,5 +1,17 @@
# Installation
+## Table of Contents
+
+ * [Using the all-in-one Docker recipe](#using-the-all-in-one-docker-recipe)
+ * [Reset Kuzzle with Docker recipe](#reset-kuzzle-with-docker-recipe)
+ * [Reset Kuzzle and insert sorme fixtures with Docker recipe](#reset-kuzzle-and-insert-sorme-fixtures-with-docker-recipe)
+ * [Initialize Kuzzle mapping with Docker recipe](#initialize-kuzzle-mapping-with-docker-recipe)
+ * [Using Vagrant](#using-vagrant)
+ * [From source or NPM](#from-source-or-npm)
+ * [Manual install](#manual-install)
+ * [Default](#default)
+ * [Change external services hosts](#change-external-services-hosts)
+
## Using the all-in-one Docker recipe
If you are running Docker and just want to get your own Kuzzle running, you can use the provided docker-compose file.
diff --git a/docs/plugins.md b/docs/plugins.md
index 835cc83cc7..8d674a8b5c 100644
--- a/docs/plugins.md
+++ b/docs/plugins.md
@@ -1,3 +1,30 @@
+# Table of Contents
+
+* [Table of Contents](#table-of-contents)
+* [About](#about)
+* [Plugins Configuration](#plugins-configuration)
+* [Default plugins](#default-plugins)
+ * [Logger](#logger)
+ * ["Passport Local" Authentication](#passport-local-authentication" aria-hidden="true">"Passport Local)
+ * [Socket.io communication support](#socketio-communication-support)
+* [How to create a plugin](#how-to-create-a-plugin)
+ * [Configuration](#configuration)
+ * [The plugin context](#the-plugin-context)
+ * [Architecture](#architecture)
+ * [The plugin init function](#the-plugin-init-function)
+ * [Listener plugins](#listener-plugins)
+ * [Pipe plugins](#pipe-plugins)
+ * [Controllers](#controllers)
+ * [How it works](#how-it-works)
+ * [Protocol plugins](#protocol-plugins)
+ * [How it works](#how-it-works-1)
+ * [Example](#example)
+ * [Examples](#examples)
+* [Troubleshooting](#troubleshooting)
+ * [Proxy](#proxy)
+
+
+
# About
Plugins are external components allowing to execute functions on specific event triggering.
@@ -7,32 +34,35 @@ There are several types of plugins:
* Pipe events: perform an action and return something. Kuzzle is waiting that all pipe events are performed before continuing.
* Controllers: add a specific controller to Kuzzle.
-# Configuration
+# Plugins Configuration
-To customize plugins, you can create a file `config/customPlugins.json`. This file can override default plugin files `config/customPlugins.json` to add/remove plugins and their configurations.
-If you're using Docker, you can create your own `customPlugins.json` file and mount it in `/var/app/config/customPlugins.json`. In `docker-compose.yml` file, you can have something like
+Some plugins can be configured. To customize these plugins, all you have to do is to create a file `config/customPlugins.json`, and to put it in the `config/` Kuzzle directory.
-```
+If your Kuzzle is running inside a docker image, you'll have to inject this file in the image.
+In `docker-compose.yml` file, you can have something like:
+
+```yaml
kuzzle:
image: kuzzleio/kuzzle
volumes:
- "host/path/to/customPlugins.json:/var/app/config/customPlugins.json"
ports:
+ - "7511:7511"
- "7512:7512"
links:
- elasticsearch
- redis
```
-A plugin configuration can have attributes:
+Plugins configuration have the following default attributes:
* `url`: a git URL where the plugin can be found and cloned.
-* `version`: a version corresponding to the version given in the file `package.json` in the plugin module.
+* `version`: the NPM package version to download
* `customConfig`: config for the plugin. Each plugin has a different configuration (required or optional), check the corresponding plugin documentation for more information.
* `defaultConfig`: Don't edit this attribute. The defaultConfig is provided by the plugin itself. If you need to change the configuration, edit the `customConfig` attribute
**Note:**
-* URL or version are required. The URL is checked first, so if you have set a version and an URL, the version will be ignored.
+* A `url` or `version` parameter is required. The URL is checked first, so if you have set both a version and an URL, the version will be ignored.
# Default plugins
@@ -46,6 +76,12 @@ By default, the a standard "passport-local" plugin is enabled to authenticate us
See also the [global authentication mechanism documentation](security/authentication.md).
+## Socket.io communication support
+
+By default, the protocol plugin [socket.io](https://github.com/kuzzleio/kuzzle-plugin-socketio) is installed, allowing to access Kuzzle using Socket.io clients.
+
+The default plugin configuration opens the port `7512`. This can be changed by injecting a custom plugin configuration file.
+
# How to create a plugin
A plugin is a Javascript module that can be installed with NPM or via a public GIT repository.
@@ -56,6 +92,7 @@ The module must have a `package.json` file with a `pluginInfo` entry. The option
```json
"pluginInfo": {
+ "loadedBy": "all",
"defaultConfig": {
"service": "winston",
"level": "info",
@@ -64,13 +101,46 @@ The module must have a `package.json` file with a `pluginInfo` entry. The option
}
```
+The `loadedBy` option tells Kuzzle to install and load the plugin only by corresponding instance types.
+The accepted values are: `all`, `server` and `worker`. Default value: `all`.
+
+## The plugin context
+
+Plugins don't have access to the Kuzzle instance. Instead, Kuzzle provides a plugin ``context`` to the ``plugin.init()`` function.
+
+Here is the list of shared objects contained in the provided ``context``:
+
+| Object | Purpose |
+|--------|------------------------------|
+| ``RequestObject`` | Constructor for standardized requests sent to Kuzzle |
+| ``ResponseObject`` | Constructor for the standardized Kuzzle non-realtime response objects |
+| ``RealTimeResponseObject`` | Constructor for the standardized Kuzzle realtime response objects |
+| Errors... | Kuzzle error constructors. The complete list can be found in the ``lib/api/core/errors`` directory |
+| ``repositories()`` | Getter function to the security roles, profiles and users repositories |
+| ``getRouter()`` | Getter function to the Kuzzle protocol communication system |
+
## Architecture
Your main javascript file in your plugin must have a function `init` and expose a `hooks` and/or a `pipes` and/or a `controllers` object. All functions defined in these files must be exposed as main object.
-### Hooks
-Hook events are triggered and are not blocking functions. Typically, if we want to log something, we will use hook events.
+## The plugin init function
+
+All plugins must expose a ``init`` function. Its purpose is to initialize the plugins according to its configuration.
+
+Kuzzle calls these ``init`` function at startup, during initialization.
+
+Expected arguments:
+``function (config, context, isDummy)``
+
+Where:
+* ``config``: JSON object containing the plugin configuration (the content of the ``defaultConfig`` or the ``customConfig`` configuration)
+* ``context``: the plugin context (see above)
+* ``isDummy``: boolean. True: asks the plugin to not really start itself, but instead mock its functionalities (useful when testing plugins, kuzzle, or both)
+
+### Listener plugins
+
+Hook events are triggered and are non-blocking functions. Listener plugins are configured to be called on these hooks.
```js
// Somewhere in Kuzzle
@@ -78,16 +148,18 @@ kuzzle.pluginsManager.trigger('event:hookEvent', message);
```
```js
-// In hooks.js file in the plugin
+/*
+ Plugin hooks configuration.
+ Let's assume that we store this configuration in a "hooks.js" file
+ */
module.exports = {
'event:hookEvent': 'myFunction'
}
```
```js
-// In main plugin index file
-module.exports = function () {
-
+// Plugin implementation
+module.exports = function ()
this.hooks = require('./config/hooks.js');
this.init = function (config, context, isDummy) {
// do something
@@ -95,22 +167,23 @@ module.exports = function () {
this.myFunction = function (message, event) {
console.log('Event', event, 'is triggered');
- console.log('There is the message', message);
+ console.log('Here is the message', message);
}
}
```
-### Pipes
+### Pipe plugins
-When an event pipe is triggered, we are waiting for all the functions attached on this event. A function attached on a pipe event has access to the data and can even change them.
-A function must take in its last parameter a callback. This callback must be called at the end of the function with `callback(error, object)`:
+When a pipe event is triggered, we are waiting for all plugins attached on this event. A plugin attached on a pipe event has access to the data and can even change them.
+A pipe plugin constructor must take in its last parameter a callback. This callback must be called at the end of the function with `callback(error, object)`:
* error: if there is an error during the function, this parameter must be set. If everything is ok, you can call the function with null
* object: the object to pass to the next function
-Functions are called in chain. When the `callback()` function is called, the next function attached on the event is triggered.
+Plugins are called in chain. When the `callback()` function is called, the next function attached on the event is triggered.
+If the plugin fails to call the callback before timeout, Kuzzle will raise an error and forward it to the requesting clients.
-Pipe events are useful when you want to modify or validate an object with a plugin.
+Pipe plugins are useful when you want to modify or validate an object.
```js
// Somewhere in Kuzzle
@@ -121,7 +194,7 @@ kuzzle.pluginsManager.trigger('event:pipeEvent', requestObject)
```
```js
-// in pipes.js file in the plugin
+// Plugin pipes configuration
module.exports = {
'event:pipeEvent': 'addCreatedAt'
}
@@ -147,13 +220,13 @@ In this example, in Kuzzle, the `modifiedRequestObject` has now a `createdAt` at
### Controllers
-A plugin controller is a plugin that adds some controller actions into Kuzzle.
+A plugin controller is a plugin that adds new controller and actions to Kuzzle.
It must expose to Kuzzle:
__A `controllers` object listing one or more controllers:__
```js
-// in controllers.js file in the plugin
+// Plugin controller configuration
module.exports = {
'mycontroller': 'MyController'
};
@@ -162,43 +235,39 @@ module.exports = {
__A `routes` object listing the HTTP routes for the REST API:__
```js
-// in routes.js file in the plugin
+// Plugin REST routes configuration
module.exports = [
{verb: 'get', url: '/foo/:name', controller: 'mycontroller', action: 'myAction'},
{verb: 'post', url: '/foo', controller: 'mycontroller', action: 'myAction'},
];
```
-_NB: you can describe any routes as you want, according to the actions you need to implement.
+_NB: you can describe any routes you want, according to the actions you need to implement.
For each action, you can declare either a GET action, or a POST action, or both of them._
__The controller code, implementing your actions:__
```js
-// in myController.js file
-var q = require('q');
-
+// Controller implementation
module.exports = function MyController (context) {
-
this.myAction = function (requestObject)
var
- deferred = q.defer(),
responseBody = {},
response;
- // here write the code of your action.
+ // implement here the result of this controller action
+
// Sample response object creation with the context variable:
response = new context.ResponseObject(requestObject, responseBody);
// the function must return a Promise:
- deferred.resolve(response);
- return deferred.promise;
+ return Promise.resolve(response);
};
};
```
```js
-// In main plugin index file
+// Main plugin file
module.exports = function () {
this.controllers = require('./config/controllers.js');
@@ -226,12 +295,12 @@ which can be used by the controller actions.
#### How it works
-* With Websocket and MQ protocols, _controller_ attribute is prefixed by the plugin name:
+* With non-REST protocols, the _controller_ attribute is prefixed with the plugin name.
+
Sample:
```js
{
- requestId: 'xxxxxxxxx',
controller: 'myplugin/mycontroller',
action: 'myAction',
body: {
@@ -240,29 +309,134 @@ Sample:
}
```
-* With REST protocol, we use the routes configured in _routes.js_, prefixed by "\_plugin/" + the plugin name:
+* With REST protocol, we use the routes configured in _routes.js_.
+These routes are automatically prefixed with "\_plugin/" + the plugin name.
+
Samples:
GET action:
```
-GET http://kuzzle:7512/api/_plugin/myplugin/foo/John%20Doe
+GET http://kuzzle:7511/api/1.0/_plugin/myplugin/foo/John%20Doe
```
POST action:
```
-POST http://kuzzle:7512/api/_plugin/myplugin/foo
+POST http://kuzzle:7511/api/1.0/_plugin/myplugin/foo
{"name": "John Doe"}
```
+### Protocol plugins
+
+Kuzzle core only supports REST communications. All other supported protocols are implemented as protocol plugins.
+By default, the Kuzzle official docker image is shipped with the [Socket.io](https://github.com/kuzzleio/kuzzle-plugin-socketio) protocol.
+
+#### How it works
+
+Protocol plugins allow Kuzzle to support any existing protocol. These plugins ensure a two-way communication between clients and Kuzzle.
+
+Messages emanating from Kuzzle are emitted using the following hooks. Protocol plugins are free to ignore some or all of these hooks:
+
+| Hook | Emitted object | Description |
+|------|----------------|-----------------------------|
+| ``protocol:joinChannel`` | `{channel, id}`| Tells protocol plugins that the connection `id` subscribed to the channel `channel` |
+| ``protocol:leaveChannel`` | `{channel, id}` | Tells protocol plugins that the connection `id` left the channel `channel` |
+| ``protocol:broadcast`` | `{channel, payload}` | Asks protocol plugins to emit a data `payload` to clients connected to the channel `channel` |
+
+*For more information about channels, see our [API Documentation](http://kuzzleio.github.io/kuzzle-api-documentation/#on)*
+
+
+
+Requests sent by clients to Kuzzle can be forwarded by protocol plugins using methods exposed in the plugin context.
+To access these methods, simply call ``context.getRouter().``:
+
+| Router method | Arguments | Returns | Description |
+|-----------------|--------------|---------|--------------------------|
+| ``newConnection`` | ``protocol name`` (string)
``connection ID`` (string) | A promise resolving to a ``context`` object | Declare a new connection to Kuzzle. |
+| ``execute`` | ``optional JWT Headers`` (string)
``RequestObject`` (object)
``context`` (obtained with ``newConnection``) | A promise resolving to the corresponding ``ResponseObject`` | Execute a client request. |
+| ``removeConnection`` | ``context`` (obtained with ``newConnection``) | | Asks Kuzzle to remove the corresponding connection and all its subscriptions |
+
+#### Example
+
+First, link protocol hooks to their corresponding implementation methods:
+```js
+// Content of a hooks.js file:
+module.exports = {
+ 'protocol:broadcast': 'broadcast',
+ 'protocol:joinChannel': 'join',
+ 'protocol:leaveChannel': 'leave'
+};
+```
+
+Then, implement the corresponding methods:
+```js
+// Protocol plugin implementation
+module.exports = function () {
+ this.hooks = require('./hooks.js');
+ // for instance, maintain client contexts in a global object
+ this.contexts = {};
+
+ this.init = function (config, context, isDummy) {
+ // Protocol initialization. Usually opens a network port to listen to
+ // incoming messages
+
+ // whenever a client is connected
+ context.getRouter().newConnection("this protocol name", "connection unique ID")
+ .then(context => {
+ this.contexts["connection unique ID"] = context;
+ });
+
+ // whenever a client sends a request
+ context.getRouter().execute(null, requestObject, this.contexts["id"])
+ .then(response => {
+ // forward the response to the client
+ })
+ .catch(error => {
+ // errors are encapsulated in a ResponseObject. You may simply
+ // forward it to the client too
+ });
+
+ // whenever a client is disconnected
+ context.getRouter().removeConnection(this.contexts["id"]);
+ };
+
+ this.broadcast = function (data) {
+ /*
+ Linked to the protocol:broadcast hook, emitted
+ by Kuzzle when a "data.payload" needs to be broadcasted to the
+ "data.channel" channel
+
+ The payload is a ResponseObject
+ */
+ };
+
+ this.join = function (data) {
+ /*
+ Linked to the protocol:joinChannel hook, emitted
+ by Kuzzle when the connection "data.id" joins the
+ channel "data.channel"
+ */
+ };
+
+ this.leave = function (data) {
+ /*
+ Linked to the protocol:leaveChannel hook, emitted
+ by Kuzzle when the connection "data.id" leaves the
+ channel "data.channel"
+ */
+ };
+};
+```
+
## Examples
-* [kuzzle-plugin-logger](https://github.com/kuzzleio/kuzzle-plugin-logger).
-* [kuzzle-plugin-helloworld](https://github.com/kuzzleio/kuzzle-plugin-helloworld).
+* [kuzzle-plugin-logger](https://github.com/kuzzleio/kuzzle-plugin-logger)
+* [kuzzle-plugin-helloworld](https://github.com/kuzzleio/kuzzle-plugin-helloworld)
+* [kuzzle-plugin-socketio](https://github.com/kuzzleio/kuzzle-plugin-socketio)
# Troubleshooting
## Proxy
-If you are using Docker and your network is behind a proxy, you need to run this [container](https://hub.docker.com/r/klabs/forgetproxy/) to let Kuzzle container use your proxy to download the plugin
+If you are using Docker and your network is behind a proxy, you may need to run this [container](https://hub.docker.com/r/klabs/forgetproxy/). This image lets other docker images accessing to external networks using the server proxy configuration.
diff --git a/docs/request_scenarios/read_http.md b/docs/request_scenarios/read_http.md
index 0303987a8f..27f854bbb6 100644
--- a/docs/request_scenarios/read_http.md
+++ b/docs/request_scenarios/read_http.md
@@ -14,7 +14,7 @@ The following diagram shows how request data is exchanged between the client app
\#1. The REST client asks for a content using a HTTP GET Request
For instance, to retrieve the document '739c26bc-7a09-469a-803d-623c4045b0cb' in the collection 'users':
-```GET http://kuzzle:7512/api/users/739c26bc-7a09-469a-803d-623c4045b0cb```
+```GET http://kuzzle:7511/api/users/739c26bc-7a09-469a-803d-623c4045b0cb```
\#2. The HTTP router handles the input request and forward the message to the ```Funnel Controller```.
diff --git a/features/fixtures/functionalTestsFixtures.json b/features/fixtures/functionalTestsFixtures.json
new file mode 100644
index 0000000000..2702667c8f
--- /dev/null
+++ b/features/fixtures/functionalTestsFixtures.json
@@ -0,0 +1,16 @@
+{
+ "index-test": {
+ "testCollection": [
+ { "create": { "_id": "alovelace"} },
+ { "username": "alovelace", "name": {"first": "Ada", "last": "Lovelace"} }
+ ]
+ },
+ "index-test-alt": {
+ "testCollection": [
+ { "create": { "_id": "ghopper"} },
+ { "username": "ghopper", "name": {"first": "Grace", "last": "Hopper"} }
+ ]
+ }
+}
+
+
diff --git a/features/step_definitions/collections.js b/features/step_definitions/collections.js
index 2de64bb304..69b3f57ecf 100644
--- a/features/step_definitions/collections.js
+++ b/features/step_definitions/collections.js
@@ -40,7 +40,7 @@ var apiSteps = function () {
return callback();
}
- callback('Expected to find the collection <' + collection + '> in this collections list: ' + this.result.collections);
+ callback('Expected to find the collection <' + collection + '> in this collections list: ' + JSON.stringify(this.result.collections));
});
this.Then(/^I remove the collection and schema(?: from index "([^"]*)")?$/, function (index, callback) {
diff --git a/features/step_definitions/serverInfo.js b/features/step_definitions/serverInfo.js
index aabd4a3af3..1aac23b9b8 100644
--- a/features/step_definitions/serverInfo.js
+++ b/features/step_definitions/serverInfo.js
@@ -1,5 +1,5 @@
var apiSteps = function () {
- this.When('I get server informations', function (callback) {
+ this.When(/^I get server informations$/, function (callback) {
this.api.getServerInfo()
.then(body => {
if (body.error) {
@@ -16,7 +16,7 @@ var apiSteps = function () {
.catch(error => callback(error));
});
- this.Then('I can retrieve the Kuzzle API version', function(callback) {
+ this.Then(/^I can retrieve the Kuzzle API version$/, function(callback) {
if (this.result.serverInfo && this.result.serverInfo.kuzzle && this.result.serverInfo.kuzzle.api) {
this.apiVersion = this.result.serverInfo.kuzzle.api;
return callback();
diff --git a/features/support/apiREST.js b/features/support/apiREST.js
index 7a89b74f28..b1b491e078 100644
--- a/features/support/apiREST.js
+++ b/features/support/apiREST.js
@@ -1,7 +1,7 @@
var
config = require('./config')(),
rp = require('request-promise'),
- apiVersion;
+ apiVersion = '1.0';
var ApiREST = function () {
this.world = null;
@@ -13,14 +13,12 @@ ApiREST.prototype.init = function (world) {
ApiREST.prototype.disconnect = function () {};
-ApiREST.prototype.pathApi = function (path) {
- var basePath = '/api';
-
- if (apiVersion) {
- basePath += '/' + apiVersion;
- }
+ApiREST.prototype.apiPath = function (path) {
+ return config.url + '/api/1.0/' + path;
+};
- return config.url + basePath + '/' + path;
+ApiREST.prototype.apiBasePath = function (path) {
+ return config.url + '/api/' + path;
};
ApiREST.prototype.callApi = function (options) {
@@ -29,7 +27,7 @@ ApiREST.prototype.callApi = function (options) {
ApiREST.prototype.get = function (id, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + id),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + id),
method: 'GET',
json: true
};
@@ -39,7 +37,7 @@ ApiREST.prototype.get = function (id, index) {
ApiREST.prototype.search = function (filters, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_search'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_search'),
method: 'POST',
json: filters
};
@@ -49,7 +47,7 @@ ApiREST.prototype.search = function (filters, index) {
ApiREST.prototype.count = function (filters, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_count'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_count'),
method: 'POST',
json: filters
};
@@ -59,7 +57,7 @@ ApiREST.prototype.count = function (filters, index) {
ApiREST.prototype.create = function (body, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_create'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_create'),
method: 'POST',
json: body
};
@@ -69,7 +67,7 @@ ApiREST.prototype.create = function (body, index) {
ApiREST.prototype.publish = function (body, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection),
method: 'POST',
json: body
};
@@ -79,7 +77,7 @@ ApiREST.prototype.publish = function (body, index) {
ApiREST.prototype.createOrUpdate = function (body, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + body._id),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + body._id),
method: 'PUT',
json: body
};
@@ -89,7 +87,7 @@ ApiREST.prototype.createOrUpdate = function (body, index) {
ApiREST.prototype.update = function (id, body, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + id + '/_update'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + id + '/_update'),
method: 'PUT',
json: body
};
@@ -99,7 +97,7 @@ ApiREST.prototype.update = function (id, body, index) {
ApiREST.prototype.deleteById = function (id, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + id),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/' + id),
method: 'DELETE',
json: true
};
@@ -109,7 +107,7 @@ ApiREST.prototype.deleteById = function (id, index) {
ApiREST.prototype.deleteByQuery = function (filters, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_query'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_query'),
method: 'DELETE',
json: filters
};
@@ -119,7 +117,7 @@ ApiREST.prototype.deleteByQuery = function (filters, index) {
ApiREST.prototype.deleteCollection = function (index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection),
method: 'DELETE',
json: true
};
@@ -129,7 +127,7 @@ ApiREST.prototype.deleteCollection = function (index) {
ApiREST.prototype.bulkImport = function (bulk, index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_bulk'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_bulk'),
method: 'POST',
json: bulk
};
@@ -139,7 +137,7 @@ ApiREST.prototype.bulkImport = function (bulk, index) {
ApiREST.prototype.globalBulkImport = function (bulk) {
var options = {
- url: this.pathApi('_bulk'),
+ url: this.apiPath('_bulk'),
method: 'POST',
json: bulk
};
@@ -149,7 +147,7 @@ ApiREST.prototype.globalBulkImport = function (bulk) {
ApiREST.prototype.putMapping = function (index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_mapping'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_mapping'),
method: 'PUT',
json: this.world.schema
};
@@ -159,7 +157,7 @@ ApiREST.prototype.putMapping = function (index) {
ApiREST.prototype.getStats = function (dates) {
var options = {
- url: this.pathApi('_getStats'),
+ url: this.apiPath('_getStats'),
method: 'POST',
json: dates
};
@@ -169,7 +167,7 @@ ApiREST.prototype.getStats = function (dates) {
ApiREST.prototype.getLastStats = function () {
var options = {
- url: this.pathApi('_getLastStats'),
+ url: this.apiPath('_getLastStats'),
method: 'GET',
json: {}
};
@@ -179,7 +177,7 @@ ApiREST.prototype.getLastStats = function () {
ApiREST.prototype.getAllStats = function () {
var options = {
- url: this.pathApi('_getAllStats'),
+ url: this.apiPath('_getAllStats'),
method: 'GET',
json: {}
};
@@ -193,7 +191,7 @@ ApiREST.prototype.listCollections = function (index, type) {
index = index || this.world.fakeIndex;
options = {
- url: this.pathApi(index + '/_listCollections'),
+ url: this.apiPath(index + '/_listCollections'),
method: 'GET',
json: true
};
@@ -207,7 +205,7 @@ ApiREST.prototype.listCollections = function (index, type) {
ApiREST.prototype.now = function () {
var options = {
- url: this.pathApi('_now'),
+ url: this.apiPath('_now'),
method: 'GET',
json: true
};
@@ -217,7 +215,7 @@ ApiREST.prototype.now = function () {
ApiREST.prototype.truncateCollection = function (index) {
var options = {
- url: this.pathApi(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_truncate'),
+ url: this.apiPath(((typeof index !== 'string') ? this.world.fakeIndex : index) + '/' + this.world.fakeCollection + '/_truncate'),
method: 'DELETE',
json: true
};
@@ -227,7 +225,7 @@ ApiREST.prototype.truncateCollection = function (index) {
ApiREST.prototype.listIndexes = function () {
var options = {
- url: this.pathApi('_listIndexes'),
+ url: this.apiPath('_listIndexes'),
method: 'GET',
json: true
};
@@ -237,7 +235,7 @@ ApiREST.prototype.listIndexes = function () {
ApiREST.prototype.deleteIndexes = function () {
var options = {
- url: this.pathApi('_deleteIndexes'),
+ url: this.apiPath('_deleteIndexes'),
method: 'DELETE',
json: true
};
@@ -247,7 +245,7 @@ ApiREST.prototype.deleteIndexes = function () {
ApiREST.prototype.createIndex = function (index) {
var options = {
- url: this.pathApi(index),
+ url: this.apiPath(index),
method: 'PUT',
json: true
};
@@ -257,7 +255,7 @@ ApiREST.prototype.createIndex = function (index) {
ApiREST.prototype.deleteIndex = function (index) {
var options = {
- url: this.pathApi(index),
+ url: this.apiPath(index),
method: 'DELETE',
json: true
};
@@ -267,7 +265,7 @@ ApiREST.prototype.deleteIndex = function (index) {
ApiREST.prototype.getServerInfo = function () {
var options = {
- url: this.pathApi('_serverInfo'),
+ url: this.apiBasePath('_serverInfo'),
method: 'GET',
json: true
};
diff --git a/features/support/apiWebsocket.js b/features/support/apiWebsocket.js
index f82ffef184..e4c60ad565 100644
--- a/features/support/apiWebsocket.js
+++ b/features/support/apiWebsocket.js
@@ -120,7 +120,7 @@ var initSocket = function (socketName) {
}
if (!this.listSockets[socketName]) {
- socket = io(config.url, { 'force new connection': true });
+ socket = io(config.ws, { 'force new connection': true });
this.listSockets[socketName] = socket;
// the default socket is the socket with name 'client1'
diff --git a/features/support/config.js b/features/support/config.js
index d381588379..274db9343f 100644
--- a/features/support/config.js
+++ b/features/support/config.js
@@ -8,7 +8,8 @@ var config = require('rc')('kuzzle');
module.exports = function () {
var defaultUrls = {
- url: 'http://localhost:7512',
+ url: 'http://localhost:7511',
+ ws: 'http://localhost:7512',
mqttUrl: 'mqtt://localhost:1883',
amqpUrl: 'amqp://localhost:5672',
stompUrl: 'stomp://localhost:61613'
diff --git a/features/support/env.js b/features/support/env.js
new file mode 100644
index 0000000000..30fb423dec
--- /dev/null
+++ b/features/support/env.js
@@ -0,0 +1,5 @@
+var configure = function () {
+ this.setDefaultTimeout(30 * 1000);
+};
+
+module.exports = configure;
diff --git a/features/support/hooks.js b/features/support/hooks.js
index 29130d3ab0..53d9db2482 100644
--- a/features/support/hooks.js
+++ b/features/support/hooks.js
@@ -43,28 +43,6 @@ var myHooks = function () {
callback();
});
-
- this.registerHandler('BeforeFeature', (event, callback) => {
- this.api = setAPI(this, 'Websocket');
- this.api.createIndex((new this.World()).fakeIndex)
- .then(this.api.createIndex((new this.World()).fakeAltIndex))
- .then(() => {
- setTimeout(callback, 1000);
- })
- .catch(error => callback(new Error(error)));
- });
-
- this.registerHandler('AfterFeature', function (event, callback) {
- this.api = setAPI(this, 'Websocket');
- this.api.deleteIndexes()
- .then(function () {
- callback();
- })
- .catch(function (error) {
- callback(new Error(error));
- });
- });
-
this.After(function (scenario, callback) {
this.api.deleteCollection()
.then(function () {
diff --git a/lib/api/Kuzzle.js b/lib/api/Kuzzle.js
index 5c56d83d41..4e01658e80 100644
--- a/lib/api/Kuzzle.js
+++ b/lib/api/Kuzzle.js
@@ -1,5 +1,4 @@
var
- winston = require('winston'),
EventEmitter = require('eventemitter2').EventEmitter2,
// build all hooks defined in config/hooks.js file
Hooks = require('../hooks'),
@@ -22,8 +21,6 @@ function Kuzzle () {
this.isServer = false;
}
- this.log = winston;
-
// Add hooks, workers and services
this.hooks = new Hooks(this);
this.workers = new Workers(this);
diff --git a/lib/api/controllers/routerController.js b/lib/api/controllers/routerController.js
index a7ccdc66c7..5f8cdd8964 100644
--- a/lib/api/controllers/routerController.js
+++ b/lib/api/controllers/routerController.js
@@ -1,11 +1,13 @@
var
_ = require('lodash'),
+ q = require('q'),
stringify = require('json-stable-stringify'),
Router = require('router'),
bodyParser = require('body-parser'),
finalhandler = require('finalhandler'),
RequestObject = require('../core/models/requestObject'),
ResponseObject = require('../core/models/responseObject'),
+ PluginImplementationError = require('../core/errors/pluginImplementationError'),
BadRequestError = require('../core/errors/badRequestError');
module.exports = function RouterController (kuzzle) {
@@ -13,6 +15,103 @@ module.exports = function RouterController (kuzzle) {
this.pluginRouter = null;
this.routename = 'kuzzle';
this.kuzzle = kuzzle;
+ this.connections = {};
+
+ /**
+ * Declares a new connection on a given protocol. Called by protocol plugins.
+ * Returns a context object to be used with router.execute() and router.removeConnection()
+ *
+ * @param {string} protocol - protocol name
+ * @param {string} connectionId - unique connection identifier
+ * @return {promise} connection context, to be used with other router functions
+ */
+ this.newConnection = function (protocol, connectionId) {
+ var error;
+
+ if (!connectionId || !protocol || typeof connectionId !== 'string' || typeof protocol !== 'string') {
+ error = new PluginImplementationError('Rejected new connection declaration: invalid arguments');
+ kuzzle.pluginsManager.trigger('log:error', error);
+ return q.reject(error);
+ }
+
+ if (!this.connections[connectionId]) {
+ this.connections[connectionId] = {
+ connection: {type: protocol, id: connectionId},
+ user: null
+ };
+ }
+
+ kuzzle.statistics.newConnection(this.connections[connectionId]);
+
+ return q(this.connections[connectionId]);
+ };
+
+ /**
+ * Called by protocol plugins: forward a received request to Kuzzle.
+ * Return a promise resolved or rejected with the corresponding ResponseObject
+ *
+ * A note about the JWT headers: if this value is falsey, if no "authorization" field is found, if the token is not
+ * properly formatted or if the token itself is invalid, then the corresponding user will automatically
+ * be set to "anonymous".
+ *
+ * @param {Object} jwtHeaders - Optional JWT headers
+ * @param {Object} requestObject - the request to execute
+ * @param {String} context - connection context, obtained using the newConnection() method
+ * @return {Promise} ResponseObject
+ */
+ this.execute = function (jwtHeaders, requestObject, context) {
+ var error;
+
+ if (!requestObject) {
+ error = new PluginImplementationError('Request execution error: no provided request');
+ kuzzle.pluginsManager.trigger('log:error', error);
+ return q.reject(new ResponseObject({}, error));
+ }
+
+ if (!context || !context.connection) {
+ error = new PluginImplementationError('Unable to execute request: ' + requestObject +
+ '\nReason: invalid context. Use context.getRouter().newConnection() to get a valid context.');
+ kuzzle.pluginsManager.trigger('log:error', error);
+ return q.reject(new ResponseObject({}, error));
+ }
+
+ if (!context.connection.id || !this.connections[context.connection.id]) {
+ error = new PluginImplementationError('Unable to execute request: unknown context. ' +
+ 'Has context.getRouter().newConnection() been called before executing requests?');
+ kuzzle.pluginsManager.trigger('log:error', error);
+ return q.reject(new ResponseObject({}, error));
+ }
+
+ return kuzzle.repositories.user.loadFromToken(getBearerTokenFromHeaders(jwtHeaders))
+ .then(user => {
+ context.user = user;
+
+ return kuzzle.funnel.execute(requestObject, context);
+ })
+ .then(response => {
+ return response;
+ })
+ .catch(e => {
+ kuzzle.pluginsManager.trigger('log:error', e);
+ return q.reject(new ResponseObject({}, e));
+ });
+ };
+
+ /**
+ * Called by protocol plugins: removes a connection from the connection pool.
+ * @param {object} context - connection context, obtained using the newConnection() method
+ */
+ this.removeConnection = function (context) {
+ if (context.connection.id && this.connections[context.connection.id]) {
+ delete this.connections[context.connection.id];
+ kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
+ kuzzle.statistics.dropConnection(context.connection);
+ }
+ else {
+ kuzzle.pluginsManager.trigger('log:error', new PluginImplementationError('Unable to remove connection: ' +
+ context + '.\nReason: unknown context'));
+ }
+ };
/**
* Initializes the HTTP routes for the Kuzzle REST API.
@@ -124,61 +223,6 @@ module.exports = function RouterController (kuzzle) {
this.router(request, response, finalhandler(request, response));
};
- /**
- * Handles requests coming from websocket connections
- *
- * @param {Object} socket client
- */
- this.routeWebsocket = function (socket) {
- var
- routerCtrl = this,
- context = {
- connection: {type: 'websocket', id: socket.id},
- user: null
- };
-
- kuzzle.statistics.newConnection(context.connection);
-
- socket.on(routerCtrl.routename, function (data) {
- var
- requestObject;
-
- requestObject = new RequestObject(data, {}, 'websocket');
-
- kuzzle.pluginsManager.trigger('log:silly', 'Handle Websocket for controller ' + data.controller);
-
- // Execute the funnel. Forward any non-empty response to the user.
- kuzzle.repositories.user.loadFromToken(getBearerTokenFromHeaders(data.headers))
- .then(function (user) {
- context.user = user;
-
- return kuzzle.funnel.execute(requestObject, context);
- })
- .then(function onExecuteSuccess (responseObject) {
- kuzzle.io.to(socket.id).emit(requestObject.requestId, responseObject.toJson());
- })
- .catch(function onExecuteError(error) {
- var errorObject = new ResponseObject({}, error);
- kuzzle.pluginsManager.trigger('log:error', error);
- kuzzle.io.to(socket.id).emit(requestObject.requestId, errorObject.toJson());
- });
- });
-
- // handles socket disconnections
- socket.on('disconnect', function () {
- kuzzle.pluginsManager.trigger('websocket:disconnect', 'A client is disconnected');
- kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
- kuzzle.statistics.dropConnection(context.connection);
- });
-
- // handles socket crashes
- socket.on('error', function (error) {
- kuzzle.pluginsManager.trigger('websocket:error', error);
- kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
- kuzzle.statistics.dropConnection(context.connection);
- });
- };
-
/**
* Handles requests coming from MQ protocols: AMQP, MQTT & STOMP
*
@@ -246,7 +290,7 @@ module.exports = function RouterController (kuzzle) {
kuzzle.services.list.mqBroker.addExchange('mqtt.' + context.connection.id, errorObject.toJson());
}
});
- }); // end listenExchange
+ });
};
};
@@ -335,7 +379,7 @@ function executeFromRest(params, request, response) {
/**
* Extract the Bearer token from the given headers
- * @param {Array} headers
+ * @param {Object} headers
* @returns {*}
*/
function getBearerTokenFromHeaders (headers) {
diff --git a/lib/api/core/errors/pluginImplementationError.js b/lib/api/core/errors/pluginImplementationError.js
new file mode 100644
index 0000000000..1129278dca
--- /dev/null
+++ b/lib/api/core/errors/pluginImplementationError.js
@@ -0,0 +1,11 @@
+var
+ inherits = require('util').inherits,
+ KuzzleError = require('./kuzzleError');
+
+function PluginImplementationError(message) {
+ KuzzleError.call(this, message + '\nThis is probably not a Kuzzle error, but a problem with a plugin implementation.', 500);
+}
+inherits(PluginImplementationError, KuzzleError);
+PluginImplementationError.prototype.name = 'PluginImplementationError';
+
+module.exports = PluginImplementationError;
diff --git a/lib/api/core/hotelClerk.js b/lib/api/core/hotelClerk.js
index d3b2ea6301..7ddd8bb532 100644
--- a/lib/api/core/hotelClerk.js
+++ b/lib/api/core/hotelClerk.js
@@ -668,12 +668,9 @@ function removeRoomForCustomer (connection, roomId) {
deferred.resolve(roomId);
- // @TODO: should call a "leave channel" method instead
- if (connection.type === 'websocket' && this.kuzzle.io.sockets.connected[connection.id]) {
- Object.keys(this.rooms[roomId].channels).forEach(channel => {
- this.kuzzle.io.sockets.connected[connection.id].leave(channel);
- });
- }
+ Object.keys(this.rooms[roomId].channels).forEach(channel => {
+ this.kuzzle.pluginsManager.trigger('protocol:leaveChannel', {channel, id: connection.id});
+ });
this.rooms[roomId].customers.splice(this.rooms[roomId].customers.indexOf(connection.id), 1);
@@ -778,27 +775,23 @@ function subscribeToRoom (roomId, requestObject, context) {
deferred = q.defer();
createChannelConfiguration(requestObject)
- .then(channel => {
- var channelName = roomId + '-' + crypto.createHash('md5').update(JSON.stringify(channel)).digest('hex');
+ .then(channel => {
+ var channelName = roomId + '-' + crypto.createHash('md5').update(JSON.stringify(channel)).digest('hex');
- if (!this.customers[connection.id] || !this.customers[connection.id][roomId]) {
- addRoomForCustomer.call(this, connection, roomId, requestObject.metadata);
-
- this.kuzzle.notifier.notify(roomId, {
- error: null,
- result: new RealTimeResponseObject(roomId, requestObject, {count: this.rooms[roomId].customers.length})
- });
- }
+ if (!this.customers[connection.id] || !this.customers[connection.id][roomId]) {
+ addRoomForCustomer.call(this, connection, roomId, requestObject.metadata);
- // @TODO: should call a "join channel" method instead
- if (connection.type === 'websocket') {
- this.kuzzle.io.sockets.connected[connection.id].join(channelName);
- }
+ this.kuzzle.notifier.notify(roomId, {
+ error: null,
+ result: new RealTimeResponseObject(roomId, requestObject, {count: this.rooms[roomId].customers.length})
+ });
+ }
- this.rooms[roomId].channels[channelName] = channel;
- deferred.resolve(new RealTimeResponseObject(roomId, requestObject, {channel: channelName}));
- })
- .catch(error => deferred.reject(error));
+ this.kuzzle.pluginsManager.trigger('protocol:joinChannel', {channel: channelName, id: connection.id});
+ this.rooms[roomId].channels[channelName] = channel;
+ deferred.resolve(new RealTimeResponseObject(roomId, requestObject, {channel: channelName}));
+ })
+ .catch(error => deferred.reject(error));
return deferred.promise;
}
diff --git a/lib/api/core/notifier.js b/lib/api/core/notifier.js
index 3f9d8368fb..a2876cc365 100644
--- a/lib/api/core/notifier.js
+++ b/lib/api/core/notifier.js
@@ -22,7 +22,6 @@ module.exports = function NotifierController (kuzzle) {
*
* @param rooms
* @param {Object} response
- * @param connection
* @returns {boolean}
*/
this.notify = function (rooms, response) {
@@ -84,11 +83,7 @@ module.exports = function NotifierController (kuzzle) {
*/
function send (room, responseObject) {
this.hotelClerk.getChannels(room, responseObject).forEach(channel => {
- // @TODO: replace with the protocol plugin broadcast functions
- if (this.io) {
- this.io.to(channel).emit(channel, responseObject);
- }
-
+ this.pluginsManager.trigger('protocol:broadcast', {channel, payload: responseObject});
this.services.list.mqBroker.addExchange(channel, responseObject);
});
}
diff --git a/lib/api/core/pluginsContext.js b/lib/api/core/pluginsContext.js
index b565aebe50..7d88269fb3 100644
--- a/lib/api/core/pluginsContext.js
+++ b/lib/api/core/pluginsContext.js
@@ -5,6 +5,7 @@ var
module.exports = function PluginContext(kuzzle) {
var
context = {
+ RequestObject: require('./models/requestObject'),
ResponseObject: require('./models/responseObject'),
RealTimeResponseObject: require('./models/realTimeResponseObject')
},
@@ -23,10 +24,18 @@ module.exports = function PluginContext(kuzzle) {
walk.walkSync(path.join(__dirname, 'errors'), options);
// Add lazy-loading repositories getter:
- context.repositories = function() {
+ context.repositories = function () {
return kuzzle.repositories;
};
+ // Add lazy-loading router getter:
+ context.getRouter = function () {
+ return {
+ newConnection: kuzzle.router.newConnection.bind(kuzzle.router),
+ execute: kuzzle.router.execute.bind(kuzzle.router),
+ removeConnection: kuzzle.router.removeConnection.bind(kuzzle.router)
+ };
+ };
return context;
};
diff --git a/lib/api/core/pluginsManager.js b/lib/api/core/pluginsManager.js
index 65d31600bf..90e68b37dc 100644
--- a/lib/api/core/pluginsManager.js
+++ b/lib/api/core/pluginsManager.js
@@ -8,60 +8,105 @@ var
path = require('path'),
_ = require('lodash'),
childProcess = require('child_process'),
- pathConfig = path.join(__dirname, '..', '..', '..', 'config');
+ pathConfig = path.join(__dirname, '..', '..', '..', 'config'),
+ lockfile = require('proper-lockfile');
-module.exports = function PluginsManager (kuzzle) {
+/*
+ We use the console to display information, as there may be no logger plugin available while installing/launching
+ plugins
+ */
+
+/*eslint-disable no-console */
+
+module.exports = function PluginsManager (kuzzle) {
this.kuzzle = kuzzle;
this.plugins = {};
this.pipes = {};
this.controllers = {};
this.routes = [];
this.isDummy = false;
+ this.isServer = false;
this.config = kuzzle.config.pluginsManager;
/**
* Initialize configured plugin in config/defaultPlugins.json and config/customPlugins.json
*
- * @param {Boolean} install, true if modules must be installed and JSON file synchronized
+ * @param {Boolean} isServer, true if this is a server instance, false for worker instances
* @param {Boolean} isDummy, true if we are trying to test pluginsManager
+ * @returns {Promise}
*/
- this.init = function (install, isDummy) {
+ this.init = function (isServer, isDummy) {
var
pathDefaultPlugins = path.join(pathConfig, 'defaultPlugins.json'),
pathCustomPlugins = path.join(pathConfig, 'customPlugins.json'),
- defaultPlugins = require(pathDefaultPlugins),
- customPlugins = {};
+ defaultPlugins,
+ updateInProgress = false,
+ customPlugins = {},
+ deferred;
this.isDummy = isDummy;
+ this.isServer = isServer;
+
+ if (this.isDummy) {
+ return q({});
+ }
if (!childProcess.hasOwnProperty('execSync')) {
- kuzzle.log.error('Make sure you\'re using Node version >= 0.12');
+ console.error('Make sure you\'re using Node version >= 0.12');
process.exit(1);
}
- if (fs.existsSync(pathCustomPlugins)) {
- customPlugins = require(pathCustomPlugins);
- }
+ deferred = q.defer();
+
+ /*
+ Prevents multiple plugin installations at the same time.
+ Delay installation for an instance only if it's installed on the same computer than another one.
+
+ Skip plugin installation if we're locked, as it means that another instance is already updating plugins
+ */
+ updateInProgress = fs.existsSync('./node_modules.lock');
- if (install) {
- if (installPlugins.call(this, defaultPlugins)) {
- fs.writeFileSync(pathDefaultPlugins, JSON.stringify(defaultPlugins, null, 2));
+ lockfile.lock('./node_modules', {retries: 1000}, (err, release) => {
+ if (err) {
+ return deferred.reject(err);
}
- if (installPlugins.call(this, customPlugins, defaultPlugins)) {
- fs.writeFileSync(pathCustomPlugins, JSON.stringify(customPlugins, null, 2));
+ defaultPlugins = require(pathDefaultPlugins);
+
+ if (fs.existsSync(pathCustomPlugins)) {
+ customPlugins = require(pathCustomPlugins);
}
- }
- this.plugins = constructList(defaultPlugins, customPlugins);
+ if (!updateInProgress) {
+ if (installPlugins.call(this, defaultPlugins)) {
+ fs.writeFileSync(pathDefaultPlugins, JSON.stringify(defaultPlugins, null, 2));
+ }
+
+ if (installPlugins.call(this, customPlugins, defaultPlugins)) {
+ fs.writeFileSync(pathCustomPlugins, JSON.stringify(customPlugins, null, 2));
+ }
+ }
+
+ release();
+
+ this.plugins = constructList(defaultPlugins, customPlugins, this.isServer);
+ loadPlugins(this.plugins);
+ deferred.resolve();
+ });
+
+ return deferred.promise;
};
/**
* Attach events hooks and pipes given by plugins
*/
this.run = function () {
- _.forEach(this.plugins, function (plugin, pluginName) {
+ if (this.isDummy) {
+ return false;
+ }
+
+ _.forEach(this.plugins, (plugin, pluginName) => {
var
context = new PluginContext(kuzzle),
pipeWarnTime = this.config.pipeWarnTime,
@@ -71,10 +116,12 @@ module.exports = function PluginsManager (kuzzle) {
return true;
}
+ console.log('Starting plugin: ', pluginName);
+
plugin.object.init(plugin.config, context, this.isDummy);
if (plugin.object.hooks) {
- _.forEach(plugin.object.hooks, function (fn, event) {
+ _.forEach(plugin.object.hooks, (fn, event) => {
if (plugin.object[fn]) {
kuzzle.on(event, function (message) {
plugin.object[fn](message, event);
@@ -91,7 +138,7 @@ module.exports = function PluginsManager (kuzzle) {
pipeTimeout = plugin.config.pipeTimeout;
}
- _.forEach(plugin.object.pipes, function (fn, pipe) {
+ _.forEach(plugin.object.pipes, (fn, pipe) => {
if (plugin.object[fn]) {
if (!this.pipes[pipe]) {
this.pipes[pipe] = [];
@@ -129,26 +176,27 @@ module.exports = function PluginsManager (kuzzle) {
});
});
}
- }.bind(this));
+ });
}
if (plugin.object.controllers) {
- _.forEach(plugin.object.controllers, function (controller, controllerName) {
+ _.forEach(plugin.object.controllers, (controller, controllerName) => {
if (plugin.object[controller]) {
this.controllers[pluginName+'/'+controllerName] = plugin.object[controller];
}
- }.bind(this));
+ });
}
if (plugin.object.routes) {
- async.each(plugin.object.routes, function (route) {
+ async.each(plugin.object.routes, route => {
route.url = '/_plugin/'+pluginName+route.url;
route.controller = pluginName+'/'+route.controller;
this.routes.push(route);
- }.bind(this));
+ });
}
- }.bind(this));
+ console.log('Plugin ' + pluginName + ' started');
+ });
};
/**
@@ -161,13 +209,13 @@ module.exports = function PluginsManager (kuzzle) {
this.trigger = function (event, data) {
if (this.isDummy) {
this.kuzzle.emit(event, data);
- return Promise.resolve(data);
+ return q(data);
}
return triggerPipes.call(this, event, data)
- .then(function (modifiedData) {
+ .then(modifiedData => {
return triggerHooks.call(this, event, modifiedData);
- }.bind(this));
+ });
};
/**
@@ -189,7 +237,7 @@ module.exports = function PluginsManager (kuzzle) {
function triggerHooks(event, data) {
this.kuzzle.emit(event, data);
- return Promise.resolve(data);
+ return q(data);
}
/**
@@ -249,7 +297,7 @@ function installPlugins(plugins, basePlugins) {
newInstalled = false,
pluginInstallId;
- _.forEach(plugins, function (plugin, name) {
+ _.forEach(plugins, (plugin, name) => {
if (plugin.url) {
pluginInstallId = plugin.url;
}
@@ -257,7 +305,7 @@ function installPlugins(plugins, basePlugins) {
pluginInstallId = name + '@' + plugin.version;
}
else {
- this.kuzzle.log.error('Plugin', name, 'has no version. The version is mandatory if there is no URL.');
+ console.error('Plugin', name, 'has no version. The version is mandatory if there is no URL.');
return true;
}
@@ -265,8 +313,6 @@ function installPlugins(plugins, basePlugins) {
return true;
}
- this.kuzzle.log.info('Install plugin ' + name);
-
newInstalled = true;
npmInstall(pluginInstallId);
initConfig.call(this, plugin, name);
@@ -276,26 +322,24 @@ function installPlugins(plugins, basePlugins) {
if (plugin.activated === undefined) {
plugin.activated = (basePlugins !== undefined && basePlugins[name] && basePlugins[name].activated === true);
}
-
- }.bind(this));
+ });
return newInstalled;
}
-function constructList(defaultPlugins, customPlugins, withoutObject) {
+function constructList(defaultPlugins, customPlugins, isServer) {
var
- allPlugins = _.extend(defaultPlugins, customPlugins);
+ allPlugins = _.extend(defaultPlugins, customPlugins),
+ pluginsList = {};
+ // Load plugins configuration
_.forEach(allPlugins, function (plugin, name) {
if (!plugin.name) {
plugin.name = name;
}
- if (!withoutObject) {
- plugin.object = new (require(name))();
- }
-
if (!plugin.defaultConfig && !plugin.customConfig) {
+ plugin.config = {};
return true;
}
@@ -317,7 +361,22 @@ function constructList(defaultPlugins, customPlugins, withoutObject) {
delete plugin.customConfig;
});
- return allPlugins;
+
+ /*
+ Plugins can be loaded by servers or workers. The "loadedBy" property tells by what type of kuzzle instance
+ the plugin should be loaded.
+ Accepted values: all, server, worker
+ Default value: all
+ */
+ _.forEach(allPlugins, (plugin, name) => {
+ if (plugin.config.loadedBy && plugin.config.loadedBy !== 'all' && (plugin.config.loadedBy === 'server') !== isServer) {
+ return true;
+ }
+
+ pluginsList[name] = plugin;
+ });
+
+ return pluginsList;
}
/**
@@ -350,7 +409,7 @@ function initConfig(plugin, name) {
pluginPackage = require(path.join(getPathPlugin(name), 'package.json'));
}
catch (e) {
- this.kuzzle.log.error(new InternalError('There is a problem with plugin ' + name + '. Check the plugin name'));
+ console.error(new InternalError('There is a problem with plugin ' + name + '. Check the plugin name'));
}
// If there is no information about plugin in the package.json
@@ -401,6 +460,14 @@ function needInstall(name, from) {
* @param name
* @returns {String}
*/
-function getPathPlugin(name) {
+function getPathPlugin (name) {
return path.join(__dirname, '..', '..', '..', 'node_modules', name);
}
+
+function loadPlugins(plugins) {
+ _.forEach(plugins, (plugin, name) => {
+ plugin.object = new (require(name))();
+ });
+}
+
+/*eslint-enable no-console */
diff --git a/lib/api/core/servers.js b/lib/api/core/servers.js
index 4028f9679a..f738146636 100644
--- a/lib/api/core/servers.js
+++ b/lib/api/core/servers.js
@@ -4,10 +4,7 @@ var
module.exports = {
initAll: function (kuzzle, params) {
- var server;
-
- server = runHttpServer(kuzzle, params);
- runWebsocketServer(server, kuzzle, params);
+ runHttpServer(kuzzle, params);
runMQListener(kuzzle, params);
}
};
@@ -19,7 +16,7 @@ module.exports = {
*/
function runHttpServer (kuzzle, params) {
var
- port = process.env.KUZZLE_PORT || params.port || 7512,
+ port = process.env.KUZZLE_PORT || params.port || 7511,
server;
kuzzle.router.initRouterHttp();
@@ -34,22 +31,6 @@ function runHttpServer (kuzzle, params) {
return server;
}
-/**
- * Run a websocket server forwarding requests to the router controller
- * @param server
- * @param kuzzle
- */
-function runWebsocketServer (server, kuzzle) {
- kuzzle.io = require('socket.io')(server);
- kuzzle.io.set('origins', '*:*');
-
- kuzzle.io.on('connection', function (socket) {
- kuzzle.router.routeWebsocket(socket);
- });
-
- kuzzle.pluginsManager.trigger('server:websocketStarted', 'Starting: WebSocket server');
-}
-
/**
* Asks the router controller to start listening to messages coming from RabbitMQ
* @param kuzzle
diff --git a/lib/api/prepareDb.js b/lib/api/prepareDb.js
index 7ff64fdbfc..2651e20aa3 100644
--- a/lib/api/prepareDb.js
+++ b/lib/api/prepareDb.js
@@ -116,15 +116,12 @@ function importFixtures() {
this.pluginsManager.trigger('log:info', '== Importing fixtures for collection ' + collection + '...');
this.services.list.writeEngine.import(new RequestObject(fixture))
- .then(function () {
- callback();
- })
- .catch(function (error) {
+ .then(() => callback())
+ .catch(error => {
+ this.pluginsManager.trigger('log:error', 'Fixture import error' + error);
callback('Fixture import error' + error);
});
- }, function (error) {
- callbackIndex(error);
- });
+ }, error => callbackIndex(error));
}, error => {
if (error) {
deferred.reject(error);
diff --git a/lib/api/start.js b/lib/api/start.js
index 25c7f11be0..549a226ac6 100644
--- a/lib/api/start.js
+++ b/lib/api/start.js
@@ -55,67 +55,70 @@ module.exports = function start (params, feature) {
this.config.version = packageInfo.version;
this.pluginsManager = new PluginsManager(this);
- this.pluginsManager.init(this.isServer, feature.dummy);
- this.pluginsManager.run();
-
- if (!this.isWorker) {
- if (!feature.dummy) {
- this.services.init({server: true});
-
- this.services.list.readEngine.listIndexes(new RequestObject({}))
- .then(result => {
- result.data.indexes.forEach(index => {
- this.indexes[index] = [];
-
- this.services.list.readEngine.listCollections(new RequestObject({index: index}))
- .then(resultCollections => {
- this.indexes[index] = resultCollections.data.collections;
+ this.pluginsManager.init(this.isServer, feature.dummy)
+ .then(() => {
+ this.pluginsManager.run();
+
+ if (!this.isWorker) {
+ if (!feature.dummy) {
+ this.services.init({server: true});
+
+ this.services.list.readEngine.listIndexes(new RequestObject({}))
+ .then(result => {
+ result.data.indexes.forEach(index => {
+ this.indexes[index] = [];
+
+ this.services.list.readEngine.listCollections(new RequestObject({index: index}))
+ .then(resultCollections => {
+ this.indexes[index] = resultCollections.data.collections;
+ });
});
- });
- });
- }
- else {
- this.services.init({server: false, blacklist: ['mqBroker', 'perf', 'writeEngine', 'readEngine', 'notificationCache', 'monitoring', 'remoteActions', 'statsCache']});
- }
+ });
+ }
+ else {
+ this.services.init({server: false, blacklist: ['mqBroker', 'perf', 'writeEngine', 'readEngine', 'notificationCache', 'monitoring', 'remoteActions', 'statsCache']});
+ }
- // The funnel controller dispatch messages between the router controller and other controllers
- this.funnel = new FunnelController(this);
- this.funnel.init();
+ // The funnel controller dispatch messages between the router controller and other controllers
+ this.funnel = new FunnelController(this);
+ this.funnel.init();
- // The router controller listens to client requests and pass them to the funnel controller
- this.router = new RouterController(this);
+ // The router controller listens to client requests and pass them to the funnel controller
+ this.router = new RouterController(this);
- // Room subscriptions core components
- this.hotelClerk = new HotelClerk(this);
- this.dsl = new Dsl(this);
+ // Room subscriptions core components
+ this.hotelClerk = new HotelClerk(this);
+ this.dsl = new Dsl(this);
- // Notifications core component
- this.notifier = new Notifier(this);
- this.notifier.init();
+ // Notifications core component
+ this.notifier = new Notifier(this);
+ this.notifier.init();
- // Statistics core component
- this.statistics = new Statistics(this);
+ // Statistics core component
+ this.statistics = new Statistics(this);
- // Worker response listener
- this.workerListener = new WorkerListener(this, this.config.queues.workerWriteResponseQueue);
+ // Worker response listener
+ this.workerListener = new WorkerListener(this, this.config.queues.workerWriteResponseQueue);
- if (!feature.dummy) {
- // Initialize hooks
- this.hooks.init();
+ if (!feature.dummy) {
+ // Initialize hooks
+ this.hooks.init();
- // Starts the servers in charge of listening to client queries (HTTP, MQ or WebSocket)
- servers.initAll(this, params);
- }
- }
+ // Starts the servers in charge of listening to client queries (HTTP, MQ or WebSocket)
+ servers.initAll(this, params);
+ }
+ }
- // Start a single set of workers
- if (this.isWorker === undefined || this.isWorker === true) {
- this.workers.init();
- }
+ // Start a single set of workers
+ if (this.isWorker === undefined || this.isWorker === true) {
+ this.workers.init();
+ }
- // the repositories need to be instanciated after the services are initialized
- this.repositories = require('./core/models/repositories')(this);
+ // the repositories need to be instanciated after the services are initialized
+ this.repositories = require('./core/models/repositories')(this);
+ kuzzleStarted.resolve({});
+ })
+ .catch(err => kuzzleStarted.reject(err));
- kuzzleStarted.resolve({});
return kuzzleStarted.promise;
};
diff --git a/lib/services/newrelic.js b/lib/services/newrelic.js
index 1eb2bc73fb..2da413282d 100644
--- a/lib/services/newrelic.js
+++ b/lib/services/newrelic.js
@@ -20,7 +20,7 @@ module.exports = function (kuzzle) {
this.kuzzle.hooks.add(controller+':websocket:start', 'monitoring:logWs');
}.bind(this));
- this.kuzzle.log('Monitoring service is enabled');
+ this.kuzzle.pluginsManager.trigger('log:info', 'Monitoring service is enabled');
};
/**
diff --git a/package.json b/package.json
index 35017be853..63077b1fef 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
"enable": "node bin/kuzzle enable",
"disable": "node bin/kuzzle disable",
"preversion": "git checkout master && git pull",
- "postversion": "git push && git push --tags"
+ "postversion": "git push && git push --tags"
},
"directories": {
"lib": "lib"
@@ -43,14 +43,13 @@
"node-uuid": "1.4.3",
"passport": "0.3.2",
"portfinder": "^0.4.0",
+ "proper-lockfile": "^1.1.1",
"q": "2.0.3",
"rc": "1.1.2",
"redis": "2.3.0",
"request-promise": "1.0.2",
"router": "1.1.3",
- "socket.io": "1.3.7",
"walk": "2.3.9",
- "winston": "2.0.0",
"ws": "0.8.0"
},
"repository": {
diff --git a/test/api/controllers/adminController.test.js b/test/api/controllers/adminController.test.js
index 17fafc540b..bac5d58e5e 100644
--- a/test/api/controllers/adminController.test.js
+++ b/test/api/controllers/adminController.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
@@ -15,7 +14,6 @@ describe('Test: admin controller', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.repositories.role.validateAndSaveRole = role => {
diff --git a/test/api/controllers/authController.test.js b/test/api/controllers/authController.test.js
index 5058a10b3d..c48bc108c8 100644
--- a/test/api/controllers/authController.test.js
+++ b/test/api/controllers/authController.test.js
@@ -2,7 +2,6 @@ var
should = require('should'),
jwt = require('jsonwebtoken'),
q = require('q'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
passport = require('passport'),
util = require('util'),
@@ -64,7 +63,6 @@ describe('Test the auth controller', function () {
before(function (done) {
requestObject = new RequestObject({ controller: 'auth', action: 'login', body: {strategy: 'mockup', username: 'jdoe'} }, {}, 'unit-test');
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
passport.use(new MockupStrategy( 'mockup', function(username, callback) {
diff --git a/test/api/controllers/bulkController.test.js b/test/api/controllers/bulkController.test.js
index 12809b76cd..ed68f1cfef 100644
--- a/test/api/controllers/bulkController.test.js
+++ b/test/api/controllers/bulkController.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
RequestObject = require.main.require('lib/api/core/models/requestObject');
@@ -12,13 +11,9 @@ describe('Test the bulk controller', function () {
kuzzle,
requestObject = new RequestObject({ controller: 'bulk' }, { collection: 'unit-test-bulkController' }, 'unit-test');
- before(function (done) {
+ before(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
- kuzzle.start(params, {dummy: true})
- .then(function () {
- done();
- });
+ return kuzzle.start(params, {dummy: true});
});
it('should activate a hook on a bulk import request', function (done) {
diff --git a/test/api/controllers/funnelController/execute.test.js b/test/api/controllers/funnelController/execute.test.js
index 1eef6334b6..6b77ed3dfe 100644
--- a/test/api/controllers/funnelController/execute.test.js
+++ b/test/api/controllers/funnelController/execute.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
UnauthorizedError = require.main.require('lib/api/core/errors/unauthorizedError'),
params = require('rc')('kuzzle'),
@@ -22,7 +21,6 @@ describe('Test execute function in funnel controller', function () {
beforeEach(function (callback) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
kuzzle.start(params, {dummy: true})
.then(function () {
diff --git a/test/api/controllers/readController.test.js b/test/api/controllers/readController.test.js
index 081984e17d..398749b16c 100644
--- a/test/api/controllers/readController.test.js
+++ b/test/api/controllers/readController.test.js
@@ -1,7 +1,6 @@
var
should = require('should'),
q = require('q'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
BadRequestError = require.main.require('lib/api/core/errors/badRequestError'),
@@ -21,7 +20,6 @@ var
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.services.list.readEngine = {
diff --git a/test/api/controllers/routerController/executeFromRest.test.js b/test/api/controllers/routerController/executeFromRest.test.js
index e1e06a4907..2a7c139b93 100644
--- a/test/api/controllers/routerController/executeFromRest.test.js
+++ b/test/api/controllers/routerController/executeFromRest.test.js
@@ -5,7 +5,6 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
q = require('q'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -62,8 +61,6 @@ describe('Test: routerController.executeFromRest', function () {
};
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
-
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.funnel.execute = mockupFunnel;
diff --git a/test/api/controllers/routerController/initRouterHttp.test.js b/test/api/controllers/routerController/initRouterHttp.test.js
index ddbf1262dd..94d2c72eba 100644
--- a/test/api/controllers/routerController/initRouterHttp.test.js
+++ b/test/api/controllers/routerController/initRouterHttp.test.js
@@ -5,7 +5,6 @@
var
should = require('should'),
- winston = require('winston'),
http = require('http'),
q = require('q'),
params = require('rc')('kuzzle'),
@@ -68,7 +67,6 @@ describe('Test: routerController.initRouterHttp', function () {
*/
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
var mockResponse = function (params, request, response) {
if (!params.action) {
diff --git a/test/api/controllers/routerController/routeMQListener.test.js b/test/api/controllers/routerController/routeMQListener.test.js
index 6ef1d966a9..9913210f13 100644
--- a/test/api/controllers/routerController/routeMQListener.test.js
+++ b/test/api/controllers/routerController/routeMQListener.test.js
@@ -5,7 +5,6 @@
var
should = require('should'),
- winston = require('winston'),
q = require('q'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -54,7 +53,6 @@ describe('Test: routerController.routeMQListener', function () {
};
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
diff --git a/test/api/controllers/routerController/routeWebsocket.test.js b/test/api/controllers/routerController/routeWebsocket.test.js
deleted file mode 100644
index 4800676854..0000000000
--- a/test/api/controllers/routerController/routeWebsocket.test.js
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * This file tests the routeWebsocket function, which handles websockets
- * connections, listens to requests and forward them to the funnel controller.
- *
- * Since this function only controls events received by the socket passed as
- * an argument, we'll use a simple event emitter to test its behavior
- */
-
-var
- should = require('should'),
- winston = require('winston'),
- params = require('rc')('kuzzle'),
- EventEmitter = require('events').EventEmitter,
- Kuzzle = require.main.require('lib/api/Kuzzle'),
- rewire = require('rewire'),
- RouterController = rewire('../../../../lib/api/controllers/routerController'),
- RequestObject = require.main.require('lib/api/core/models/requestObject'),
- ResponseObject = require.main.require('lib/api/core/models/responseObject');
-
-
-require('should-promised');
-
-describe('Test: routerController.routeWebsocket', function () {
- var
- kuzzle,
- router,
- messageSent,
- emitter = new EventEmitter(),
- forwardedObject = {},
- timer,
- timeout = 500;
-
- before(function (done) {
- var
- mockupFunnel = function (requestObject) {
- forwardedObject = new ResponseObject(requestObject, {});
-
- if (requestObject.data.body.resolve) {
- if (requestObject.data.body.empty) {
- return Promise.resolve({});
- }
- else {
- return Promise.resolve(forwardedObject);
- }
- }
- else {
- return Promise.reject(new Error('rejected'));
- }
- };
-
- kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
-
- kuzzle.start(params, {dummy: true})
- .then(function () {
- kuzzle.funnel.execute = mockupFunnel;
- kuzzle.io = {
- emit: () => messageSent = true,
- to: () => { return kuzzle.io; }
- };
- router = new RouterController(kuzzle);
- router.routeWebsocket(emitter);
- done();
- });
- });
-
- beforeEach(function () {
- messageSent = false;
- forwardedObject = false;
- });
-
- it('should have registered a global listener', function () {
- should(emitter.listeners(router.routename).length).be.exactly(1);
- });
-
- it('should embed incoming requests into a well-formed request object', function (done) {
- var emittedObject = {body: {resolve: true}, controller: 'read', action: 'get'};
-
- emitter.emit(router.routename, emittedObject);
-
- this.timeout(timeout);
- timer = setInterval(function () {
- if (forwardedObject === false) {
- return;
- }
-
- try {
- should(forwardedObject.data.body).not.be.null();
- should(forwardedObject.data.body).be.exactly(emittedObject.body);
- should(forwardedObject.protocol).be.exactly('websocket');
- should(forwardedObject.controller).be.exactly('read');
- should(forwardedObject.action).be.exactly('get');
- should(messageSent).be.true();
- done();
- }
- catch (e) {
- done(e);
- }
-
- clearInterval(timer);
- timer = false;
- }, 5);
- });
-
- it('should notify with an error object in case of rejection', function (done) {
- var
- emittedObject = {body: {resolve: false}, controller: 'read', action: 'get'},
- eventReceived = false;
-
- kuzzle.once('log:error', () => eventReceived = true);
- emitter.emit(router.routename, emittedObject);
-
- this.timeout(timeout);
- timer = setInterval(function () {
- if (forwardedObject === false) {
- return;
- }
-
- try {
- should(messageSent).be.true();
- should(eventReceived).be.true();
- done();
- }
- catch (e) {
- done(e);
- }
-
- clearInterval(timer);
- timer = false;
- }, 5);
- });
-
- it('should handle sockets clean disconnection', function (done) {
- var
- removeCustomers = false,
- hasListener;
-
- this.timeout(50);
-
- kuzzle.hotelClerk.removeCustomerFromAllRooms = function () {
- removeCustomers = true;
- };
-
- kuzzle.once('websocket:disconnect', function () {
- done();
- });
-
- hasListener = emitter.emit('disconnect');
-
- should(hasListener).be.true();
- should(removeCustomers).be.true();
- });
-
- it('should handle sockets crashes', function (done) {
- var
- removeCustomers = false,
- hasListener;
-
- this.timeout(50);
-
- kuzzle.hotelClerk.removeCustomerFromAllRooms = function () {
- removeCustomers = true;
- };
-
- kuzzle.once('websocket:error', function () {
- done();
- });
-
- hasListener = emitter.emit('error');
-
- should(hasListener).be.true();
- should(removeCustomers).be.true();
- });
-});
diff --git a/test/api/controllers/routerController/routerController.test.js b/test/api/controllers/routerController/routerController.test.js
index a7b1c208a8..dde9dcc991 100644
--- a/test/api/controllers/routerController/routerController.test.js
+++ b/test/api/controllers/routerController/routerController.test.js
@@ -1,13 +1,21 @@
var
should = require('should'),
+ params = require('rc')('kuzzle'),
+ Kuzzle = require.main.require('lib/api/Kuzzle'),
rewire = require('rewire'),
- RouterController = rewire('../../../../lib/api/controllers/routerController');
+ q = require('q'),
+ RouterController = rewire('../../../../lib/api/controllers/routerController'),
+ RequestObject = require.main.require('lib/api/core/models/requestObject'),
+ ResponseObject = require.main.require('lib/api/core/models/responseObject'),
+ PluginImplementationError = require.main.require('lib/api/core/errors/pluginImplementationError');
-describe('Test: routerController', () => {
- var
- getBearerTokenFromHeader = RouterController.__get__('getBearerTokenFromHeaders');
+require('should-promised');
+describe('Test: routerController', () => {
describe('#getBearerTokenFromHeaders', () => {
+ var
+ getBearerTokenFromHeader = RouterController.__get__('getBearerTokenFromHeaders');
+
it('should extract the bearer token from the header', () => {
var result = getBearerTokenFromHeader({
authorization: 'Bearer sometoken'
@@ -16,4 +24,159 @@ describe('Test: routerController', () => {
should(result).be.exactly('sometoken');
});
});
+
+ describe('#newConnection', () => {
+ var
+ kuzzle,
+ protocol = 'foo',
+ userId = 'bar';
+
+ before(() => {
+ kuzzle = new Kuzzle();
+ return kuzzle.start(params, {dummy: true});
+ });
+
+ it('should return a promise', () => {
+ return should(kuzzle.router.newConnection(protocol, userId)).be.fulfilled();
+ });
+
+ it('should have registered the connection', () => {
+ var context = kuzzle.router.connections[userId];
+ should(context).be.an.Object();
+ should(context.connection).be.an.Object();
+ should(context.connection.id).be.eql(userId);
+ should(context.connection.type).be.eql(protocol);
+ should(context.user).be.null();
+ });
+
+ it('should declare a new connection to the statistics core component', () => {
+ var
+ newConnectionDeclared = false;
+
+ kuzzle.statistics.newConnection = context => {
+ should(context).be.an.Object();
+ should(context.connection).be.an.Object();
+ should(context.connection.id).be.eql(userId);
+ should(context.connection.type).be.eql(protocol);
+ should(context.user).be.null();
+ newConnectionDeclared = true;
+ };
+
+ kuzzle.router.newConnection(protocol, userId);
+ should(newConnectionDeclared).be.true();
+ });
+
+ it('should return an error if no user ID is provided', () => {
+ return should(kuzzle.router.newConnection(protocol, undefined)).be.rejectedWith(PluginImplementationError);
+ });
+
+ it('should return an error if no protocol is provided', () => {
+ return should(kuzzle.router.newConnection(undefined, userId)).be.rejectedWith(PluginImplementationError);
+ });
+ });
+
+ describe('#execute', () => {
+ var
+ kuzzle,
+ context,
+ requestObject = new RequestObject({
+ controller: 'read',
+ action: 'now'
+ });
+
+ before((done) => {
+ kuzzle = new Kuzzle();
+ kuzzle.start(params, {dummy: true})
+ .then(() => {
+ return kuzzle.router.newConnection('foo', 'bar');
+ })
+ .then(res => {
+ context = res;
+ done();
+ })
+ .catch(error => done(error));
+ });
+
+ it('should return a fulfilled promise with the right arguments', () => {
+ return should(kuzzle.router.execute(undefined, requestObject, context)).be.fulfilled();
+ });
+
+ it('should return an error if no request object is provided', () => {
+ return should(kuzzle.router.execute(undefined, undefined, context)).be.rejectedWith(ResponseObject);
+ });
+
+ it('should return an error if an invalid context is provided', () => {
+ return should(kuzzle.router.execute(undefined, requestObject, {})).be.rejectedWith(ResponseObject);
+ });
+
+ it('should return an error if an invalid context ID is provided', () => {
+ var
+ invalidContext = {
+ connection: {
+ id: 'hey',
+ type: 'jude'
+ }
+ };
+ return should(kuzzle.router.execute(undefined, requestObject, invalidContext)).be.rejectedWith(ResponseObject);
+ });
+
+ it('should forward any error that occured during execution back to the protocol plugin', () => {
+ kuzzle.funnel.execute = () => { return q.reject(new Error('rejected')); };
+
+ return should(kuzzle.router.execute(undefined, requestObject, context)).be.rejectedWith(ResponseObject);
+ });
+ });
+
+ describe('#removeConnection', () => {
+ var
+ kuzzle,
+ context;
+
+ beforeEach((done) => {
+ kuzzle = new Kuzzle();
+ kuzzle.start(params, {dummy: true})
+ .then(() => {
+ return kuzzle.router.newConnection('foo', 'bar');
+ })
+ .then(res => {
+ context = res;
+ done();
+ })
+ .catch(error => done(error));
+ });
+
+ it('should remove the context from the context pool', () => {
+ var
+ unsubscribed = false,
+ loggedStats = false;
+
+ kuzzle.hotelClerk.removeCustomerFromAllRooms = connection => {
+ should(connection).be.an.Object().and.be.eql(context.connection);
+ unsubscribed = true;
+ };
+
+ kuzzle.statistics.dropConnection = connection => {
+ should(connection).be.an.Object().and.be.eql(context.connection);
+ loggedStats = true;
+ };
+
+ kuzzle.router.removeConnection(context);
+ should(kuzzle.router.connections).be.empty();
+ should(unsubscribed).be.true();
+ should(loggedStats).be.true();
+ });
+
+ it('should trigger a log:error hook if the context is unknown', function (done) {
+ var
+ fakeContext = {
+ connection: { id: 'Madness? No.', type: 'THIS IS SPARTAAAAAAA!'},
+ user: null
+ };
+
+ this.timeout(50);
+
+ kuzzle.once('log:error', () => done());
+ kuzzle.router.removeConnection(fakeContext);
+ });
+ });
});
diff --git a/test/api/controllers/subscribeController.test.js b/test/api/controllers/subscribeController.test.js
index ff08ede5bd..2981c94ea6 100644
--- a/test/api/controllers/subscribeController.test.js
+++ b/test/api/controllers/subscribeController.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
@@ -25,7 +24,6 @@ describe('Test: subscribe controller', function () {
before(function (done) {
context = {};
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.repositories.role.roles.guest = new Role();
diff --git a/test/api/controllers/writeController.test.js b/test/api/controllers/writeController.test.js
index 9a3bf558b7..ddf5ba0764 100644
--- a/test/api/controllers/writeController.test.js
+++ b/test/api/controllers/writeController.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
RequestObject = require.main.require('lib/api/core/models/requestObject');
@@ -17,7 +16,6 @@ describe('Test: write controller', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.services.list.writeEngine = {};
diff --git a/test/api/core/hotelClerck/addSubscription.test.js b/test/api/core/hotelClerck/addSubscription.test.js
index 4613d4021b..ec517b1af3 100644
--- a/test/api/core/hotelClerck/addSubscription.test.js
+++ b/test/api/core/hotelClerck/addSubscription.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
InternalError = require.main.require('lib/api/core/errors/internalError'),
BadRequestError = require.main.require('lib/api/core/errors/badRequestError'),
@@ -34,7 +33,6 @@ describe('Test: hotelClerk.addSubscription', function () {
beforeEach(function (done) {
require.cache = {};
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
return kuzzle.start(params, {dummy: true})
@@ -115,36 +113,24 @@ describe('Test: hotelClerk.addSubscription', function () {
});
});
- it('should call a function join when the type is websocket', function () {
- var
- joinedRooms = [],
- requestObject = new RequestObject({
- controller: 'subscribe',
- collection: collection,
- index: index,
- body: filter
- });
+ it('should trigger a protocol:joinChannel hook', function (done) {
+ var requestObject = new RequestObject({
+ controller: 'subscribe',
+ collection: collection,
+ index: index,
+ body: filter
+ });
- // mockup internal function kuzzle called when type is websocket
- connection.type = 'websocket';
- kuzzle.io = {
- sockets: {
- connected: {
- connectionid: {
- join: function (channel) {
- joinedRooms.push(channel);
- }
- }
- }
- }
- };
- kuzzle.notifier = {notify: function () {}};
+ this.timeout(50);
- return kuzzle.hotelClerk.addSubscription(requestObject, context)
- .then(function () {
- should(joinedRooms).containEql(channel);
- delete connection.type;
- });
+ kuzzle.once('protocol:joinChannel', (data) => {
+ should(data).be.an.Object();
+ should(data.channel).be.a.String();
+ should(data.id).be.eql(context.connection.id);
+ done();
+ });
+
+ kuzzle.hotelClerk.addSubscription(requestObject, context);
});
it('should return the same response when the user has already subscribed to the filter', done => {
diff --git a/test/api/core/hotelClerck/countSubscription.test.js b/test/api/core/hotelClerck/countSubscription.test.js
index 6bc69386fe..3fee14bb5c 100644
--- a/test/api/core/hotelClerck/countSubscription.test.js
+++ b/test/api/core/hotelClerck/countSubscription.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -18,7 +17,6 @@ describe('Test: hotelClerk.countSubscription', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
return kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.repositories.role.roles.guest = new Role();
diff --git a/test/api/core/hotelClerck/getChannels.test.js b/test/api/core/hotelClerck/getChannels.test.js
index 8b9403d71e..94e4f1f508 100644
--- a/test/api/core/hotelClerck/getChannels.test.js
+++ b/test/api/core/hotelClerck/getChannels.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
ResponseObject = require.main.require('lib/api/core/models/responseObject'),
params = require('rc')('kuzzle'),
@@ -37,7 +36,6 @@ describe('Test: hotelClerk.getChannels', function () {
beforeEach(function () {
responseObject = new ResponseObject(new RequestObject({collection: 'foo', body: dataGrace}));
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
return kuzzle.start(params, {dummy: true});
diff --git a/test/api/core/hotelClerck/getRealtimeCollections.test.js b/test/api/core/hotelClerck/getRealtimeCollections.test.js
index 85f22bb7e4..84545ad593 100644
--- a/test/api/core/hotelClerck/getRealtimeCollections.test.js
+++ b/test/api/core/hotelClerck/getRealtimeCollections.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
@@ -12,8 +11,6 @@ describe('Test: hotelClerk.getRealtimeCollections', function () {
beforeEach(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
-
return kuzzle.start(params, {dummy: true});
});
diff --git a/test/api/core/hotelClerck/listSubscriptions.test.js b/test/api/core/hotelClerck/listSubscriptions.test.js
index 79e51a9967..730292f57f 100644
--- a/test/api/core/hotelClerck/listSubscriptions.test.js
+++ b/test/api/core/hotelClerck/listSubscriptions.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -31,7 +30,6 @@ describe('Test: hotelClerk.addSubscription', function () {
beforeEach(function (done) {
require.cache = {};
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
return kuzzle.start(params, {dummy: true})
diff --git a/test/api/core/hotelClerck/removeAllRooms.test.js b/test/api/core/hotelClerck/removeAllRooms.test.js
index 03722bc51c..15e44844be 100644
--- a/test/api/core/hotelClerck/removeAllRooms.test.js
+++ b/test/api/core/hotelClerck/removeAllRooms.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
BadRequestError = require.main.require('lib/api/core/errors/badRequestError'),
NotFoundError = require.main.require('lib/api/core/errors/notFoundError'),
@@ -37,7 +36,6 @@ describe('Test: hotelClerk.removeRooms', function () {
beforeEach(function (done) {
require.cache = {};
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
return kuzzle.start(params, {dummy: true})
diff --git a/test/api/core/hotelClerck/removeCustomerFromAllRooms.test.js b/test/api/core/hotelClerck/removeCustomerFromAllRooms.test.js
index b0d0ce0c61..72c433a003 100644
--- a/test/api/core/hotelClerck/removeCustomerFromAllRooms.test.js
+++ b/test/api/core/hotelClerck/removeCustomerFromAllRooms.test.js
@@ -1,7 +1,6 @@
var
should = require('should'),
q = require('q'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -42,7 +41,6 @@ describe('Test: hotelClerk.removeCustomerFromAllRooms', function () {
beforeEach(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
kuzzle.start(params, {dummy: true})
.then(function () {
diff --git a/test/api/core/hotelClerck/removeSubscription.test.js b/test/api/core/hotelClerck/removeSubscription.test.js
index 5844057e9d..d4979dd21f 100644
--- a/test/api/core/hotelClerck/removeSubscription.test.js
+++ b/test/api/core/hotelClerck/removeSubscription.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -62,7 +61,6 @@ describe('Test: hotelClerk.removeSubscription', function () {
beforeEach(function (done) {
notified = null;
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
kuzzle.start(params, {dummy: true})
.then(function () {
@@ -179,27 +177,16 @@ describe('Test: hotelClerk.removeSubscription', function () {
});
});
- it('should call a function leave when the type is websocket', function () {
- var leavedRooms = [];
-
- connection.type = 'websocket';
- kuzzle.io = {
- sockets: {
- connected: {
- connectionid: {
- leave: function (channel) {
- leavedRooms.push(channel);
- }
- }
- }
- }
- };
- kuzzle.notifier = {notify: function () {}};
+ it('should trigger a protocol:leaveChannel hook', function (done) {
+ this.timeout(50);
- return kuzzle.hotelClerk.removeSubscription(unsubscribeRequest, context)
- .then(function () {
- should(leavedRooms).containEql(channel);
- delete connection.type;
- });
+ kuzzle.once('protocol:leaveChannel', (data) => {
+ should(data).be.an.Object();
+ should(data.channel).be.a.String();
+ should(data.id).be.eql(context.connection.id);
+ done();
+ });
+
+ kuzzle.hotelClerk.removeSubscription(unsubscribeRequest, context);
});
});
diff --git a/test/api/core/models/realTimeResponseObject.test.js b/test/api/core/models/realTimeResponseObject.test.js
index 2ef7befd2e..b776b0bfd2 100644
--- a/test/api/core/models/realTimeResponseObject.test.js
+++ b/test/api/core/models/realTimeResponseObject.test.js
@@ -3,7 +3,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
uuid = require('node-uuid'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
diff --git a/test/api/core/models/requestObject.test.js b/test/api/core/models/requestObject.test.js
index 42d1cac76e..9cfe9bccd1 100644
--- a/test/api/core/models/requestObject.test.js
+++ b/test/api/core/models/requestObject.test.js
@@ -3,7 +3,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
uuid = require('node-uuid'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
diff --git a/test/api/core/models/responseObject.test.js b/test/api/core/models/responseObject.test.js
index 7737181ed9..e7092590bd 100644
--- a/test/api/core/models/responseObject.test.js
+++ b/test/api/core/models/responseObject.test.js
@@ -4,7 +4,6 @@
var
should = require('should'),
async = require('async'),
- winston = require('winston'),
rewire = require('rewire'),
uuid = require('node-uuid'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
diff --git a/test/api/core/notifier/checkNewRoutes.test.js b/test/api/core/notifier/checkNewRoutes.test.js
index 4f70278e32..4893f2b54a 100644
--- a/test/api/core/notifier/checkNewRoutes.test.js
+++ b/test/api/core/notifier/checkNewRoutes.test.js
@@ -6,7 +6,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
_ = require('lodash'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
@@ -50,8 +49,6 @@ describe('Test: notifier.checkNewRoutes', function () {
before(function () {
kuzzle = new Kuzzle();
-
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
return kuzzle.start(params, {dummy: true});
});
diff --git a/test/api/core/notifier/init.test.js b/test/api/core/notifier/init.test.js
index b4fa3f4aca..1be6a5c8eb 100644
--- a/test/api/core/notifier/init.test.js
+++ b/test/api/core/notifier/init.test.js
@@ -4,7 +4,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -18,7 +17,6 @@ describe('Test: notifier.init', function () {
before(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
return kuzzle.start(params, {dummy: true});
});
diff --git a/test/api/core/notifier/notify.test.js b/test/api/core/notifier/notify.test.js
index a1064969df..67535a9e70 100644
--- a/test/api/core/notifier/notify.test.js
+++ b/test/api/core/notifier/notify.test.js
@@ -5,7 +5,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -19,7 +18,6 @@ describe('Test: notifier.notify', function () {
before(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
return kuzzle.start(params, {dummy: true});
});
diff --git a/test/api/core/notifier/notifyDocumentCreate.test.js b/test/api/core/notifier/notifyDocumentCreate.test.js
index 1b52680996..06a9c88e19 100644
--- a/test/api/core/notifier/notifyDocumentCreate.test.js
+++ b/test/api/core/notifier/notifyDocumentCreate.test.js
@@ -8,7 +8,6 @@
var
should = require('should'),
q = require('q'),
- winston = require('winston'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
ResponseObject = require.main.require('lib/api/core/models/responseObject'),
@@ -46,7 +45,6 @@ describe('Test: notifier.notifyDocumentCreate', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.services.list.notificationCache = mockupCacheService;
diff --git a/test/api/core/notifier/notifyDocumentDelete.test.js b/test/api/core/notifier/notifyDocumentDelete.test.js
index 8ca2f2a585..94dedaa44c 100644
--- a/test/api/core/notifier/notifyDocumentDelete.test.js
+++ b/test/api/core/notifier/notifyDocumentDelete.test.js
@@ -7,7 +7,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
ResponseObject = require.main.require('lib/api/core/models/responseObject'),
@@ -50,7 +49,6 @@ describe('Test: notifier.notifyDocumentDelete', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.services.list.notificationCache = mockupCacheService;
diff --git a/test/api/core/notifier/notifyDocumentUpdate.test.js b/test/api/core/notifier/notifyDocumentUpdate.test.js
index 7a84e695c3..9f1018ab7d 100644
--- a/test/api/core/notifier/notifyDocumentUpdate.test.js
+++ b/test/api/core/notifier/notifyDocumentUpdate.test.js
@@ -7,7 +7,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
ResponseObject = require.main.require('lib/api/core/models/responseObject'),
@@ -84,7 +83,6 @@ describe('Test: notifier.notifyDocumentUpdate', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.services.list.notificationCache = mockupCacheService;
diff --git a/test/api/core/notifier/publish.test.js b/test/api/core/notifier/publish.test.js
index 0362e7f5f8..2be48f0c4c 100644
--- a/test/api/core/notifier/publish.test.js
+++ b/test/api/core/notifier/publish.test.js
@@ -5,7 +5,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -27,7 +26,6 @@ describe('Test: notifier.publish', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(() => {
kuzzle.services.list.notificationCache = {
diff --git a/test/api/core/notifier/send.test.js b/test/api/core/notifier/send.test.js
index 75e5a25c30..49db82a933 100644
--- a/test/api/core/notifier/send.test.js
+++ b/test/api/core/notifier/send.test.js
@@ -5,7 +5,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -13,58 +12,36 @@ var
require('should-promised');
-var mockupio = {
- emitted: false,
- id: undefined,
- room: undefined,
- response: undefined,
-
- init: function () {
- this.emitted = false;
- this.id = this.room = this.response = undefined;
- },
-
- to: function (connectionId) { this.id = connectionId; return this; },
-
- emit: function (room, response) {
- this.room = room;
- this.response = response;
- this.emitted = true;
- }
-};
-
describe('Test: notifier.send', function () {
var
kuzzle;
- before(function (done) {
+ before(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
- kuzzle.start(params, {dummy: true})
- .then(function () {
- kuzzle.io = mockupio;
- done();
- });
+ return kuzzle.start(params, {dummy: true});
});
- it('should broadcast to channels if no connection is provided', function () {
+ it('should emit a protocol:broadcast hook on channels to be notified', function (done) {
var
room = 'foo',
response = 'bar',
channel = 'stubChannel';
- mockupio.init();
+ this.timeout(50);
+
kuzzle.hotelClerk.getChannels = function () { return [channel]; };
kuzzle.services.list.mqBroker.addExchange = function (replyTopic, msg) {
should(replyTopic).be.exactly(channel);
should(msg).be.exactly(response);
};
- (Notifier.__get__('send')).call(kuzzle, room, response);
+ kuzzle.once('protocol:broadcast', (data) => {
+ should(data).be.an.Object();
+ should(data.channel).be.eql(channel);
+ should(data.payload).be.eql(response);
+ done();
+ });
- should(mockupio.emitted).be.true();
- should(mockupio.id).be.exactly(channel);
- should(mockupio.room).be.exactly(channel);
- should(mockupio.response).be.exactly(response);
+ (Notifier.__get__('send')).call(kuzzle, room, response);
});
});
diff --git a/test/api/core/notifier/workerNotification.test.js b/test/api/core/notifier/workerNotification.test.js
index c77a4d7b15..2902f58192 100644
--- a/test/api/core/notifier/workerNotification.test.js
+++ b/test/api/core/notifier/workerNotification.test.js
@@ -8,7 +8,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
ResponseObject = require.main.require('lib/api/core/models/responseObject'),
@@ -122,7 +121,6 @@ describe('Test: notifier.workerNotification', function () {
this.timeout(1000);
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true}).then(function () {
responseObject.action = 'create';
responseObject.collection = false;
diff --git a/test/api/core/pluginsManager/constructList.test.js b/test/api/core/pluginsManager/constructList.test.js
index 0b2e24b1f5..e4acbf2108 100644
--- a/test/api/core/pluginsManager/constructList.test.js
+++ b/test/api/core/pluginsManager/constructList.test.js
@@ -29,7 +29,7 @@ describe('Plugins manager constructList', function () {
},
mergedPlugins;
- mergedPlugins = constructList(defaultPlugins, customPlugins, true);
+ mergedPlugins = constructList(defaultPlugins, customPlugins);
should(mergedPlugins.foo).be.Object();
should(mergedPlugins.bar).be.Object();
});
@@ -54,7 +54,7 @@ describe('Plugins manager constructList', function () {
},
mergedPlugins;
- mergedPlugins = constructList(defaultPlugins, customPlugins, true);
+ mergedPlugins = constructList(defaultPlugins, customPlugins);
should(mergedPlugins.foo.config).be.Object();
should(mergedPlugins.foo.config).have.property('bar');
@@ -92,7 +92,7 @@ describe('Plugins manager constructList', function () {
},
mergedPlugins;
- mergedPlugins = constructList(defaultPlugins, customPlugins, true);
+ mergedPlugins = constructList(defaultPlugins, customPlugins);
should(mergedPlugins.foo.config).be.Object();
should(mergedPlugins.foo.config).have.property('bar');
@@ -131,7 +131,7 @@ describe('Plugins manager constructList', function () {
},
mergedPlugins;
- mergedPlugins = constructList(defaultPlugins, customPlugins, true);
+ mergedPlugins = constructList(defaultPlugins, customPlugins);
should(mergedPlugins.foo.config).be.Object();
should(mergedPlugins.foo.config).have.property('bar');
@@ -154,9 +154,74 @@ describe('Plugins manager constructList', function () {
defaultPlugins = {},
mergedPlugins;
- mergedPlugins = constructList(defaultPlugins, customPlugins, true);
+ mergedPlugins = constructList(defaultPlugins, customPlugins);
should(mergedPlugins.foo.config).be.Object();
should(mergedPlugins.foo.config).have.property('bar');
});
+
+ it('should add server plugins only on server instances', function () {
+ var
+ plugins,
+ defaultPlugins = {
+ serverPlugin: {
+ defaultConfig: {
+ loadedBy: 'server'
+ }
+ },
+ workerPlugin: {
+ defaultConfig: {
+ loadedBy: 'worker'
+ }
+ }
+ };
+
+ plugins = constructList(defaultPlugins, {}, true);
+
+ should(plugins.serverPlugin).be.an.Object();
+ should(plugins.workerPlugin).be.undefined();
+ });
+
+ it('should run worker plugins only on worker instances', function () {
+ var
+ plugins,
+ defaultPlugins = {
+ serverPlugin: {
+ defaultConfig: {
+ loadedBy: 'server'
+ }
+ },
+ workerPlugin: {
+ defaultConfig: {
+ loadedBy: 'worker'
+ }
+ }
+ };
+
+ plugins = constructList(defaultPlugins, {}, false);
+
+ should(plugins.serverPlugin).be.undefined();
+ should(plugins.workerPlugin).be.an.Object();
+ });
+
+ it('should always start plugins with loadedBy="all"', function () {
+ var
+ plugins,
+ defaultPlugins = {
+ serverPlugin: {
+ defaultConfig: {
+ loadedBy: 'all'
+ }
+ },
+ workerPlugin: {
+ defaultConfig: {
+ }
+ }
+ };
+
+ plugins = constructList(defaultPlugins, {}, true);
+
+ should(plugins.serverPlugin).be.an.Object();
+ should(plugins.workerPlugin).be.an.Object();
+ });
});
\ No newline at end of file
diff --git a/test/api/core/pluginsManager/init.test.js b/test/api/core/pluginsManager/init.test.js
new file mode 100644
index 0000000000..b4eadacb71
--- /dev/null
+++ b/test/api/core/pluginsManager/init.test.js
@@ -0,0 +1,136 @@
+var
+ should = require('should'),
+ rewire = require('rewire'),
+ PluginsManager = rewire('../../../../lib/api/core/pluginsManager');
+
+describe('Plugins manager initialization', function () {
+ var
+ kuzzle = {
+ config: {
+ pluginsManager: {}
+ }
+ },
+ installed = false,
+ configWritten = false,
+ locked = false;
+
+ before(function () {
+ PluginsManager.__set__('console', {
+ log: () => {},
+ error: () => {}
+ });
+
+ PluginsManager.__set__('installPlugins', function () {
+ installed = true;
+ return true;
+ });
+
+ PluginsManager.__set__('loadPlugins', function () {});
+
+ PluginsManager.__set__('fs', {
+ writeFileSync: function () {
+ configWritten = true;
+ return false;
+ },
+ existsSync: function (path) {
+ // prevents "require" on the non-existent custom plugins file
+ if (path.includes('customPlugins')) {
+ return false;
+ }
+
+ return locked;
+ }
+ });
+ });
+
+ beforeEach(function () {
+ installed = false;
+ configWritten = false;
+ locked = false;
+ });
+
+ it('should exit Kuzzle if nodejs does not support sync fs methods', function (done) {
+ var exitted = false;
+
+ PluginsManager.__with__({
+ childProcess: {
+ /*jshint -W001 */
+ hasOwnProperty: () => { return false; }
+ },
+ process: {
+ exit: () => exitted = true
+ }
+ })(function () {
+ var pluginManager = new PluginsManager(kuzzle);
+ pluginManager.init(true, false)
+ .then(() => {
+ should(exitted).be.true();
+ done();
+ })
+ .catch(err => done(err));
+ });
+ });
+
+ it('should wait for the lock to be released before installing plugins', function (done) {
+ var
+ released = false;
+
+ this.timeout(100);
+
+ PluginsManager.__with__({
+ lockfile: {
+ lock: function (foo, bar, cb) {
+ setTimeout(function () {
+ if (installed) {
+ return done(new Error('Plugin installation started before locks were released'));
+ }
+
+ cb(null, function () { released = true; });
+ }, 20);
+ }
+ }
+ })(function () {
+ var pluginManager = new PluginsManager(kuzzle);
+ pluginManager.init(true, false)
+ .then(() => {
+ should(installed).be.true();
+ should(released).be.true();
+ should(configWritten).be.true();
+ done();
+ })
+ .catch(err => done(err));
+ });
+ });
+
+ it('should not install plugins if locked by another instance', function (done) {
+ var
+ released = false;
+
+ this.timeout(100);
+ locked = true;
+
+ PluginsManager.__with__({
+ lockfile: {
+ lock: function (foo, bar, cb) {
+ setTimeout(function () {
+ if (installed) {
+ return done(new Error('Plugin installation started before locks were released'));
+ }
+
+ cb(null, function () { released = true; });
+ }, 20);
+ }
+ }
+ })(function () {
+ var pluginManager = new PluginsManager(kuzzle);
+ pluginManager.init(true, false)
+ .then(() => {
+ should(installed).be.false();
+ should(released).be.true();
+ should(configWritten).be.false();
+ done();
+ })
+ .catch(err => done(err));
+ });
+ });
+});
diff --git a/test/api/core/pluginsManager/installPlugins.test.js b/test/api/core/pluginsManager/installPlugins.test.js
index 85b010d56b..a3d51f3efe 100644
--- a/test/api/core/pluginsManager/installPlugins.test.js
+++ b/test/api/core/pluginsManager/installPlugins.test.js
@@ -10,7 +10,7 @@ describe('Test plugins manager installation', function () {
before(function () {
PluginsManager.__set__('initConfig', function () {});
PluginsManager.__set__('npmInstall', function () {});
- PluginsManager.__set__('kuzzle', {log: {info: function () {}, error: function () {}}});
+ PluginsManager.__set__('console', {log: function () {}, error: function () {}});
installPlugins = PluginsManager.__get__('installPlugins');
});
diff --git a/test/api/core/pluginsManager/run.test.js b/test/api/core/pluginsManager/run.test.js
index 101e1fa20e..2825b05689 100644
--- a/test/api/core/pluginsManager/run.test.js
+++ b/test/api/core/pluginsManager/run.test.js
@@ -27,6 +27,10 @@ describe('Test plugins manager run', function () {
kuzzle,
pluginsManager;
+ before(function () {
+ PluginsManager.__set__('console', {log: function () {}, error: function () {}});
+ });
+
beforeEach(() => {
kuzzle = new EventEmitter({
wildcard: true,
@@ -71,6 +75,7 @@ describe('Test plugins manager run', function () {
done();
}
},
+ config: {},
activated: true
}];
@@ -89,6 +94,7 @@ describe('Test plugins manager run', function () {
done();
}
},
+ config: {},
activated: true
}];
@@ -110,6 +116,7 @@ describe('Test plugins manager run', function () {
callback(null, object);
}
},
+ config: {},
activated: true
}];
@@ -138,6 +145,7 @@ describe('Test plugins manager run', function () {
callback();
}
},
+ config: {},
activated: true
}];
@@ -163,6 +171,7 @@ describe('Test plugins manager run', function () {
callback(true);
}
},
+ config: {},
activated: true
}];
@@ -183,6 +192,7 @@ describe('Test plugins manager run', function () {
hooks: {'log:warn': 'warn'},
warn: (msg) => { warnings.push(msg); }
},
+ config: {},
activated: true
});
@@ -252,6 +262,7 @@ describe('Test plugins manager run', function () {
},
FooController: function(){done();}
},
+ config: {},
activated: true
}
};
@@ -286,6 +297,7 @@ describe('Test plugins manager run', function () {
done();
}
},
+ config: {},
activated: true
}];
@@ -298,11 +310,13 @@ describe('Test plugins manager run', function () {
myplugin: {
object: {
init: function () {},
+ config: {},
routes: [
{verb: 'get', url: '/bar/:name', controller: 'foo', action: 'bar'},
{verb: 'post', url: '/bar', controller: 'foo', action: 'bar'}
]
},
+ config: {},
activated: true
}
};
@@ -320,5 +334,4 @@ describe('Test plugins manager run', function () {
.be.equal(pluginsManager.routes[0].action)
.and.be.equal('bar');
});
-
});
diff --git a/test/api/core/pluginsManager/trigger.test.js b/test/api/core/pluginsManager/trigger.test.js
index 8c724ff42f..0123219679 100644
--- a/test/api/core/pluginsManager/trigger.test.js
+++ b/test/api/core/pluginsManager/trigger.test.js
@@ -1,10 +1,14 @@
var
should = require('should'),
params = require('rc')('kuzzle'),
- PluginsManager = require.main.require('lib/api/core/pluginsManager'),
+ rewire = require('rewire'),
+ PluginsManager = rewire('../../../../lib/api/core/pluginsManager'),
EventEmitter = require('eventemitter2').EventEmitter2;
describe('Test plugins manager trigger', function () {
+ before(function () {
+ PluginsManager.__set__('console', {log: function () {}, error: function () {}});
+ });
it('should trigger hooks event', function (done) {
var
@@ -29,6 +33,7 @@ describe('Test plugins manager trigger', function () {
done();
}
},
+ config: {},
activated: true
}];
diff --git a/test/api/core/sandbox/sandbox.test.js b/test/api/core/sandbox/sandbox.test.js
index 8fb4cd821e..ab06d3c171 100644
--- a/test/api/core/sandbox/sandbox.test.js
+++ b/test/api/core/sandbox/sandbox.test.js
@@ -106,8 +106,8 @@ describe('Test: sandbox/sandboxTest', () => {
revert = LocalSandbox.__set__({
process: {
- debugPort: 17512,
- execArgv: ['--debug-port=17512']
+ debugPort: 17511,
+ execArgv: ['--debug-port=17511']
}
});
diff --git a/test/api/core/servers.test.js b/test/api/core/servers.test.js
index 981fab3207..169ad40d88 100644
--- a/test/api/core/servers.test.js
+++ b/test/api/core/servers.test.js
@@ -3,7 +3,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
http = require('http'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
@@ -17,30 +16,24 @@ describe('Test: core/servers', function () {
kuzzle,
port = 6667,
httpServer = false,
- websocketServer = false,
mqServer = false,
restRedirected = false;
before(function (done) {
+ this.timeout(200);
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.router.initRouterHttp = function () { httpServer = true; };
- kuzzle.router.routeWebsocket = function () { websocketServer = true; };
kuzzle.router.routeMQListener = function () { mqServer = true; };
kuzzle.router.routeHttp = function () { restRedirected = true; };
-
Servers.initAll(kuzzle, { port: port });
- kuzzle.io.emit('connection', {});
-
done();
});
});
it('should register all three servers at initialization', function () {
should(httpServer).be.true();
- should(websocketServer).be.true();
should(mqServer).be.true();
});
diff --git a/test/api/core/statistics.test.js b/test/api/core/statistics.test.js
index 667a028ab5..9b8db82d96 100644
--- a/test/api/core/statistics.test.js
+++ b/test/api/core/statistics.test.js
@@ -3,7 +3,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -27,7 +26,6 @@ describe('Test: statistics core component', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(() => {
return kuzzle.services.list.statsCache.init(kuzzle, {service: 'statsCache'});
diff --git a/test/api/core/workerListener.test.js b/test/api/core/workerListener.test.js
index 5d4efb1801..898a2834f4 100644
--- a/test/api/core/workerListener.test.js
+++ b/test/api/core/workerListener.test.js
@@ -3,7 +3,6 @@
*/
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
uuid = require('node-uuid'),
params = require('rc')('kuzzle'),
@@ -30,7 +29,6 @@ describe('Test: workerListener', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
kuzzle.services.list.broker.listen = function (room, cb) {
diff --git a/test/api/dsl/index/removeRoom.test.js b/test/api/dsl/index/removeRoom.test.js
index 7d2467eef9..dc11bf5c82 100644
--- a/test/api/dsl/index/removeRoom.test.js
+++ b/test/api/dsl/index/removeRoom.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
params = require('rc')('kuzzle'),
@@ -34,7 +33,6 @@ describe('Test removeRoom function index.js file from DSL', function () {
beforeEach(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
kuzzle.start(params, {dummy: true})
.then(function () {
diff --git a/test/api/dsl/index/testFilters.test.js b/test/api/dsl/index/testFilters.test.js
index d18f5f3766..ba8bb9bd51 100644
--- a/test/api/dsl/index/testFilters.test.js
+++ b/test/api/dsl/index/testFilters.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
RequestObject = require.main.require('lib/api/core/models/requestObject'),
params = require('rc')('kuzzle'),
@@ -105,7 +104,6 @@ describe('Test: dsl.testFilters', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
diff --git a/test/api/dsl/index/testRooms.test.js b/test/api/dsl/index/testRooms.test.js
index 126949017a..ecf26e5c9a 100644
--- a/test/api/dsl/index/testRooms.test.js
+++ b/test/api/dsl/index/testRooms.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
rewire = require('rewire'),
@@ -16,7 +15,6 @@ describe('Test: dsl.removeRoomFromFields', function () {
before(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
return kuzzle.start(params, {dummy: true});
});
diff --git a/test/hooks/index.test.js b/test/hooks/index.test.js
index e3e16165d6..e3e9ea4781 100644
--- a/test/hooks/index.test.js
+++ b/test/hooks/index.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
_ = require('lodash'),
Kuzzle = require.main.require('lib/api/Kuzzle');
@@ -22,7 +21,6 @@ describe('Test main file for hooks managers', function () {
beforeEach(function () {
kuzzle = new Kuzzle();
kuzzle.removeAllListeners();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
});
it('should be rejected on init when a hook is undefined in config', function () {
diff --git a/test/services/broker.test.js b/test/services/broker.test.js
index 36908a5324..3e84c39777 100644
--- a/test/services/broker.test.js
+++ b/test/services/broker.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
rewire = require('rewire'),
@@ -18,7 +17,6 @@ describe('Testing: broker service', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
Broker = rewire('../../lib/services/' + kuzzle.config.services.broker);
diff --git a/test/services/implementations/internalbroker.test.js b/test/services/implementations/internalbroker.test.js
index 84632670b6..bf8391fc44 100644
--- a/test/services/implementations/internalbroker.test.js
+++ b/test/services/implementations/internalbroker.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
IPCBroker = rewire('../../../lib/services/internalbroker'),
params = require('rc')('kuzzle'),
@@ -26,7 +25,6 @@ describe('Test: Internal Broker service ', function () {
port: '6666'
};
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
brokerServer = new IPCBroker(kuzzle, { isServer: true });
brokerClient = new IPCBroker(kuzzle, { isServer: false });
diff --git a/test/services/init.test.js b/test/services/init.test.js
index 1541e7f347..431744c9bd 100644
--- a/test/services/init.test.js
+++ b/test/services/init.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle');
@@ -11,64 +10,69 @@ describe('Test service initialization function', function () {
beforeEach(function () {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.removeAllListeners();
});
it('should build an internal broker service with correct methods', function () {
- kuzzle.start(params, {dummy: true});
-
- should(kuzzle.services.list.broker).be.an.Object().and.not.be.empty();
- should(kuzzle.services.list.broker.init).be.a.Function();
- should(kuzzle.services.list.broker.add).be.a.Function();
- should(kuzzle.services.list.broker.broadcast).be.a.Function();
- should(kuzzle.services.list.broker.listen).be.a.Function();
- should(kuzzle.services.list.broker.listenOnce).be.a.Function();
- should(kuzzle.services.list.broker.close).be.a.Function();
+ return kuzzle.start(params, {dummy: true})
+ .then(() => {
+ should(kuzzle.services.list.broker).be.an.Object().and.not.be.empty();
+ should(kuzzle.services.list.broker.init).be.a.Function();
+ should(kuzzle.services.list.broker.add).be.a.Function();
+ should(kuzzle.services.list.broker.broadcast).be.a.Function();
+ should(kuzzle.services.list.broker.listen).be.a.Function();
+ should(kuzzle.services.list.broker.listenOnce).be.a.Function();
+ should(kuzzle.services.list.broker.close).be.a.Function();
+ });
});
it('should build a MQ broker service with correct methods', function () {
- kuzzle.start(params, {dummy: true});
-
- should(kuzzle.services.list.mqBroker).be.an.Object().and.not.be.empty();
- should(kuzzle.services.list.mqBroker.init).be.a.Function();
- should(kuzzle.services.list.mqBroker.toggle).be.a.Function();
- should(kuzzle.services.list.mqBroker.add).be.a.Function();
- should(kuzzle.services.list.mqBroker.addExchange).be.a.Function();
- should(kuzzle.services.list.mqBroker.listenExchange).be.a.Function();
- should(kuzzle.services.list.mqBroker.replyTo).be.a.Function();
- should(kuzzle.services.list.mqBroker.listen).be.a.Function();
- should(kuzzle.services.list.mqBroker.listenOnce).be.a.Function();
- should(kuzzle.services.list.mqBroker.close).be.a.Function();
+ return kuzzle.start(params, {dummy: true})
+ .then(() => {
+ should(kuzzle.services.list.mqBroker).be.an.Object().and.not.be.empty();
+ should(kuzzle.services.list.mqBroker.init).be.a.Function();
+ should(kuzzle.services.list.mqBroker.toggle).be.a.Function();
+ should(kuzzle.services.list.mqBroker.add).be.a.Function();
+ should(kuzzle.services.list.mqBroker.addExchange).be.a.Function();
+ should(kuzzle.services.list.mqBroker.listenExchange).be.a.Function();
+ should(kuzzle.services.list.mqBroker.replyTo).be.a.Function();
+ should(kuzzle.services.list.mqBroker.listen).be.a.Function();
+ should(kuzzle.services.list.mqBroker.listenOnce).be.a.Function();
+ should(kuzzle.services.list.mqBroker.close).be.a.Function();
+ });
});
it('should build a readEngine service with correct methods', function () {
- kuzzle.start(params, {dummy: true});
-
- should(kuzzle.services.list.readEngine).be.an.Object();
- should(kuzzle.services.list.readEngine.init).be.a.Function();
- should(kuzzle.services.list.readEngine.search).be.a.Function();
- should(kuzzle.services.list.readEngine.get).be.a.Function();
+ return kuzzle.start(params, {dummy: true})
+ .then(() => {
+ should(kuzzle.services.list.readEngine).be.an.Object();
+ should(kuzzle.services.list.readEngine.init).be.a.Function();
+ should(kuzzle.services.list.readEngine.search).be.a.Function();
+ should(kuzzle.services.list.readEngine.get).be.a.Function();
+ });
});
it('should build a writeEngine service with correct methods', function () {
- kuzzle.start(params, {dummy: true});
-
- should(kuzzle.services.list.writeEngine).be.an.Object();
- should(kuzzle.services.list.writeEngine.init).be.a.Function();
- should(kuzzle.services.list.writeEngine.create).be.a.Function();
- should(kuzzle.services.list.writeEngine.update).be.a.Function();
- should(kuzzle.services.list.writeEngine.deleteByQuery).be.a.Function();
- should(kuzzle.services.list.writeEngine.deleteCollection).be.a.Function();
- should(kuzzle.services.list.writeEngine.import).be.a.Function();
+ return kuzzle.start(params, {dummy: true})
+ .then(() => {
+ should(kuzzle.services.list.writeEngine).be.an.Object();
+ should(kuzzle.services.list.writeEngine.init).be.a.Function();
+ should(kuzzle.services.list.writeEngine.create).be.a.Function();
+ should(kuzzle.services.list.writeEngine.update).be.a.Function();
+ should(kuzzle.services.list.writeEngine.deleteByQuery).be.a.Function();
+ should(kuzzle.services.list.writeEngine.deleteCollection).be.a.Function();
+ should(kuzzle.services.list.writeEngine.import).be.a.Function();
+ });
});
it('should build a cache service', function () {
- kuzzle.start(params, {dummy: true});
- should(kuzzle.services.list.notificationCache).be.an.Object();
- should(kuzzle.services.list.notificationCache.add).be.a.Function();
- should(kuzzle.services.list.notificationCache.remove).be.a.Function();
- should(kuzzle.services.list.notificationCache.search).be.a.Function();
+ return kuzzle.start(params, {dummy: true})
+ .then(() => {
+ should(kuzzle.services.list.notificationCache).be.an.Object();
+ should(kuzzle.services.list.notificationCache.add).be.a.Function();
+ should(kuzzle.services.list.notificationCache.remove).be.a.Function();
+ should(kuzzle.services.list.notificationCache.search).be.a.Function();
+ });
});
it('should not init services in blacklist', function () {
diff --git a/test/services/redis.test.js b/test/services/redis.test.js
index d683b42772..05b29db88d 100644
--- a/test/services/redis.test.js
+++ b/test/services/redis.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
q = require('q'),
params = require('rc')('kuzzle'),
Redis = require.main.require('lib/services/redis'),
@@ -16,7 +15,6 @@ describe('Test redis service', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(() => {
kuzzle.config.cache.databases.push(dbname);
diff --git a/test/services/remoteActions.test.js b/test/services/remoteActions.test.js
index e5b8b8d1dd..f147e83859 100644
--- a/test/services/remoteActions.test.js
+++ b/test/services/remoteActions.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -16,7 +15,6 @@ describe('Testing: Remote Actions service', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
remoteActions = new RemoteActions(kuzzle);
diff --git a/test/workers/index.test.js b/test/workers/index.test.js
index 9cea26e801..ae3492de44 100644
--- a/test/workers/index.test.js
+++ b/test/workers/index.test.js
@@ -2,7 +2,6 @@ var
should = require('should'),
_ = require('lodash'),
q = require('q'),
- winston = require('winston'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
WLoader = require('../../lib/workers/index');
@@ -15,7 +14,6 @@ describe('Testing: workers loader', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
Object.keys(kuzzle.config.workers).forEach(function (workerGroup) {
diff --git a/test/workers/write.test.js b/test/workers/write.test.js
index c6a2f75dd3..0968d8ba0a 100644
--- a/test/workers/write.test.js
+++ b/test/workers/write.test.js
@@ -1,6 +1,5 @@
var
should = require('should'),
- winston = require('winston'),
rewire = require('rewire'),
params = require('rc')('kuzzle'),
Kuzzle = require.main.require('lib/api/Kuzzle'),
@@ -16,7 +15,6 @@ describe('Testing: write worker', function () {
before(function (done) {
kuzzle = new Kuzzle();
- kuzzle.log = new (winston.Logger)({transports: [new (winston.transports.Console)({level: 'silent'})]});
kuzzle.start(params, {dummy: true})
.then(function () {
diff --git a/vagrant/vagrant.yml b/vagrant/vagrant.yml
index eae31c10db..a6d0cfb276 100644
--- a/vagrant/vagrant.yml
+++ b/vagrant/vagrant.yml
@@ -25,7 +25,7 @@ virtualmachine:
# List of ports to be forwarded to your host:
# override with empty array if you do not want to forward ports
# (in that case, you will need a private IP address to use Kuzzle - see above)
- forwarded_port: { 7512: 7512, 8081: 7512, 1883: 1883, 5672: 5672, 15672: 15672, 61613: 61613 }
+ forwarded_port: { 7511: 7511, 8081: 7511, 7512: 7512, 1883: 1883, 5672: 5672, 15672: 15672, 61613: 61613 }
### END Network Settings