api_pi 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|