Compare commits

..

No commits in common. "master" and "v1.0.0" have entirely different histories.

23 changed files with 58 additions and 755 deletions

View File

@ -1,50 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
labels: bug
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
HELP US HELP YOU, PLEASE
- Do a quick search to avoid duplicate issues
- Provide as much information as possible (reproduction sandbox, use case for features, etc.)
- Consider using a more suitable venue for questions such as Stack Overflow, Gitter, etc.
Please fill in the *entire* template below.
-->
## Steps to reproduce
<!-- Describe how to reproduce the issue -->
## Current Behavior
<!-- Describe the observed result -->
## Expected Behavior
<!-- Describe what did you expect instead, what is the desired outcome? -->
## Link to reproduction sandbox
<!--
See https://loopback.io/doc/en/contrib/Reporting-issues.html#loopback-3x-bugs
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
## Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->
## Related Issues
<!-- Did you find other bugs that looked similar? -->
_See [Reporting Issues](http://loopback.io/doc/en/contrib/Reporting-issues.html) for more tips on writing good issues_

View File

@ -1,25 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature
---
## Suggestion
<!-- A summary of what you'd like to see added or changed -->
## Use Cases
<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->
## Examples
<!-- Show how this would be used and what the behavior would be -->
## Acceptance criteria
TBD - will be filled by the team.

View File

@ -1,27 +0,0 @@
---
name: Question
about: The issue tracker is not for questions. Please use Stack Overflow or other resources for help.
labels: question
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
THE ISSUE TRACKER IS NOT FOR QUESTIONS.
DO NOT CREATE A NEW ISSUE TO ASK A QUESTION.
Please use one of the following resources for help:
**Questions**
- https://stackoverflow.com/tags/loopbackjs
- https://groups.google.com/forum/#!forum/loopbackjs
- https://gitter.im/strongloop/loopback
**Immediate support**
- https://strongloop.com/api-connect-faqs/
- https://strongloop.com/node-js/subscription-plans/
-->

View File

@ -1,11 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://loopback.io/doc/en/contrib/Reporting-issues.html#security-issues
about: Do not report security vulnerabilities using GitHub issues. Please send an email to `reachsl@us.ibm.com` instead.
- name: Get help on StackOverflow
url: https://stackoverflow.com/tags/loopbackjs
about: Please ask and answer questions on StackOverflow.
- name: Join our mailing list
url: https://groups.google.com/forum/#!forum/loopbackjs
about: You can also post your question to our mailing list.

View File

@ -1,18 +0,0 @@
<!--
Please provide a high-level description of the changes made by your pull request.
Include references to all related GitHub issues and other pull requests, for example:
Fixes #123
Implements #254
See also #23
-->
## Checklist
👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback-context) 👈
- [ ] `npm test` passes on your machine
- [ ] New tests added or existing tests modified to cover all changes
- [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html)
- [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html)

24
.github/stale.yml vendored
View File

@ -1,24 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- critical
- p1
- major
- good first issue
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been closed due to continued inactivity. Thank you for your understanding.
If you believe this to be in error, please contact one of the code owners,
listed in the `CODEOWNERS` file at the top-level of this repository.

View File

@ -1,6 +1,7 @@
sudo: false
language: node_js
node_js:
- "8"
- "10"
- "12"
- "0.10"
- "0.12"
- "4"
- "6"

View File

@ -1,89 +1,3 @@
2021-01-19, Version 3.5.2
=========================
* chore: update LTS status to End-of-Life (Rifa Achrinza)
2020-03-06, Version 3.5.1
=========================
* Update LTS status in README (Miroslav Bajtoš)
2020-02-17, Version 3.5.0
=========================
* Add support for Node.js 12 (Ahmet Cetin)
* chore: enable stalebot (Diana Lau)
* chore: improve issue and PR templates (Nora)
* Drop support for Node.js 6.x (Miroslav Bajtoš)
* chore: update copyrights years (Agnes Lin)
2019-01-02, Version 3.4.0
=========================
* Travis: enable Node.js 10.x (Miroslav Bajtoš)
* Node version ^10.14 added to engines list (Ahmet Cetin)
* add lts annoucement (jannyHou)
* Upgrade dependecies, fix new linter errors (Miroslav Bajtoš)
* Drop support for Node.js 4.x, 5.x and 7.x (Miroslav Bajtoš)
* Create Issue and PR Templates (#36) (Sakib Hasan)
* Add CODEOWNERS file (Diana Lau)
2017-07-21, Version 3.3.0
=========================
* add nodejs v8.2.1 support (Oleg Kubrakov)
2017-07-10, Version 3.2.0
=========================
* Add Node.js 7 to package.json and .travis.yml (Edgars Zagorskis)
2017-03-17, Version 3.1.0
=========================
* fix typo in readme (biniam)
* Add bind option to getCurrentContext() (Emiliano Daddario)
* Upgrade eslint & config to latest (Miroslav Bajtoš)
2017-01-06, Version 3.0.0
=========================
* Rework README, add info from docs site (Miroslav Bajtoš)
* Drop continuation-local-storage, use cls-hooked (josieusa)
* Update paid support URL (Siddhi Pai)
* Add app using loopback-context (Amir Jafarian)
* Drop support for Node v0.10 and v0.12 (Siddhi Pai)
* Start the development of the next major version (Siddhi Pai)
* Update deps to loopback 3.0.0 RC (Miroslav Bajtoš)
* make warning less ambigious (Carl Fürstenberg)
2016-08-10, Version 1.0.0
=========================

View File

@ -1,6 +0,0 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners,
# the last matching pattern has the most precendence.
# Core team members from IBM
* @bajtos @josieusa

View File

@ -1,9 +1,9 @@
### Contributing ###
Thank you for your interest in `loopback-context`, an open source project
Thank you for your interest in `loopback-context-cls`, an open source project
administered by StrongLoop.
Contributing to `loopback-context` is easy. In a few simple steps:
Contributing to `loopback-context-cls` is easy. In a few simple steps:
* Ensure that your effort is aligned with the project's roadmap by
talking to the maintainers, especially if you are going to spend a

238
README.md
View File

@ -1,90 +1,25 @@
# loopback-context
**⚠️ LoopBack 3 has reached end of life. We are no longer accepting pull requests or providing
support for community users. The only exception is fixes for critical bugs and security
vulnerabilities provided as part of support for IBM API Connect customers. (See
[Module Long Term Support Policy](#module-long-term-support-policy) below.)**
We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as
soon as possible. Refer to our
[Migration Guide](https://loopback.io/doc/en/lb4/migration-overview.html)
for more information on how to upgrade.
## Overview
Current context for LoopBack applications, based on cls-hooked.
Current context for LoopBack applications, based on
node-continuation-local-storage.
## WARNING
**`cls-hooked` module uses undocumented `AsyncWrap` API that was introduced to Node.js relatively recently. While this new API seems to be more reliable than the old `async-listener` used by `continuation-local-storage`, there are still cases where the context (local storage) is not preserved correctly. Please consider this risk before using loopback-context.**
The module node-continuation-local-storage is known to have many problems,
see e.g. [issue #59](https://github.com/othiym23/node-continuation-local-storage/issues/59).
As a result, loopback-context does not work in many situations, as can be
seen from issues reported in LoopBack's
[issue tracker](https://github.com/strongloop/loopback/issues?utf8=%E2%9C%93&q=is%3Aissue%20getCurrentcontext).
### Known issues
**We recommend AGAINST using this module.**
- [when](https://www.npmjs.com/package/when), a popular Promise
implementation, breaks context propagation. Please consider using the
built-in `Promise` implementation provided by Node.js or
[Bluebird](https://www.npmjs.com/package/bluebird) instead.
- Express middleware chains which contain a "bad" middleware (i.e. one which
breaks context propagation inside its function body, in a way mentioned in
this doc) especially if called before other "good" ones needs refactoring,
in order to prevent the context from getting mixed up among HTTP requests.
See usage below for details.
Discussion: https://github.com/strongloop/loopback-context/issues/17
In general, any module that implements a custom task queue or a connection pool
is prone to break context storage. This is an inherent problem of continuation
local storage that needs to be fixed at lower level - first in Node.js core
and then in modules implementing task queues and connection pools.
## Installation
```
$ npm install --save loopback-context cls-hooked
```
Make sure you are running on a Node.js version supported by this module
(`^4.5`, `^5.10`, `^6.0`, `^7.0`, `^8.2.1` or `^10.14`). When installing, check the output of `npm install`
and make sure there are no `engine` related warnings.
If you are running on Node v6, you can try the new alternative
[cls-hooked](https://github.com/Jeff-Lewis/cls-hooked).
## Usage
### Setup cls-hooked
To minimize the likelihood of loosing context in your application, you should
ensure that `cls-hooked` is loaded as the first module of your application, so
that it can wrap certain Node.js APIs before any other modules start using these
APIs.
Our recommended approach is to add `-r cls-hooked` to node's list of
arguments when starting your LoopBack application.
```
$ node -r cls-hooked .
```
If you are using a process manager like `strong-pm` or `pm2`, then consult
their documentation whether it's possible to configure the arguments used to
spawn worker processes. Note that `slc run` does not support this feature yet,
see [strong-supervisor#56](https://github.com/strongloop/strong-supervisor/issues/56).
Alternatively, you can add the following line as the first line of your main
application file:
```js
require('cls-hooked');
```
This approach should be compatible with all process managers, including
`strong-pm`. However, we feel that relying on the order of `require` statements
is error-prone.
### Configure context propagation
To setup your LoopBack application to create a new context for each incoming
HTTP request, configure `per-context` middleware in your
`server/middleware.json` as follows:
1) Add `per-request` middleware to your
`server/middleware-config.json`:
```json
{
@ -95,28 +30,7 @@ HTTP request, configure `per-context` middleware in your
}
```
**IMPORTANT: By default, the HTTP req/res objects are not set onto the current context. You
need to set `enableHttpContext` to true to enable automatic population
of req/res objects.**
```json
{
"initial": {
"loopback-context#per-request": {
"params": {
"enableHttpContext": true
}
}
}
}
```
### Use the current context
Once youve enabled context propagation, you can access the current context
object using `LoopBackContext.getCurrentContext()`. The context will be
available in middleware (if it is loaded after the context middleware),
remoting hooks, model hooks, and custom methods.
2) Then you can access the context from your code:
```js
var LoopBackContext = require('loopback-context');
@ -130,126 +44,6 @@ MyModel.myMethod = function(cb) {
});
```
### Bind for concurrency
In order to workaround the aforementioned concurrency issue with `when` (and
similar `Promise`-like and other libraries implementing custom queues and/or
connection pools), it's recommended to activate context binding inside each
HTTP request or concurrent `runInContext()` call, by using the `bind` option, as
in this example:
var ctx = LoopBackContext.getCurrentContext({ bind: true });
With the option enabled, this both creates the context, and binds the access
methods of the context (i.e. `get` and `set`), at once.
**Warning**: this only works if it's **the first expression evaluated** in every
middleware/operation hook/`runInContext()` call etc. that uses
`getCurrentContext`. (It must be the first expression; it may not be enough if
it's at the first line). Explanation: you must bind the context while it's still
correct, i.e. before it gets mixed up between concurrent operations affected by
bugs. Therefore, to be sure, you must bind it before *any* operation.
Also, with respect to the "bad", context-breaking middleware use case mentioned in "Known issues"
before, the following 2 lines need to be present at the beginning of the middleware
body. At least the "bad" one; but, as a preventive measure, they can be present
in every other middleware of every chain as well, being backward-compatible:
var badMiddleware = function(req, res, next) {
// these 2 lines below are needed
var ctx = LoopBackContext.getCurrentContext({bind: true});
next = ctx.bind(next);
...
The `bind` option defaults to `false`. This is only in order to prevent breaking
legacy apps; but if your app doesn't have such issue, then you can safely use
`bind: true` everywhere in your app (e.g. with a
[codemod](https://github.com/facebook/jscodeshift), or by monkey-patching
`getCurrentContext()` globally, if you prefer an automated fashion).
**Warning**: this only applies to application modules. In fact, if the module
affected by the concurrency issue is of this kind, you can easily refactor/write
your own code so to enable `bind`. Not if it's a 3rd-party module, nor a
Loopback non-core module, unless you fork and fix it.
### Use current authenticated user in remote methods
In advanced use cases, for example when you want to add custom middleware, you
have to add the context middleware at the right position in the middleware
chain (before the middleware that depends on
`LoopBackContext.getCurrentContext`).
**IMPORTANT: `LoopBackContext.perRequest()` detects the situation when it is
invoked multiple times on the same request and returns immediately in
subsequent runs.**
Here is a snippet using a middleware function to place the currently
authenticated user into the context so that remote methods may use it:
**server/middleware/store-current-user.js**
```js
module.exports = function(options) {
return function storeCurrentUser(req, res, next) {
if (!req.accessToken) {
return next();
}
app.models.UserModel.findById(req.accessToken.userId, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
return next(new Error('No user with this access token was found.'));
}
var loopbackContext = LoopBackContext.getCurrentContext();
if (loopbackContext) {
loopbackContext.set('currentUser', user);
}
next();
});
};
};
```
**server/middleware.json**
```json
{
"initial": {
"loopback-context#per-request": {}
},
"auth": {
"loopback#token": {}
},
"auth:after": {
"./middleware/store-current-user": {}
}
}
```
**common/models/YourModel.json**
```js
var LoopBackContext = require('loopback-context');
module.exports = function(YourModel) {
...
//remote method
YourModel.someRemoteMethod = function(arg1, arg2, cb) {
var ctx = LoopBackContext.getCurrentContext();
var currentUser = ctx && ctx.get('currentUser');
console.log('currentUser.username: ', currentUser.username); // voila!
...
cb(null);
};
...
};
```
## Module Long Term Support Policy
This module adopts the [Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy, with the following End Of Life (EOL) dates:
| Version | Status | Published | EOL |
| ------- | --------------- | --------- | -------- |
| 3.x | End-of-Life | Jan 2017 | Dec 2020 |
| 1.x | End-of-Life | Aug 2016 | Apr 2019 |
Learn more about our LTS plan in the [docs](https://loopback.io/doc/en/contrib/Long-term-support.html).
See the official LoopBack
[documentation](https://docs.strongloop.com/display/APIC/Using+current+context)
for more details.

View File

@ -1,5 +1,5 @@
// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: loopback-context
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-context-cls
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,43 +0,0 @@
// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: loopback-context
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var contextPerRequest = require('../server/middleware/per-request.js');
// Use `var lbContext = require('loopback-context');` in your app
var lbContext = require('../');
var loopback = require('loopback');
var app = loopback();
// Configure the context middleware
app.middleware('initial', contextPerRequest());
// Store a request property in the context
app.use(function saveHostToContext(req, res, next) {
var currentContext = lbContext.getCurrentContext();
if (currentContext)
currentContext.set('host', req.hostname);
next();
});
app.use(loopback.rest());
var Color = loopback.createModel('color', {name: String});
Color.beforeRemote('**', function(ctx, unused, next) {
// Inside LoopBack code, you can read the property from the context
var currentContext = lbContext.getCurrentContext();
if (currentContext)
console.log('Request to host %s',
currentContext && currentContext.get('host'));
next();
});
app.dataSource('db', {connector: 'memory'});
app.model(Color, {dataSource: 'db'});
app.listen(3000, function() {
console.log('A list of colors is available at http://localhost:3000/colors');
});

View File

@ -1,10 +1,7 @@
{
"name": "loopback-context",
"version": "3.5.2",
"description": "Current context for LoopBack applications, based on cls-hooked",
"engines": {
"node": "^8.2.1 || ^10.14 || ^12.15"
},
"version": "1.0.0",
"description": "Current context for LoopBack applications, based on node-continuation-local-storage",
"keywords": [
"StrongLoop",
"LoopBack",
@ -23,18 +20,15 @@
},
"license": "MIT",
"dependencies": {
"cls-hooked": "^4.2.0"
"continuation-local-storage": "^3.1.7"
},
"devDependencies": {
"async-1.5.2": "file:./test/stub-modules/async-1.5.2",
"chai": "^4.1.2",
"dirty-chai": "^2.0.1",
"eslint": "^5.0.1",
"eslint-config-loopback": "^10.0.0",
"loopback": "^3.0.0",
"mocha": "^5.2.0",
"supertest": "^3.1.0",
"when-3.7.7": "file:./test/stub-modules/when-3.7.7"
},
"author": "IBM Corp."
"chai": "^3.5.0",
"dirty-chai": "^1.2.2",
"eslint": "^2.13.1",
"eslint-config-loopback": "^4.0.0",
"loopback": "^3.0.0-alpha.1",
"mocha": "^2.5.3",
"supertest": "^1.2.0"
}
}

View File

@ -1,26 +1,33 @@
// Copyright IBM Corp. 2016,2017. All Rights Reserved.
// Node module: loopback-context
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
// Node module: loopback-context-cls
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var cls = require('cls-hooked');
var domain = require('domain');
// Require CLS only when using the current context feature.
// As soon as this require is done, all the instrumentation/patching
// of async-listener is fired which is not ideal.
//
// Some users observed stack overflows due to promise instrumentation
// and other people have seen similar things:
// https://github.com/othiym23/async-listener/issues/57
// It all goes away when instrumentation is disabled.
var cls = function() {
return require('continuation-local-storage');
};
var LoopBackContext = module.exports;
/**
* Get the current context object. The context is preserved
* across async calls, it behaves like a thread-local storage.
*
* @options {Object} [options]
* @property {Boolean} bind Bind get/set/bind methods of the context to the
* context that's current at the time getCurrentContext() is invoked. This
* can be used to work around 3rd party code breaking CLS context propagation.
* @returns {Namespace} The context object or null.
*/
LoopBackContext.getCurrentContext = function(options) {
LoopBackContext.getCurrentContext = function() {
// A placeholder method, see LoopBackContext.createContext() for the real version
return null;
};
@ -78,30 +85,11 @@ LoopBackContext.createContext = function(scopeName) {
process.context = process.context || {};
var ns = process.context[scopeName];
if (!ns) {
ns = cls.createNamespace(scopeName);
ns = cls().createNamespace(scopeName);
process.context[scopeName] = ns;
// Set up LoopBackContext.getCurrentContext()
LoopBackContext.getCurrentContext = function(options) {
if (!ns || !ns.active) {
return null;
}
if (!options || !options.bind) {
return ns;
}
/**
* **NOTE**
* This only re-binds get, set and bind methods, the most used.
* If you use other methods of the context, e.g. runInContext(), etc.,
* you may run into unexpected issues that are fixed only for get & set.
*/
var boundContext = Object.create(ns);
boundContext.get = boundContext.bind(ns.get);
boundContext.set = boundContext.bind(ns.set);
// Call to Function.prototype.bind(), not ns.bind()
boundContext.bind = ns.bind.bind(ns);
return boundContext;
LoopBackContext.getCurrentContext = function() {
return ns && ns.active ? ns : null;
};
}
return ns;

View File

@ -1,5 +1,5 @@
// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: loopback-context
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Node module: loopback-context-cls
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,8 +1,3 @@
// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: loopback-context
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var chai = require('chai');

View File

@ -1,12 +1,10 @@
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Node module: loopback-context
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Node module: loopback-context-cls
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var asyncV152 = require('async-1.5.2');
var whenV377 = require('when-3.7.7');
var LoopBackContext = require('..');
var Domain = require('domain');
var EventEmitter = require('events').EventEmitter;
@ -52,7 +50,7 @@ describe('LoopBack Context', function() {
TestModel.test = function(inst, cb) {
var tmpCtx = LoopBackContext.getCurrentContext();
if (tmpCtx) tmpCtx.set('data', 'a value stored in context');
if (process.domain) cb = process.domain.bind(cb); // IMPORTANT
if (process.domain) cb = process.domain.bind(cb); // IMPORTANT
runInOtherDomain(cb);
};
@ -100,150 +98,4 @@ describe('LoopBack Context', function() {
});
});
});
// Credits for the original idea for this test case to @marlonkjoseph
// Original source of the POC gist of the idea:
// https://gist.github.com/marlonkjoseph/f42f3c71f746896a0d4b7279a34ea753
// Heavily edited by others
it('keeps context when using waterfall() from async 1.5.2',
function(done) {
LoopBackContext.runInContext(function() {
// Trigger async waterfall callbacks
asyncV152.waterfall([
function pushToContext(next) {
var ctx = LoopBackContext.getCurrentContext();
expect(ctx).is.an('object');
ctx.set('test-key', 'test-value');
next();
},
function pullFromContext(next) {
var ctx = LoopBackContext.getCurrentContext();
expect(ctx).is.an('object');
var testValue = ctx && ctx.get('test-key', 'test-value');
next(null, testValue);
},
function verify(testValue, next) {
expect(testValue).to.equal('test-value');
next();
},
], done);
});
});
it('handles concurrent then() calls with when v3.7.7 promises & bind option',
function() {
return Promise.all([
runWithPushedValue('test-value-1', {bind: true}),
runWithPushedValue('test-value-2', {bind: true}),
])
.then(function verify(values) {
var failureCount = getFailureCount(values);
expect(failureCount).to.equal(0);
});
});
it('fails once without bind option and when v3.7.7 promises',
function() {
return Promise.all([
runWithPushedValue('test-value-3'),
runWithPushedValue('test-value-4'),
])
.then(function verify(values) {
var failureCount = getFailureCount(values);
expect(failureCount).to.equal(1);
});
});
var timeout = 100;
function runWithPushedValue(pushedValue, options) {
return new Promise(function concurrentExecutor(outerResolve, reject) {
LoopBackContext.runInContext(function pushToContext() {
var ctx = LoopBackContext.getCurrentContext(options);
expect(ctx).is.an('object');
ctx.set('test-key', pushedValue);
var whenPromise = whenV377().delay(timeout);
whenPromise.then(function pullFromContextAndReturn() {
var pulledValue = ctx && ctx.get('test-key');
outerResolve({
pulledValue: pulledValue,
pushedValue: pushedValue,
});
}).catch(reject);
});
});
}
function getFailureCount(values) {
var failureCount = 0;
values.forEach(function(v) {
if (v.pulledValue !== v.pushedValue) {
failureCount++;
}
});
return failureCount;
}
it('doesn\'t mix up req\'s in chains of ' +
'Express-middleware-like func\'s if next() cb is bound',
function() {
return Promise.all([
runWithRequestId('test-value-5', true),
runWithRequestId('test-value-6', true),
])
.then(function verify(values) {
var failureCount = getFailureCount(values);
expect(failureCount).to.equal(0);
});
});
it('fails & mixes up ctx among requests in mw chains if next() cb is unbound',
function() {
return Promise.all([
runWithRequestId('test-value-7'),
runWithRequestId('test-value-8'),
])
.then(function verify(values) {
var failureCount = getFailureCount(values);
expect(failureCount).to.equal(1);
});
});
function runWithRequestId(pushedValue, bindNextCb) {
return new Promise(function chainExecutor(outerResolve, reject) {
LoopBackContext.runInContext(function concurrentChain() {
function middlewareBreakingCls(req, res, next) {
var ctx = LoopBackContext.getCurrentContext({bind: true});
if (bindNextCb) {
next = ctx.bind(next);
}
ctx.set('test-key', pushedValue);
var whenPromise = whenV377().delay(timeout);
whenPromise.then(next).catch(reject);
};
function middlewareReadingContext(req, res, next) {
var ctx = LoopBackContext.getCurrentContext({bind: true});
var pulledValue = ctx && ctx.get('test-key');
next(null, pulledValue);
};
// Run the chain
var req = null;
var res = null;
middlewareBreakingCls(req, res, function(err) {
if (err) return reject(err);
middlewareReadingContext(req, res, function(err, result) {
if (err) return reject(err);
outerResolve({
pulledValue: result,
pushedValue: pushedValue,
});
});
});
});
});
}
});

View File

@ -1 +0,0 @@
-r cls-hooked

View File

@ -1,7 +0,0 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-context
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = require('async');

View File

@ -1,8 +0,0 @@
{
"name": "async-1.5.2",
"version": "1.5.2",
"description":"async version 1.5.2",
"dependencies": {
"async":"1.5.2"
}
}

View File

@ -1,7 +0,0 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: loopback-context
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
module.exports = require('when');

View File

@ -1,8 +0,0 @@
{
"name": "when-3.7.7",
"version": "3.7.7",
"description":"when version 3.7.7",
"dependencies": {
"when":"3.7.7"
}
}