groem 0.0.4
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/.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
|
+
|