groem 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +24 -0
- data/.gitignore +3 -0
- data/Gemfile +3 -0
- data/HISTORY.markdown +9 -0
- data/README.markdown +185 -0
- data/TODO.markdown +7 -0
- data/groem.gemspec +24 -0
- data/lib/groem.rb +10 -0
- data/lib/groem/app.rb +197 -0
- data/lib/groem/client.rb +169 -0
- data/lib/groem/constants.rb +74 -0
- data/lib/groem/marshal.rb +349 -0
- data/lib/groem/notification.rb +140 -0
- data/lib/groem/response.rb +86 -0
- data/lib/groem/route.rb +37 -0
- data/lib/groem/version.rb +3 -0
- data/spec/functional/app_notify_adhoc_spec.rb +73 -0
- data/spec/functional/app_notify_spec.rb +390 -0
- data/spec/functional/app_register_spec.rb +113 -0
- data/spec/functional/client_spec.rb +361 -0
- data/spec/integration/notify.rb +318 -0
- data/spec/integration/register.rb +133 -0
- data/spec/shared/dummy_server.rb +198 -0
- data/spec/shared/dummy_server_helper.rb +31 -0
- data/spec/shared/marshal_helper.rb +40 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/unit/app_spec.rb +77 -0
- data/spec/unit/marshal_request_spec.rb +380 -0
- data/spec/unit/marshal_response_spec.rb +162 -0
- data/spec/unit/notification_spec.rb +205 -0
- data/spec/unit/response_spec.rb +7 -0
- data/spec/unit/route_spec.rb +93 -0
- metadata +141 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
2
|
+
|
3
|
+
describe 'Groem::Marshal::Response.load' do
|
4
|
+
|
5
|
+
|
6
|
+
describe 'when valid REGISTER response -OK' do
|
7
|
+
# TODO
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'when valid REGISTER response -ERROR' do
|
11
|
+
#TODO
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'when valid NOTIFY response -OK' do
|
15
|
+
|
16
|
+
before do
|
17
|
+
@input = <<-__________
|
18
|
+
GNTP/1.0 -OK NONE
|
19
|
+
Response-Action: NOTIFY
|
20
|
+
Application-Name: SurfWriter
|
21
|
+
Notification-ID : 999
|
22
|
+
|
23
|
+
__________
|
24
|
+
dummy = Class.new { include(Groem::Marshal::Response) }
|
25
|
+
@subject = dummy.load(@input, false)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return three element array' do
|
29
|
+
@subject.must_be_kind_of Array
|
30
|
+
@subject.size.must_equal 3
|
31
|
+
puts
|
32
|
+
puts '--------- Groem::Marshal::Response.load when valid NOTIFY response -OK ----------'
|
33
|
+
puts @subject.inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return OK status code (== 0)' do
|
37
|
+
@subject[0].to_i.must_equal 0
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return headers hash with 3 keys' do
|
41
|
+
@subject[1].keys.size.must_equal 3
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return Notification-ID header matching input' do
|
45
|
+
@subject[1]['Notification-ID'].must_equal '999'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should return empty callback hash' do
|
49
|
+
@subject[2].must_be_empty
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'when valid NOTIFY response -ERROR' do
|
55
|
+
|
56
|
+
before do
|
57
|
+
@input = <<-__________
|
58
|
+
GNTP/1.0 -ERROR NONE
|
59
|
+
Error-Code: 303
|
60
|
+
Error-Description : REQUIRED_HEADER_MISSING
|
61
|
+
Response-Action: NOTIFY
|
62
|
+
|
63
|
+
__________
|
64
|
+
dummy = Class.new { include(Groem::Marshal::Response) }
|
65
|
+
@subject = dummy.load(@input, false)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should return three element array' do
|
69
|
+
@subject.must_be_kind_of Array
|
70
|
+
@subject.size.must_equal 3
|
71
|
+
puts
|
72
|
+
puts '--------- Groem::Marshal::Response.load when valid NOTIFY response -ERROR ----------'
|
73
|
+
puts @subject.inspect
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should return status code matching input error code (== 303)' do
|
77
|
+
@subject[0].to_i.must_equal 303
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should return headers hash with 2 keys' do
|
81
|
+
@subject[1].keys.size.must_equal 2
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should return Response-Action header matching input' do
|
85
|
+
@subject[1]['Response-Action'].must_equal 'NOTIFY'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should not return header for Error-Code' do
|
89
|
+
@subject[1].keys.wont_include 'error_code'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should return empty result' do
|
93
|
+
@subject[2].must_be_empty
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'when valid NOTIFY response -CALLBACK' do
|
99
|
+
|
100
|
+
before do
|
101
|
+
@input = [
|
102
|
+
"GNTP/1.0 -CALLBACK NONE",
|
103
|
+
"Application-Name: SurfWriter",
|
104
|
+
"Response-Action: NOTIFY",
|
105
|
+
"Notification-ID: 999",
|
106
|
+
"Notification-Callback-Result : CLICKED",
|
107
|
+
" Notification-Callback-Timestamp: 2010-10-01 22:21:00Z",
|
108
|
+
"Notification-Callback-Context :Test",
|
109
|
+
"Notification-Callback-Context-Type: Confirm"
|
110
|
+
].join("\r\n") + "\r\n"
|
111
|
+
dummy = Class.new { include(Groem::Marshal::Response) }
|
112
|
+
@subject = dummy.load(@input, false)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should return three element array' do
|
116
|
+
@subject.must_be_kind_of Array
|
117
|
+
@subject.size.must_equal 3
|
118
|
+
puts
|
119
|
+
puts '--------- Groem::Marshal::Response.load when valid NOTIFY response -CALLBACK ----------'
|
120
|
+
puts @subject.inspect
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should return OK status code (== 0)' do
|
124
|
+
@subject[0].to_i.must_equal 0
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should return headers hash with 3 keys' do
|
128
|
+
@subject[1].keys.size.must_equal 3
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should return Notification-ID matching input' do
|
132
|
+
@subject[1]['Notification-ID'].must_equal '999'
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should return context matching input' do
|
136
|
+
@subject[2]['Notification-Callback-Context'].must_equal 'Test'
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should return context-type matching input' do
|
140
|
+
@subject[2]['Notification-Callback-Context-Type'].must_equal 'Confirm'
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should return timestamp matching input' do
|
144
|
+
@subject[2]['Notification-Callback-Timestamp'].must_equal '2010-10-01 22:21:00Z'
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should return result matching input' do
|
148
|
+
@subject[2]['Notification-Callback-Result'].must_equal 'CLICKED'
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should not return header for Notification-Callback-*' do
|
152
|
+
%w{Notifiction-Callback-Context
|
153
|
+
Notification-Callback-Context-Type
|
154
|
+
Notification-Callback-Timestamp
|
155
|
+
Notification-Callback-Result}.each do |key|
|
156
|
+
@subject[1].keys.wont_include key
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
2
|
+
|
3
|
+
describe 'Groem::Notification #[]' do
|
4
|
+
|
5
|
+
describe 'after initializing' do
|
6
|
+
it 'should set the notification_name header based on input' do
|
7
|
+
@subject = Groem::Notification.new('verb')
|
8
|
+
@subject['headers']['Notification-Name'].must_equal 'verb'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should not set the notification_title header if none passed' do
|
12
|
+
@subject = Groem::Notification.new('verb')
|
13
|
+
@subject['headers'].keys.wont_include 'Notification-Title'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should set the notification_title header based on input' do
|
17
|
+
@subject = Groem::Notification.new('verb', 'title')
|
18
|
+
@subject['headers']['Notification-Title'].must_equal 'title'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should default the environment when no options passed' do
|
22
|
+
@subject = Groem::Notification.new('verb')
|
23
|
+
@subject['environment'].must_equal Groem::Notification::DEFAULT_ENV
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should default enabled to \'True\' when option not passed' do
|
27
|
+
@subject = Groem::Notification.new('verb')
|
28
|
+
@subject.enabled.must_equal 'True'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should merge keys from input environment option into default environment' do
|
32
|
+
input = {'version' => '1.2',
|
33
|
+
'request_method' => 'HELLO',
|
34
|
+
'encryption_id' => 'ABC'
|
35
|
+
}
|
36
|
+
@subject = Groem::Notification.new('verb', {:environment => input})
|
37
|
+
@subject['environment'].must_equal Groem::Notification::DEFAULT_ENV.merge(input)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should set each notify option in headers hash prefixed by \'notification_\', besides environment' do
|
41
|
+
opts = {:environment => {},
|
42
|
+
:title => 'what',
|
43
|
+
:text => 'False',
|
44
|
+
:sticky => 'True'
|
45
|
+
}
|
46
|
+
@subject = Groem::Notification.new('verb', opts)
|
47
|
+
@subject['headers']['Notification-Title'].must_equal 'what'
|
48
|
+
@subject['headers']['Notification-Text'].must_equal 'False'
|
49
|
+
@subject['headers']['Notification-Sticky'].must_equal 'True'
|
50
|
+
@subject['headers'].keys.wont_include 'environment'
|
51
|
+
@subject['headers'].keys.wont_include 'Notification-Environment'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should set application_name option in headers hash' do
|
55
|
+
opts = {:environment => {},
|
56
|
+
:application_name => 'Obama'
|
57
|
+
}
|
58
|
+
@subject = Groem::Notification.new('verb', opts)
|
59
|
+
@subject['headers']['Application-Name'].must_equal 'Obama'
|
60
|
+
@subject['headers'].keys.wont_include 'Notification-Application-Name'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should set automatic notification_id in headers hash' do
|
64
|
+
@subject = Groem::Notification.new('verb')
|
65
|
+
@subject['headers'].keys.must_include 'Notification-ID'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should set any unknown options in headers hash not prefixed by \'notification_\'' do
|
69
|
+
opts = {:boo => 'bear', :sister_of_goldilocks => 'Reba'}
|
70
|
+
@subject = Groem::Notification.new('verb', opts)
|
71
|
+
@subject['headers']['Boo'].must_equal 'bear'
|
72
|
+
@subject['headers']['Sister-Of-Goldilocks'].must_equal 'Reba'
|
73
|
+
@subject['headers'].keys.wont_include 'Notification-Boo'
|
74
|
+
@subject['headers'].keys.wont_include 'Notification-Sister-Of-Goldilocks'
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'after setting header' do
|
80
|
+
|
81
|
+
it 'should add the header to the headers hash based on input' do
|
82
|
+
@subject = Groem::Notification.new('verb')
|
83
|
+
@subject.header('x_header', 'boo')
|
84
|
+
@subject['headers']['X-Header'].must_equal 'boo'
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'after setting callback' do
|
90
|
+
|
91
|
+
before do
|
92
|
+
@subject = Groem::Notification.new('verb')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should add the notification_callback_context header to the headers hash' do
|
96
|
+
@subject.callback 'success'
|
97
|
+
@subject['headers']['Notification-Callback-Context'].must_equal 'success'
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should add the notification_callback_context_type header to the headers hash, when :type passed as an option' do
|
101
|
+
@subject.callback 'success', :type => 'test'
|
102
|
+
@subject['headers']['Notification-Callback-Context-Type'].must_equal 'test'
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should add the notification_callback_target header to the headers hash, when :target passed as an option' do
|
106
|
+
@subject.callback 'success', :target => '10.10.0.2'
|
107
|
+
@subject['headers']['Notification-Callback-Target'].must_equal '10.10.0.2'
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should set the notification_callback_context and _type to the notification name, when no argments passed' do
|
111
|
+
@subject.callback
|
112
|
+
@subject['headers']['Notification-Callback-Context'].must_equal @subject.name
|
113
|
+
@subject['headers']['Notification-Callback-Context-Type'].must_equal @subject.name
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'after reset!' do
|
119
|
+
|
120
|
+
it 'should not set the same notification_id' do
|
121
|
+
@subject = Groem::Notification.new('verb')
|
122
|
+
id = @subject['headers']['Notification_ID']
|
123
|
+
@subject.reset!
|
124
|
+
@subject['headers']['Notification-ID'].wont_equal id
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'Groem::Notification #dup' do
|
132
|
+
|
133
|
+
before do
|
134
|
+
|
135
|
+
@input_opts = { :environment => {'protocol' => 'GNTP',
|
136
|
+
'version' => '2.0',
|
137
|
+
'request_method' => 'NOTIFY',
|
138
|
+
'encryption_id' => 'ABC'
|
139
|
+
},
|
140
|
+
:application_name => 'Foo',
|
141
|
+
:display_name => 'Name here',
|
142
|
+
:enabled => 'True',
|
143
|
+
:text => 'Text here',
|
144
|
+
:sticky => 'False',
|
145
|
+
:priority => 'High',
|
146
|
+
:coalescing_id => '12345'
|
147
|
+
}
|
148
|
+
@input_name = 'verb'
|
149
|
+
@input_title = 'title'
|
150
|
+
@headers = [['X-Header-Thing', 'Blackbeard'],
|
151
|
+
['X-Another-Thing', 'Creamcicle']]
|
152
|
+
|
153
|
+
@input = Groem::Notification.new(@input_name, @input_title, @input_opts)
|
154
|
+
@input.header @headers[0][0], @headers[0][1]
|
155
|
+
@input.header @headers[1][0], @headers[1][1]
|
156
|
+
@input.callback
|
157
|
+
@subject = @input.dup
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should have equal name' do
|
161
|
+
@subject.name.must_equal @input.name
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should have equal title' do
|
165
|
+
@subject.title.must_equal @input.title
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should have equal attributes' do
|
169
|
+
@input.each_pair do |k, v|
|
170
|
+
@subject.__send__(k).must_equal v
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should have matching callback' do
|
175
|
+
%w{Notification-Callback-Context
|
176
|
+
Notification-Callback-Context-Type
|
177
|
+
Notification-Callback-Target}.each do |key|
|
178
|
+
@subject[key].must_equal @input[key]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should not have same name reference' do
|
183
|
+
@subject.name.wont_be_same_as @input.name
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should not have same title reference' do
|
187
|
+
@subject.title.wont_be_same_as @input.title
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should not have same reference for each attribute' do
|
191
|
+
@input.each_pair do |k, v|
|
192
|
+
@subject.__send__(k).wont_be_same_as v
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should not have matching callback after changing' do
|
197
|
+
@subject.callback 'ZZing', :type => 'Zam', :target => 'www.zombo.com'
|
198
|
+
%w{Notification-Callback-Context
|
199
|
+
Notification-Callback-Context-Type
|
200
|
+
Notification-Callback-Target}.each do |key|
|
201
|
+
@subject['headers'][key].wont_equal @input['headers'][key]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
2
|
+
|
3
|
+
describe 'Groem::Route.parse' do
|
4
|
+
|
5
|
+
it 'should parse nil path' do
|
6
|
+
@subject = Groem::Route.parse 'action', nil
|
7
|
+
@subject.must_equal ['action', nil, nil]
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should parse empty path' do
|
11
|
+
@subject = Groem::Route.parse 'action', ''
|
12
|
+
@subject.must_equal ['action', '', nil]
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should parse action and path' do
|
16
|
+
@subject = Groem::Route.parse 'action', 'context', 'type'
|
17
|
+
@subject.must_equal ['action', 'context', 'type']
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should parse path with less than 2 parts' do
|
21
|
+
@subject = Groem::Route.parse 'action', 'context'
|
22
|
+
@subject.must_equal ['action', 'context', nil]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should parse path with greater than 2 parts' do
|
26
|
+
@subject = Groem::Route.parse 'action', 'context', 'type', 'extra'
|
27
|
+
@subject.must_equal ['action', 'context', 'type']
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'Groem::Route#parse' do
|
33
|
+
|
34
|
+
it 'should parse nil path' do
|
35
|
+
@subject = Groem::Route.new('action')
|
36
|
+
@subject.pattern.must_equal ['action', nil, nil]
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should parse splatted path' do
|
40
|
+
@subject = Groem::Route.new('action', 'context', 'type')
|
41
|
+
@subject.pattern.must_equal ['action', 'context', 'type']
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should parse array path' do
|
45
|
+
@subject = Groem::Route.new('action', ['context', 'type'])
|
46
|
+
@subject.pattern.must_equal ['action', 'context', 'type']
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
describe 'Groem::Route.matches?' do
|
53
|
+
|
54
|
+
it 'should match identical pattern' do
|
55
|
+
@pattern = ['action', 'context', 'type']
|
56
|
+
Groem::Route.matches?(@pattern, ['action', 'context', 'type'])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should match nil part of pattern' do
|
60
|
+
@pattern = ['action', nil, 'type']
|
61
|
+
Groem::Route.matches?(@pattern, ['action', 'context', 'type'])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should match multiple nil parts of pattern' do
|
65
|
+
@pattern = [nil, nil, 'type']
|
66
|
+
Groem::Route.matches?(@pattern, ['action', 'context', 'type'])
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'Groem::Route#<=>' do
|
72
|
+
|
73
|
+
it 'should sort by standard array sort if no nil parts in pattern' do
|
74
|
+
subject = [ s1 = Groem::Route.new('action', 'c','d'),
|
75
|
+
s2 = Groem::Route.new('bacon', 'b','c'),
|
76
|
+
s3 = Groem::Route.new('action', 'b','c')
|
77
|
+
]
|
78
|
+
subject.sort.must_equal [s3, s1, s2]
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should sort nil parts after non-nil parts in pattern' do
|
82
|
+
subject = [ s1 = Groem::Route.new('action', 'c','d'),
|
83
|
+
s2 = Groem::Route.new('bacon', 'b','c'),
|
84
|
+
s3 = Groem::Route.new('action', 'b','c'),
|
85
|
+
s4 = Groem::Route.new('action', nil,'c'),
|
86
|
+
s5 = Groem::Route.new('action', nil,'b'),
|
87
|
+
s6 = Groem::Route.new('action', 'c',nil)
|
88
|
+
]
|
89
|
+
subject.sort.must_equal [s3, s1, s6, s5, s4, s2]
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|