Skip to content

Commit

Permalink
Merge 761737e into 0791cbf
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Kliment committed Jun 30, 2015
2 parents 0791cbf + 761737e commit 51c6a74
Show file tree
Hide file tree
Showing 16 changed files with 1,162 additions and 423 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Expand Up @@ -7,6 +7,9 @@ node_js:

sudo: false

before_script:
- gem install dredd_worker

notifications:
email:
recipients:
Expand Down
14 changes: 7 additions & 7 deletions docs/hooks.md
Expand Up @@ -80,6 +80,8 @@ Dredd supports following types of hooks:
- Any modifications on the `transaction` object is propagated to the actual HTTP transactions.
- You can use `hooks.log` function inside the hook to print yours debug messages and informations.

- [`configuration`](https://dredd.readthedocs.org/en/latest/usage/#configuration-object-for-dredd-class) object is populated on the `hooks` object

### Sync API

```javascript
Expand Down Expand Up @@ -135,6 +137,11 @@ hooks.beforeEach(function (transaction, done) {
done();
});

hooks.before("Machines > Machines collection > Get Machines", function (transaction, done) {
hooks.log("before");
done();
});

hooks.beforeEachValidation(function (transaction, done) {
hooks.log('beforeEachValidation');
done();
Expand All @@ -145,13 +152,6 @@ hooks.beforeValidation("Machines > Machines collection > Get Machines", function
done();
});

hooks.before("Machines > Machines collection > Get Machines", function (transaction, done) {
hooks.log("before");
done();
});



hooks.after("Machines > Machines collection > Get Machines", function (transaction, done) {
hooks.log("after");
done();
Expand Down
2 changes: 1 addition & 1 deletion scripts/cov
Expand Up @@ -17,6 +17,6 @@ cp -r ./test ./src-cov/test
cp ./package.json ./src-cov

# Excluding test breaking coveralls report :( Reporting to coveralls.io for further investigation
$MOCHA --reporter $REPORTER --recursive --timeout 120000 --compilers 'coffee:coffee-script/register' -i -g 'Using workaround for hooks in ruby' -i -g 'when using --server' -i -g 'Command line interface' './src-cov/test/**/*-test.coffee'
$MOCHA --reporter $REPORTER --recursive --timeout 120000 --compilers 'coffee:coffee-script/register' -i -g 'Using workaround for hooks in ruby' -i -g 'when using --server' -i -g 'Command line interface' -i -g 'Using workaround for hooks in python' './src-cov/test/**/*-test.coffee'

rm -rf ./src-cov
158 changes: 95 additions & 63 deletions src/add-hooks.coffee
Expand Up @@ -4,6 +4,7 @@ proxyquire = require('proxyquire').noCallThru()
glob = require 'glob'
fs = require 'fs'
async = require 'async'
clone = require 'clone'

Hooks = require './hooks'
logger = require './logger'
Expand All @@ -13,6 +14,8 @@ mergeSandboxedHooks = require './merge-sandboxed-hooks'
addHooks = (runner, transactions, callback) ->
# Note: runner.configuration.options must be defined

customConfigCwd = runner?.configuration?.custom?.cwd

fixLegacyTransactionNames = (allHooks) ->
pattern = /^\s>\s/g
for hookType in ['beforeHooks', 'afterHooks']
Expand All @@ -26,39 +29,59 @@ addHooks = (runner, transactions, callback) ->

delete allHooks[hookType][transactionName]

runner.logs ?= []
runner.hooks = new Hooks(logs: runner.logs, logger: logger)
runner.hooks.transactions ?= {}
loadHookFile = (filename, basePath) ->
basePath ?= customConfigCwd or process.cwd()
filePath = path.resolve(basePath, filename)

customConfigCwd = runner?.configuration?.custom?.cwd
try
proxyquire filePath, {
'hooks': runner.hooks
}

for transaction in transactions
runner.hooks.transactions[transaction.name] = transaction
# Fixing #168 issue
fixLegacyTransactionNames runner.hooks

pattern = runner?.configuration?.options?.hookfiles
if not pattern
if runner.configuration.hooksData?
if runner.configuration.options.sandbox == true
if typeof(runner.configuration.hooksData) != 'object' or Array.isArray(runner.configuration.hooksData) != false
return callback(new Error("hooksData option must be an object e.g. {'filename.js':'console.log(\"Hey!\")'}"))
catch error
logger.warn 'Skipping hook loading...'
logger.warn 'Error reading hook file "' + filePath + '"'
logger.warn 'This probably means one or more of your hookfiles is invalid.'
logger.warn 'Message: ' + error.message if error.message?
logger.warn 'Stack: ' + error.stack if error.stack?

# run code in sandbox
async.eachSeries Object.keys(runner.configuration.hooksData), (key, nextHook) ->
data = runner.configuration.hooksData[key]
loadSandboxHooksFromStrings = (callback) ->
if typeof(runner.configuration.hooksData) != 'object' or Array.isArray(runner.configuration.hooksData) != false
return callback(new Error("hooksData option must be an object e.g. {'filename.js':'console.log(\"Hey!\")'}"))

# run code in sandbox
sandboxHooksCode data, (sandboxError, result) ->
return nextHook(sandboxError) if sandboxError
# run code in sandbox
async.eachSeries Object.keys(runner.configuration.hooksData), (key, nextHook) ->
data = runner.configuration.hooksData[key]

# merge stringified hooks
runner.hooks = mergeSandboxedHooks(runner.hooks, result)
# run code in sandbox
sandboxHooksCode data, (sandboxError, result) ->
return nextHook(sandboxError) if sandboxError

# Fixing #168 issue
fixLegacyTransactionNames runner.hooks
# merge stringified hooks
runner.hooks = mergeSandboxedHooks(runner.hooks, result)

# Fixing #168 issue
fixLegacyTransactionNames runner.hooks

nextHook()

, callback

runner.logs ?= []
runner.hooks = new Hooks(logs: runner.logs, logger: logger)
runner.hooks.transactions ?= {}

nextHook()
for transaction in transactions
runner.hooks.transactions[transaction.name] = transaction

, callback
# Loading hooks from string, sandbox mode must be enabled
if not runner?.configuration?.options?.hookfiles
if runner.configuration.hooksData?
if runner.configuration.options.sandbox == true
loadSandboxHooksFromStrings(callback)
else
msg = """
Not sandboxed hooks loading from strings is not implemented,
Expand All @@ -67,54 +90,63 @@ addHooks = (runner, transactions, callback) ->
callback(new Error(msg))
else
return callback()

# Loading hookfiles from fs
else
patternArray = [].concat pattern

async.eachSeries patternArray, (item, nextPattern) ->
files = glob.sync item
# Clone the configuration object to hooks.configuration to make it
# accessible in the node.js hooks API
runner.hooks.configuration = clone runner?.configuration

files = []

# If the language is empty or it is not to nodejs
if runner?.configuration?.options?.language == "" or
runner?.configuration?.options?.language == undefined or
runner?.configuration?.options?.language == "nodejs"

# Expand globs
globs = [].concat runner?.configuration?.options?.hookfiles

for globItem in globs
files = files.concat glob.sync(globItem)

logger.info 'Found Hookfiles: ' + files

# Running in not sandboxed mode
if not runner.configuration.options.sandbox == true
try
for file in files
proxyquire path.resolve((customConfigCwd or process.cwd()), file), {
'hooks': runner.hooks
}

# Fixing #168 issue
fixLegacyTransactionNames runner.hooks
return nextPattern()
catch error
logger.warn 'Skipping hook loading...'
logger.warn 'Error reading hook files (' + files + ')'
logger.warn 'This probably means one or more of your hookfiles is invalid.'
logger.warn 'Message: ' + error.message if error.message?
logger.warn 'Stack: ' + error.stack if error.stack?
return nextPattern()

# Running in sandboxed mode
else
logger.info 'Loading hookfiles in sandboxed context: ' + files
async.eachSeries files, (fileName, nextFile) ->
resolvedPath = path.resolve((customConfigCwd or process.cwd()), fileName)
# If other language than nodejs, run (proxyquire) hooks worker client
# Worker client will start the worker server and pass the "hookfiles" options as CLI arguments to it
else
workerClientPath = path.resolve __dirname, './hooks-worker-client.js'
files = [workerClientPath]

# load hook file content
fs.readFile resolvedPath, 'utf8', (readingError, data) ->
return nextFile(readingError) if readingError
# Loading files in non sandboxed nodejs
if not runner.configuration.options.sandbox == true
for file in files
loadHookFile file

# run code in sandbox
sandboxHooksCode data, (sandboxError, result) ->
return nextFile(sandboxError) if sandboxError
return callback()

runner.hooks = mergeSandboxedHooks(runner.hooks, result)
# Loading files in sandboxed mode
else

logger.info 'Loading hookfiles in sandboxed context: ' + files

async.eachSeries files, (fileName, nextFile) ->
resolvedPath = path.resolve((customConfigCwd or process.cwd()), fileName)
# load hook file content
fs.readFile resolvedPath, 'utf8', (readingError, data) ->
return nextFile(readingError) if readingError
# run code in sandbox
sandboxHooksCode data, (sandboxError, result) ->
return nextFile(sandboxError) if sandboxError
runner.hooks = mergeSandboxedHooks(runner.hooks, result)

# Fixing #168 issue
fixLegacyTransactionNames runner.hooks

nextFile()
, callback

# Fixing #168 issue
fixLegacyTransactionNames runner.hooks

nextFile()
, nextPattern
, callback

module.exports = addHooks
1 change: 1 addition & 0 deletions src/apply-configuration.coffee
Expand Up @@ -43,6 +43,7 @@ applyConfiguration = (config) ->
names: false
hookfiles: null
sandbox: false
language: 'nodejs'

# normalize options and config
for own key, value of config
Expand Down

0 comments on commit 51c6a74

Please sign in to comment.