Navigation Menu

Skip to content

Commit

Permalink
Load blueprint-file from provided URL from http/https network with a …
Browse files Browse the repository at this point in the history
…timeout of 5 secs
  • Loading branch information
kuba-kubula committed Feb 12, 2015
1 parent 5c68878 commit 06c7699
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 9 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -28,6 +28,7 @@
"optimist": "~0.6.1",
"protagonist": "~0.17.1",
"proxyquire": "^1.3.1",
"request": "",
"setimmediate": "^1.0.2",
"uri-template": "~1.0.0",
"winston": "^0.9.0"
Expand Down
48 changes: 41 additions & 7 deletions src/dredd.coffee
Expand Up @@ -5,6 +5,8 @@ glob = require 'glob'
fs = require 'fs'
protagonist = require 'protagonist'
async = require 'async'
request = require 'request'
url = require 'url'

logger = require './logger'
options = require './options'
Expand All @@ -14,6 +16,8 @@ handleRuntimeProblems = require './handle-runtime-problems'
blueprintAstToRuntime = require './blueprint-ast-to-runtime'
configureReporters = require './configure-reporters'

CONNECTION_ERRORS = ['ECONNRESET', 'ENOTFOUND', 'ESOCKETTIMEDOUT', 'ETIMEDOUT', 'ECONNREFUSED', 'EHOSTUNREACH', 'EPIPE']

class Dredd
constructor: (config) ->
@tests = []
Expand Down Expand Up @@ -41,6 +45,9 @@ class Dredd
# expand all globs
expandGlobs = (cb) ->
async.each config.options.path, (globToExpand, globCallback) ->
if /^http(s)?:\/\//.test globToExpand
config.files = config.files.concat globToExpand
return globCallback()
glob globToExpand, (err, match) ->
globCallback err if err
config.files = config.files.concat match
Expand All @@ -58,16 +65,43 @@ class Dredd

# load all files
loadFiles = (cb) ->
async.each config.files, (file, loadCallback) ->
fs.readFile file, 'utf8', (loadingError, data) ->
return loadCallback(loadingError) if loadingError
config.data[file] = {raw: data, filename: file}
loadCallback()

, (err) =>
# 6 parallel connections is a standard limit when connecting to one hostname,
# use the same limit of parallel connections for reading/downloading files
async.eachLimit config.files, 6, (fileUrlOrPath, loadCallback) ->
try
fileUrl = url.parse fileUrlOrPath
catch
fileUrl = null

if fileUrl and fileUrl.protocol in ['http:', 'https:'] and fileUrl.host
downloadFile fileUrlOrPath, loadCallback
else
readLocalFile fileUrlOrPath, loadCallback

, (err) ->
return callback(err, stats) if err
cb()

downloadFile = (fileUrl, downloadCallback) ->
request.get
url: fileUrl
timeout: 5000
json: false
, (downloadError, res, body) ->
if downloadError
downloadCallback {message: "Error when loading file from URL '#{fileUrl}'. Is the provided URL correct?"}
else if not body or res.statusCode < 200 or res.statusCode >= 300
downloadCallback {message: "Unable to load file from URL '#{fileUrl}'. Server did not send any blueprint back and responded with status code #{res.statusCode}."}
else
config.data[fileUrl] = {raw: body, filename: fileUrl}
downloadCallback()

readLocalFile = (filePath, readCallback) ->
fs.readFile filePath, 'utf8', (readingError, data) ->
return readCallback(readingError) if readingError
config.data[filePath] = {raw: data, filename: filePath}
readCallback()

# parse all file blueprints
parseBlueprints = (cb) ->
async.each Object.keys(config.data), (file, parseCallback) ->
Expand Down
112 changes: 110 additions & 2 deletions test/integration/cli-test.coffee
Expand Up @@ -5,7 +5,7 @@ clone = require 'clone'
bodyParser = require 'body-parser'
fs = require 'fs'

PORT = '3333'
PORT = 3333
CMD_PREFIX = ''

stderr = ''
Expand Down Expand Up @@ -38,7 +38,7 @@ execCommand = (cmd, options = {}, callback) ->

describe "Command line interface", () ->

describe "When blueprint file not found", (done) ->
describe "When blueprint file not found", ->
before (done) ->
cmd = "./bin/dredd ./test/fixtures/nonexistent_path.md http://localhost:#{PORT}"

Expand All @@ -50,6 +50,114 @@ describe "Command line interface", () ->
it 'should print error message to stderr', () ->
assert.include stderr, 'not found'


describe "When blueprint file should be loaded from 'http(s)://...' url", ->
server = null
loadedFromServer = null
connectedToServer = null
notFound = null
fileFound = null

errorCmd = "./bin/dredd http://localhost:#{PORT+1}/connection-error.apib http://localhost:#{PORT+1}"
wrongCmd = "./bin/dredd http://localhost:#{PORT}/not-found.apib http://localhost:#{PORT}"
goodCmd = "./bin/dredd http://localhost:#{PORT}/file.apib http://localhost:#{PORT}"

afterEach ->
connectedToServer = null

before (done) ->
app = express()

app.use (req, res, next) ->
connectedToServer = true
next()

app.get '/', (req, res) ->
res.sendStatus 404

app.get '/file.apib', (req, res) ->
fileFound = true
res.type('text')
stream = fs.createReadStream './test/fixtures/single-get.apib'
stream.pipe res

app.get '/machines', (req, res) ->
res.setHeader 'Content-Type', 'application/json'
machine =
type: 'bulldozer'
name: 'willy'
response = [machine]
res.status(200).send response

app.get '/not-found.apib', (req, res) ->
notFound = true
res.status(404).end()

server = app.listen PORT, ->
done()

after (done) ->
server.close ->
app = null
server = null
done()

describe 'and I try to load a file from bad hostname at all', ->
before (done) ->
execCommand errorCmd, ->
done()

after ->
connectedToServer = null

it 'should not send a GET to the server', ->
assert.isNull connectedToServer

it 'should exit with status 1', ->
assert.equal exitStatus, 1

it 'should print error message to stderr', ->
assert.include stderr, 'Error when loading file from URL'
assert.include stderr, 'Is the provided URL correct?'
assert.include stderr, 'connection-error.apib'

describe 'and I try to load a file that does not exist from an existing server', ->
before (done) ->
execCommand wrongCmd, ->
done()

after ->
connectedToServer = null

it 'should connect to the right server', ->
assert.isTrue connectedToServer

it 'should send a GET to server at wrong URL', ->
assert.isTrue notFound

it 'should exit with status 1', ->
assert.equal exitStatus, 1

it 'should print error message to stderr', ->
assert.include stderr, 'Unable to load file from URL'
assert.include stderr, 'responded with status code 404'
assert.include stderr, 'not-found.apib'

describe 'and I try to load a file that actually is there', ->
before (done) ->
execCommand goodCmd, ->
done()

it 'should send a GET to the right server', ->
assert.isTrue connectedToServer

it 'should send a GET to server at good URL', ->
assert.isTrue fileFound

it 'should exit with status 0', ->
assert.equal exitStatus, 0


describe "Arguments with existing blueprint and responding server", () ->
describe "when executing the command and the server is responding as specified in the blueprint", () ->

Expand Down

0 comments on commit 06c7699

Please sign in to comment.