weasel_diesel 1.0.0

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.
@@ -0,0 +1,5 @@
1
+ class HelloWorldController < SinatraServiceController
2
+ def list
3
+ "Hello #{params[:name]}"
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ describe_service "hello_world.xml" do |service|
2
+ service.formats :xml
3
+ service.http_verb :get
4
+ service.disable_auth # on by default
5
+
6
+ service.param.string :name, :default => 'World'
7
+
8
+ service.response do |response|
9
+ response.element(:name => "greeting") do |e|
10
+ e.attribute "message" => :string, :doc => "The greeting message sent back."
11
+ end
12
+ end
13
+
14
+ service.documentation do |doc|
15
+ doc.overall "This service provides a simple hello world implementation example."
16
+ doc.params :name, "The name of the person to greet."
17
+ doc.example "<code>http://ps3.yourgame.com/hello_world.xml?name=Matt</code>"
18
+ end
19
+
20
+ end
@@ -0,0 +1,124 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe "WeaselDiesel JSON response description" do
4
+
5
+ # JSON response example
6
+ =begin
7
+ { vouchers: [
8
+ {
9
+ id : 1,
10
+ redeemed : false,
11
+ created_at : 123123123123,
12
+ option: {
13
+ id : 1231,
14
+ price: 123.32
15
+ }
16
+ },
17
+ {
18
+ id : 2,
19
+ redeemed : true,
20
+ created_at : 123123123123,
21
+ option: {
22
+ id : 1233,
23
+ price: 1.32
24
+ }
25
+ },
26
+ ] }
27
+ =end
28
+
29
+ before :all do
30
+ @timestamp = Time.now.to_i
31
+ @service = describe_service "json_list" do |service|
32
+ service.formats :json
33
+ service.response do |response|
34
+ response.array :vouchers do |node|
35
+ node.key :id
36
+ node.type :Voucher
37
+ node.string :name, :mock => "test"
38
+ node.integer :id, :doc => "Identifier"
39
+ node.boolean :redeemed
40
+ node.datetime :created_at, :mock => @timestamp
41
+ node.object :option do |option|
42
+ option.integer :id
43
+ option.integer :deal_id, :mock => 1
44
+ option.float :price
45
+ end
46
+ end
47
+ end
48
+ end
49
+ @response = @service.response
50
+ @root_node = @response.nodes.find{|n| n.name == :vouchers}
51
+
52
+ end
53
+
54
+ it "should handle the json root node" do
55
+ @root_node.should_not be_nil
56
+ end
57
+
58
+ it "should handle a node property list" do
59
+ props = @root_node.properties
60
+ props.should_not be_empty
61
+ {:id => :integer, :redeemed => :boolean, :created_at => :datetime}.each do |key, type|
62
+ prop = props.find{|prop| prop.name == key}
63
+ prop.should_not be_nil
64
+ prop.type.should == type
65
+ end
66
+ end
67
+
68
+ it "should handle a nested object with properties" do
69
+ @root_node.objects.should_not be_nil
70
+ option = @root_node.objects.find{|o| o.name == :option}
71
+ option.should_not be_nil
72
+ {:id => :integer, :deal_id => :integer, :price => :float}.each do |key, type|
73
+ prop = option.properties.find{|prop| prop.name == key}
74
+ if prop.nil?
75
+ puts option.properties.inspect
76
+ puts [key, type].inspect
77
+ end
78
+ prop.should_not be_nil
79
+ prop.type.should == type
80
+ end
81
+ end
82
+
83
+ it "should allow some meta attributes" do
84
+ atts = @root_node.meta_attributes
85
+ atts.should_not be_nil
86
+ {:key => :id, :type => :Voucher}.each do |type, value|
87
+ meta = atts.find{|att| att.type == type}
88
+ puts [type, atts].inspect if meta.nil?
89
+ meta.should_not be_nil
90
+ meta.value.should == value
91
+ end
92
+ @root_node.key.should == :id
93
+ @root_node.type.should == :Voucher
94
+ end
95
+
96
+ it "should handle mocked values properly" do
97
+ created_at = @root_node.properties.find{|prop| prop.name == :created_at}
98
+ created_at.opts[:mock].should == @timestamp
99
+ option = @root_node.objects.find{|prop| prop.name == :option}
100
+ deal_id = option.properties.find{|prop| prop.name == :deal_id}
101
+ deal_id.opts[:mock].should == 1
102
+ name = @root_node.properties.find{|prop| prop.name == :name}
103
+ name.opts[:mock].should == "test"
104
+ end
105
+
106
+ it "should allow an anonymous object at the root of the response" do
107
+ service = describe_service "json_anonymous_obj" do |service|
108
+ service.formats :json
109
+ service.response do |response|
110
+ response.object do |obj|
111
+ obj.integer :id
112
+ obj.string :foo
113
+ end
114
+ end
115
+ end
116
+ response = service.response
117
+ response.nodes.should_not be_empty
118
+ obj = response.nodes.first
119
+ obj.should_not be_nil
120
+ obj.properties.find{|prop| prop.name == :id}.should_not be_nil
121
+ obj.properties.find{|prop| prop.name == :foo}.should_not be_nil
122
+ end
123
+
124
+ end
@@ -0,0 +1,225 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+ require File.expand_path("../lib/json_response_verification", File.dirname(__FILE__))
3
+
4
+ WeaselDiesel.send(:include, JSONResponseVerification)
5
+
6
+ describe "JSON response verification" do
7
+
8
+ before :all do
9
+ @service = describe_service "json_response_verification" do |service|
10
+ service.response do |response|
11
+ response.element(:name => :user) do |user|
12
+ user.integer :id
13
+ user.string :name
14
+ user.datetime :created_at
15
+ user.object :creds do |creds|
16
+ creds.integer :id
17
+ creds.float :price
18
+ creds.boolean :enabled
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ @second_service = describe_service "anonym_obj_json_response_verification" do |service|
25
+ service.response do |response|
26
+ response.object do |user|
27
+ user.integer :id
28
+ user.string :name, :null => true
29
+ user.datetime :created_at
30
+ user.object :creds do |creds|
31
+ creds.integer :id
32
+ creds.float :price
33
+ creds.boolean :enabled
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ @third_service = describe_service "with_array" do |service|
40
+ service.response do |response|
41
+ response.array :users do |node|
42
+ node.integer :id
43
+ node.string :name
44
+ node.boolean :admin, :doc => "true if the user is an admin"
45
+ node.string :state, :doc => "test", :null => true
46
+ node.datetime :last_login_at
47
+ end
48
+ end
49
+ end
50
+
51
+ @forth_service = describe_service "with_nested_array" do |service|
52
+ service.response do |response|
53
+ response.array :users do |node|
54
+ node.integer :id
55
+ node.string :name
56
+ node.boolean :admin, :doc => "true if the user is an admin"
57
+ node.string :state, :doc => "test"
58
+ node.array :pets do |pet|
59
+ pet.integer :id
60
+ pet.string :name
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ @optional_prop_service = describe_service "opt_prop_service" do |service|
67
+ service.response do |response|
68
+ response.object do |obj|
69
+ obj.string :email, :null => true
70
+ obj.integer :city_id, :null => true
71
+ obj.string :full_name, :null => true
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+
79
+ def valid_response(namespaced=true)
80
+ response = {
81
+ "id" => 1,
82
+ "name" => "matt",
83
+ "created_at" => "2011-09-22T16:32:46-07:00",
84
+ "creds" => { "id" => 42, "price" => 2010.07, "enabled" => false }
85
+ }
86
+ namespaced ? {"user" => response} : response
87
+ end
88
+
89
+ def valid_array_response
90
+ {"users" => [
91
+ {"id" => 1,
92
+ "admin" => true,
93
+ "name" => "Heidi",
94
+ "state" => "retired",
95
+ "last_login_at" => "2011-09-22T22:46:35-07:00"
96
+ },
97
+ {"id" => 2,
98
+ "admin" => false,
99
+ "name" => "Giana",
100
+ "state" => "playing",
101
+ "last_login_at" => "2011-09-22T22:46:35-07:00"
102
+ }]
103
+ }
104
+ end
105
+
106
+ def valid_nested_array_response
107
+ {"users" => [
108
+ {"id" => 1,
109
+ "admin" => true,
110
+ "name" => "Heidi",
111
+ "state" => "retired",
112
+ "pets" => []
113
+ },
114
+ {"id" => 2,
115
+ "admin" => false,
116
+ "name" => "Giana",
117
+ "state" => "playing",
118
+ "pets" => [{"id" => 23, "name" => "medor"}, {"id" => 34, "name" => "rex"}]
119
+ }]
120
+ }
121
+ end
122
+
123
+
124
+ it "should validate the response" do
125
+ valid, errors = @service.validate_hash_response(valid_response)
126
+ errors.should == []
127
+ valid.should be_true
128
+ errors.should be_empty
129
+ end
130
+
131
+ it "should detect that the response is missing the top level object" do
132
+ response = valid_response
133
+ response.delete("user")
134
+ valid, errors = @service.validate_hash_response(response)
135
+ valid.should be_false
136
+ errors.should_not be_empty
137
+ end
138
+
139
+ it "should detect that a property integer type is wrong" do
140
+ response = valid_response
141
+ response["user"]["id"] = 'test'
142
+ valid, errors = @service.validate_hash_response(response)
143
+ valid.should be_false
144
+ errors.should_not be_empty
145
+ errors.first.should match(/id/)
146
+ errors.first.should match(/wrong type/)
147
+ end
148
+
149
+ it "should detect that an integer attribute value is nil" do
150
+ response = valid_response
151
+ response["user"]["id"] = nil
152
+ valid, errors = @service.validate_hash_response(response)
153
+ valid.should be_false
154
+ errors.should_not be_empty
155
+ errors.first.should match(/id/)
156
+ errors.first.should match(/wrong type/)
157
+ end
158
+
159
+ it "should detect that a string attribute value is nil [bug]" do
160
+ response = valid_response
161
+ response["user"]["name"] = nil
162
+ valid, errors = @service.validate_hash_response(response)
163
+ valid.should be_false
164
+ errors.should_not be_empty
165
+ errors.first.should match(/name/)
166
+ errors.first.should match(/wrong type/)
167
+ end
168
+
169
+
170
+ it "should detect that a nested object is missing" do
171
+ response = valid_response
172
+ response["user"].delete("creds")
173
+ valid, errors = @service.validate_hash_response(response)
174
+ valid.should be_false
175
+ errors.first.should match(/creds/)
176
+ errors.first.should match(/missing/)
177
+ end
178
+
179
+ it "should validate non namespaced responses" do
180
+ valid, errors = @second_service.validate_hash_response(valid_response(false))
181
+ valid.should be_true
182
+ end
183
+
184
+ it "should validate nil attributes if marked as nullable" do
185
+ response = valid_response(false)
186
+ response["name"] = nil
187
+ valid, errors = @second_service.validate_hash_response(response)
188
+ valid.should be_true
189
+ end
190
+
191
+
192
+ it "should validate array items" do
193
+ valid, errors = @third_service.validate_hash_response(valid_array_response)
194
+ valid.should be_true
195
+ errors.should be_empty
196
+ end
197
+
198
+ it "should validate an empty array" do
199
+ response = valid_array_response
200
+ response["users"] = []
201
+ valid, errors = @third_service.validate_hash_response(response)
202
+ valid.should be_true
203
+ end
204
+
205
+ it "should catch error in an array item" do
206
+ response = valid_array_response
207
+ response["users"][1]["id"] = 'test'
208
+ valid, errors = @third_service.validate_hash_response(response)
209
+ valid.should be_false
210
+ errors.should_not be_empty
211
+ end
212
+
213
+ it "should validate nested arrays" do
214
+ valid, errors = @forth_service.validate_hash_response(valid_nested_array_response)
215
+ valid.should be_true
216
+ end
217
+
218
+
219
+ it "should respect optional properties" do
220
+ valid, errors = @optional_prop_service.validate_hash_response({})
221
+ valid.should be_true
222
+ end
223
+
224
+
225
+ end
@@ -0,0 +1,102 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe ParamsVerification do
4
+
5
+ before :all do
6
+ @service = WSList.all.find{|s| s.url == 'services/test.xml'}
7
+ @service.should_not be_nil
8
+ @valid_params = {'framework' => 'RSpec', 'version' => '1.02', 'user' => {'id' => '123'}}
9
+ end
10
+
11
+ it "should validate valid params" do
12
+ params = @valid_params.dup
13
+ lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should_not raise_exception
14
+ end
15
+
16
+ it "should return the params" do
17
+ params = @valid_params.dup
18
+ returned_params = ParamsVerification.validate!(params, @service.defined_params)
19
+ returned_params.should be_an_instance_of(Hash)
20
+ returned_params.keys.size.should >= 3
21
+ end
22
+
23
+ it "should set the default value for an optional param" do
24
+ params = @valid_params.dup
25
+ params['timestamp'].should be_nil
26
+ returned_params = ParamsVerification.validate!(params, @service.defined_params)
27
+ returned_params['timestamp'].should_not be_nil
28
+ end
29
+
30
+ it "should set the default value for a namespace optional param" do
31
+ params = {'framework' => 'RSpec', 'version' => '1.02', 'user' => {'id' => '123'}}
32
+ params['user']['mailing_list'].should be_nil
33
+ returned_params = ParamsVerification.validate!(params, @service.defined_params)
34
+ returned_params['user']['mailing_list'].should be_true
35
+ end
36
+
37
+ it "should raise an exception when a required param is missing" do
38
+ params = @valid_params.dup
39
+ params.delete('framework')
40
+ lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::MissingParam)
41
+ end
42
+
43
+ it "should cast a comma delimited string into an array when param marked as an array" do
44
+ service = WSList.all.find{|s| s.url == "services/array_param.xml"}
45
+ service.should_not be_nil
46
+ params = {'seq' => "a,b,c,d,e,g"}
47
+ validated = ParamsVerification.validate!(params, service.defined_params)
48
+ validated['seq'].should == %W{a b c d e g}
49
+ end
50
+
51
+ it "should not raise an exception if a req array param doesn't contain a comma" do
52
+ service = WSList.all.find{|s| s.url == "services/array_param.xml"}
53
+ params = {'seq' => "a b c d e g"}
54
+ lambda{ ParamsVerification.validate!(params, service.defined_params) }.should_not raise_exception(ParamsVerification::InvalidParamType)
55
+ end
56
+
57
+ it "should raise an exception when a param is of the wrong type" do
58
+ params = @valid_params.dup
59
+ params['user']['id'] = 'abc'
60
+ lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamType)
61
+ end
62
+
63
+ it "should raise an exception when a param is under the minvalue" do
64
+ params = @valid_params.dup
65
+ params['num'] = 1
66
+ lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamType)
67
+ end
68
+
69
+ it "should raise an exception when a param isn't in the param option list" do
70
+ params = @valid_params.dup
71
+ params['alpha'] = 'z'
72
+ lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
73
+ end
74
+
75
+ it "should raise an exception when a nested optional param isn't in the param option list" do
76
+ params = @valid_params.dup
77
+ params['user']['sex'] = 'large'
78
+ lambda{ ParamsVerification.validate!(params, @service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamType)
79
+ # other service
80
+ params = {'preference' => {'region_code' => 'us', 'language_code' => 'de'}}
81
+ service = WSList.all.find{|s| s.url == 'preferences.xml'}
82
+ service.should_not be_nil
83
+ lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
84
+ end
85
+
86
+ it "should raise an exception when a required param is present but doesn't match the limited set of options" do
87
+ service = describe_service "search" do |service|
88
+ service.params { |p| p.string :by, :options => ['name', 'code', 'last_four'], :required => true }
89
+ end
90
+ params = {'by' => 'foo'}
91
+ lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception(ParamsVerification::InvalidParamValue)
92
+ end
93
+
94
+
95
+ it "should validate that no params are passed when accept_no_params! is set on a service" do
96
+ service = WSList.all.find{|s| s.url == "services/test_no_params.xml"}
97
+ service.should_not be_nil
98
+ params = @valid_params.dup
99
+ lambda{ ParamsVerification.validate!(params, service.defined_params) }.should raise_exception
100
+ end
101
+
102
+ end