spaceborne 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1dcf4d04a9ffe84ac8e4fb669a2eec42f8fcbf9f
4
- data.tar.gz: 6abc0a1a78d0651274724a2a0a07edc9d5d8a66e
3
+ metadata.gz: 1be4d255659704a43dfd8522c9e028e9cd34da75
4
+ data.tar.gz: 809d3a5002bb4de524e927ee403dfc8b4a6d79a5
5
5
  SHA512:
6
- metadata.gz: a170cf92402110c4c7a2aea73fb342e47c2a2de35a2a2e606a6f0ec2bb3fafb42292559e79e24da750c2221b4c3a70e9a9af1ccd8b048c9bce0fdc50afd123c5
7
- data.tar.gz: b5c318f6a08ceaa849321ee31467551d48974340bdf1fc907074946316982e1bfa930f6d7ff430f411fe5d9ab9cd660090e0453486f22a33e3f408d0fddf6d4c
6
+ metadata.gz: 620ae1514021b81d429d15f0fc9136c26be3f276bc131ee185701fc04a9bef2adc9215fe281733c3ded12add2f28dfbf8dddb51078653e9aa2d2de4bb9778ee5
7
+ data.tar.gz: ec66899ff1c619a07a462ca388c47e44eddcf655abb0161a9389d5d22c17ffd6133fe0afdffb056f14f5f382d51ea42d573429915ebb1da792a8299b7e13a43c
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
1
  --format documentation
2
- --color
3
- --tag ~todos
2
+ --color
data/Gemfile CHANGED
@@ -1,4 +1,10 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in spaceborne.gemspec
4
3
  gemspec
4
+
5
+ gem 'coveralls', require: false
6
+
7
+ group :test do
8
+ gem 'webmock'
9
+ gem 'sinatra'
10
+ end
data/README.md CHANGED
@@ -12,48 +12,224 @@ gem 'spaceborne'
12
12
 
13
13
  And then execute:
14
14
 
15
- $ bundle
15
+ ```ruby
16
+ $ bundle
17
+ ```
16
18
 
17
19
  Or install it yourself as:
18
20
 
19
- $ gem install spaceborne
21
+ ```ruby
22
+ $ gem install spaceborne
23
+ ```
20
24
 
21
25
  ## Creating API tests
22
26
 
27
+ ### Making a request
28
+
29
+ Spaceborne/airborne use curlyrest/rest-client to make the API requests. These are done in the manner that you actually think about the request, the http action verb, the url, headers, and body(optional depending on the verb). When creating a test, you can call any of the following methods: get, post, put, patch, delete, head, options.
30
+
31
+ #### Parts of a request
32
+
33
+ | part | description | restrictions |
34
+ |:--- |:----|:----|
35
+ |url|uri describing destination of the request|not including query/fragment|
36
+ |headers|hash of request headers|*optional request modifiers*|
37
+ |body|data being passed in the request|not on head/get requests|
38
+ |query|data passed on url after '?'|added as a 'params' hash in headers|
39
+
40
+ #### Optional request modifiers
41
+ These are passed as headers, but will be removed from the actual request, taking the desired effect.
42
+
43
+ | modifier | values | effect|
44
+ |:---|:---|:---|
45
+ |:use_curl| true, 'debug'|executes the command via curl, and if 'debug', output the command and response|
46
+ |:use_proxy| url of the proxy | sends the request to the proxy |
47
+ |:nonjson_data|true|forces content-type to application/x-www-form-urlencoded|
48
+
49
+ #### Request examples
50
+ passing request headers
51
+
52
+ ```ruby
53
+ get 'http://example.com/api/v1/my_api', { 'x-auth-token' => 'my_token' }
54
+ ```
55
+
56
+ passing a body (`post`, `put`, `patch`, `delete`) as a hash
57
+
58
+ ```ruby
59
+ post 'http://example.com/api/v1/my_api', { :name => 'John Doe' }, { 'x-auth-token' => 'my_token' }
60
+ ```
61
+
62
+ passing Query params via headers
63
+
64
+ ```ruby
65
+ post 'http://example.com/api/v1/my_api', { }, { 'params' => {'param_key' => 'param_value' } }
66
+ ```
67
+
68
+ make the request using curl and show me the entire request/response
69
+
70
+ ```ruby
71
+ get 'http://example.com/api/v1/my_api', { 'x-auth-token' => 'my_token', use_curl: 'debug' }
72
+ ```
73
+
74
+
75
+ ### Validating a response
76
+
77
+ Most of the power of spaceborne comes from being able to write expectations in a compact form that has great power at being able to perform the actual validation you have in mind. This allows you to build up positive and negative test cases and choose what parts of the response are important, or ignored. Here's an example that we'll look at.
78
+
23
79
  ```ruby
24
80
  require 'spaceborne'
25
81
 
26
- describe 'sample spec' do
27
- it 'should validate types' do
82
+ describe 'simple get sample' do
83
+ it 'should pass validation' do
28
84
  wrap_request do
29
85
  get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" }
30
86
  expect_json_types(name: :string)
87
+ expect_json(name: 'John Doe')
31
88
  end
32
89
  end
90
+ end
91
+ ```
92
+ The parts of the example outside of the wrap_request block are typical rspec. The wrap_request is a spaceborne concept, saying that if anything fails inside of the block, to ouput to stdout information about the request, and response. This is to work around the issue of an expectation failing, and having good info about why, but having no idea what the request or response were that caused the failure. The actual request is done on the get line. Validation of the response is the following expect_ lines.
93
+
94
+ #### Parts of response to validate
95
+
96
+ * HTTP Status
97
+ * `expect_status`(200) - expect to get a status of 200
98
+ * Headers
99
+ * `expect_header`(validators)
100
+ * `expect_header_types`(validators)
101
+ * JSON
102
+ * `expect_json`(validators)
103
+ * `expect_json`(path, validators)
104
+ * `expect_json_types`(validators)
105
+ * `expect_json_types`(path, validators)
106
+ * `expect_json_keys`(validators)
107
+ * `expect_json_keys`(path, validators)
108
+ * `expect_json_sizes`(validators)
109
+ * `expect_json_sizes`(path, validators)
110
+
111
+ ##### Validators
112
+ The validators mimic the structure of the response you're validating. For example, if your API returns the following json on a get call with Alex specified in the URL:
33
113
 
34
- it 'should validate values' do
35
- wrap_request do
36
- get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" }
37
- expect_json(name: 'John Doe')
38
- end
114
+ ```ruby
115
+ {
116
+ "name": "Alex",
117
+ "address": {
118
+ "street": "Area 51",
119
+ "city": "Roswell",
120
+ "state": "NM",
121
+ "coordinates": {
122
+ "latitude": 33.3872,
123
+ "longitude": 104.5281 } },
124
+ "phones": [
125
+ { "type": "cell",
126
+ "number": "123-456-7890"},
127
+ { "type": "home",
128
+ "number": "987-654-3210"} ]
129
+ }
130
+ ```
131
+
132
+ some possible validations are:
133
+
134
+ ```ruby
135
+ expect_json(name: 'Alex') # exact match because you asked for Alex
136
+ expect_json_types(name: :string, address: {street: :string, city: :string, state: :string,
137
+ coordinates: {latitude: :float, longitude: :float}},
138
+ phones: :array_of_objects) # all the types and structure (cannot go into arrays this way)
139
+ expect_json('address', state: /^[A-Z]{2}$/) # ensures address/state has 2 capital letters
140
+ expect_json_types('phones.*', type: :string, number: :string) # looks at all elements in array
141
+ expect_json_types('phones.1', type: :string, number: :string) # looks at second element in array
142
+ expect_json_keys('address', [:street, :city, :state, :coordinates]) # ensure specified keys present
143
+ expect_json_sizes(phones: 2) # expect the phones array size to be 2
144
+ ```
145
+
146
+ Additionally, if an entire object could be null, but you'd still want to test the types if it does exist, you can wrap the expectations in a call to `optional`:
147
+
148
+ ```ruby
149
+ it 'should allow optional nested hash' do
150
+ get '/simple_path_get' #may or may not return coordinates
151
+ expect_json_types('address.coordinates', optional(latitude: :float, longitude: :float))
152
+ end
153
+ ```
154
+
155
+ Additionally, when calling `expect_json`, you can provide a regex pattern in a call to `regex`:
156
+
157
+ ```ruby
158
+ describe 'sample spec' do
159
+ it 'should validate types' do
160
+ get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" }
161
+ expect_json(name: regex("^John"))
39
162
  end
40
163
  end
41
164
  ```
42
165
 
43
- ## Development
166
+ When calling `expect_json` or `expect_json_types`, you can optionally provide a block and run your own `rspec` expectations:
44
167
 
45
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
168
+ ```ruby
169
+ describe 'sample spec' do
170
+ it 'should validate types' do
171
+ get 'http://example.com/api/v1/simple_get' #json api that returns { "name" : "John Doe" }
172
+ expect_json(name: -> (name){ expect(name.length).to eq(8) })
173
+ end
174
+ end
175
+ ```
46
176
 
177
+ When calling `expect_*_types`, these are the valid types that can be tested against:
178
+
179
+ * `:int` or `:integer`
180
+ * `:float`
181
+ * `:bool` or `:boolean`
182
+ * `:string`
183
+ * `:date`
184
+ * `:object`
185
+ * `:null`
186
+ * `:array`
187
+ * `:array_of_integers` or `:array_of_ints`
188
+ * `:array_of_floats`
189
+ * `:array_of_strings`
190
+ * `:array_of_booleans` or `:array_of_bools`
191
+ * `:array_of_objects`
192
+ * `:array_of_arrays`
193
+
194
+ If the properties are optional and may not appear in the response, you can append `_or_null` to the types above.
195
+
196
+ Validation for headers follows the same pattern as above, although nesting of multiple levels isn't going to be needed.
197
+
47
198
  ## Extensions to Airborne
48
199
 
49
200
  1. Uses curlyrest to allow extension of rest-client with curl requests
50
- 2. Bundles groups of expectations so that if any fail, you will actually see the request and response printed out, rather than just seeing the expectation that failed
51
- 3. json_body is only calculated once after request rather than on each call
201
+ 2. Uses wrap_request to bundle groups of expectations so that if any fail, you will actually see the request and response printed out, rather than just seeing the expectation that failed
202
+ 3. json_body is only parsed once after a request rather than on each expect call
52
203
  4. Expectations for headers use the same form as the expectations for json bodies
53
204
  * `expect_header same arguments/handling as expect_json`
54
205
  * `expect_header_types same arguments/handling as expect_json_types`
55
- 5. Expectations returning a hash with keys that are unknown, but that have a defined structure are supported
56
- 6. It is possible to use non-json data in a request
206
+ 5. It is possible to use non-json data in a request
207
+ 6. Expectations on a response with an array of hashes with keys that are unknown, but that have a defined structure are supported (using the '*' in a path)
208
+
209
+ The following example shows how this works
210
+
211
+ ```ruby
212
+ { "array_of_hashes": [
213
+ { "husband": {"first": "fred", "last": "flinstone"}},
214
+ { "buddy": {"first": "barney", "last": "rubble"}},
215
+ { "wife": {"first": "wilma", "last": "flinstone"}}
216
+ ],
217
+ "hash_of_hashes":
218
+ { "husband": {"first": "fred", "last": "flinstone"},
219
+ "buddy": {"first": "barney", "last": "rubble"},
220
+ "wife": {"first": "wilma", "last": "flinstone"}
221
+ }
222
+ }
223
+ ```
224
+ You can now validate the fact that each element in the collection has a key which is variant, but a value that has a defined format (first and last are strings).
225
+
226
+ expect_json_types('array_of_hashes.*.*', first: :string, last: :string)
227
+ expect_json_types('hash_of_hashes.*', first: :string, last: :string)
228
+
229
+
230
+ ## Development
231
+
232
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
57
233
 
58
234
  ## Contributing
59
235
 
data/lib/spaceborne.rb CHANGED
@@ -37,7 +37,7 @@ module Airborne
37
37
  def make_request(method, url, options = {})
38
38
  @json_body = nil
39
39
  @request_body = nil
40
- if options[:headers].has_key?(:use_proxy)
40
+ if options[:headers] && options[:headers].has_key?(:use_proxy)
41
41
  proxy_option = options[:headers][:use_proxy]
42
42
  RestClient.proxy = proxy_option
43
43
  end
@@ -69,7 +69,7 @@ module Airborne
69
69
 
70
70
  private
71
71
  def base_headers
72
- { "Content-Type" => 'application/json' }.merge(Airborne.configuration.headers || {})
72
+ { content_type: :json }.merge(Airborne.configuration.headers || {})
73
73
  end
74
74
  end
75
75
 
@@ -113,7 +113,11 @@ module Airborne
113
113
  def get_by_path(path, json, &block)
114
114
  fail PathError, "Invalid Path, contains '..'" if /\.\./ =~ path
115
115
  type = false
116
- parts = path.split('.')
116
+ if path.class == Symbol
117
+ parts = path.to_s.split('.')
118
+ else
119
+ parts = path.split('.')
120
+ end
117
121
  parts.each_with_index do |part, index|
118
122
  if part == '*' || part == '?'
119
123
  ensure_array_or_hash(path, json)
@@ -1,3 +1,3 @@
1
1
  module Spaceborne
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
data/spaceborne.gemspec CHANGED
@@ -19,10 +19,15 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.add_runtime_dependency 'rspec', '~> 3.1'
23
+ spec.add_runtime_dependency 'rest-client', '< 3.0', '>= 1.7.3'
24
+ spec.add_runtime_dependency 'rack-test', '~> 0.6', '>= 0.6.2'
25
+ spec.add_runtime_dependency 'rack'
26
+ spec.add_runtime_dependency 'activesupport'
27
+ spec.add_development_dependency 'webmock', '~> 0'
28
+
22
29
  spec.add_development_dependency "bundler", "~> 1.11"
23
30
  spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "rspec", "~> 3.0"
25
- spec.add_development_dependency "rest-client", "~> 2.0"
26
31
  spec.add_development_dependency "byebug", "~> 2.0"
27
32
  spec.add_development_dependency "airborne", "~> 0.2.13"
28
33
  spec.add_development_dependency "curlyrest", "~> 0.1.0"
metadata CHANGED
@@ -1,71 +1,139 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spaceborne
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Williams
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-05 00:00:00.000000000 Z
11
+ date: 2018-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
14
+ name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
20
- type: :development
19
+ version: '3.1'
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '3.1'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.7.3
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: '3.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.7.3
47
+ - !ruby/object:Gem::Dependency
48
+ name: rack-test
29
49
  requirement: !ruby/object:Gem::Requirement
30
50
  requirements:
31
51
  - - "~>"
32
52
  - !ruby/object:Gem::Version
33
- version: '10.0'
53
+ version: '0.6'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 0.6.2
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '0.6'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 0.6.2
67
+ - !ruby/object:Gem::Dependency
68
+ name: rack
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: activesupport
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: webmock
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
34
102
  type: :development
35
103
  prerelease: false
36
104
  version_requirements: !ruby/object:Gem::Requirement
37
105
  requirements:
38
106
  - - "~>"
39
107
  - !ruby/object:Gem::Version
40
- version: '10.0'
108
+ version: '0'
41
109
  - !ruby/object:Gem::Dependency
42
- name: rspec
110
+ name: bundler
43
111
  requirement: !ruby/object:Gem::Requirement
44
112
  requirements:
45
113
  - - "~>"
46
114
  - !ruby/object:Gem::Version
47
- version: '3.0'
115
+ version: '1.11'
48
116
  type: :development
49
117
  prerelease: false
50
118
  version_requirements: !ruby/object:Gem::Requirement
51
119
  requirements:
52
120
  - - "~>"
53
121
  - !ruby/object:Gem::Version
54
- version: '3.0'
122
+ version: '1.11'
55
123
  - !ruby/object:Gem::Dependency
56
- name: rest-client
124
+ name: rake
57
125
  requirement: !ruby/object:Gem::Requirement
58
126
  requirements:
59
127
  - - "~>"
60
128
  - !ruby/object:Gem::Version
61
- version: '2.0'
129
+ version: '10.0'
62
130
  type: :development
63
131
  prerelease: false
64
132
  version_requirements: !ruby/object:Gem::Requirement
65
133
  requirements:
66
134
  - - "~>"
67
135
  - !ruby/object:Gem::Version
68
- version: '2.0'
136
+ version: '10.0'
69
137
  - !ruby/object:Gem::Dependency
70
138
  name: byebug
71
139
  requirement: !ruby/object:Gem::Requirement