em-campfire 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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