em-campfire 0.0.1 → 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.
@@ -1,47 +1,58 @@
1
- require "spec_helper"
1
+ require "messages_helper"
2
+
3
+ class MessageTester < ModuleHarness
4
+ include EventMachine::Campfire::Messages
5
+ include EventMachine::Campfire::Rooms
6
+ end
2
7
 
3
8
  describe EventMachine::Campfire::Messages do
4
-
5
- before :each do
6
- stub_rooms_data_request
7
- stub_join_room_request(123)
8
- stub_stream_room_request(123)
9
- EM.run_block { @adaptor = a(EM::Campfire) }
9
+ before :each do
10
+ @adaptor = MessageTester.new
10
11
  end
12
+
13
+ describe "posting messages" do
14
+ it "should say" do
15
+ @adaptor.expects(:send_message).with(123, "foo", "TextMessage")
16
+ @adaptor.say("foo", 123)
17
+ end
11
18
 
12
- it "should say a message" do
13
- mock_logger
14
- stub = stub_message_post_request
15
-
16
- EM.run_block {
17
- @adaptor.join 123
18
- @adaptor.say "Hi", 123
19
- }
20
- stub.should have_been_requested
21
- logger_output.should =~ /DEBUG.*Posted Textmessage "Hi" to room 123/
19
+ it "should paste" do
20
+ @adaptor.expects(:send_message).with(123, "foo", "PasteMessage")
21
+ @adaptor.paste("foo", 123)
22
+ end
23
+
24
+ it "should play" do
25
+ @adaptor.expects(:send_message).with(123, "foo", "SoundMessage")
26
+ @adaptor.play("foo", 123)
27
+ end
22
28
  end
23
29
 
24
- it "should paste a message" do
25
- mock_logger
26
- stub = stub_message_post_request
27
-
28
- EM.run_block {
29
- @adaptor.join 123
30
- @adaptor.paste "Hi", 123
31
- }
32
- stub.should have_been_requested
33
- logger_output.should =~ /DEBUG.*Posted PasteMessage "Hi" to room 123/
30
+ it "should not try to post a message to a room it hasn't joined" do
31
+ mock_logger(MessageTester)
32
+ EM.run_block { @adaptor.say "Hi", 123 }
33
+
34
+ logger_output.should =~ %r{Couldn't post message "Hi" to room 123 as no rooms have been joined}
34
35
  end
35
-
36
- it "should play a sound" do
37
- mock_logger
38
- stub = stub_message_post_request
39
-
40
- EM.run_block {
41
- @adaptor.join 123
42
- @adaptor.play "nyan", 123
43
- }
44
- stub.should have_been_requested
45
- logger_output.should =~ /DEBUG.*Posted SoundMessage "nyan" to room 123/
36
+
37
+ context "having successfully joined a room" do
38
+ before :each do
39
+ mock_logger(MessageTester)
40
+ stub_join_room_request(123)
41
+ EM.run_block { @adaptor.join(123) }
42
+ end
43
+
44
+ it "should say a message" do
45
+ stub = stub_message_post_request
46
+ EM.run_block { @adaptor.say("Hi", 123) }
47
+ stub.should have_been_requested
48
+ logger_output.should =~ /DEBUG.*Posted TextMessage "Hi" to room 123/
49
+ end
50
+
51
+ it "should handle message posting failure" do
52
+ stub = stub_message_post_request(500)
53
+ EM.run_block { @adaptor.say("Hi", 123) }
54
+ stub.should have_been_requested
55
+ logger_output.should =~ %r{ERROR.*Couldn't post message "Hi" to room 123 using url https://oxygen.campfirenow.com/room/123/speak.json, http response from the API was 500}
56
+ end
46
57
  end
47
58
  end
@@ -1,47 +1,221 @@
1
- require "spec_helper"
1
+ require "rooms_helper"
2
+
3
+ class RoomsTestContainer < ModuleHarness
4
+ include EventMachine::Campfire::Rooms
5
+
6
+ def cache; @cache ||= EventMachine::Campfire::Cache.new; end
7
+ def process_message; end
8
+ end
2
9
 
3
10
  describe EventMachine::Campfire::Rooms do
4
-
5
11
  before :each do
6
- @message_post_url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/123/speak.json"
7
- stub_rooms_data_request
8
- EM.run_block { @adaptor = a(EM::Campfire) }
12
+ mock_logger(RoomsTestContainer)
13
+ @adaptor = RoomsTestContainer.new
9
14
  end
10
15
 
11
- context "#join" do
12
- before :each do
13
- EM.run_block { @adaptor = a EM::Campfire }
14
- end
15
-
16
+ describe "#join" do
16
17
  it "should allow joining by id" do
17
- mock_logger
18
-
19
18
  join_stub = stub_join_room_request(123)
20
- stream_stub = stub_stream_room_request(123)
21
19
  EM.run_block { @adaptor.join(123) }
22
20
  logger_output.should =~ /INFO.*Joined room 123 successfully/
23
21
  join_stub.should have_been_requested
24
22
  end
25
-
26
- it "should allow joining by name" do
23
+
24
+ it "should not be able to join an invalid room" do
25
+ join_stub = stub_join_room_request(9999999, 302)
26
+ EM.run_block { @adaptor.join(9999999) }
27
+ logger_output.should =~ /Error joining room: 9999999/
28
+ end
29
+
30
+ it "should call a passed block on success" do
27
31
  join_stub = stub_join_room_request(123)
28
- stream_stub = stub_stream_room_request(123)
29
- EM.run_block { @adaptor.join("foo") }
30
- join_stub.should have_been_requested
32
+ object = mock()
33
+ object.expects(:ping).with("foo")
34
+
35
+ EM.run_block {
36
+ @adaptor.join(123) {|room_id| object.ping("foo") }
37
+ }
31
38
  end
32
-
33
- it "should not be able to join an invalid room" do
34
- mock_logger
35
- stream_stub = stub_stream_room_request(9999999999999999)
36
- url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/9999999999999999/join.json"
37
- join_stub = stub_request(:post, url).
38
- with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).
39
- to_return(:status => 302, :body => "", :headers => {})
40
-
41
- EM.run_block { @adaptor.join(9999999999999999) }
42
- logger_output.should =~ /Error joining room: 9999999999999999/
43
- join_stub.should have_been_requested
44
- stream_stub.should_not have_been_requested
39
+ end
40
+
41
+ describe "streaming" do
42
+ it "should stream a room" do
43
+ stream_stub = stub_stream_room_request(123, stream_message_json)
44
+ @adaptor.expects(:process_message).with(stream_message)
45
+ EM.run_block { @adaptor.stream(123)}
46
+ stream_stub.should have_been_requested
47
+ logger_output.should =~ /INFO.*Disconnected from #{stream_url_for_room(123)}/
48
+ end
49
+
50
+ it "should handle invalid json" do
51
+ invalid_json = "{:one => two}\n"
52
+ stream_stub = stub_stream_room_request(123, invalid_json)
53
+ @adaptor.expects(:process_message).never
54
+ EM.run_block { @adaptor.stream(123)}
55
+ stream_stub.should have_been_requested
56
+ logger_output.should =~ /Couldn't parse json data for room 123, data was #{invalid_json}, error was: parse error: invalid object key \(must be a string\)/
57
+ end
58
+
59
+ it "should handle server timeouts" do
60
+ request = stub_timeout_stream_room_request(123)
61
+
62
+ EM.run_block {@adaptor.stream(123)}
63
+ logger_output.should =~ /ERROR.*Couldn't stream room 123 at url #{stream_url_for_room(123)}, error was WebMock timeout error/
64
+ end
65
+
66
+ it "should re-connect to a streaming URL when timed out" do
67
+ request = stub_timeout_stream_room_request(123)
68
+
69
+ EM.run_block {@adaptor.stream(123)}
70
+ request.should have_been_requested.twice
71
+ logger_output.should =~ /ERROR.*Couldn't stream room 123 at url #{stream_url_for_room(123)}, error was WebMock timeout error/
72
+ end
73
+
74
+ it "should handle server errors streaming data" do
75
+ request = stub_stream_room_request(123, "", 500)
76
+
77
+ EM.run_block {@adaptor.stream(123)}
78
+ request.should have_been_requested
79
+ logger_output.should =~ /ERROR.*Couldn't stream room with url #{stream_url_for_room(123)}, http response from API was 500/
80
+ end
81
+
82
+ it "should re-connect to a streaming URL when disconnected" do
83
+ stream_stub = stub_stream_room_request(123, "")
84
+ EM.run {
85
+ @adaptor.stream(123)
86
+ # Re-connecting takes two ticks
87
+ EM.next_tick { EM.next_tick {EM.stop} }
88
+ }
89
+ logger_output.should =~ /INFO.*Disconnected from #{stream_url_for_room(123)}/
90
+ stream_stub.should have_been_requested.twice
91
+ end
92
+ end
93
+
94
+ describe "fetching metadata" do
95
+ describe "for individual rooms" do
96
+ it "should fetch room data" do
97
+ request = stub_room_data_request(123)
98
+ yielded_data = nil
99
+
100
+ EM.run_block {
101
+ @adaptor.room_data_from_room_id(123) {|data| yielded_data = data}
102
+ }
103
+
104
+ yielded_data.should eql(valid_room_cache_data[123])
105
+ request.should have_been_requested
106
+ logger_output.should =~ /DEBUG.*Fetched room data for 123 \(#{valid_room_cache_data[123]['name']}\)/
107
+ end
108
+
109
+ it "should handle server errors fetching data" do
110
+ request = stub_room_data_request(123, 500)
111
+
112
+ EM.run_block {@adaptor.room_data_from_room_id(123)}
113
+ request.should have_been_requested
114
+ logger_output.should =~ /ERROR.*Couldn't fetch room data with url #{room_data_url(123)}, http response from API was 500/
115
+ end
116
+
117
+
118
+ it "should handle server timeouts" do
119
+ request = stub_timeout_room_data_request(123)
120
+
121
+ EM.run_block {@adaptor.room_data_from_room_id(123)}
122
+ request.should have_been_requested
123
+ logger_output.should =~ /ERROR.*Couldn't connect to url #{room_data_url(123)} to fetch room data/
124
+ end
125
+
126
+ it "should not update the room data cache when room data is fresh" do
127
+ request = stub_room_data_request(123, 304)
128
+ room_data = valid_room_cache_data[123]
129
+ room_data_with_etag = room_data.merge({'etag' => etag_for_data(room_data)})
130
+ @adaptor.cache.expects(:get).with("room-data-123").returns(room_data_with_etag)
131
+ @adaptor.cache.expects(:set).never
132
+
133
+ EM.run_block { @adaptor.room_data_from_room_id(123) }
134
+ logger_output.should =~ /DEBUG.*HTTP response was 304, serving room data for room 123 \(#{room_data['name']}\) from cache/
135
+ end
136
+
137
+ it "should update the room data cache when room data is stale" do
138
+ request = stub_room_data_request(123)
139
+ room_data = valid_room_cache_data[123]
140
+ room_data_with_etag = room_data.merge({'etag' => etag_for_data(valid_room_cache_data[123])})
141
+ @adaptor.cache.expects(:get).with("room-data-123").returns(valid_room_cache_data[123].merge({'etag' => etag_for_data("no such etag")}))
142
+ @adaptor.cache.expects(:set).with("room-data-123", valid_room_cache_data[123].merge({'etag' => etag_for_data(room_data)}))
143
+
144
+ EM.run_block { @adaptor.room_data_from_room_id(123) }
145
+ end
146
+ end
147
+
148
+ describe "for all rooms" do
149
+ before :each do
150
+ @cache_response = {'etag' => etag_for_room_list_data, 'data' => room_list_data_api_response['rooms']}
151
+ @adaptor.cache.expects(:get).with("room-list-data").returns(@cache_response)
152
+ end
153
+
154
+ it "should fetch a room list" do
155
+ request = stub_room_list_data_request
156
+ rooms_data = room_list_data_api_response
157
+ rooms_data_with_etag = rooms_data.merge({'etag' => etag_for_data(rooms_data)})
158
+
159
+ yielded_data = nil
160
+
161
+ EM.run_block {
162
+ @adaptor.room_data_for_all_rooms {|data| yielded_data = data}
163
+ }
164
+
165
+ yielded_data.should eql(room_list_data_api_response['rooms'])
166
+
167
+ request.should have_been_requested
168
+ logger_output.should =~ /DEBUG.*Fetched room data for all rooms/
169
+ end
170
+
171
+ it "should handle server errors fetching data" do
172
+ request = stub_room_list_data_request(500)
173
+
174
+ EM.run_block {@adaptor.room_data_for_all_rooms}
175
+
176
+ request.should have_been_requested
177
+ logger_output.should =~ /ERROR.*Couldn't fetch room list with url #{rooms_data_url}, http response from API was 500/
178
+ end
179
+
180
+ it "should handle server timeouts" do
181
+ request = stub_timeout_room_list_data_request
182
+
183
+ EM.run_block {@adaptor.room_data_for_all_rooms}
184
+ request.should have_been_requested
185
+
186
+ logger_output.should =~ /ERROR.*Error processing url #{rooms_data_url} to fetch room data: WebMock timeout error/
187
+ end
188
+
189
+ describe "when the cached data is fresh" do
190
+ before :each do
191
+ stub_room_list_data_request(304)
192
+ rooms_data = room_list_data_api_response
193
+ @rooms_data_with_etag = rooms_data.merge({'etag' => etag_for_room_list_data})
194
+ end
195
+
196
+ it "should not update the cached room list" do
197
+ @adaptor.cache.expects(:set).never
198
+
199
+ EM.run_block { @adaptor.room_data_for_all_rooms }
200
+ end
201
+
202
+ it "should serve cached data" do
203
+ yielded_data = nil
204
+
205
+ EM.run_block {
206
+ @adaptor.room_data_for_all_rooms { |data| yielded_data = data }
207
+ }
208
+
209
+ logger_output.should =~ /DEBUG.*HTTP response was 304, serving room list data from cache/
210
+ yielded_data.should eql(@cache_response)
211
+ end
212
+ end
213
+
214
+ it "should update the room list data cache when room data is stale" do
215
+ stub_room_list_data_request
216
+ @adaptor.cache.expects(:set).with("room-list-data", {'data' => room_list_data_api_response['rooms'], 'etag' => 'new etag'})
217
+ EM.run_block { @adaptor.room_data_for_all_rooms }
218
+ end
45
219
  end
46
220
  end
47
221
  end
@@ -0,0 +1,192 @@
1
+ require "users_helper"
2
+
3
+ class UsersTestContainer < ModuleHarness
4
+ include EventMachine::Campfire::Users
5
+
6
+ def cache; @cache ||= EventMachine::Campfire::Cache.new; end
7
+ end
8
+
9
+ describe EventMachine::Campfire::Users do
10
+ before :each do
11
+ @adaptor = UsersTestContainer.new
12
+ end
13
+
14
+ describe "#is_me?" do
15
+ it "should return true if the passed user_id belongs to me" do
16
+ @adaptor.cache.stubs(:get).with('user-data-me').returns(valid_user_cache_data['me'])
17
+
18
+ EM.run_block {
19
+ @adaptor.is_me?(789).should eql(true)
20
+ }
21
+ end
22
+
23
+ it "should return false if the passed user_id doesn't belong to me" do
24
+ @adaptor.cache.stubs(:get).with('user-data-me').returns(valid_user_cache_data['me'])
25
+
26
+ EM.run_block {
27
+ @adaptor.is_me?(123).should eql(false)
28
+ }
29
+ end
30
+
31
+ it "should use cached data if available" do
32
+ @adaptor.cache.expects(:get).with('user-data-me').returns(valid_user_cache_data['me'])
33
+ @adaptor.expects(:fetch_user_data_for_self).never
34
+ EM.run_block { @adaptor.is_me?(789) }
35
+ end
36
+
37
+ it "should fetch data if no cached data is available" do
38
+ mock_logger(UsersTestContainer)
39
+ @adaptor.cache.expects(:get).with('user-data-me').returns(nil)
40
+ @adaptor.expects(:fetch_user_data_for_self).once.yields(valid_user_cache_data['me'])
41
+
42
+ EM.run_block {
43
+ @adaptor.is_me?(789)
44
+ }
45
+ logger_output.should =~ /DEBUG.*No user data cache exists for me, fetching it now/
46
+ end
47
+ end
48
+
49
+ describe "fetching user data" do
50
+ before :each do
51
+ mock_logger(UsersTestContainer)
52
+ end
53
+
54
+ it "should get correct data for a user_id" do
55
+ stub_user_data_request(123)
56
+ yielded_data = nil
57
+ EM.run_block {
58
+ @adaptor.fetch_user_data_for_user_id(123) do |user_data|
59
+ yielded_data = user_data
60
+ end
61
+ }
62
+
63
+ yielded_data["name"].should eql(valid_user_cache_data[123]["name"])
64
+
65
+ logger_output.should =~ %r{DEBUG.+Got the user data for 123}
66
+ end
67
+
68
+ it "should handle server errors" do
69
+ stub_user_data_request(123, 502)
70
+ EM.run_block {
71
+ @adaptor.fetch_user_data_for_user_id(123)
72
+ }
73
+
74
+ logger_output.should =~ %r{ERROR.+Couldn't fetch user data for user 123 with url .+, http response from API was 502}
75
+ end
76
+
77
+ it "should handle server timeouts" do
78
+ stub_timeout_user_data_request(123)
79
+ EM.run_block {
80
+ @adaptor.fetch_user_data_for_user_id(123)
81
+ }
82
+
83
+ logger_output.should =~ %r{ERROR.+Couldn't connect to .+ to fetch user data for user 123}
84
+ end
85
+
86
+ describe "when the cache is fresh" do
87
+ before :each do
88
+ @user_data = valid_user_cache_data[456]
89
+ end
90
+
91
+ it "should not update the user cache data" do
92
+ stub_user_data_request(123, 304)
93
+ @adaptor.cache.expects(:get).with("user-data-123").returns(@user_data)
94
+ @adaptor.cache.expects(:set).never
95
+
96
+ EM.run_block {
97
+ @adaptor.fetch_user_data_for_user_id(123)
98
+ }
99
+ end
100
+
101
+ it "should serve cached data" do
102
+ @adaptor.cache.expects(:get).with("user-data-456").returns(@user_data)
103
+ stub_user_data_request(456, 304)
104
+ yielded_data = nil
105
+
106
+ EM.run_block {
107
+ @adaptor.fetch_user_data_for_user_id(456) { |data| yielded_data = data }
108
+ }
109
+
110
+ logger_output.should =~ %r{DEBUG.+HTTP response was 304, serving user data for user 456 \(#{@user_data['name']}\) from cache}
111
+ yielded_data.should eql(@user_data)
112
+ end
113
+ end
114
+
115
+ it "should update the user data cache when user data is stale" do
116
+ user_data = valid_user_cache_data[123]
117
+ user_data_with_etag = user_data.merge({"etag" => etag_for_data(user_data)})
118
+ stub_user_data_request(123)
119
+ @adaptor.cache.expects(:get).with("user-data-123").returns(user_data)
120
+ @adaptor.cache.expects(:set).with("user-data-123", user_data_with_etag)
121
+
122
+ EM.run_block {
123
+ @adaptor.fetch_user_data_for_user_id(123)
124
+ }
125
+ end
126
+
127
+ describe "about self" do
128
+ it "should get correct data for self" do
129
+ stub = stub_self_data_request
130
+ yielded_data = nil
131
+ EM.run_block {
132
+ @adaptor.fetch_user_data_for_self {|data| yielded_data = data }
133
+ }
134
+ stub.should have_been_requested
135
+ yielded_data.should eql(valid_user_cache_data['me'])
136
+ # FIXME: Can't work out why these debug messages get dumped to the terminal when others don't
137
+ logger_output.should =~ /DEBUG.+Got the user data for self/
138
+ end
139
+
140
+ it "should handle server errors" do
141
+ stub_self_data_request(502)
142
+ EM.run_block { @adaptor.fetch_user_data_for_self }
143
+
144
+ logger_output.should =~ %r{ERROR.+Couldn't fetch user data for self with url .+, http response from API was 502}
145
+ end
146
+
147
+ it "should handle server timeouts" do
148
+ stub_timeout_self_data_request
149
+ EM.run_block { @adaptor.fetch_user_data_for_self }
150
+
151
+ logger_output.should =~ %r{ERROR.+Couldn't connect to .+ to fetch user data for self}
152
+ end
153
+
154
+ describe "when the cache is fresh" do
155
+ before :each do
156
+ @user_data = valid_user_cache_data['me']
157
+ end
158
+
159
+ it "should not update the user cache data" do
160
+ stub_self_data_request(304)
161
+ @adaptor.cache.expects(:get).with("user-data-me").returns(@user_data)
162
+ @adaptor.cache.expects(:set).never
163
+
164
+ EM.run_block { @adaptor.fetch_user_data_for_self }
165
+ end
166
+
167
+ it "should serve cached data" do
168
+ @adaptor.cache.expects(:get).with("user-data-me").returns(@user_data)
169
+ stub_self_data_request(304)
170
+ yielded_data = nil
171
+
172
+ EM.run_block {
173
+ @adaptor.fetch_user_data_for_self { |data| yielded_data = data }
174
+ }
175
+
176
+ logger_output.should =~ %r{DEBUG.+HTTP response was 304, serving user data for self from cache}
177
+ yielded_data.should eql(@user_data)
178
+ end
179
+ end
180
+
181
+ it "should update the user data cache when user data is stale" do
182
+ user_data = valid_user_cache_data['me']
183
+ user_data_with_etag = user_data.merge({"etag" => etag_for_data(user_data)})
184
+ stub_self_data_request
185
+ @adaptor.cache.expects(:get).with("user-data-me").returns(user_data)
186
+ @adaptor.cache.expects(:set).with("user-data-me", user_data_with_etag)
187
+
188
+ EM.run_block { @adaptor.fetch_user_data_for_self }
189
+ end
190
+ end
191
+ end
192
+ end