rest-assured 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -1
- data/Gemfile.lock +40 -24
- data/README.markdown +96 -66
- data/db/migrate/20111208155906_add_response_headers_to_doubles.rb +9 -0
- data/features/rest_api/doubles.feature +5 -0
- data/features/ruby_api/create_double.feature +40 -0
- data/features/ruby_api/verify_requests.feature +43 -9
- data/features/ruby_api/wait_for_requests.feature +5 -2
- data/features/step_definitions/doubles_steps.rb +10 -14
- data/features/step_definitions/redirect_rules_steps.rb +0 -4
- data/features/step_definitions/ruby_api_steps.rb +15 -16
- data/features/support/env.rb +0 -2
- data/lib/rest-assured.rb +0 -1
- data/lib/rest-assured/client/resources.rb +4 -0
- data/lib/rest-assured/models/double.rb +20 -17
- data/lib/rest-assured/routes/double.rb +15 -3
- data/lib/rest-assured/routes/response.rb +1 -0
- data/lib/rest-assured/version.rb +1 -1
- data/spec/functional/double_routes_spec.rb +29 -7
- data/spec/functional/response_spec.rb +12 -1
- data/spec/models/double_spec.rb +8 -1
- metadata +8 -4
data/Gemfile
CHANGED
@@ -17,7 +17,11 @@ gem 'launchy'
|
|
17
17
|
gem 'rake'
|
18
18
|
gem "spork", "> 0.9.0.rc"
|
19
19
|
gem "guard-spork"
|
20
|
-
|
20
|
+
if RUBY_PLATFORM =~ /darwin/
|
21
|
+
gem 'growl_notify'
|
22
|
+
gem 'rb-fsevent'
|
23
|
+
end
|
21
24
|
gem 'sinatra-activerecord'
|
22
25
|
gem 'mysql'
|
23
26
|
gem 'sqlite3', '~> 1.3.4'
|
27
|
+
gem 'thin'
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rest-assured (0.
|
4
|
+
rest-assured (0.3.0)
|
5
5
|
activerecord (~> 3.1.0)
|
6
6
|
activeresource (~> 3.1.0)
|
7
7
|
haml (>= 3.1.3)
|
@@ -11,21 +11,22 @@ PATH
|
|
11
11
|
GEM
|
12
12
|
remote: http://rubygems.org/
|
13
13
|
specs:
|
14
|
-
activemodel (3.1.
|
15
|
-
activesupport (= 3.1.
|
14
|
+
activemodel (3.1.3)
|
15
|
+
activesupport (= 3.1.3)
|
16
16
|
builder (~> 3.0.0)
|
17
17
|
i18n (~> 0.6)
|
18
|
-
activerecord (3.1.
|
19
|
-
activemodel (= 3.1.
|
20
|
-
activesupport (= 3.1.
|
18
|
+
activerecord (3.1.3)
|
19
|
+
activemodel (= 3.1.3)
|
20
|
+
activesupport (= 3.1.3)
|
21
21
|
arel (~> 2.2.1)
|
22
22
|
tzinfo (~> 0.3.29)
|
23
|
-
activeresource (3.1.
|
24
|
-
activemodel (= 3.1.
|
25
|
-
activesupport (= 3.1.
|
26
|
-
activesupport (3.1.
|
23
|
+
activeresource (3.1.3)
|
24
|
+
activemodel (= 3.1.3)
|
25
|
+
activesupport (= 3.1.3)
|
26
|
+
activesupport (3.1.3)
|
27
27
|
multi_json (~> 1.0)
|
28
28
|
addressable (2.2.6)
|
29
|
+
archive-tar-minitar (0.5.2)
|
29
30
|
arel (2.2.1)
|
30
31
|
awesome_print (0.4.0)
|
31
32
|
builder (3.0.0)
|
@@ -40,18 +41,22 @@ GEM
|
|
40
41
|
capybara (~> 1.0)
|
41
42
|
childprocess (0.2.2)
|
42
43
|
ffi (~> 1.0.6)
|
43
|
-
columnize (0.3.
|
44
|
+
columnize (0.3.5)
|
44
45
|
cucumber (1.1.0)
|
45
46
|
builder (>= 2.1.2)
|
46
47
|
diff-lcs (>= 1.1.2)
|
47
48
|
gherkin (~> 2.5.0)
|
48
49
|
json (>= 1.4.6)
|
49
50
|
term-ansicolor (>= 1.0.6)
|
51
|
+
daemons (1.1.4)
|
50
52
|
database_cleaner (0.6.7)
|
51
53
|
diff-lcs (1.1.3)
|
52
|
-
|
54
|
+
eventmachine (0.12.10)
|
55
|
+
ffi (1.0.11)
|
53
56
|
gherkin (2.5.4)
|
54
57
|
json (>= 1.4.6)
|
58
|
+
growl_notify (0.0.3)
|
59
|
+
rb-appscript
|
55
60
|
guard (0.8.8)
|
56
61
|
thor (~> 0.14.6)
|
57
62
|
guard-spork (0.3.1)
|
@@ -65,10 +70,10 @@ GEM
|
|
65
70
|
json_pure (1.6.1)
|
66
71
|
launchy (2.0.5)
|
67
72
|
addressable (~> 2.2.6)
|
68
|
-
|
69
|
-
|
73
|
+
linecache19 (0.5.12)
|
74
|
+
ruby_core_source (>= 0.1.4)
|
70
75
|
mime-types (1.16)
|
71
|
-
multi_json (1.0.
|
76
|
+
multi_json (1.0.4)
|
72
77
|
mysql (2.8.1)
|
73
78
|
nokogiri (1.5.0)
|
74
79
|
rack (1.3.5)
|
@@ -79,8 +84,8 @@ GEM
|
|
79
84
|
rack-test (0.6.1)
|
80
85
|
rack (>= 1.0)
|
81
86
|
rake (0.9.2.2)
|
87
|
+
rb-appscript (0.6.1)
|
82
88
|
rb-fsevent (0.4.3.1)
|
83
|
-
rbx-require-relative (0.0.5)
|
84
89
|
rspec (2.7.0)
|
85
90
|
rspec-core (~> 2.7.0)
|
86
91
|
rspec-expectations (~> 2.7.0)
|
@@ -89,15 +94,20 @@ GEM
|
|
89
94
|
rspec-expectations (2.7.0)
|
90
95
|
diff-lcs (~> 1.1.2)
|
91
96
|
rspec-mocks (2.7.0)
|
92
|
-
ruby-debug (0.
|
93
|
-
columnize (>= 0.1)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
ruby-debug-base19 (0.11.25)
|
98
|
+
columnize (>= 0.3.1)
|
99
|
+
linecache19 (>= 0.5.11)
|
100
|
+
ruby_core_source (>= 0.1.4)
|
101
|
+
ruby-debug19 (0.11.6)
|
102
|
+
columnize (>= 0.3.1)
|
103
|
+
linecache19 (>= 0.5.11)
|
104
|
+
ruby-debug-base19 (>= 0.11.19)
|
105
|
+
ruby_core_source (0.1.5)
|
106
|
+
archive-tar-minitar (>= 0.5.2)
|
97
107
|
rubyzip (0.9.4)
|
98
|
-
selenium-webdriver (2.
|
108
|
+
selenium-webdriver (2.12.2)
|
99
109
|
childprocess (>= 0.2.1)
|
100
|
-
ffi (
|
110
|
+
ffi (~> 1.0.9)
|
101
111
|
json_pure
|
102
112
|
rubyzip
|
103
113
|
shoulda-matchers (1.0.0.beta3)
|
@@ -111,6 +121,10 @@ GEM
|
|
111
121
|
spork (0.9.0.rc9)
|
112
122
|
sqlite3 (1.3.4)
|
113
123
|
term-ansicolor (1.0.7)
|
124
|
+
thin (1.3.1)
|
125
|
+
daemons (>= 1.0.9)
|
126
|
+
eventmachine (>= 0.12.6)
|
127
|
+
rack (>= 1.0.0)
|
114
128
|
thor (0.14.6)
|
115
129
|
tilt (1.3.3)
|
116
130
|
tzinfo (0.3.31)
|
@@ -126,6 +140,7 @@ DEPENDENCIES
|
|
126
140
|
capybara-firebug
|
127
141
|
cucumber
|
128
142
|
database_cleaner
|
143
|
+
growl_notify
|
129
144
|
guard-spork
|
130
145
|
interactive_editor
|
131
146
|
launchy
|
@@ -135,8 +150,9 @@ DEPENDENCIES
|
|
135
150
|
rb-fsevent
|
136
151
|
rest-assured!
|
137
152
|
rspec
|
138
|
-
ruby-
|
153
|
+
ruby-debug19
|
139
154
|
shoulda-matchers
|
140
155
|
sinatra-activerecord
|
141
156
|
spork (> 0.9.0.rc)
|
142
157
|
sqlite3 (~> 1.3.4)
|
158
|
+
thin
|
data/README.markdown
CHANGED
@@ -15,9 +15,13 @@ You are going to need ruby >= 1.8.7.
|
|
15
15
|
|
16
16
|
First make sure there is database adapter:
|
17
17
|
|
18
|
-
bash$ gem install
|
18
|
+
bash$ gem install sqlite3 # or mysql
|
19
19
|
|
20
|
-
If using mysql, rest-assured expects database 'rest\_assured' to be accessible by user 'root' with no password. Those are defaults and
|
20
|
+
If using mysql, rest-assured expects database 'rest\_assured' to be accessible by user 'root' with no password. Those are defaults and can be changed with cli options.
|
21
|
+
|
22
|
+
It is also recommended to have thin installed. This improves startup time (over default webrick) and also it works in-memory sqlite (which webrick does not):
|
23
|
+
|
24
|
+
bash$ gem install thin
|
21
25
|
|
22
26
|
Then install gem and run:
|
23
27
|
|
@@ -28,23 +32,21 @@ Or clone from github and run:
|
|
28
32
|
|
29
33
|
bash$ git clone git@github.com:BBC/rest-assured.git
|
30
34
|
bash$ cd rest-assured && bundle install
|
31
|
-
bash$ ./bin/rest-assured -
|
35
|
+
bash$ ./bin/rest-assured -d :memory: & # in-memory sqlite db
|
32
36
|
|
33
|
-
This starts an instance of rest-assured on port 4578
|
37
|
+
This starts an instance of rest-assured on port 4578. It is accessible via REST or web interfaces on 'http://localhost:4578'
|
34
38
|
|
35
39
|
Various options (such as ssl, port, db credentials, etc.) are available through command line options. Check out `rest-assured -h` to see what they are.
|
36
40
|
|
37
|
-
NOTE that although sqlite is an option, I found it locking under
|
38
|
-
|
39
|
-
## REST API
|
41
|
+
NOTE that although sqlite is an extremely handy option (especially with :memory:), I found it sometimes locking tables under non-trivial load. Hence there is mysql - more setup, but always works. But may be that is just me sqliting it wrong.
|
40
42
|
|
41
|
-
|
43
|
+
## Doubles
|
42
44
|
|
43
|
-
Double is a stub/mock of
|
45
|
+
Double is a stub/mock of HTTP request.
|
44
46
|
|
45
|
-
|
47
|
+
### Ruby Client API
|
46
48
|
|
47
|
-
Rest-assured provides client library
|
49
|
+
Rest-assured provides client library to work with doubles. Set it up in env.rb/spec_helper.rb first:
|
48
50
|
|
49
51
|
```ruby
|
50
52
|
require 'rest-assured/client'
|
@@ -52,107 +54,127 @@ require 'rest-assured/client'
|
|
52
54
|
RestAssured::Client.config.server_address = 'http://localhost:4578' # or wherever your rest-assured is
|
53
55
|
```
|
54
56
|
|
55
|
-
You can then create doubles in your tests
|
57
|
+
You can then create doubles in your tests:
|
56
58
|
|
57
59
|
```ruby
|
58
60
|
RestAssured::Double.create(fullpath: '/products', content: 'this is content')
|
59
61
|
```
|
60
62
|
|
61
|
-
|
63
|
+
Now GET 'http://localhost:4578/products' will be returning 'this is content'.
|
64
|
+
|
65
|
+
You can also verify what requests happen on a double. Say this is a Given part of a test:
|
62
66
|
|
63
67
|
```ruby
|
64
68
|
@double = RestAssured::Double.create(fullpath: '/products', verb: 'POST')
|
65
69
|
```
|
66
70
|
|
67
|
-
|
71
|
+
Then let us assume that 'http://localhost:4578/products' got POSTed as a result of some actions in When part. Now we can examine requests happened on that double in Then part:
|
68
72
|
|
69
73
|
```ruby
|
70
|
-
@double.wait_for_requests(1, :timeout => 10) #
|
74
|
+
@double.wait_for_requests(1, :timeout => 10) # defaults to 5 seconds
|
71
75
|
|
72
76
|
req = @double.requests.first
|
73
77
|
|
74
78
|
req.body.should == expected_payload
|
75
79
|
JSON.parse(req.params).should == expected_params_hash
|
76
|
-
JSON.parse(req.rack_env)['ACCEPT'].should == '
|
80
|
+
JSON.parse(req.rack_env)['ACCEPT'].should == 'text/html'
|
77
81
|
```
|
78
82
|
|
79
|
-
|
83
|
+
Use plain rest api to clear doubles/redirects between tests:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
RestClient.delete "#{RestAssured::Client.config.server_address}/redirects/all"
|
87
|
+
RestClient.delete "#{RestAssured::Client.config.server_address}/doubles/all"
|
88
|
+
```
|
89
|
+
|
90
|
+
### Plain REST API
|
91
|
+
|
92
|
+
#### Create double
|
80
93
|
|
81
|
-
|
82
|
-
HTTP POST to '/doubles.json' creates double and returns its json representation.
|
94
|
+
HTTP POST to '/doubles' creates double and returns its json representation.
|
83
95
|
The following options can be passed as request parameters:
|
84
96
|
|
85
97
|
- __fullpath__ - e.g., '/some/api/object', or with parameters in query string (useful for doubling GETs) - '/some/other/api/object?a=2&b=c'. Mandatory.
|
86
98
|
- __content__ - whatever you want this double to respond with. Optional.
|
87
99
|
- __verb__ - one of http the following http verbs: GET, POST, PUT, DELETE. Optional. GET is default.
|
88
100
|
- __status__ - status returned when double is requested. Optional. 200 is default.
|
89
|
-
|
90
|
-
Example (using ruby RestClient):
|
101
|
+
- __response_headers__ - key/value map of headers. Optional.
|
91
102
|
|
92
|
-
|
93
|
-
response = RestClient.post 'http://localhost:4578/doubles', { fullpath: '/api/v2/products?type=fresh', verb: 'GET', content: 'this is list of products', status: 200 }
|
94
|
-
puts response.body
|
95
|
-
```
|
96
|
-
Produces:
|
103
|
+
Example:
|
97
104
|
|
98
|
-
|
105
|
+
bash$ curl -d 'fullpath=/api/something&content=awesome&response_headers%5BContent-Type%5D=text%2Fhtml' http://localhost:4578/doubles
|
106
|
+
{"double":{"active":true,"content":"awesome","description":null,"fullpath":"/api/something","id":1,"response_headers":{"Content-Type":"text/html"},"status":200,"verb":"GET"}}
|
99
107
|
|
100
|
-
|
108
|
+
bash$ curl http://localhost:4578/api/something
|
109
|
+
awesome
|
101
110
|
|
102
111
|
If there is more than one double for the same fullpath and verb, the last created one gets served. In UI you can manually control which double is 'active' (gets served).
|
103
112
|
|
104
|
-
|
105
|
-
HTTP GET to '/double/:id.json' returns json with double current state. Use id from create json as :id.
|
106
|
-
|
107
|
-
Example (using ruby RestClient):
|
108
|
-
|
109
|
-
```ruby
|
110
|
-
response = RestClient.get 'http://localhost:4578/doubles/123.json'
|
111
|
-
puts response.body
|
112
|
-
```
|
113
|
-
|
114
|
-
Assuming the above double has been requested once, this call would produce
|
113
|
+
#### Get double state
|
115
114
|
|
116
|
-
|
117
|
-
|
118
|
-
|
115
|
+
HTTP GET to '/doubles/:id.json' returns json with double current state. Use id from create json as :id.
|
116
|
+
|
117
|
+
Example:
|
118
|
+
|
119
|
+
bash$ curl http://localhost:4578/doubles/1.json | prettify_json.rb
|
120
|
+
{
|
121
|
+
"double": {
|
122
|
+
"verb": "GET",
|
123
|
+
"fullpath": "/api/something",
|
124
|
+
"response_headers": {
|
125
|
+
"Content-Type": "text/html"
|
126
|
+
},
|
127
|
+
"id": 1,
|
128
|
+
"requests": [
|
129
|
+
{
|
130
|
+
"double_id": 1,
|
131
|
+
"created_at": "2011-12-12T11:13:33+00:00",
|
132
|
+
"body": "",
|
133
|
+
"rack_env": "{\"SERVER_SOFTWARE\":\"thin 1.3.1 codename Triple Espresso\",\"SERVER_NAME\":\"localhost\",\"rack.version\":[1,0],\"rack.multithread\":false,\"rack.multiprocess\":false,\"rack.run_once\":false,\"REQUEST_METHOD\":\"GET\",\"REQUEST_PATH\":\"/api/something\",\"PATH_INFO\":\"/api/something\",\"REQUEST_URI\":\"/api/something\",\"HTTP_VERSION\":\"HTTP/1.1\",\"HTTP_USER_AGENT\":\"curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3\",\"HTTP_HOST\":\"localhost:4578\",\"HTTP_ACCEPT\":\"*/*\",\"GATEWAY_INTERFACE\":\"CGI/1.2\",\"SERVER_PORT\":\"4578\",\"QUERY_STRING\":\"\",\"SERVER_PROTOCOL\":\"HTTP/1.1\",\"rack.url_scheme\":\"http\",\"SCRIPT_NAME\":\"\",\"REMOTE_ADDR\":\"127.0.0.1\",\"async.callback\":{},\"async.close\":{},\"rack.session\":{\"session_id\":\"2d206d4edb880d41ae098bf0551c6904a4914f8632d101606b5304d4f651ce52\",\"tracking\":{\"HTTP_USER_AGENT\":\"06e79511d71287ca292dced4ef07c8fff9400376\",\"HTTP_ACCEPT_ENCODING\":\"da39a3ee5e6b4b0d3255bfef95601890afd80709\",\"HTTP_ACCEPT_LANGUAGE\":\"da39a3ee5e6b4b0d3255bfef95601890afd80709\"},\"__FLASH__\":{}},\"rack.session.options\":{\"key\":\"rack.session\",\"path\":\"/\",\"domain\":null,\"expire_after\":null,\"secure\":false,\"httponly\":true,\"defer\":false,\"renew\":false,\"sidbits\":128,\"secure_random\":{\"pid\":7885},\"secret\":\"bf80c75d713c92d2e3f94ea58be318c3f8988a3ed79d997f9cf883cc7aab1141225477ed81da7fe62ac77ecac3f979d255328dcbe8caa1bb342f4be6cb850983\",\"coder\":{},\"id\":\"2d206d4edb880d41ae098bf0551c6904a4914f8632d101606b5304d4f651ce52\"},\"rack.request.cookie_hash\":{},\"rack.session.unpacked_cookie_data\":{\"session_id\":\"2d206d4edb880d41ae098bf0551c6904a4914f8632d101606b5304d4f651ce52\"},\"x-rack.flash\":{\"opts\":{\"sweep\":true},\"store\":{\"session_id\":\"2d206d4edb880d41ae098bf0551c6904a4914f8632d101606b5304d4f651ce52\",\"tracking\":{\"HTTP_USER_AGENT\":\"06e79511d71287ca292dced4ef07c8fff9400376\",\"HTTP_ACCEPT_ENCODING\":\"da39a3ee5e6b4b0d3255bfef95601890afd80709\",\"HTTP_ACCEPT_LANGUAGE\":\"da39a3ee5e6b4b0d3255bfef95601890afd80709\"},\"__FLASH__\":{}},\"flagged\":[]},\"rack.request.query_string\":\"\",\"rack.request.query_hash\":{}}",
|
134
|
+
"id": 1,
|
135
|
+
"params": "{}"
|
136
|
+
}
|
137
|
+
],
|
138
|
+
"content": "awesome",
|
139
|
+
"description": null,
|
140
|
+
"status": 200,
|
141
|
+
"active": true
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
The above assumes that that double has been requested once. Request history is in "requests" array (in chronological order). Each element contains the following data (keys):
|
119
146
|
|
120
147
|
- __body__ - request payload
|
121
|
-
- __params__ - request parameters
|
148
|
+
- __params__ - request parameters. json
|
122
149
|
- __created_at__ - request timestamp
|
123
|
-
- __rack_env__ - raw request dump (
|
150
|
+
- __rack_env__ - raw request dump (json) including request headers
|
151
|
+
|
152
|
+
#### Delete all doubles
|
124
153
|
|
125
|
-
##### Delete all doubles
|
126
154
|
HTTP DELETE to '/doubles/all' deletes all doubles. Useful for cleaning up between tests.
|
127
155
|
|
128
|
-
|
156
|
+
## Redirects
|
129
157
|
|
130
158
|
It is sometimes desirable to only double certain calls while letting others through to the 'real' services. Meet Redirects. Kind of "rewrite rules" for requests that didn't match any double. Here is the rest API for managing redirects:
|
131
159
|
|
132
|
-
|
160
|
+
### Create redirect
|
161
|
+
|
133
162
|
HTTP POST to '/redirects' creates redirect.
|
134
163
|
The following options can be passed as request parameters:
|
135
164
|
|
136
165
|
- __pattern__ - regex (perl5 style) tested against request fullpath. Mandatory
|
137
166
|
- __to__ - url base e.g., 'https://myserver:8787/api'. Mandatory
|
138
167
|
|
139
|
-
Example
|
140
|
-
|
141
|
-
|
142
|
-
RestClient.post 'http://localhost:4578/redirects', { pattern: '^/auth', to: 'https://myserver.com/api' }
|
143
|
-
```
|
168
|
+
Example:
|
169
|
+
|
170
|
+
bash$ curl -d 'pattern=^/auth&to=https://myserver.com/api' http://localhost:4578/redirects
|
144
171
|
|
145
172
|
Now request (any verb) to 'http://localhost:4578/auth/services/1' will get redirected to 'https://myserver.com/api/auth/services/1.' Provided of course there is no double matched for that fullpath and verb.
|
146
173
|
Much like rewrite rules, redirects are evaluated in order (of creation). In UI you can manually rearrange the order.
|
147
174
|
|
148
|
-
|
149
|
-
HTTP DELETE to '/redirects/all' deletes all redirects. Useful for cleaning up between tests.
|
150
|
-
|
151
|
-
## TODO
|
175
|
+
### Delete all redirects
|
152
176
|
|
153
|
-
|
154
|
-
* Bring UI upto date with rest-api (add verbs, statuses, request history)
|
155
|
-
* Add custom response headers
|
177
|
+
HTTP DELETE to '/redirects/all' deletes all redirects. Useful for cleaning up between tests.
|
156
178
|
|
157
179
|
## Author
|
158
180
|
|
@@ -160,11 +182,19 @@ RestClient.post 'http://localhost:4578/redirects', { pattern: '^/auth', to: 'htt
|
|
160
182
|
|
161
183
|
## Changelog
|
162
184
|
|
163
|
-
0.
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
185
|
+
#### 0.3 (12 Dec 2011)
|
186
|
+
|
187
|
+
* you can now specify response headers for double to respond with
|
188
|
+
|
189
|
+
#### 0.2
|
190
|
+
|
191
|
+
* adds verifications
|
192
|
+
* adds ruby client
|
193
|
+
* adds custom return statuses
|
194
|
+
* adds ssl
|
195
|
+
* adds mysql support
|
196
|
+
|
197
|
+
#### 0.1
|
198
|
+
|
199
|
+
* initial public release
|
170
200
|
|
@@ -16,6 +16,11 @@ Feature: use doubles via api
|
|
16
16
|
| /api/some?a=3&b=dd | more content | | GET | | 200 |
|
17
17
|
| /api/empty | | POST | POST | | 200 |
|
18
18
|
|
19
|
+
@now
|
20
|
+
Scenario: view created double details
|
21
|
+
When I create a double
|
22
|
+
Then I should be able to get json representation of that double from response
|
23
|
+
|
19
24
|
Scenario Outline: request fullpath that matches double
|
20
25
|
Given there is double with "<fullpath>" as fullpath, "<content>" as response content, "<verb>" as request verb and "<status>" as status
|
21
26
|
When I "<verb>" "<fullpath>"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Feature: create double using ruby client api
|
2
|
+
As ruby developer
|
3
|
+
I want to be able to create doubles via client api
|
4
|
+
So that interactions with rest-assured server are completely hidden from me
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given rest-assured is running locally:
|
8
|
+
"""
|
9
|
+
RestAssured::Client.config.server_address = 'http://localhost:9876'
|
10
|
+
"""
|
11
|
+
|
12
|
+
Scenario: create double with defaults
|
13
|
+
When I create a double:
|
14
|
+
"""
|
15
|
+
@double = RestAssured::Double.create(:fullpath => '/some/api')
|
16
|
+
"""
|
17
|
+
Then it should have the following defaults:
|
18
|
+
"""
|
19
|
+
@double.verb.should == 'GET'
|
20
|
+
@double.response_headers.should == {}
|
21
|
+
@double.status.should == 200
|
22
|
+
@double.content.should == nil
|
23
|
+
|
24
|
+
get @double.fullpath
|
25
|
+
last_response.should be_ok
|
26
|
+
"""
|
27
|
+
|
28
|
+
Scenario: create double with specified response headers
|
29
|
+
When I create a double:
|
30
|
+
"""
|
31
|
+
@double = RestAssured::Double.create(:fullpath => '/some/api', :response_headers => { 'Content-Type' => 'text/html' })
|
32
|
+
"""
|
33
|
+
Then it should have the following defaults:
|
34
|
+
"""
|
35
|
+
@double.response_headers.should == { 'Content-Type' => 'text/html' }
|
36
|
+
|
37
|
+
get @double.fullpath
|
38
|
+
last_response.headers['Content-Type'].should == 'text/html'
|
39
|
+
"""
|
40
|
+
|
@@ -1,15 +1,49 @@
|
|
1
|
-
Feature:
|
2
|
-
In order to
|
1
|
+
Feature: verify requests that happened on double
|
2
|
+
In order to check that my app is performing correct requests
|
3
3
|
As test developer
|
4
4
|
I want to be able to get double 'call history'
|
5
5
|
|
6
|
+
Background:
|
7
|
+
Given rest-assured is running locally:
|
8
|
+
"""
|
9
|
+
RestAssured::Client.config.server_address = 'http://localhost:9876'
|
10
|
+
"""
|
11
|
+
|
6
12
|
Scenario: no calls made to double
|
7
|
-
Given
|
8
|
-
|
9
|
-
|
13
|
+
Given I created a double:
|
14
|
+
"""
|
15
|
+
@double = RestAssured::Double.create(:fullpath => '/some/api')
|
16
|
+
"""
|
17
|
+
When I request call history for that double:
|
18
|
+
"""
|
19
|
+
@requests = @double.reload.requests
|
20
|
+
"""
|
21
|
+
Then it should be empty:
|
22
|
+
"""
|
23
|
+
@requests.should be_empty
|
24
|
+
"""
|
10
25
|
|
11
26
|
Scenario: some calls made to double
|
12
|
-
Given
|
13
|
-
|
14
|
-
|
15
|
-
|
27
|
+
Given I created a double:
|
28
|
+
"""
|
29
|
+
@double = RestAssured::Double.create(:fullpath => '/some/path', :content => 'some content', :verb => 'POST')
|
30
|
+
"""
|
31
|
+
When that double gets requested:
|
32
|
+
"""
|
33
|
+
post @double.fullpath, { :foo => 'bar' }.to_json, "CONTENT_TYPE" => "application/json"
|
34
|
+
post @double.fullpath, { :fooz => 'baaz'}, 'SOME_HEADER' => 'header_data'
|
35
|
+
"""
|
36
|
+
And I request call history for that double:
|
37
|
+
"""
|
38
|
+
@requests = @double.reload.requests
|
39
|
+
"""
|
40
|
+
Then I should see history records for those requests:
|
41
|
+
"""
|
42
|
+
@requests.first.body.should == { :foo => 'bar' }.to_json
|
43
|
+
@requests.first.params.should == '{}'
|
44
|
+
JSON.parse( @requests.first.rack_env )["CONTENT_TYPE"].should == 'application/json'
|
45
|
+
|
46
|
+
@requests.last.body.should == 'fooz=baaz'
|
47
|
+
JSON.parse( @requests.last.params ).should == { 'fooz' => 'baaz' }
|
48
|
+
JSON.parse( @requests.last.rack_env )["SOME_HEADER"].should == 'header_data'
|
49
|
+
"""
|
@@ -4,7 +4,11 @@ Feature: wait for requests on double to happen
|
|
4
4
|
I want to be able to wait until specified number of requests happen
|
5
5
|
|
6
6
|
Background:
|
7
|
-
Given
|
7
|
+
Given rest-assured is running locally:
|
8
|
+
"""
|
9
|
+
RestAssured::Client.config.server_address = 'http://localhost:9876'
|
10
|
+
"""
|
11
|
+
And I created a double:
|
8
12
|
"""
|
9
13
|
@double = RestAssured::Double.create(:fullpath => '/some/api')
|
10
14
|
"""
|
@@ -29,7 +33,6 @@ Feature: wait for requests on double to happen
|
|
29
33
|
Expected 3 requests. Got 2.
|
30
34
|
"""
|
31
35
|
|
32
|
-
@now
|
33
36
|
Scenario: custom timeout
|
34
37
|
When I wait for 3 requests:
|
35
38
|
"""
|
@@ -4,22 +4,23 @@ Given /^there are no doubles$/ do
|
|
4
4
|
RestAssured::Models::Double.destroy_all
|
5
5
|
end
|
6
6
|
|
7
|
-
When /^I create a double with "([^"]*)" as fullpath and "([^"]*)" as response content$/ do |fullpath, content|
|
8
|
-
post '/doubles', { :fullpath => fullpath, :content => content }
|
9
|
-
last_response.should be_ok
|
10
|
-
end
|
11
|
-
|
12
7
|
When /^I create a double with "([^""]*)" as fullpath, "([^""]*)" as response content, "([^""]*)" as request verb and status as "([^""]*)"$/ do |fullpath, content, verb, status|
|
13
8
|
post '/doubles', { :fullpath => fullpath, :content => content, :verb => verb, :status => status }
|
14
9
|
last_response.should be_ok
|
15
10
|
end
|
16
11
|
|
17
|
-
|
18
|
-
|
12
|
+
When /^I create a double$/ do
|
13
|
+
post '/doubles', { :fullpath => '/api/something' }
|
14
|
+
@create_a_double_response = last_response.body
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^I should be able to get json representation of that double from response$/ do
|
18
|
+
d = RestAssured::Models::Double.last
|
19
|
+
JSON.parse( @create_a_double_response ).should == JSON.parse( d.to_json )
|
19
20
|
end
|
20
21
|
|
21
|
-
Then /^
|
22
|
-
|
22
|
+
Then /^I should get (#{CAPTURE_A_NUMBER}) in response status$/ do |status|
|
23
|
+
last_response.status.should == status
|
23
24
|
end
|
24
25
|
|
25
26
|
Then /^there should be (#{CAPTURE_A_NUMBER}) double with "([^""]*)" as fullpath, "([^""]*)" as response content, "([^""]*)" as request verb and status as "(#{CAPTURE_A_NUMBER})"$/ do |n, fullpath, content, verb, status|
|
@@ -34,11 +35,6 @@ Given /^there is double with "([^"]*)" as fullpath, "([^"]*)" as response conten
|
|
34
35
|
RestAssured::Models::Double.create(:fullpath => fullpath, :content => content, :verb => verb, :status => status)
|
35
36
|
end
|
36
37
|
|
37
|
-
Given /^I register "([^"]*)" as fullpath and "([^"]*)" as response content$/ do |fullpath, content|
|
38
|
-
post '/doubles', { :fullpath => fullpath, :content => content }
|
39
|
-
last_response.should be_ok
|
40
|
-
end
|
41
|
-
|
42
38
|
When /^I request "([^"]*)"$/ do |fullpath|
|
43
39
|
get fullpath
|
44
40
|
end
|
@@ -1,29 +1,24 @@
|
|
1
|
-
Given /^
|
2
|
-
|
1
|
+
Given /^rest\-assured is running locally:$/ do |code|
|
2
|
+
eval code
|
3
3
|
end
|
4
4
|
|
5
|
-
When /^that double gets requested
|
6
|
-
|
7
|
-
post @double.fullpath, { :fooz => 'baaz'}, 'SOME_HEADER' => 'header_data'
|
5
|
+
When /^that double gets requested:$/ do |code|
|
6
|
+
eval code
|
8
7
|
end
|
9
8
|
|
10
|
-
When /^I request call history for that double
|
11
|
-
|
9
|
+
When /^I request call history for that double:$/ do |code|
|
10
|
+
eval code
|
12
11
|
end
|
13
12
|
|
14
|
-
Then /^I should see history records for those requests
|
15
|
-
|
16
|
-
JSON.parse( @requests.first.rack_env )["CONTENT_TYPE"].should == 'application/json'
|
17
|
-
|
18
|
-
JSON.parse( @requests.last.params ).should == { 'fooz' => 'baaz' }
|
19
|
-
JSON.parse( @requests.last.rack_env )["SOME_HEADER"].should == 'header_data'
|
13
|
+
Then /^I should see history records for those requests:$/ do |code|
|
14
|
+
eval code
|
20
15
|
end
|
21
16
|
|
22
|
-
Then /^it should be empty
|
23
|
-
|
17
|
+
Then /^it should be empty:$/ do |code|
|
18
|
+
eval code
|
24
19
|
end
|
25
20
|
|
26
|
-
Given /^I created a double:$/ do |string|
|
21
|
+
Given /^I created? a double:$/ do |string|
|
27
22
|
# expected string is:
|
28
23
|
# @double = RestAssured::Double.create(:fullpath => '/some/api', :verb => 'POST')
|
29
24
|
eval string
|
@@ -67,3 +62,7 @@ Then /^it should raise MoreRequestsExpected error after with the following messa
|
|
67
62
|
@more_reqs_exc.should be_instance_of RestAssured::MoreRequestsExpected
|
68
63
|
@more_reqs_exc.message.should =~ /#{string}/
|
69
64
|
end
|
65
|
+
|
66
|
+
Then /^it should have the following defaults:$/ do |code|
|
67
|
+
eval code
|
68
|
+
end
|
data/features/support/env.rb
CHANGED
data/lib/rest-assured.rb
CHANGED
@@ -3,7 +3,9 @@ require 'net/http'
|
|
3
3
|
module RestAssured
|
4
4
|
module Models
|
5
5
|
class Double < ActiveRecord::Base
|
6
|
-
attr_accessible :fullpath, :content, :description, :verb, :status
|
6
|
+
attr_accessible :fullpath, :content, :description, :verb, :status, :response_headers
|
7
|
+
|
8
|
+
serialize :response_headers, Hash
|
7
9
|
|
8
10
|
VERBS = %w{GET POST PUT DELETE}
|
9
11
|
STATUSES = Net::HTTPResponse::CODE_TO_OBJ.keys.map(&:to_i)
|
@@ -20,28 +22,29 @@ module RestAssured
|
|
20
22
|
has_many :requests, :dependent => :destroy
|
21
23
|
|
22
24
|
private
|
23
|
-
def toggle_active
|
24
|
-
ne = id ? '!=' : 'IS NOT'
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
def toggle_active
|
27
|
+
ne = id ? '!=' : 'IS NOT'
|
28
|
+
|
29
|
+
if active && Double.where("fullpath = ? AND active = ? AND id #{ne} ?", fullpath, true, id).exists?
|
30
|
+
Double.where("fullpath = ? AND id #{ne} ?", fullpath, id).update_all :active => false
|
31
|
+
end
|
28
32
|
end
|
29
|
-
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
+
def set_verb
|
35
|
+
self.verb = 'GET' unless verb.present?
|
36
|
+
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
def set_status
|
39
|
+
self.status = 200 unless status.present?
|
40
|
+
end
|
38
41
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
def set_active
|
43
|
+
if active && f = Double.where(:fullpath => fullpath).last
|
44
|
+
f.active = true
|
45
|
+
f.save
|
46
|
+
end
|
43
47
|
end
|
44
|
-
end
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
@@ -26,10 +26,22 @@ module RestAssured
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
router.post /^\/doubles(\.json)?$/ do
|
30
|
-
|
29
|
+
router.post /^\/doubles(\.json)?$/ do
|
30
|
+
begin
|
31
|
+
data = request.body.read
|
32
|
+
d = JSON.parse(data)['double']
|
33
|
+
rescue
|
34
|
+
d = params['double'] || {
|
35
|
+
:fullpath => params['fullpath'],
|
36
|
+
:content => params['content'],
|
37
|
+
:description => params['description'],
|
38
|
+
:verb => params['verb'],
|
39
|
+
:status => params['status']
|
40
|
+
}
|
41
|
+
d.merge!(:response_headers => params['response_headers']) if params['response_headers']
|
42
|
+
end
|
31
43
|
|
32
|
-
@double = Models::Double.create(
|
44
|
+
@double = Models::Double.create(d)
|
33
45
|
|
34
46
|
if browser?
|
35
47
|
if @double.errors.blank?
|
@@ -10,6 +10,7 @@ module RestAssured
|
|
10
10
|
|
11
11
|
d.requests.create!(:rack_env => env.to_json, :body => body, :params => request.params.to_json)
|
12
12
|
|
13
|
+
app.headers d.response_headers
|
13
14
|
app.body d.content
|
14
15
|
app.status d.status
|
15
16
|
elsif r = Models::Redirect.ordered.find { |r| request.fullpath =~ /#{r.pattern}/ }
|
data/lib/rest-assured/version.rb
CHANGED
@@ -3,11 +3,27 @@ require File.expand_path('../../spec_helper', __FILE__)
|
|
3
3
|
module RestAssured
|
4
4
|
describe 'Double routes' do
|
5
5
|
let :test_double do
|
6
|
-
{
|
6
|
+
{
|
7
|
+
:fullpath => '/api/google?a=5',
|
8
|
+
:content => 'some awesome content',
|
9
|
+
:verb => 'POST',
|
10
|
+
:status => '201',
|
11
|
+
:response_headers => { 'ACCEPT' => 'text/html' }
|
12
|
+
}
|
7
13
|
end
|
14
|
+
|
8
15
|
let :valid_params do
|
9
|
-
|
16
|
+
params = {
|
17
|
+
'double[fullpath]' => test_double[:fullpath],
|
18
|
+
'double[content]' => test_double[:content],
|
19
|
+
'double[verb]' => test_double[:verb],
|
20
|
+
'double[status]' => test_double[:status],
|
21
|
+
'double[response_headers]' => test_double[:response_headers]
|
22
|
+
}
|
23
|
+
|
24
|
+
params
|
10
25
|
end
|
26
|
+
|
11
27
|
let :invalid_params do
|
12
28
|
valid_params.except('double[fullpath]')
|
13
29
|
end
|
@@ -40,7 +56,9 @@ module RestAssured
|
|
40
56
|
|
41
57
|
last_request.fullpath.should == '/doubles'
|
42
58
|
last_response.body.should =~ /Double created/
|
43
|
-
|
59
|
+
|
60
|
+
d = Models::Double.where(test_double.except(:response_headers)).first
|
61
|
+
d.response_headers['ACCEPT'].should == 'text/html'
|
44
62
|
end
|
45
63
|
|
46
64
|
it "reports failure when creating with invalid parameters" do
|
@@ -87,7 +105,7 @@ module RestAssured
|
|
87
105
|
last_response.should be_ok
|
88
106
|
last_response.body.should =~ /Double deleted/
|
89
107
|
|
90
|
-
Models::Double.exists?(test_double).should be_false
|
108
|
+
Models::Double.exists?(test_double.except(:response_headers)).should be_false
|
91
109
|
end
|
92
110
|
end
|
93
111
|
|
@@ -96,7 +114,9 @@ module RestAssured
|
|
96
114
|
post '/doubles', test_double
|
97
115
|
|
98
116
|
last_response.should be_ok
|
99
|
-
|
117
|
+
|
118
|
+
d = Models::Double.where(test_double.except(:response_headers)).first
|
119
|
+
d.response_headers['ACCEPT'].should == 'text/html'
|
100
120
|
end
|
101
121
|
|
102
122
|
it "reports failure when creating with invalid parameters" do
|
@@ -121,8 +141,10 @@ module RestAssured
|
|
121
141
|
post '/doubles.json', { :double => test_double }.to_json, 'CONTENT_TYPE' => 'Application/json'
|
122
142
|
|
123
143
|
last_response.should be_ok
|
124
|
-
|
125
|
-
|
144
|
+
|
145
|
+
d = Models::Double.where(test_double.except(:response_headers)).first
|
146
|
+
d.response_headers['ACCEPT'].should == 'text/html'
|
147
|
+
last_response.body.should == d.to_json
|
126
148
|
end
|
127
149
|
|
128
150
|
it "reports failure when creating with invalid parameters" do
|
@@ -25,7 +25,12 @@ module RestAssured
|
|
25
25
|
|
26
26
|
context 'when double matches request' do
|
27
27
|
before do
|
28
|
-
@double = Models::Double.create
|
28
|
+
@double = Models::Double.create \
|
29
|
+
:fullpath => '/some/path',
|
30
|
+
:content => 'content',
|
31
|
+
:response_headers => { 'ACCEPT' => 'text/html' },
|
32
|
+
:status => 201
|
33
|
+
|
29
34
|
request.stub(:fullpath).and_return(@double.fullpath)
|
30
35
|
end
|
31
36
|
|
@@ -41,6 +46,12 @@ module RestAssured
|
|
41
46
|
Response.perform(rest_assured_app)
|
42
47
|
end
|
43
48
|
|
49
|
+
it 'sets response headers to those in Double#response_headers' do
|
50
|
+
rest_assured_app.should_receive(:headers).with(@double.response_headers)
|
51
|
+
|
52
|
+
Response.perform(rest_assured_app)
|
53
|
+
end
|
54
|
+
|
44
55
|
it 'records request' do
|
45
56
|
requests = double
|
46
57
|
Models::Double.stub_chain('where.first').and_return(double(:requests => requests).as_null_object)
|
data/spec/models/double_spec.rb
CHANGED
@@ -3,7 +3,13 @@ require File.expand_path('../../spec_helper', __FILE__)
|
|
3
3
|
module RestAssured::Models
|
4
4
|
describe Double do
|
5
5
|
let :valid_params do
|
6
|
-
{
|
6
|
+
{
|
7
|
+
:fullpath => '/some/api',
|
8
|
+
:content => 'some content',
|
9
|
+
:verb => 'GET',
|
10
|
+
:status => '303',
|
11
|
+
:response_headers => { 'ACCEPT' => 'text/html' }
|
12
|
+
}
|
7
13
|
end
|
8
14
|
|
9
15
|
it { should validate_presence_of(:fullpath) }
|
@@ -13,6 +19,7 @@ module RestAssured::Models
|
|
13
19
|
it { should allow_mass_assignment_of(:content) }
|
14
20
|
it { should allow_mass_assignment_of(:verb) }
|
15
21
|
it { should allow_mass_assignment_of(:status) }
|
22
|
+
it { should allow_mass_assignment_of(:response_headers) }
|
16
23
|
|
17
24
|
it { should have_many(:requests) }
|
18
25
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-assured
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Artem Avetisyan
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-12-12 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: sinatra
|
@@ -128,9 +128,11 @@ files:
|
|
128
128
|
- db/migrate/20111013122857_create_requests.rb
|
129
129
|
- db/migrate/20111016174101_rename_method_to_verb.rb
|
130
130
|
- db/migrate/20111021113953_add_status_to_doubles.rb
|
131
|
+
- db/migrate/20111208155906_add_response_headers_to_doubles.rb
|
131
132
|
- features/command_line_options.feature
|
132
133
|
- features/rest_api/doubles.feature
|
133
134
|
- features/rest_api/redirects.feature
|
135
|
+
- features/ruby_api/create_double.feature
|
134
136
|
- features/ruby_api/verify_requests.feature
|
135
137
|
- features/ruby_api/wait_for_requests.feature
|
136
138
|
- features/step_definitions/command_line_options_steps.rb
|
@@ -235,6 +237,7 @@ test_files:
|
|
235
237
|
- features/command_line_options.feature
|
236
238
|
- features/rest_api/doubles.feature
|
237
239
|
- features/rest_api/redirects.feature
|
240
|
+
- features/ruby_api/create_double.feature
|
238
241
|
- features/ruby_api/verify_requests.feature
|
239
242
|
- features/ruby_api/wait_for_requests.feature
|
240
243
|
- features/step_definitions/command_line_options_steps.rb
|
@@ -258,3 +261,4 @@ test_files:
|
|
258
261
|
- spec/models/redirect_spec.rb
|
259
262
|
- spec/models/request_spec.rb
|
260
263
|
- spec/spec_helper.rb
|
264
|
+
has_rdoc:
|