riot-gear 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +9 -0
- data/CHANGELOG +22 -0
- data/Gemfile +1 -1
- data/lib/riot/gear/context/once.rb +42 -0
- data/lib/riot/gear/context.rb +1 -0
- data/lib/riot/gear/middleware/riotparty.rb +152 -153
- data/lib/riot/gear/middleware.rb +2 -1
- data/lib/riot/gear/version.rb +1 -1
- data/lib/riot/gear.rb +5 -0
- data/riot-gear.gemspec +3 -3
- data/test/once_block_test.rb +21 -0
- data/test/riotparty_proxy_methods_test.rb +5 -2
- data/test/teststrap.rb +1 -0
- metadata +10 -6
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGELOG
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# @markup markdown
|
2
2
|
|
3
|
+
# 0.0.10
|
4
|
+
|
5
|
+
* Defines a new setup block called `once`. Useful for running a single block before assertions, but only inside the context it was defined in [jaknowlden]
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
context ThingsMaker do
|
9
|
+
once do
|
10
|
+
topic.post "/things/make", :query => { :name => "Jacques" }
|
11
|
+
end
|
12
|
+
|
13
|
+
format :json
|
14
|
+
get "/things/1"
|
15
|
+
|
16
|
+
asserts_json("name").equals("Jacques")
|
17
|
+
|
18
|
+
context "makes no more things" do
|
19
|
+
get "/things/2"
|
20
|
+
asserts_status(404) # becuase the post didn't run again ... see ... yeah
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
3
25
|
# 0.0.9
|
4
26
|
|
5
27
|
* get, post, put, delete can have responses saved for use in other requests within the same (or nested) context [jaknowlden]
|
data/Gemfile
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
class Riot::Gear::OnceRunnable < Riot::RunnableBlock
|
2
|
+
def initialize(description, &definition)
|
3
|
+
super("[once] #{description}", &definition)
|
4
|
+
@ran = false
|
5
|
+
end
|
6
|
+
|
7
|
+
# Applies the provided +&definition+ to the +situation+. But, it only
|
8
|
+
# does so once.
|
9
|
+
#
|
10
|
+
# @param [Riot::Situation] situation An instance of a {Riot::Situation}
|
11
|
+
# @return [Array<Symbol>]
|
12
|
+
def run(situation)
|
13
|
+
if @ran
|
14
|
+
[:once_ignored]
|
15
|
+
else
|
16
|
+
@ran = true
|
17
|
+
situation.evaluate(&definition)
|
18
|
+
[:once]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Riot::Gear::OnceContextHelper
|
24
|
+
# A setup helper that will only run once and only in the context it
|
25
|
+
# was defined in. This will not be run in any of its sub-contexts
|
26
|
+
# and it will run before any assertions ... the same as any other
|
27
|
+
# setup block.
|
28
|
+
#
|
29
|
+
# once "doing this one thing" do
|
30
|
+
# topic.post "/user/things", :query => {"name" => "x"}
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @param [String] description A description of what the block is for
|
34
|
+
# @param [lambda] &definition The block that will be executed once
|
35
|
+
# @return [Riot::Gear::OnceRunnable]
|
36
|
+
def once(description="", &definition)
|
37
|
+
@setups << Riot::Gear::OnceRunnable.new(description, &definition)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Riot::Context.instance_eval { include Riot::Gear::OnceContextHelper }
|
42
|
+
|
data/lib/riot/gear/context.rb
CHANGED
@@ -1,173 +1,172 @@
|
|
1
1
|
require 'httparty'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
class RiotPartyMiddleware < ::Riot::ContextMiddleware
|
12
|
-
register
|
3
|
+
# Here we prepare a {Riot::Context} to have HTTParty bound to it. Basically, this means that you can
|
4
|
+
# use HTTParty within a context the same way you would inside any class or you would normally use it in.
|
5
|
+
# Anything you can do with HTTParty, you can do within a context ... and then you can test it :)
|
6
|
+
#
|
7
|
+
# Great pains are made to ensure that the HTTParty setup bound to one context does not interfere setup
|
8
|
+
# bound to another context.
|
9
|
+
class Riot::Gear::RiotPartyMiddleware < ::Riot::ContextMiddleware
|
10
|
+
register
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
private
|
12
|
+
# Prepares the context for HTTParty support.
|
13
|
+
#
|
14
|
+
# @param [Riot::Context] context the context to prepare
|
15
|
+
def call(context)
|
16
|
+
setup_faux_class(context)
|
17
|
+
setup_helpers(context)
|
18
|
+
proxy_action_methods(context)
|
19
|
+
proxy_httparty_hookups(context)
|
20
|
+
middleware.call(context)
|
21
|
+
end
|
26
22
|
|
27
|
-
|
28
|
-
# theory.
|
29
|
-
#
|
30
|
-
# @param [Riot::Context] context the context to create the setup for
|
31
|
-
# @todo Fix this so that settings like +base_uri+ can be inherited
|
32
|
-
def setup_faux_class(context)
|
33
|
-
context.setup(true) do
|
34
|
-
@saved_responses = {}
|
23
|
+
private
|
35
24
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
25
|
+
# Only cluttering anonymous classes with HTTParty stuff. Keeps each context safe from collision ... in
|
26
|
+
# theory.
|
27
|
+
#
|
28
|
+
# @param [Riot::Context] context the context to create the setup for
|
29
|
+
# @todo Fix this so that settings like +base_uri+ can be inherited
|
30
|
+
def setup_faux_class(context)
|
31
|
+
context.setup(true) do
|
32
|
+
if topic
|
33
|
+
topic
|
34
|
+
else
|
35
|
+
@saved_responses = {}
|
36
|
+
Class.new { include HTTParty }
|
37
|
+
end
|
38
|
+
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
context.helper(:response) do |name=nil|
|
41
|
+
@saved_responses[name] || @smoke_response
|
42
|
+
end
|
43
|
+
end # setup_faux_class
|
46
44
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
# Returns the list of methods that do something; like make a network call.
|
46
|
+
#
|
47
|
+
# @return [Array<Symbol>]
|
48
|
+
def actionable_methods; [:get, :post, :put, :delete, :head]; end
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
50
|
+
# Returns the list of methods that configure actionable HTTParty methods. The {HTTParty.options} and
|
51
|
+
# {HTTParty.default_options} methods are explicitly excluded from this list
|
52
|
+
#
|
53
|
+
# @return [Array<Symbol>]
|
54
|
+
def proxiable_methods
|
55
|
+
methods = HTTParty::ClassMethods.instance_methods.map { |m| m.to_s.to_sym }
|
56
|
+
methods - actionable_methods - [:options, :default_options]
|
57
|
+
end
|
60
58
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
result = topic.__send__(method_name, path, options || {})
|
97
|
-
@saved_responses[name] = result
|
98
|
-
@smoke_response = result # TODO remove this after it's certain no usages in the wild
|
99
|
-
end
|
59
|
+
# Bind the set of actionable methods to a given context.
|
60
|
+
#
|
61
|
+
# Basically, we're just passing standard HTTParty setup methods onto situation via hookups. These
|
62
|
+
# hookups - so long as the topic hasn't changed yet - are bound to an anonymous class that has
|
63
|
+
# HTTParty included to it. Meaning, this is how you call get, post, put, delete from within a
|
64
|
+
# test.
|
65
|
+
#
|
66
|
+
# There are couple of different forms for these actions. As you would expect, there's:
|
67
|
+
#
|
68
|
+
# get "/path", :query => {...}, ...
|
69
|
+
#
|
70
|
+
# But you can also record the response for use later in the test:
|
71
|
+
#
|
72
|
+
# post(:new_thing) do
|
73
|
+
# { :path => "/things", :body => ... }
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# get do # this response will be used for assertions since it's last
|
77
|
+
# { :path => "/things/#{response(:new_thing).id}/settings" }
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# @param [Riot::Context] context the context to add the helper to
|
81
|
+
def proxy_action_methods(context)
|
82
|
+
context_eigen = (class << context; self; end)
|
83
|
+
actionable_methods.each do |method_name|
|
84
|
+
context_eigen.__send__(:define_method, method_name) do |*args, &settings_block|
|
85
|
+
hookup do
|
86
|
+
if settings_block
|
87
|
+
name = args.first
|
88
|
+
options = instance_eval(&settings_block)
|
89
|
+
path = options.delete(:path) || "/"
|
90
|
+
else
|
91
|
+
name = nil
|
92
|
+
path, options = *args
|
100
93
|
end
|
101
|
-
|
94
|
+
#debug_start = Time.now
|
95
|
+
result = topic.__send__(method_name, path, options || {})
|
96
|
+
#puts "TIME #{(Time.now - debug_start) * 1000.0}ms #{topic.base_uri}#{path}"
|
97
|
+
@saved_responses[name] = result
|
98
|
+
@smoke_response = result # TODO remove this after it's certain no usages in the wild
|
99
|
+
end
|
102
100
|
end
|
101
|
+
end # methods.each
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
end # methods.each
|
104
|
+
# Bind the set of proxiable (non-action) methods to a given context.
|
105
|
+
#
|
106
|
+
# @param [Riot::Context] context the context to add the helper to
|
107
|
+
def proxy_httparty_hookups(context)
|
108
|
+
context_eigen = (class << context; self; end)
|
109
|
+
proxiable_methods.each do |method_name|
|
110
|
+
context_eigen.__send__(:define_method, method_name) do |*args|
|
111
|
+
hookup { topic.__send__(method_name, *args) }
|
114
112
|
end
|
113
|
+
end # methods.each
|
114
|
+
end
|
115
115
|
|
116
|
-
|
117
|
-
|
116
|
+
#
|
117
|
+
# Helpful helpers
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
119
|
+
def setup_helpers(context)
|
120
|
+
helper_json_path(context)
|
121
|
+
helper_cookie_value(context)
|
122
|
+
end
|
123
123
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
148
|
-
end
|
124
|
+
# Maps a JSON string to a Hash tree. For instance, give this hash:
|
125
|
+
#
|
126
|
+
# json_object = {"a" => {"b" => {"c" => {"d" => "foo"}}}}
|
127
|
+
#
|
128
|
+
# You could retrieve the value of 'd' via JSON notation in any of the following ways:
|
129
|
+
#
|
130
|
+
# json_path(json_object, "a.b.c.d")
|
131
|
+
# => "foo"
|
132
|
+
# json_path(json_object, "a['b'].c['d']")
|
133
|
+
# => "foo"
|
134
|
+
#
|
135
|
+
# You can even work with array indexes
|
136
|
+
#
|
137
|
+
# json_object = {"a" => {"b" => "c" => ["foo", {"d" => "bar"}]}}
|
138
|
+
# json_path(json_object, "a[b].c[1].d")
|
139
|
+
# => "bar"
|
140
|
+
#
|
141
|
+
# @param [Riot::Context] context the context to add the helper to
|
142
|
+
def helper_json_path(context)
|
143
|
+
context.helper(:json_path) do |dictionary, path|
|
144
|
+
return nil if path.to_s.empty?
|
145
|
+
path.scan(/[^\[\].'"]+/).inject(dictionary) do |dict,key|
|
146
|
+
dict[key =~ /^\d+$/ ? key.to_i : key.strip]
|
149
147
|
end
|
148
|
+
end
|
149
|
+
end
|
150
150
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
end
|
168
|
-
end
|
151
|
+
# Splits up the cookies found in the Set-Cookie header. I'm sure I could use HTTParty for this somehow,
|
152
|
+
# but this seemed just as straightforward. You will get back a hash of the
|
153
|
+
# {cookie-name => cookie-bits} pairs
|
154
|
+
#
|
155
|
+
# {
|
156
|
+
# "session_cookie" => {"value => "fooberries", "path" => "/", ...},
|
157
|
+
# "stupid_marketing_tricks" => {"value" => "personal-information", ...},
|
158
|
+
# ...
|
159
|
+
# }
|
160
|
+
#
|
161
|
+
# @param [Riot::Context] context the context to add the helper to
|
162
|
+
def helper_cookie_value(context)
|
163
|
+
context.helper(:cookie_values) do
|
164
|
+
response.header["set-cookie"].split("\n").inject({}) do |jar, cookie_str|
|
165
|
+
(name, value), *bits = cookie_str.split(/; ?/).map { |bit| bit.split('=') }
|
166
|
+
jar.merge!(name => bits.inject({"value" => value}) { |h, (k,v)| h.merge!(k => v) })
|
169
167
|
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end # Riot::Gear::RiotPartyMiddleware
|
170
172
|
|
171
|
-
end # Middleware
|
172
|
-
end # Gear
|
173
|
-
end # Riot
|
data/lib/riot/gear/middleware.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
require 'riot/gear/middleware/riotparty'
|
1
|
+
require 'riot/gear/middleware/riotparty'
|
2
|
+
|
data/lib/riot/gear/version.rb
CHANGED
data/lib/riot/gear.rb
CHANGED
data/riot-gear.gemspec
CHANGED
@@ -13,9 +13,9 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.files = `git ls-files`.split("\n")
|
14
14
|
s.homepage = %q{http://github.com/thumblemonks/riot-gear}
|
15
15
|
s.require_paths = ["lib"]
|
16
|
-
s.test_files = `git ls-files --
|
16
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
17
17
|
|
18
|
-
s.add_dependency 'riot', '>=0.12.
|
19
|
-
s.add_dependency 'httparty', '>=0.
|
18
|
+
s.add_dependency 'riot', '>=0.12.6'
|
19
|
+
s.add_dependency 'httparty', '>=0.12.0'
|
20
20
|
end
|
21
21
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'teststrap'
|
2
|
+
|
3
|
+
context "[Context] A once block:" do
|
4
|
+
once do
|
5
|
+
@instance_var_x = "foo"
|
6
|
+
end
|
7
|
+
|
8
|
+
asserts("var x defined in same context as once block") { @instance_var_x }.equals("foo")
|
9
|
+
|
10
|
+
context "inner-context A" do
|
11
|
+
asserts("var x defined in out context") { @instance_var_x }.nil
|
12
|
+
asserts("var y defined in once block from this context") { @instance_var_y }.equals("bar")
|
13
|
+
|
14
|
+
# defining this below the asserts just for fun, to make sure it
|
15
|
+
# is eval'ed before the asserts are run
|
16
|
+
once do
|
17
|
+
@instance_var_y = "bar"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -74,10 +74,13 @@ context "A Riot Gear context" do
|
|
74
74
|
end.raises(HTTParty::UnsupportedFormat, "':json' Must be one of: nothing")
|
75
75
|
|
76
76
|
context "with a custom parser that supports a provided format" do
|
77
|
-
|
77
|
+
HappyPartyParser = Class.new do
|
78
|
+
def supports_format?(fmt) true; end
|
79
|
+
end
|
78
80
|
|
81
|
+
parser(HappyPartyParser.new)
|
79
82
|
setup { topic.default_options[:parser] }
|
80
|
-
asserts_topic.kind_of(
|
83
|
+
asserts_topic.kind_of(HappyPartyParser)
|
81
84
|
end # with a custom parser that supports a provided format
|
82
85
|
|
83
86
|
default_timeout 100000
|
data/test/teststrap.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riot-gear
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: riot
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.12.
|
21
|
+
version: 0.12.6
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.12.
|
29
|
+
version: 0.12.6
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: httparty
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ! '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 0.
|
37
|
+
version: 0.12.0
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 0.
|
45
|
+
version: 0.12.0
|
46
46
|
description: Riot + HTTParty smoke testing framework. You'd use it for integration
|
47
47
|
testing with real HTTP requests and responses
|
48
48
|
email: gus@gusg.us
|
@@ -51,6 +51,7 @@ extensions: []
|
|
51
51
|
extra_rdoc_files: []
|
52
52
|
files:
|
53
53
|
- .gitignore
|
54
|
+
- .travis.yml
|
54
55
|
- .yardopts
|
55
56
|
- CHANGELOG
|
56
57
|
- Gemfile
|
@@ -62,6 +63,7 @@ files:
|
|
62
63
|
- lib/riot/gear/context/asserts_header.rb
|
63
64
|
- lib/riot/gear/context/asserts_json.rb
|
64
65
|
- lib/riot/gear/context/asserts_status.rb
|
66
|
+
- lib/riot/gear/context/once.rb
|
65
67
|
- lib/riot/gear/context/persist_cookie.rb
|
66
68
|
- lib/riot/gear/middleware.rb
|
67
69
|
- lib/riot/gear/middleware/riotparty.rb
|
@@ -74,6 +76,7 @@ files:
|
|
74
76
|
- test/assertions/asserts_json_test.rb
|
75
77
|
- test/helpers/cookie_values_test.rb
|
76
78
|
- test/helpers/json_path_test.rb
|
79
|
+
- test/once_block_test.rb
|
77
80
|
- test/riotparty_proxy_methods_test.rb
|
78
81
|
- test/setting_up_gear_context_test.rb
|
79
82
|
- test/teststrap.rb
|
@@ -109,6 +112,7 @@ test_files:
|
|
109
112
|
- test/assertions/asserts_json_test.rb
|
110
113
|
- test/helpers/cookie_values_test.rb
|
111
114
|
- test/helpers/json_path_test.rb
|
115
|
+
- test/once_block_test.rb
|
112
116
|
- test/riotparty_proxy_methods_test.rb
|
113
117
|
- test/setting_up_gear_context_test.rb
|
114
118
|
- test/teststrap.rb
|