Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions lib/add-tests.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ async = require 'async'
_ = require 'underscore'
csonschema = require 'csonschema'

selectSchemes = (names, schemes) ->
return _.pick(schemes, names)

parseSchema = (source) ->
if source.contains('$schema')
Expand Down Expand Up @@ -32,16 +34,31 @@ addTests = (raml, tests, hooks, parent, callback, testFactory) ->

return callback() unless raml.resources

parent ?= {
path: "",
params: {}
}

top_securedBy = raml.securedBy ? parent.securedBy

if not parent.security_schemes?
parent.security_schemes = {}
for scheme_map in raml.securitySchemes ? []
for scheme_name, scheme of scheme_map
parent.security_schemes[scheme_name] ?= []
parent.security_schemes[scheme_name].push(scheme)

# Iterate endpoint
async.each raml.resources, (resource, callback) ->
path = resource.relativeUri
params = {}
query = {}

resource_securedBy = resource.securedBy ? top_securedBy

# Apply parent properties
if parent
path = parent.path + path
params = _.clone parent.params
path = parent.path + path
params = _.clone parent.params

# Setup param
if resource.uriParameters
Expand All @@ -55,27 +72,29 @@ addTests = (raml, tests, hooks, parent, callback, testFactory) ->
# Iterate response method
async.each resource.methods, (api, callback) ->
method = api.method.toUpperCase()
headers = parseHeaders(api.headers)
method_securedBy = api.securedBy ? resource_securedBy

# Setup query
if api.queryParameters
for qkey, qvalue of api.queryParameters
if (!!qvalue.required)
query[qkey] = qvalue.example


# Iterate response status
for status, res of api.responses

buildTest = (status, res, security) ->
testName = "#{method} #{path} -> #{status}"
if security?
testName += " (#{security})"
if testName in hooks.skippedTests
return null

# Append new test to tests
test = testFactory.create(testName, hooks.contentTests[testName])
tests.push test

# Update test.request
test.request.path = path
test.request.method = method
test.request.headers = parseHeaders(api.headers)
test.request.headers = headers

# select compatible content-type in request body (to support vendor tree types, i.e. application/vnd.api+json)
contentType = (type for type of api.body when type.match(/^application\/(.*\+)?json/i))?[0]
Expand All @@ -102,13 +121,32 @@ addTests = (raml, tests, hooks, parent, callback, testFactory) ->
contentType = (type for type of res.body when type.match(/^application\/(.*\+)?json/i))?[0]
if res.body[contentType]?.schema
test.response.schema = parseSchema res.body[contentType].schema
return test

# Iterate response status
for status, res of api.responses
t = buildTest(status, res)
if t?
tests.push t

for scheme, lst of selectSchemes(method_securedBy, parent.security_schemes)
for l in lst
for status, res of l.describedBy?.responses ? {}
t = buildTest(status, res, scheme)
if t?
tests.push t

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

# Recursive
addTests resource, tests, hooks, {path, params}, callback, testFactory
new_parent = {
path, params,
securedBy: resource_securedBy,
security_schemes: parent.security_schemes
}
addTests resource, tests, hooks, new_parent, callback, testFactory
, callback


Expand Down
43 changes: 43 additions & 0 deletions test/fixtures/multiple-resources.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#%RAML 0.8

title: World Music API
baseUri: http://example.api.com/{version}
version: v1

/songs:
/song1:
get:
responses:
200:
body:
application/json:
schema: |
{ "$schema": "http://json-schema.org/schema",
"type": "object",
"description": "A canonical song",
"properties": {
"title": { "type": "string" },
"artist": { "type": "string" }
},
"required": [ "title", "artist" ]
}
example: |
{ "title": "A Beautiful Day", "artist": "Mike" }
/song2:
get:
responses:
200:
body:
application/json:
schema: |
{ "$schema": "http://json-schema.org/schema",
"type": "object",
"description": "A canonical song",
"properties": {
"title": { "type": "string" },
"artist": { "type": "string" }
},
"required": [ "title", "artist" ]
}
example: |
{ "title": "A Beautiful Day", "artist": "Mike" }
53 changes: 53 additions & 0 deletions test/fixtures/three-levels-security-top.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#%RAML 0.8

title: World Music API
baseUri: http://example.api.com/{version}
version: v1

securitySchemes:
- oauth_2_0: !include ./oauth_2_0.yml
- another_oauth_2_0: !include ./oauth_2_0.yml
- third_oauth_2_0: !include ./oauth_2_0.yml

securedBy: [oauth_2_0, another_oauth_2_0]

/machines:
get:
responses:
200:
body:
application/json:
schema: |
[
type: 'string'
name: 'string'
]
/{machine_id}:
securedBy: [oauth_2_0]
uriParameters:
machine_id:
description: |
The ID of the Machine
type: string
example: '1'
delete:
responses:
204:
/parts:
get:
responses:
200:
body:
application/json:
schema: |
type: 'string'
name: 'string'
put:
securedBy: [third_oauth_2_0]
responses:
200:
body:
application/json:
schema: |
type: 'string'
name: 'string'
110 changes: 110 additions & 0 deletions test/unit/add-tests-test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,35 @@ describe '#addTests', ->
assert.isNull res.headers
assert.isNull res.body

describe 'when hooks skip one POST', ->
tests = []
testFactory = new TestFactory()
callback = ''

before (done) ->

hooks.skippedTests = ["POST /machines -> 201"]
ramlParser.loadFile("#{RAML_DIR}/1-get-1-post.raml")
.then (data) ->
callback = sinon.stub()
callback.returns(done())

addTests data, tests, hooks, callback, testFactory
, done
return
after ->
tests = []
hooks.skippedTests = []

it 'should run callback', ->
assert.ok callback.called

it 'should add 1 test', ->
assert.lengthOf tests, 1

it 'should set test.name', ->
assert.equal tests[0].name, 'GET /machines -> 200'

describe 'when RAML includes multiple referencing schemas', ->

tests = []
Expand Down Expand Up @@ -247,6 +276,57 @@ describe '#addTests', ->
assert.deepEqual test.request.params,
machine_id: '1'

describe 'when RAML has securedBy set at top level', ->
tests = []
testFactory = new TestFactory()
callback = ''

before (done) ->

ramlParser.loadFile(
"#{RAML_DIR}/three-levels-security-top.raml"
).then (data) ->
callback = sinon.stub()
callback.returns(done())

addTests data, tests, hooks, callback, testFactory
, done
return
after ->
tests = []

it 'should run callback', ->
assert.ok callback.called

it 'should added 16 tests', ->
assert.lengthOf tests, 16

it 'should set test.name', ->
assert.equal tests[0].name, 'GET /machines -> 200'
assert.equal tests[1].name, 'GET /machines -> 401 (oauth_2_0)'
assert.equal tests[2].name, 'GET /machines -> 403 (oauth_2_0)'
assert.equal tests[3].name, 'GET /machines -> 401 (another_oauth_2_0)'
assert.equal tests[4].name, 'GET /machines -> 403 (another_oauth_2_0)'
assert.equal tests[5].name, 'DELETE /machines/{machine_id} -> 204'
assert.equal tests[6].name,
'DELETE /machines/{machine_id} -> 401 (oauth_2_0)'
assert.equal tests[7].name,
'DELETE /machines/{machine_id} -> 403 (oauth_2_0)'
assert.equal tests[8].name, 'GET /machines/{machine_id}/parts -> 200'
assert.equal tests[9].name,
'GET /machines/{machine_id}/parts -> 401 (oauth_2_0)'
assert.equal tests[10].name,
'GET /machines/{machine_id}/parts -> 403 (oauth_2_0)'
assert.equal tests[11].name,
'GET /machines/{machine_id}/parts -> 401 (another_oauth_2_0)'
assert.equal tests[12].name,
'GET /machines/{machine_id}/parts -> 403 (another_oauth_2_0)'
assert.equal tests[13].name, 'PUT /machines/{machine_id}/parts -> 200'
assert.equal tests[14].name,
'PUT /machines/{machine_id}/parts -> 401 (third_oauth_2_0)'
assert.equal tests[15].name,
'PUT /machines/{machine_id}/parts -> 403 (third_oauth_2_0)'

describe 'when RAML has resource not defined method', ->

tests = []
Expand Down Expand Up @@ -408,3 +488,33 @@ describe '#addTests', ->

it 'should not append query parameters', ->
assert.deepEqual tests[0].request.query, {}

describe 'when RAML has multiple resources', ->

tests = []
testFactory = new TestFactory()
callback = ''

before (done) ->
ramlParser.loadFile("#{RAML_DIR}/multiple-resources.raml")
.then (data) ->
console.error("got data")
callback = sinon.stub()
callback.returns(done())

console.error("calling addTests")
addTests data, tests, hooks, callback, testFactory
, done
return
after ->
tests = []

it 'should run callback', ->
assert.ok callback.called

it 'should add 2 tests', ->
assert.lengthOf tests, 2

it 'should set test.name', ->
assert.equal tests[0].name, 'GET /songs/song1 -> 200'
assert.equal tests[1].name, 'GET /songs/song2 -> 200'