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,140 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'uuidtools'
|
3
|
+
|
4
|
+
module Groem
|
5
|
+
|
6
|
+
class Notification < Struct.new(:environment,
|
7
|
+
:application_name,
|
8
|
+
:name,
|
9
|
+
:display_name,
|
10
|
+
:enabled,
|
11
|
+
:title,
|
12
|
+
:text,
|
13
|
+
:sticky,
|
14
|
+
:priority,
|
15
|
+
:coalescing_id,
|
16
|
+
:headers
|
17
|
+
)
|
18
|
+
include Groem::Marshal::Request
|
19
|
+
|
20
|
+
DEFAULT_ENV = {'protocol' => 'GNTP', 'version' => '1.0',
|
21
|
+
'request_method' => 'NOTIFY', 'encryption_id' => 'NONE'
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(name, *args)
|
25
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
26
|
+
title = args.shift
|
27
|
+
self.environment, self.headers, @callback = {}, {}, {}
|
28
|
+
self.environment = DEFAULT_ENV.merge(opts.delete(:environment) || {})
|
29
|
+
self.name = name.to_s if name
|
30
|
+
self.title = title.to_s if title
|
31
|
+
self.enabled = 'True'
|
32
|
+
self.headers = opts.delete(:headers) || {}
|
33
|
+
opts.each_pair do |opt, val|
|
34
|
+
if self.respond_to?(:"#{opt}=")
|
35
|
+
self.__send__ :"#{opt}=", val.to_s
|
36
|
+
else
|
37
|
+
header(opt, val.to_s)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
reset!
|
41
|
+
end
|
42
|
+
|
43
|
+
def [](key)
|
44
|
+
to_request[key]
|
45
|
+
end
|
46
|
+
|
47
|
+
def reset!
|
48
|
+
@to_request = nil
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def reset_callback!
|
53
|
+
@callback = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def dup
|
57
|
+
attrs = {}; self.each_pair {|k, v| attrs[k] = v.dup if v}
|
58
|
+
n = self.class.new(self.name, attrs)
|
59
|
+
n.callback(:context => callback_context,
|
60
|
+
:type => callback_type,
|
61
|
+
:target => callback_target) if @callback
|
62
|
+
n
|
63
|
+
end
|
64
|
+
|
65
|
+
def header key, value
|
66
|
+
reset!
|
67
|
+
self.headers[growlify_key(key)] = value
|
68
|
+
end
|
69
|
+
|
70
|
+
def icon(uri_or_file)
|
71
|
+
# TODO if not uri
|
72
|
+
reset!
|
73
|
+
header GNTP_NOTIFICATION_ICON_KEY, uri_or_file
|
74
|
+
end
|
75
|
+
|
76
|
+
# Note defaults name and type to notification name
|
77
|
+
def callback *args
|
78
|
+
opts = ((Hash === args.last) ? args.pop : {})
|
79
|
+
name = args.shift || opts[:context] || self.name
|
80
|
+
type = opts[:type] || self.name
|
81
|
+
target = opts[:target]
|
82
|
+
reset!
|
83
|
+
reset_callback!
|
84
|
+
@callback[GNTP_NOTIFICATION_CALLBACK_CONTEXT_KEY] = name if name
|
85
|
+
@callback[GNTP_NOTIFICATION_CALLBACK_CONTEXT_TYPE_KEY] = type if type
|
86
|
+
@callback[GNTP_NOTIFICATION_CALLBACK_TARGET_KEY] = target if target
|
87
|
+
@callback
|
88
|
+
end
|
89
|
+
|
90
|
+
def callback_context
|
91
|
+
@callback[GNTP_NOTIFICATION_CALLBACK_CONTEXT_KEY]
|
92
|
+
end
|
93
|
+
|
94
|
+
def callback_type
|
95
|
+
@callback[GNTP_NOTIFICATION_CALLBACK_CONTEXT_TYPE_KEY]
|
96
|
+
end
|
97
|
+
alias_method :callback_context_type, :callback_type
|
98
|
+
|
99
|
+
def callback_target
|
100
|
+
@callback[GNTP_NOTIFICATION_CALLBACK_TARGET_KEY]
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_register
|
104
|
+
%w{display_name enabled}.inject({}) do |memo, attr|
|
105
|
+
if val = self.__send__(:"#{attr}")
|
106
|
+
memo["Notification-#{growlify_key(attr)}"] = val
|
107
|
+
end
|
108
|
+
memo
|
109
|
+
end.merge(self.headers)
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_notify
|
113
|
+
%w{name title text sticky priority coalescing_id}.inject({}) do |memo, attr|
|
114
|
+
if val = self.__send__(:"#{attr}")
|
115
|
+
memo["Notification-#{growlify_key(attr)}"] = val
|
116
|
+
end
|
117
|
+
memo
|
118
|
+
end.merge({GNTP_APPLICATION_NAME_KEY => self.application_name}).
|
119
|
+
merge({GNTP_NOTIFICATION_ID_KEY => unique_id}).
|
120
|
+
merge(@callback).
|
121
|
+
merge(self.headers)
|
122
|
+
end
|
123
|
+
|
124
|
+
def to_request
|
125
|
+
@to_request ||= \
|
126
|
+
{'environment' => environment,
|
127
|
+
'headers' => to_notify,
|
128
|
+
'notifications' => {}
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
|
134
|
+
def unique_id
|
135
|
+
UUIDTools::UUID.timestamp_create.to_s
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Groem
|
4
|
+
class Response < Struct.new(:status,
|
5
|
+
:method,
|
6
|
+
:action,
|
7
|
+
:notification_id,
|
8
|
+
:context,
|
9
|
+
:context_type,
|
10
|
+
:callback_result,
|
11
|
+
:headers)
|
12
|
+
include Groem::Marshal::Response
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
def_delegator :@raw, :[]
|
16
|
+
|
17
|
+
def initialize(resp)
|
18
|
+
@raw = resp
|
19
|
+
self.status = resp[0]
|
20
|
+
self.headers = resp[1]
|
21
|
+
self.action = resp[1][GNTP_RESPONSE_ACTION_KEY]
|
22
|
+
self.notification_id = resp[1][GNTP_NOTIFICATION_ID_KEY]
|
23
|
+
self.context = resp[2][GNTP_NOTIFICATION_CALLBACK_CONTEXT_KEY]
|
24
|
+
self.context_type = resp[2][GNTP_NOTIFICATION_CALLBACK_CONTEXT_TYPE_KEY]
|
25
|
+
self.callback_result = resp[2][GNTP_NOTIFICATION_CALLBACK_RESULT_KEY]
|
26
|
+
self.method = if self.status.to_i == 0
|
27
|
+
if self.callback_result
|
28
|
+
GNTP_CALLBACK_RESPONSE
|
29
|
+
else
|
30
|
+
GNTP_OK_RESPONSE
|
31
|
+
end
|
32
|
+
else
|
33
|
+
GNTP_ERROR_RESPONSE
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def callback_route
|
38
|
+
[self.callback_result, self.context, self.context_type]
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_register? &blk
|
42
|
+
yield_and_return_if self.action == GNTP_REGISTER_METHOD, &blk
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_notify? &blk
|
46
|
+
yield_and_return_if self.action == GNTP_NOTIFY_METHOD, &blk
|
47
|
+
end
|
48
|
+
|
49
|
+
def ok? &blk
|
50
|
+
yield_and_return_if self.method == GNTP_OK_RESPONSE, &blk
|
51
|
+
end
|
52
|
+
|
53
|
+
def callback? &blk
|
54
|
+
yield_and_return_if self.method == GNTP_CALLBACK_RESPONSE, &blk
|
55
|
+
end
|
56
|
+
|
57
|
+
def error?(code=nil, &blk)
|
58
|
+
yield_and_return_if (self.method == GNTP_ERROR_RESPONSE && \
|
59
|
+
code.nil? || self.status == code), &blk
|
60
|
+
end
|
61
|
+
|
62
|
+
def clicked? &blk
|
63
|
+
yield_and_return_if self.callback_result == GNTP_CLICK_CALLBACK_RESULT, &blk
|
64
|
+
end
|
65
|
+
|
66
|
+
def closed? &blk
|
67
|
+
yield_and_return_if self.callback_result == GNTP_CLOSE_CALLBACK_RESULT, &blk
|
68
|
+
end
|
69
|
+
|
70
|
+
def timedout? &blk
|
71
|
+
yield_and_return_if self.callback_result == GNTP_TIMEDOUT_CALLBACK_RESULT, &blk
|
72
|
+
end
|
73
|
+
|
74
|
+
alias_method :click?, :clicked?
|
75
|
+
alias_method :close?, :closed?
|
76
|
+
alias_method :timeout?, :timedout?
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def yield_and_return_if(cond)
|
81
|
+
yield if block_given? && cond
|
82
|
+
cond
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/groem/route.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module Groem
|
3
|
+
class Route
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def parse action, *path
|
7
|
+
[action] + Array.new(2).fill {|i| path[i] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches? pattern, parts
|
11
|
+
parts = [parts] unless Array === parts
|
12
|
+
pattern.zip(parts).all? do |exp, act|
|
13
|
+
exp.nil? || exp == act
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :pattern
|
20
|
+
|
21
|
+
def initialize action, *path
|
22
|
+
path = path.flatten
|
23
|
+
@pattern = self.class.parse action, *path
|
24
|
+
end
|
25
|
+
|
26
|
+
def matches?(*args)
|
27
|
+
self.class.matches?(pattern, args.flatten)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# sort nil parts after named parts (unless named parts begin with ~)
|
32
|
+
def <=>(other)
|
33
|
+
pattern.map {|it| it || '~'} <=> other.pattern.map {|it| it || '~'}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
2
|
+
|
3
|
+
describe 'Groem::App #notify with ad-hoc callback' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@p_svr = DummyServerHelper.fork_server(:callback => ['CLICK', 2])
|
7
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
8
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
DummyServerHelper.kill_server(@p_svr)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should receive CLICK callback matching ad-hoc callback spec' do
|
16
|
+
ok_count = 0
|
17
|
+
cb_count = 0
|
18
|
+
|
19
|
+
app = @subject
|
20
|
+
app.register do
|
21
|
+
notification 'Foo' do |n|
|
22
|
+
n.display_name = 'Hoo'
|
23
|
+
n.callback 'First', :type => '1'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
app.when_click :type => '2' do |resp|
|
28
|
+
cb_count += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
app.when_click 'Second' do |resp|
|
32
|
+
cb_count += 1
|
33
|
+
end
|
34
|
+
|
35
|
+
app.when_click 'First' do |resp|
|
36
|
+
flunk 'Expected callback context \'Second\', got \'First\''
|
37
|
+
end
|
38
|
+
|
39
|
+
app.when_click :type => '1' do |resp|
|
40
|
+
flunk 'Expected callback context type \'2\', got \'1\''
|
41
|
+
end
|
42
|
+
|
43
|
+
app.notify('Foo', :callback => {:context => 'Second', :type => '2'})
|
44
|
+
|
45
|
+
cb_count.must_equal 2
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should trigger callback with ad-hoc state, but not change state of registered callback' do
|
49
|
+
|
50
|
+
app = @subject
|
51
|
+
app.register do
|
52
|
+
notification 'Foo' do |n|
|
53
|
+
n.display_name = 'Hoo'
|
54
|
+
n.callback 'First', :type => '1'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
app.when_click do |resp|
|
59
|
+
puts resp[0..2].inspect
|
60
|
+
resp.context.must_equal 'Second'
|
61
|
+
resp.context_type.must_equal '2'
|
62
|
+
end
|
63
|
+
|
64
|
+
app.notify('Foo', :display_name => 'Who',
|
65
|
+
:callback => {:context => 'Second', :type => '2'})
|
66
|
+
|
67
|
+
app.notifications['Foo'].display_name.must_equal 'Hoo'
|
68
|
+
app.notifications['Foo'].callback_context.must_equal 'First'
|
69
|
+
app.notifications['Foo'].callback_type.must_equal '1'
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,390 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),'..','spec_helper')
|
2
|
+
|
3
|
+
describe 'Groem::App #notify without callbacks' do
|
4
|
+
|
5
|
+
describe 'with one notification' do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@p_svr = DummyServerHelper.fork_server(:notify => '-OK')
|
9
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
10
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
DummyServerHelper.kill_server(@p_svr)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should receive back one OK response from notify' do
|
18
|
+
count = 0
|
19
|
+
|
20
|
+
@subject.register do
|
21
|
+
notification 'hello' do end
|
22
|
+
end
|
23
|
+
|
24
|
+
@subject.notify('hello') do |resp|
|
25
|
+
count += 1
|
26
|
+
resp[0].to_i.must_equal 0
|
27
|
+
resp[2].must_be_empty
|
28
|
+
count.must_equal 1
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return OK response from notify' do
|
34
|
+
|
35
|
+
@subject.register do
|
36
|
+
notification 'hello' do end
|
37
|
+
end
|
38
|
+
|
39
|
+
ret = @subject.notify('hello')
|
40
|
+
ret.class.must_be_same_as Groem::Response
|
41
|
+
ret[0].to_i.must_equal 0
|
42
|
+
ret[2].must_be_empty
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'when notification hasnt been specified' do
|
49
|
+
|
50
|
+
before do
|
51
|
+
@p_svr = DummyServerHelper.fork_server(:notify => '-OK')
|
52
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
53
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
54
|
+
end
|
55
|
+
|
56
|
+
after do
|
57
|
+
DummyServerHelper.kill_server(@p_svr)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return nil' do
|
61
|
+
|
62
|
+
@subject.register do
|
63
|
+
notification 'hello' do end
|
64
|
+
end
|
65
|
+
|
66
|
+
@subject.notify('goodbye') do end.must_be_nil
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
module AppNotifyCallbacksHelper
|
75
|
+
|
76
|
+
|
77
|
+
def should_receive_ok_and_callback(app, rslt, timeout, opts = {})
|
78
|
+
click_name = opts[:click] || 'CLICK'
|
79
|
+
close_name = opts[:close] || 'CLOSE'
|
80
|
+
timedout_name = opts[:timedout] || 'TIMEDOUT'
|
81
|
+
ok_count = 0
|
82
|
+
click_count = 0
|
83
|
+
close_count = 0
|
84
|
+
timedout_count = 0
|
85
|
+
|
86
|
+
EM.run {
|
87
|
+
app.register do
|
88
|
+
notification 'Foo' do |n|
|
89
|
+
n.callback 'You', :type => 'shiny'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
app.when_callback click_name do |resp|
|
94
|
+
puts "App received callback: #{resp[2]['Notification-Callback-Result']}"
|
95
|
+
click_count += 1
|
96
|
+
['CLICK', 'CLICKED'].must_include resp[2]['Notification-Callback-Result']
|
97
|
+
end
|
98
|
+
|
99
|
+
app.when_callback close_name do |resp|
|
100
|
+
puts "App received callback: #{resp[2]['Notification-Callback-Result']}"
|
101
|
+
close_count += 1
|
102
|
+
['CLOSE', 'CLOSED'].must_include resp[2]['Notification-Callback-Result']
|
103
|
+
end
|
104
|
+
|
105
|
+
app.when_callback timedout_name do |resp|
|
106
|
+
puts "App received callback: #{resp[2]['Notification-Callback-Result']}"
|
107
|
+
timedout_count += 1
|
108
|
+
['TIMEDOUT', 'TIMEOUT'].must_include resp[2]['Notification-Callback-Result']
|
109
|
+
end
|
110
|
+
|
111
|
+
app.notify('Foo') do |resp|
|
112
|
+
ok_count += 1 if resp[0].to_i == 0
|
113
|
+
resp[0].to_i.must_equal 0
|
114
|
+
end
|
115
|
+
|
116
|
+
EM.add_timer(timeout + 1) {
|
117
|
+
ok_count.must_equal 1
|
118
|
+
case rslt
|
119
|
+
when 'CLICK'
|
120
|
+
click_count.must_equal 1
|
121
|
+
close_count.must_equal 0
|
122
|
+
timedout_count.must_equal 0
|
123
|
+
when 'CLOSE'
|
124
|
+
click_count.must_equal 0
|
125
|
+
close_count.must_equal 1
|
126
|
+
timedout_count.must_equal 0
|
127
|
+
when 'TIMEDOUT'
|
128
|
+
click_count.must_equal 0
|
129
|
+
close_count.must_equal 0
|
130
|
+
timedout_count.must_equal 1
|
131
|
+
end
|
132
|
+
EM.stop
|
133
|
+
}
|
134
|
+
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
def should_receive_ok_and_callback_outside_reactor(app, rslt, timeout, opts = {})
|
139
|
+
click_name = opts[:click] || 'CLICK'
|
140
|
+
close_name = opts[:close] || 'CLOSE'
|
141
|
+
timedout_name = opts[:timedout] || 'TIMEDOUT'
|
142
|
+
ok_count = 0
|
143
|
+
click_count = 0
|
144
|
+
close_count = 0
|
145
|
+
timedout_count = 0
|
146
|
+
|
147
|
+
app.register do
|
148
|
+
notification 'Foo' do |n|
|
149
|
+
n.callback 'You', :type => 'shiny'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
app.when_callback click_name do |resp|
|
154
|
+
puts "App received callback: #{resp[2]['Notification-Callback-Result']}"
|
155
|
+
click_count += 1
|
156
|
+
['CLICK', 'CLICKED'].must_include resp[2]['Notification-Callback-Result']
|
157
|
+
end
|
158
|
+
|
159
|
+
app.when_callback close_name do |resp|
|
160
|
+
puts "App received callback: #{resp[2]['Notification-Callback-Result']}"
|
161
|
+
close_count += 1
|
162
|
+
['CLOSE', 'CLOSED'].must_include resp[2]['Notification-Callback-Result']
|
163
|
+
end
|
164
|
+
|
165
|
+
app.when_callback timedout_name do |resp|
|
166
|
+
puts "App received callback: #{resp[2]['Notification-Callback-Result']}"
|
167
|
+
timedout_count += 1
|
168
|
+
['TIMEDOUT', 'TIMEOUT'].must_include resp[2]['Notification-Callback-Result']
|
169
|
+
end
|
170
|
+
|
171
|
+
app.notify('Foo') do |resp|
|
172
|
+
ok_count += 1 if resp[0].to_i == 0
|
173
|
+
resp[0].to_i.must_equal 0
|
174
|
+
end
|
175
|
+
|
176
|
+
ok_count.must_equal 1
|
177
|
+
case rslt
|
178
|
+
when 'CLICK'
|
179
|
+
click_count.must_equal 1
|
180
|
+
close_count.must_equal 0
|
181
|
+
timedout_count.must_equal 0
|
182
|
+
when 'CLOSE'
|
183
|
+
click_count.must_equal 0
|
184
|
+
close_count.must_equal 1
|
185
|
+
timedout_count.must_equal 0
|
186
|
+
when 'TIMEDOUT'
|
187
|
+
click_count.must_equal 0
|
188
|
+
close_count.must_equal 0
|
189
|
+
timedout_count.must_equal 1
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
def should_return_ok_response(app)
|
196
|
+
|
197
|
+
app.register do
|
198
|
+
notification 'Foo' do |n|
|
199
|
+
n.callback 'You', :type => 'shiny'
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
ret = app.notify('Foo')
|
204
|
+
ret.class.must_be_same_as Groem::Response
|
205
|
+
ret[0].to_i.must_equal 0
|
206
|
+
ret[2].must_be_empty
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
describe 'Groem::App #notify with simple callbacks' do
|
214
|
+
|
215
|
+
|
216
|
+
describe 'when CLICK callback returned' do
|
217
|
+
include AppNotifyCallbacksHelper
|
218
|
+
|
219
|
+
before do
|
220
|
+
@p_svr = DummyServerHelper.fork_server(:callback => ['CLICK', 2])
|
221
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
222
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
223
|
+
end
|
224
|
+
|
225
|
+
after do
|
226
|
+
DummyServerHelper.kill_server(@p_svr)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should receive ok and CLICK callback' do
|
230
|
+
should_receive_ok_and_callback(@subject, 'CLICK', 2)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should receive ok and CLICK callback outside reactor' do
|
234
|
+
should_receive_ok_and_callback_outside_reactor(@subject, 'CLICK', 2)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'should receive ok and CLICK callback using symbolized actions' do
|
238
|
+
should_receive_ok_and_callback(@subject, 'CLICK', 2,
|
239
|
+
:click => :click,
|
240
|
+
:close => :closed,
|
241
|
+
:timedout => :timedout)
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should receive ok and CLICK callback with alternate action names' do
|
245
|
+
should_receive_ok_and_callback(@subject, 'CLICK', 2,
|
246
|
+
:click => 'CLICKED',
|
247
|
+
:close => 'CLOSED',
|
248
|
+
:timedout => 'TIMEOUT')
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should return ok response' do
|
252
|
+
should_return_ok_response(@subject)
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
describe 'when CLOSE callback returned' do
|
258
|
+
include AppNotifyCallbacksHelper
|
259
|
+
|
260
|
+
before do
|
261
|
+
@p_svr = DummyServerHelper.fork_server(:callback => ['CLOSE', 2])
|
262
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
263
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
264
|
+
end
|
265
|
+
|
266
|
+
after do
|
267
|
+
DummyServerHelper.kill_server(@p_svr)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'should receive ok and CLOSE callback' do
|
271
|
+
should_receive_ok_and_callback(@subject, 'CLOSE', 2)
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'should receive ok and CLOSE callback using symbolized actions' do
|
275
|
+
should_receive_ok_and_callback(@subject, 'CLOSE', 2,
|
276
|
+
:click => :click,
|
277
|
+
:close => :closed,
|
278
|
+
:timedout => :timedout)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'should receive ok and CLOSE callback with alternate action names' do
|
282
|
+
should_receive_ok_and_callback(@subject, 'CLOSE', 2,
|
283
|
+
:click => 'CLICKED',
|
284
|
+
:close => 'CLOSED',
|
285
|
+
:timedout => 'TIMEOUT')
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'should return ok response' do
|
289
|
+
should_return_ok_response(@subject)
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
293
|
+
|
294
|
+
describe 'when TIMEDOUT callback returned' do
|
295
|
+
include AppNotifyCallbacksHelper
|
296
|
+
|
297
|
+
before do
|
298
|
+
@p_svr = DummyServerHelper.fork_server(:callback => ['TIMEDOUT', 2])
|
299
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
300
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
301
|
+
end
|
302
|
+
|
303
|
+
after do
|
304
|
+
DummyServerHelper.kill_server(@p_svr)
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'should receive ok and TIMEDOUT callback' do
|
308
|
+
should_receive_ok_and_callback(@subject, 'TIMEDOUT', 2)
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'should receive ok and TIMEDOUT callback using symbolized actions' do
|
312
|
+
should_receive_ok_and_callback(@subject, 'TIMEDOUT', 2,
|
313
|
+
:click => :click,
|
314
|
+
:close => :closed,
|
315
|
+
:timedout => :timedout)
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'should receive ok and TIMEDOUT callback with alternate action names' do
|
319
|
+
should_receive_ok_and_callback(@subject, 'TIMEDOUT', 2,
|
320
|
+
:click => 'CLICKED',
|
321
|
+
:close => 'CLOSED',
|
322
|
+
:timedout => 'TIMEOUT')
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'should return ok response' do
|
326
|
+
should_return_ok_response(@subject)
|
327
|
+
end
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
describe 'Groem::App #notify with routed callbacks' do
|
335
|
+
|
336
|
+
before do
|
337
|
+
@p_svr = DummyServerHelper.fork_server(:callback => ['CLICK', 2])
|
338
|
+
Groem::Client.response_class = MarshalHelper.dummy_response_class
|
339
|
+
@subject = Groem::App.new('test', :port => DummyServerHelper::DEFAULT_PORT)
|
340
|
+
end
|
341
|
+
|
342
|
+
after do
|
343
|
+
DummyServerHelper.kill_server(@p_svr)
|
344
|
+
end
|
345
|
+
|
346
|
+
it 'should receive ok and CLICK callback matching multiple routes' do
|
347
|
+
ok_count = 0
|
348
|
+
cb_count = 0
|
349
|
+
|
350
|
+
app = @subject
|
351
|
+
app.register do
|
352
|
+
notification 'Foo' do |n|
|
353
|
+
n.callback 'You', :type => 'shiny'
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
app.when_click 'You' do |resp|
|
358
|
+
cb_count.must_equal 1
|
359
|
+
cb_count += 1
|
360
|
+
end
|
361
|
+
|
362
|
+
app.when_click :context => 'You', :type => 'shiny' do |resp|
|
363
|
+
cb_count.must_equal 0
|
364
|
+
cb_count += 1
|
365
|
+
end
|
366
|
+
|
367
|
+
app.when_click do |resp|
|
368
|
+
cb_count.must_equal 3
|
369
|
+
cb_count += 1
|
370
|
+
end
|
371
|
+
|
372
|
+
app.when_click :type => 'shiny' do |resp|
|
373
|
+
cb_count.must_equal 2
|
374
|
+
cb_count += 1
|
375
|
+
end
|
376
|
+
|
377
|
+
app.notify('Foo') do |resp|
|
378
|
+
ok_count += 1 if resp[0].to_i == 0
|
379
|
+
resp[0].to_i.must_equal 0
|
380
|
+
end
|
381
|
+
|
382
|
+
ok_count.must_equal 1
|
383
|
+
cb_count.must_equal 4
|
384
|
+
end
|
385
|
+
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
|
390
|
+
|