api_pi 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +26 -0
- data/README.md +200 -0
- data/Rakefile +20 -0
- data/api_pi.gemspec +23 -0
- data/example/apiary.rb +30 -0
- data/lib/api_pi.rb +13 -0
- data/lib/api_pi/assertion.rb +127 -0
- data/lib/api_pi/case.rb +54 -0
- data/lib/api_pi/dsl.rb +37 -0
- data/lib/api_pi/request.rb +55 -0
- data/lib/api_pi/version.rb +3 -0
- data/test/test_helper.rb +14 -0
- data/test/unit/test_assertions.rb +101 -0
- data/test/unit/test_dsl.rb +16 -0
- data/test/unit/test_requests.rb +34 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 593aca0cfdef51079c984f36b65e73ff91782b6a
|
4
|
+
data.tar.gz: 36490547835fc125f4f35239921a11c36cacdcd4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 600be817d0712ec773b48ebee4b2fe4b6e04421e6f64f6043afc37e0fc618cc610b3177956a49b7a442639097ab73c8277f389360ae30d248c1f1964de05a3ea
|
7
|
+
data.tar.gz: 1956d03a05709903c9dedcc3e67358783984989f1c82f5adf0de666a3bed69bdc66d4856cb8002ab9b2c4a95b7d1010cdcc560624d82308c4db19b4a76a49786
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p0
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
api_pi (0.2.2)
|
5
|
+
map (~> 6.5)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.3.5)
|
11
|
+
crack (0.4.2)
|
12
|
+
safe_yaml (~> 1.0.0)
|
13
|
+
map (6.5.1)
|
14
|
+
rake (10.1.0)
|
15
|
+
safe_yaml (1.0.1)
|
16
|
+
webmock (1.17.3)
|
17
|
+
addressable (>= 2.2.7)
|
18
|
+
crack (>= 0.3.2)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
api_pi!
|
25
|
+
rake (~> 10.1)
|
26
|
+
webmock (~> 1.17)
|
data/README.md
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
# API P.I.
|
2
|
+
|
3
|
+
A ruby DSL to test expected values in a service API!
|
4
|
+
|
5
|
+
An example test can be found in the example/ directory.
|
6
|
+
|
7
|
+
## Install
|
8
|
+
|
9
|
+
Api P.I. requires ruby 2.0.0+
|
10
|
+
|
11
|
+
Clone this repository to your machine:
|
12
|
+
|
13
|
+
$ git clone git@github.ubermind.com:bewoodall/api_pi.git && cd api_pi
|
14
|
+
|
15
|
+
Build and Install the gem:
|
16
|
+
|
17
|
+
$ gem build api_pi.gemspec && gem install api_pi-VERSION.gem
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### GETting Data
|
22
|
+
|
23
|
+
To get a response from a particular service, you need to make an HTTP GET
|
24
|
+
request to a URL.
|
25
|
+
|
26
|
+
get "http://url-to-test.com/object.json" do...end
|
27
|
+
|
28
|
+
The `get` method takes a URL string and then is fed a block to build tests.
|
29
|
+
|
30
|
+
Once you GET your URL, you are ready to create test blocks.
|
31
|
+
|
32
|
+
### Setting Headers
|
33
|
+
|
34
|
+
If you need to set custom request headers, you can do so with the `set_header`
|
35
|
+
method. To set a header, call `set_header` before you `get`:
|
36
|
+
|
37
|
+
set_header "user-agent", "api-pi"
|
38
|
+
set_header "cookie", "set-cookie:my-cookies"
|
39
|
+
|
40
|
+
### Test Creation
|
41
|
+
|
42
|
+
Once you have your GET block created, you are ready to create test blocks.
|
43
|
+
Test blocks are used to group similar assertions into readable units.
|
44
|
+
|
45
|
+
For example, you may want to put your header tests into one test block:
|
46
|
+
|
47
|
+
get 'example.com/user.json' do
|
48
|
+
test 'Headers have correct data' do
|
49
|
+
# You header assertions...
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Inside of the test block, you would then put your header assertions. Once you
|
54
|
+
run your tests, your test blocks are grouped together and pass/fail based on
|
55
|
+
assertions in the test block.
|
56
|
+
|
57
|
+
### Header Querying
|
58
|
+
|
59
|
+
Header fields can be queried using the following format:
|
60
|
+
|
61
|
+
response.header.fields.in.dot.notation
|
62
|
+
|
63
|
+
`response.header` is required in order to use dot notation on header fields.
|
64
|
+
|
65
|
+
Example:
|
66
|
+
|
67
|
+
response.header.connection.is 'keep-alive'
|
68
|
+
response.header.contenttype.is 'application/json'
|
69
|
+
|
70
|
+
**Note that when using dot notation, you will need to omit dashes.
|
71
|
+
content-type should be written as contenttype.
|
72
|
+
content-length should be written as contentlength.**
|
73
|
+
|
74
|
+
### Response Code Querying
|
75
|
+
|
76
|
+
You may expect a certain response code to be returned from your HTTP GET.
|
77
|
+
To assert a specific code:
|
78
|
+
|
79
|
+
response.code.is 200
|
80
|
+
or
|
81
|
+
|
82
|
+
response.code.is "400"
|
83
|
+
|
84
|
+
### JSON Body Querying
|
85
|
+
|
86
|
+
A JSON block can be queried into using dot notation. For example:
|
87
|
+
|
88
|
+
{
|
89
|
+
"data": {
|
90
|
+
"string": "STRING",
|
91
|
+
"array": [1, 2, 3, 4],
|
92
|
+
"nest": {
|
93
|
+
"hello": "world",
|
94
|
+
"nest2": {
|
95
|
+
"good": "bye!"
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
To query the "nest2" field, you would say:
|
102
|
+
|
103
|
+
response.body.data.nest.nest2....
|
104
|
+
|
105
|
+
Querying into an Array can be done a few ways:
|
106
|
+
|
107
|
+
response.body.data.array.first
|
108
|
+
or
|
109
|
+
|
110
|
+
response.body.data.array.last
|
111
|
+
|
112
|
+
can be used to query the first and last item in the array.
|
113
|
+
|
114
|
+
To query a specific item in an array, use it's index:
|
115
|
+
|
116
|
+
response.body.data.array[1]
|
117
|
+
|
118
|
+
would query the array at index '1', which in this case is '2'
|
119
|
+
|
120
|
+
You can use rubys `each` to iterate through an array as well:
|
121
|
+
|
122
|
+
response.body.data.array.each do |a|
|
123
|
+
a.is_an Integer
|
124
|
+
end
|
125
|
+
|
126
|
+
This goes through the array and tests every item in it!
|
127
|
+
|
128
|
+
## Assertions
|
129
|
+
|
130
|
+
### is
|
131
|
+
|
132
|
+
`is` assertions are used to compare exact values.
|
133
|
+
|
134
|
+
"this".is "this" => true
|
135
|
+
200.is "200" => true
|
136
|
+
"this".is "that" => false
|
137
|
+
|
138
|
+
### is_a, is_an
|
139
|
+
|
140
|
+
The `is_a` and `is_an` assertions are used to assert Type on a field:
|
141
|
+
|
142
|
+
"Hello, World!".is_a String => true
|
143
|
+
3.14159265359.is_an Integer => true
|
144
|
+
"Not an array!".is_an Array => false
|
145
|
+
|
146
|
+
### has_key, lacks_key
|
147
|
+
|
148
|
+
The `has_key` and `lacks_key` assertions can be used to query if a certain field
|
149
|
+
is present in a JSON block:
|
150
|
+
|
151
|
+
{ "here": "present!" }.has_key "here" => true
|
152
|
+
{ "here": "present!" }.has_key "nope!" => false
|
153
|
+
|
154
|
+
{ "here": "present!" }.lacks_key "nope!" => true
|
155
|
+
{ "here": "present!" }.lacks_key "here" => false
|
156
|
+
|
157
|
+
### has_keys
|
158
|
+
|
159
|
+
`has_keys` works the same as `has_key`, except it takes multiple keys and test them all at once:
|
160
|
+
|
161
|
+
{ "here": "present!", "hello": "world!" }.has_keys "here","hello" => true
|
162
|
+
{ "here": "present!", "hello": "world!" }.has_keys "here","hope" => false
|
163
|
+
|
164
|
+
### matches
|
165
|
+
|
166
|
+
`matches` expectes a Regex formed value.
|
167
|
+
|
168
|
+
"hello".matches /ll/ => true
|
169
|
+
|
170
|
+
### includes
|
171
|
+
|
172
|
+
`includes` can be used for array to query if specific values are present:
|
173
|
+
|
174
|
+
[1,2,3,4].includes 2 => true
|
175
|
+
|
176
|
+
### not_nil?
|
177
|
+
|
178
|
+
`not_nil?` checks to see if the value is nil:
|
179
|
+
|
180
|
+
nil.not_nil? => false
|
181
|
+
"something".not_nil? => true
|
182
|
+
|
183
|
+
### stripped?
|
184
|
+
|
185
|
+
`stripped?` will test is there is whitespace before or after a string:
|
186
|
+
|
187
|
+
"works".stripped? => true
|
188
|
+
" spaces ".stripped? => false
|
189
|
+
|
190
|
+
## Testing
|
191
|
+
|
192
|
+
Api-PI is testing using Ruby's MiniTest framework. To run tests:
|
193
|
+
|
194
|
+
$ rake
|
195
|
+
|
196
|
+
To-Do
|
197
|
+
-----
|
198
|
+
|
199
|
+
* Ability to basic_auth before GET request
|
200
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
task :test => ["test:all","test:unit"]
|
4
|
+
|
5
|
+
task :default => "test:all"
|
6
|
+
|
7
|
+
namespace :test do
|
8
|
+
desc "Run all tests"
|
9
|
+
Rake::TestTask.new(:all) do |t|
|
10
|
+
t.libs << "test"
|
11
|
+
t.test_files = FileList['test/*/test_*.rb']
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Run unit tests"
|
15
|
+
Rake::TestTask.new(:unit) do |t|
|
16
|
+
t.libs << "test"
|
17
|
+
t.test_files = FileList['test/unit/test_*.rb']
|
18
|
+
t.verbose = true
|
19
|
+
end
|
20
|
+
end
|
data/api_pi.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require "api_pi/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |g|
|
6
|
+
g.name = 'api_pi'
|
7
|
+
g.version = ApiPi::VERSION
|
8
|
+
|
9
|
+
g.summary = "API validation DSL"
|
10
|
+
g.description = "A ruby DSL to validate API requests."
|
11
|
+
|
12
|
+
g.authors = "Ben Woodall"
|
13
|
+
g.email = "mail@benwoodall.com"
|
14
|
+
|
15
|
+
g.files = `git ls-files`.split("\n")
|
16
|
+
g.test_files = `git ls-files -- test/*`.split("\n")
|
17
|
+
|
18
|
+
g.extra_rdoc_files = ["README.md"]
|
19
|
+
|
20
|
+
g.add_dependency 'map', '~> 6.5'
|
21
|
+
g.add_development_dependency 'webmock', '~> 1.17'
|
22
|
+
g.add_development_dependency 'rake', '~> 10.1'
|
23
|
+
end
|
data/example/apiary.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'api_pi'
|
2
|
+
|
3
|
+
set_header "api-pi-demo-header", "api-pi-example"
|
4
|
+
|
5
|
+
get "http://apipi.apiary.io/tests" do
|
6
|
+
|
7
|
+
test "headers" do
|
8
|
+
response.header.contenttype.is "application/json"
|
9
|
+
response.code.is 200
|
10
|
+
end
|
11
|
+
|
12
|
+
test "body results.string" do
|
13
|
+
response.body.results.string.is_a String
|
14
|
+
response.body.results.string.matches /\w*/
|
15
|
+
end
|
16
|
+
|
17
|
+
test "results.int" do
|
18
|
+
response.body.results.int.is_an Integer
|
19
|
+
end
|
20
|
+
|
21
|
+
test "results" do
|
22
|
+
response.body.results.has_key "string"
|
23
|
+
response.body.results.lacks_key "nope"
|
24
|
+
response.body.results.has_keys "string","int","here","array"
|
25
|
+
end
|
26
|
+
|
27
|
+
test "results.array" do
|
28
|
+
response.body.results.array.includes 4
|
29
|
+
end
|
30
|
+
end
|
data/lib/api_pi.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'api_pi/case'
|
2
|
+
require 'api_pi/request'
|
3
|
+
require 'api_pi/dsl'
|
4
|
+
require 'api_pi/assertion'
|
5
|
+
require 'api_pi/version'
|
6
|
+
|
7
|
+
module ApiPi
|
8
|
+
|
9
|
+
# Build Headers, setting default User-Agent.
|
10
|
+
|
11
|
+
HEADER = { "user-agent" => "ApiPi-v#{ApiPi::VERSION}"}
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module ApiPi
|
2
|
+
class AssertionError < Exception;end
|
3
|
+
end
|
4
|
+
|
5
|
+
# Patches created to write test assertions
|
6
|
+
|
7
|
+
class Object
|
8
|
+
|
9
|
+
# `check_if` is used to build assertions. Create your own with it!
|
10
|
+
|
11
|
+
def check_if test, msg=nil
|
12
|
+
msg ||= "I don't know about that"
|
13
|
+
unless test then
|
14
|
+
raise ApiPi::AssertionError, msg
|
15
|
+
end
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# `is` assertions are used to compare exact values.
|
20
|
+
#
|
21
|
+
# "this".is "this" => true
|
22
|
+
# 200.is "200" => true
|
23
|
+
# "this".is "that" => false
|
24
|
+
|
25
|
+
def is this
|
26
|
+
msg = "#{self} is not #{this}"
|
27
|
+
if this.is_a? Integer
|
28
|
+
check_if self == this.to_s, msg
|
29
|
+
else
|
30
|
+
check_if self == this, msg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# The `is_a` and `is_an` assertions are used to assert Type on a field:
|
35
|
+
#
|
36
|
+
# "Hello, World!".is_a String => true
|
37
|
+
# 3.14159265359.is_a Float => true
|
38
|
+
# "Not an array!".is_an Array => false
|
39
|
+
|
40
|
+
def is_a klass
|
41
|
+
msg = "#{self} is not a #{klass}"
|
42
|
+
check_if self.is_a?(klass), msg
|
43
|
+
end
|
44
|
+
alias :is_an :is_a
|
45
|
+
|
46
|
+
# The `has_key` assertion can be used to query if a certain
|
47
|
+
# field is present in a JSON block:
|
48
|
+
#
|
49
|
+
# { "here": "present!" }.has_key "here" => true
|
50
|
+
# { "here": "present!" }.has_key "nope!" => false
|
51
|
+
|
52
|
+
def has_key kkey
|
53
|
+
msg = "#{kkey} was not found in #{self.keys.join(', ')}}"
|
54
|
+
check_if self.respond_to?(kkey), msg
|
55
|
+
end
|
56
|
+
|
57
|
+
# The `has_keys` assertion works the same as `has_key`, except it takes
|
58
|
+
# multiple keys and tests them all at once:
|
59
|
+
#
|
60
|
+
# { "here": "present!", "hello": "world!" }.has_keys "here","hello" => true
|
61
|
+
# { "here": "present!", "hello": "world!" }.has_keys "here","hope" => false
|
62
|
+
|
63
|
+
def has_keys *kkeys
|
64
|
+
not_found = []
|
65
|
+
kkeys.each do |k|
|
66
|
+
unless self.respond_to?(k)
|
67
|
+
not_found << k
|
68
|
+
end
|
69
|
+
end
|
70
|
+
if not_found.empty?
|
71
|
+
true
|
72
|
+
else
|
73
|
+
nf = not_found.join(", ")
|
74
|
+
msg = "#{nf} were not found in #{self.keys.join(', ')}"
|
75
|
+
raise ApiPi::AssertionError, msg
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# `lacks_key` is the opposite of `has_key`, in that it tests that a
|
80
|
+
# field is NOT present in a JSON block:
|
81
|
+
#
|
82
|
+
# { "here": "present!" }.lacks_key "nope!" => true
|
83
|
+
# { "here": "present!" }.lacks_key "here" => false
|
84
|
+
|
85
|
+
def lacks_key kkey
|
86
|
+
msg = "#{kkey} was found in #{self.keys.join(', ')}}"
|
87
|
+
check_if !self.respond_to?(kkey), msg
|
88
|
+
end
|
89
|
+
|
90
|
+
# `matches` expectes a Regex formed value.
|
91
|
+
#
|
92
|
+
# "hello".matches /ll/ => true
|
93
|
+
|
94
|
+
def matches regex
|
95
|
+
msg = "#{self} did not match regex #{regex}"
|
96
|
+
check_if self.match(regex), msg
|
97
|
+
end
|
98
|
+
|
99
|
+
# `includes` can be used for array to query if specific values are present:
|
100
|
+
#
|
101
|
+
# [1,2,3,4].includes 2 => true
|
102
|
+
|
103
|
+
def includes item
|
104
|
+
msg = "#{self} did not include #{item}"
|
105
|
+
check_if self.include?(item), msg
|
106
|
+
end
|
107
|
+
|
108
|
+
# `not_nil?` checks to see if the value is nil:
|
109
|
+
#
|
110
|
+
# nil.not_nil? => false
|
111
|
+
# "something".not_nil? => true
|
112
|
+
|
113
|
+
def not_nil?
|
114
|
+
msg = "#{self} was nil/null"
|
115
|
+
check_if !self.nil?, msg
|
116
|
+
end
|
117
|
+
|
118
|
+
# `stripped?` will test is there is whitespace before or after a string:
|
119
|
+
#
|
120
|
+
# "works".stripped? => true
|
121
|
+
# " spaces ".stripped? => false
|
122
|
+
|
123
|
+
def stripped?
|
124
|
+
msg = "#{self} contains whitespace"
|
125
|
+
check_if(self.strip == self, msg)
|
126
|
+
end
|
127
|
+
end
|
data/lib/api_pi/case.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module ApiPi
|
2
|
+
class Case
|
3
|
+
|
4
|
+
attr_reader :tests, :url
|
5
|
+
def initialize(url, tests)
|
6
|
+
@tests = tests
|
7
|
+
@url = url
|
8
|
+
@success_count = 0
|
9
|
+
@failure_count = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
# Begin investigating each GET request and their tests.
|
13
|
+
|
14
|
+
def investigate
|
15
|
+
puts "\nRequesting JSON from #{url} and testing"
|
16
|
+
tests.each_pair do |test, block|
|
17
|
+
print " - #{test}\n"
|
18
|
+
check test, block
|
19
|
+
end
|
20
|
+
summary
|
21
|
+
exit_status
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Runs tests and returns the results from the assertions.
|
27
|
+
|
28
|
+
def check test, block
|
29
|
+
res = []
|
30
|
+
begin
|
31
|
+
block.call
|
32
|
+
rescue ApiPi::AssertionError => e
|
33
|
+
res << e.message
|
34
|
+
end
|
35
|
+
failed = !res.empty?
|
36
|
+
failed ? @failure_count += 1 : @success_count += 1
|
37
|
+
puts "\tERROR: #{res.first}\n" if failed
|
38
|
+
end
|
39
|
+
|
40
|
+
# Text output from results of #check.
|
41
|
+
|
42
|
+
def summary
|
43
|
+
s = tests.keys.size
|
44
|
+
puts "\n#{s} tests, #{@success_count} succeeded, #{@failure_count} failed"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Exit api_pi with a status of 1 if there are any failed tests.
|
48
|
+
# Exit witha status of 0 if all tests succeeded.
|
49
|
+
|
50
|
+
def exit_status
|
51
|
+
@failure_count == 0 ? exit(0) : exit(1)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/api_pi/dsl.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'map'
|
2
|
+
|
3
|
+
module ApiPi
|
4
|
+
class Dsl
|
5
|
+
|
6
|
+
attr_reader :response, :tests
|
7
|
+
|
8
|
+
def initialize response
|
9
|
+
@tests = {}
|
10
|
+
@response = Map.new(response)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse url, block
|
14
|
+
self.instance_eval(&block)
|
15
|
+
pi = ApiPi::Case.new(url, tests)
|
16
|
+
pi.investigate
|
17
|
+
end
|
18
|
+
|
19
|
+
# Test blocks are used to group similar assertions into readable units.
|
20
|
+
#
|
21
|
+
# For example, you may want to put your header tests into one test block:
|
22
|
+
#
|
23
|
+
# get 'example.com/user.json' do
|
24
|
+
# test 'Headers have correct data' do
|
25
|
+
# # You header assertions...
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Inside of the test block, you would then put your header assertions.
|
30
|
+
# onceyou run your tests, your test blocks are grouped together and
|
31
|
+
# pass/fail based on assertions in the test block.
|
32
|
+
|
33
|
+
def test desc, &block
|
34
|
+
@tests[desc] = block
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Kernel
|
5
|
+
|
6
|
+
# Patch to add the `get` method. Create tests and assertions within.
|
7
|
+
|
8
|
+
def get url, &block
|
9
|
+
uri = URI.parse url
|
10
|
+
get = Net::HTTP::Get.new(uri)
|
11
|
+
req = Net::HTTPHeader.build_headers get
|
12
|
+
resp = Net::HTTP.start(uri.host, uri.port) { |http| http.request(req) }
|
13
|
+
json = net_parse resp
|
14
|
+
ApiPi::Dsl.new(json).parse(url, block)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Used to set headers for GET requests.
|
18
|
+
|
19
|
+
def set_header key, value
|
20
|
+
ApiPi::HEADER.merge!( { key => value } )
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Groups all of the response parsing
|
26
|
+
|
27
|
+
def net_parse response
|
28
|
+
body = { body: JSON.load(response.body) }
|
29
|
+
header = { header: response.to_dhash }
|
30
|
+
code = { code: response.code }
|
31
|
+
body.merge!(header).merge!(code)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Net::HTTPHeader
|
36
|
+
|
37
|
+
# Adds request headers from ApiPi::HEADER
|
38
|
+
def self.build_headers http_request
|
39
|
+
ApiPi::HEADER.each do |k,v|
|
40
|
+
http_request.add_field k, v
|
41
|
+
end
|
42
|
+
http_request
|
43
|
+
end
|
44
|
+
|
45
|
+
# Rebuild headers without dashes, which break JSON mapping.
|
46
|
+
|
47
|
+
def to_dhash
|
48
|
+
head = {}
|
49
|
+
self.each_header do |k,v|
|
50
|
+
new_hash = Hash[k.gsub('-',''), v]
|
51
|
+
head.merge!(new_hash)
|
52
|
+
end
|
53
|
+
head
|
54
|
+
end
|
55
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ApiPi
|
4
|
+
class TestAssertions < TestCase
|
5
|
+
|
6
|
+
def test_patch_methods
|
7
|
+
assert Object.respond_to?(:check_if), Object.check_if(true, "Yep")
|
8
|
+
assert Object.respond_to?(:is), Object.is(Object)
|
9
|
+
assert Object.respond_to?(:is_a), @map.k.is_a(String)
|
10
|
+
assert Object.respond_to?(:is_an), Object.is_an(Object)
|
11
|
+
assert Object.respond_to?(:has_key), @map.has_key(:k)
|
12
|
+
assert Object.respond_to?(:has_keys), @map.has_keys(:k,:m)
|
13
|
+
assert Object.respond_to?(:lacks_key), @map.lacks_key(:v)
|
14
|
+
assert Object.respond_to?(:matches), "string".matches(/.*/)
|
15
|
+
assert Object.respond_to?(:includes), [1,2,3].includes(2)
|
16
|
+
assert Object.respond_to?(:not_nil?), "not_nil".not_nil?
|
17
|
+
assert Object.respond_to?(:stripped?), "stripped".stripped?
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_check_if__with_true
|
21
|
+
assert check_if(true)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_check_if__with_false
|
25
|
+
assert_raises(ApiPi::AssertionError) { check_if false }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_is__with_true
|
29
|
+
assert "this".is("this")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_is__with_false
|
33
|
+
assert_raises(ApiPi::AssertionError) { "this".is("that") }
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_is__with_integers
|
37
|
+
assert "200".is(200)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_is_a__with_true
|
41
|
+
assert "string".is_a(String)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_is_a__with_false
|
45
|
+
assert_raises(ApiPi::AssertionError) { "string".is_a(Integer) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_has_key__with_true
|
49
|
+
assert @map.has_key(:k)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_has_key__with_false
|
53
|
+
assert_raises(ApiPi::AssertionError) { @map.has_key(:n) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_has_keys__with_true
|
57
|
+
assert @map.has_keys(:k,:m)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_has_keys__with_false
|
61
|
+
assert_raises(ApiPi::AssertionError) { @map.has_keys(:n,:r) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_lacks_key__with_true
|
65
|
+
assert @map.lacks_key(:n)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_lacks_key__with_false
|
69
|
+
assert_raises(ApiPi::AssertionError) { @map.lacks_key(:k) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_matches__with_true
|
73
|
+
assert @map.k.matches(/v/)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_matches__with_false
|
77
|
+
assert_raises(ApiPi::AssertionError) { @map.k.matches(/\d/) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_includes__with_true
|
81
|
+
assert @map.a.includes(1)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_includes__with_false
|
85
|
+
assert_raises(ApiPi::AssertionError) { @map.a.includes("n") }
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_not_nil__with_nil
|
89
|
+
assert_raises(ApiPi::AssertionError) { nil.not_nil? }
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_not_nil__with_not_nil
|
93
|
+
assert "not_nil".not_nil?
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_stripped?
|
97
|
+
assert "stripped".stripped?
|
98
|
+
assert_raises(ApiPi::AssertionError) { " not_stripped ". stripped? }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ApiPi
|
4
|
+
class TestDsl < TestCase
|
5
|
+
|
6
|
+
def test_response_gathering
|
7
|
+
r = ApiPi::Dsl.new(t:'t')
|
8
|
+
r.test "metadata" do
|
9
|
+
"test".is_a(String)
|
10
|
+
end
|
11
|
+
assert r.tests.has_key?('metadata'), r.tests['metadata']
|
12
|
+
assert_kind_of Proc, r.tests['metadata']
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ApiPi
|
4
|
+
class TestRequests < TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@good_url = "http://test-service.com/200.json"
|
8
|
+
@good_header = { 'Content-Type' => 'application/json' }
|
9
|
+
stub_request(:get, @good_url)
|
10
|
+
.to_return(status: 200, body: "", headers: @good_header)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_kernel_responds_to_get
|
14
|
+
assert Kernel.respond_to?(:get)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_kernel_responds_to_set_header
|
18
|
+
assert Kernel.respond_to?(:set_header)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_set_header
|
22
|
+
set_header "User-Agent", "Api-Pi Test"
|
23
|
+
set_header "Not-A-Field", "But-I-Work"
|
24
|
+
assert ApiPi::HEADER.has_key?("User-Agent")
|
25
|
+
assert ApiPi::HEADER.has_key?("Not-A-Field")
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_dhash
|
29
|
+
resp = Net::HTTP.get_response(URI(@good_url))
|
30
|
+
header = resp.to_dhash
|
31
|
+
assert header.has_key?('contenttype')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api_pi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Woodall
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: map
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: webmock
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.17'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.17'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.1'
|
55
|
+
description: A ruby DSL to validate API requests.
|
56
|
+
email: mail@benwoodall.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files:
|
60
|
+
- README.md
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .ruby-version
|
64
|
+
- Gemfile
|
65
|
+
- Gemfile.lock
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- api_pi.gemspec
|
69
|
+
- example/apiary.rb
|
70
|
+
- lib/api_pi.rb
|
71
|
+
- lib/api_pi/assertion.rb
|
72
|
+
- lib/api_pi/case.rb
|
73
|
+
- lib/api_pi/dsl.rb
|
74
|
+
- lib/api_pi/request.rb
|
75
|
+
- lib/api_pi/version.rb
|
76
|
+
- test/test_helper.rb
|
77
|
+
- test/unit/test_assertions.rb
|
78
|
+
- test/unit/test_dsl.rb
|
79
|
+
- test/unit/test_requests.rb
|
80
|
+
homepage:
|
81
|
+
licenses: []
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 2.0.0
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: API validation DSL
|
103
|
+
test_files:
|
104
|
+
- test/test_helper.rb
|
105
|
+
- test/unit/test_assertions.rb
|
106
|
+
- test/unit/test_dsl.rb
|
107
|
+
- test/unit/test_requests.rb
|