riot-gear 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|