flamethrower 0.3.0 → 0.3.2

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,5 +1,5 @@
1
1
  module Flamethrower
2
- module Server
2
+ module Connection
3
3
  include Flamethrower::Irc::Commands
4
4
 
5
5
  attr_accessor :campfire_connection, :current_user, :dispatcher, :irc_channels
@@ -11,6 +11,7 @@ module Flamethrower
11
11
  end
12
12
 
13
13
  def after_connect
14
+ send_welcome
14
15
  send_motd
15
16
  populate_irc_channels
16
17
  populate_my_user
@@ -23,10 +24,10 @@ module Flamethrower
23
24
  end
24
25
 
25
26
  def receive_data(msg)
26
- messages = msg.split("\r\n")
27
- messages.each do |message|
28
- dispatcher.handle_message(Flamethrower::Irc::Message.new(message))
27
+ @data ||= ::BufferedTokenizer.new("\r\n")
28
+ @data.extract(msg).each do |message|
29
29
  ::FLAMETHROWER_LOGGER.debug "<< #{message}"
30
+ dispatcher.handle_message(Flamethrower::Irc::Message.new(message))
30
31
  end
31
32
  end
32
33
 
@@ -1,9 +1,9 @@
1
1
  module Flamethrower
2
2
  class Dispatcher
3
- attr_reader :server
3
+ attr_reader :connection
4
4
 
5
- def initialize(server)
6
- @server = server
5
+ def initialize(connection)
6
+ @connection = connection
7
7
  end
8
8
 
9
9
  def handle_message(message)
@@ -14,11 +14,11 @@ module Flamethrower
14
14
  private
15
15
 
16
16
  def find_channel_or_error(name, error=Flamethrower::Irc::Codes::ERR_BADCHANNELKEY)
17
- channel = server.irc_channels.detect {|channel| channel.name == name}
17
+ channel = connection.irc_channels.detect {|channel| channel.name == name}
18
18
  if channel && block_given?
19
19
  yield(channel)
20
20
  else
21
- server.send_message(server.error(error))
21
+ connection.send_message(connection.error(error))
22
22
  end
23
23
  end
24
24
 
@@ -33,44 +33,44 @@ module Flamethrower
33
33
 
34
34
  def handle_ping(message)
35
35
  hostname = message.parameters.first
36
- server.send_pong(hostname)
36
+ connection.send_pong(hostname)
37
37
  end
38
38
 
39
39
  def handle_user(message)
40
40
  username, hostname, servername, realname = message.parameters
41
- server.current_user.username = username unless server.current_user.username
42
- server.current_user.hostname = hostname unless server.current_user.hostname
43
- server.current_user.servername = servername unless server.current_user.servername
44
- server.current_user.realname = realname unless server.current_user.realname
45
- if server.current_user.nick_set? && server.current_user.user_set?
46
- server.after_connect
41
+ connection.current_user.username ||= username
42
+ connection.current_user.hostname ||= hostname
43
+ connection.current_user.servername ||= servername
44
+ connection.current_user.realname ||= realname
45
+ if connection.current_user.nick_set? && connection.current_user.user_set?
46
+ connection.after_connect
47
47
  end
48
48
  end
49
49
 
50
50
  def handle_nick(message)
51
51
  nickname = message.parameters.first
52
- server.current_user.nickname = nickname
53
- if server.current_user.nick_set? && server.current_user.user_set?
54
- server.after_connect
52
+ connection.current_user.nickname = nickname
53
+ if connection.current_user.nick_set? && connection.current_user.user_set?
54
+ connection.after_connect
55
55
  end
56
56
  end
57
57
 
58
58
  def handle_topic(message)
59
59
  find_channel_or_error(message.parameters.first) do |channel|
60
60
  channel.to_campfire.send_topic(message.parameters.last) if message.parameters.size > 1
61
- server.send_topic(channel)
61
+ connection.send_topic(channel)
62
62
  end
63
63
  end
64
64
 
65
65
  def handle_mode(message)
66
66
  first_param = message.parameters.first
67
67
  error = Flamethrower::Irc::Codes::ERR_UNKNOWNCOMMAND
68
- if first_param == server.current_user.nickname
69
- server.send_user_mode
68
+ if first_param == connection.current_user.nickname
69
+ connection.send_user_mode
70
70
  return
71
71
  else
72
72
  find_channel_or_error(first_param, error) do |channel|
73
- server.send_channel_mode(channel)
73
+ connection.send_channel_mode(channel)
74
74
  end
75
75
  end
76
76
  end
@@ -78,26 +78,27 @@ module Flamethrower
78
78
  def handle_join(message)
79
79
  find_channel_or_error(message.parameters.first) do |channel|
80
80
  room = channel.to_campfire
81
- channel.users << server.current_user
81
+ channel.users << connection.current_user
82
82
  room.join
83
83
  room.start
84
+ connection.send_join(connection.current_user, channel)
84
85
  end
85
86
  end
86
87
 
87
88
  def handle_away(message)
88
89
  away_message = message.parameters.first
89
- if away_message.empty?
90
- server.current_user.away_message = nil
91
- server.send_unaway
90
+ if !away_message || away_message.empty?
91
+ connection.current_user.away_message = nil
92
+ connection.send_unaway
92
93
  else
93
- server.current_user.away_message = away_message
94
- server.send_nowaway
94
+ connection.current_user.away_message = away_message
95
+ connection.send_nowaway
95
96
  end
96
97
  end
97
98
 
98
99
  def handle_who(message)
99
100
  find_channel_or_error(message.parameters.first) do |channel|
100
- server.send_who(channel)
101
+ connection.send_who(channel)
101
102
  end
102
103
  end
103
104
 
@@ -105,12 +106,12 @@ module Flamethrower
105
106
  find_channel_or_error(message.parameters.first) do |channel|
106
107
  room = channel.to_campfire
107
108
  room.stop
108
- server.send_part(server.current_user, channel)
109
+ connection.send_part(connection.current_user, channel)
109
110
  end
110
111
  end
111
112
 
112
113
  def handle_quit(message)
113
- server.irc_channels.each {|c| c.to_campfire.stop}
114
+ connection.irc_channels.each {|c| c.to_campfire.stop}
114
115
  end
115
116
  end
116
117
  end
@@ -1,6 +1,7 @@
1
1
  module Flamethrower
2
2
  module Irc
3
3
  module Codes
4
+ RPL_WLCM = '001'
4
5
  RPL_UMODEIS = 221
5
6
  RPL_UNAWAY = 305
6
7
  RPL_NOWAWAY = 306
@@ -3,10 +3,13 @@ module Flamethrower
3
3
  module Commands
4
4
  include Flamethrower::Irc::Codes
5
5
 
6
+ def send_welcome
7
+ send_message reply(RPL_WLCM, ":Welcome to Flamethrower")
8
+ end
9
+
6
10
  def send_motd
7
11
  send_messages do |messages|
8
12
  messages << reply(RPL_MOTDSTART, ":MOTD")
9
- messages << reply(RPL_MOTD, ":Welcome to Flamethrower")
10
13
  messages << reply(RPL_MOTD, ":Fetching channel list from campfire...")
11
14
  end
12
15
  end
@@ -66,6 +69,10 @@ module Flamethrower
66
69
  send_message reply(RPL_UMODEIS, @current_user.mode)
67
70
  end
68
71
 
72
+ def send_join(user, channel)
73
+ send_message ":#{user.to_s} JOIN #{channel.name}"
74
+ end
75
+
69
76
  def send_part(user, channel)
70
77
  send_message ":#{user.to_s} PART #{channel.name}"
71
78
  end
@@ -1,6 +1,6 @@
1
1
  module Flamethrower
2
2
  class EventConnection < EventMachine::Connection
3
- include Flamethrower::Server
3
+ include Flamethrower::Connection
4
4
 
5
5
  attr_accessor :server
6
6
 
@@ -22,13 +22,19 @@ module Flamethrower
22
22
  end
23
23
 
24
24
  class EventServer
25
- attr_reader :host, :port, :campfire_connection, :connections
25
+ attr_reader :host, :port, :ascii_conversion, :campfire_connection, :connections
26
+ ASCII_DEFAULTS = {
27
+ 'enabled' => true
28
+ }
26
29
 
27
- def initialize(host, port, domain, token)
28
- @host = host || "0.0.0.0"
29
- @port = port || 6667
30
- @domain = domain
31
- @token = token
30
+ def initialize(options = {})
31
+ @host = options['host'] || "0.0.0.0"
32
+ @port = options['port'] || 6667
33
+ @domain = options['domain']
34
+ @token = options['token']
35
+ @ascii_conversion = options['ascii_conversion'] ?
36
+ ASCII_DEFAULTS.merge(options['ascii_conversion']) :
37
+ ASCII_DEFAULTS
32
38
  @connections = []
33
39
  end
34
40
 
@@ -1,6 +1,6 @@
1
1
  module Flamethrower
2
- class MockServer
3
- include Flamethrower::Server
2
+ class MockConnection
3
+ include Flamethrower::Connection
4
4
 
5
5
  def send_data(msg)
6
6
  end
@@ -9,5 +9,9 @@ module Flamethrower
9
9
  Flamethrower::Campfire::Connection.new("mydomain", "mytoken", self)
10
10
  end
11
11
 
12
+ def server
13
+ Flamethrower::EventServer.new
14
+ end
15
+
12
16
  end
13
17
  end
@@ -0,0 +1 @@
1
+ {"messages":[{"type":"KickMessage","room_id":347348,"created_at":"2011/05/02 04:30:15 +0000","id":344873939,"body":null,"user_id":899091},{"type":"TimestampMessage","room_id":347348,"created_at":"2011/05/02 17:45:00 +0000","id":345107174,"body":null,"user_id":null},{"type":"EnterMessage","room_id":347348,"created_at":"2011/05/02 17:45:17 +0000","id":345107175,"body":null,"user_id":734581},{"type":"EnterMessage","room_id":347348,"created_at":"2011/05/02 17:45:58 +0000","id":345107527,"body":null,"user_id":899091},{"type":"TextMessage","room_id":347348,"created_at":"2011/05/02 17:46:33 +0000","id":345107811,"body":"http://www.berkeleytwpschools.com/bts/Potter/Classroom%20Web%20Pages/Library/Links%20of%20the%20Month/___zumuhead.html_files/sad-eyes-dog-puppy-clip-art-thumb3033696.jpg","user_id":899091},{"type":"TimestampMessage","room_id":347348,"created_at":"2011/05/02 18:00:00 +0000","id":345116388,"body":null,"user_id":null},{"type":"KickMessage","room_id":347348,"created_at":"2011/05/02 18:00:27 +0000","id":345116389,"body":null,"user_id":734581},{"type":"KickMessage","room_id":347348,"created_at":"2011/05/02 18:00:27 +0000","id":345116395,"body":null,"user_id":899091},{"type":"TimestampMessage","room_id":347348,"created_at":"2011/05/09 04:00:00 +0000","id":347880310,"body":null,"user_id":null},{"type":"EnterMessage","room_id":347348,"created_at":"2011/05/09 04:01:34 +0000","id":347880311,"body":null,"user_id":734581}]}
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2010/12/14 20:09:23 +0000","body":"http://example.com/kitties.jpg","id":289361911,"user_id":489198,"type":"TextMessage"}
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2011/01/26 16:34:46 +0000","body":"--- \n:author_username: jeresig\n:author_avatar_url: http://a1.twimg.com/profile_images/1181631474/john_normal.jpg\n:message: \"A hilarious video pops up after you unsubscribe from Groupon emails: http://j.mp/hpes49 Punish the developer!\"\n:id: 30293022537162752\n","id":304070140,"user_id":703609,"type":"TweetMessage"}
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.join(File.dirname(__FILE__), "../lib")
2
2
 
3
3
  require 'flamethrower'
4
- require 'server/mock_server'
4
+ require 'server/mock_connection'
5
5
  require 'webmock/rspec'
6
6
  require 'json'
7
7
  require 'time'
@@ -2,26 +2,26 @@ require File.join(File.dirname(__FILE__), "../../spec_helper")
2
2
 
3
3
  describe Flamethrower::Campfire::Connection do
4
4
  before do
5
- @server = Flamethrower::MockServer.new
6
- @connection = @server.campfire_connection
5
+ @connection = Flamethrower::MockConnection.new
6
+ @campfire_connection = @connection.campfire_connection
7
7
  end
8
8
 
9
9
  describe "#fetch_my_user" do
10
- it "retrieves my user and stores it on the connection" do
10
+ it "retrieves my user and stores it on the campfire_connection" do
11
11
  stub_request(:get, "https://mydomain.campfirenow.com/users/me.json").
12
12
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
13
13
  to_return(:status => 200, :body => json_fixture("user"))
14
- EM.run_block { @connection.fetch_my_user }
15
- @server.current_user.nickname.should == "blake"
14
+ EM.run_block { @campfire_connection.fetch_my_user }
15
+ @connection.current_user.nickname.should == "blake"
16
16
  end
17
17
 
18
18
  it "renames your current user to the new current user" do
19
- @server.current_user = Flamethrower::Irc::User.new(:nickname => "bob")
19
+ @connection.current_user = Flamethrower::Irc::User.new(:nickname => "bob")
20
20
  stub_request(:get, "https://mydomain.campfirenow.com/users/me.json").
21
21
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
22
22
  to_return(:status => 200, :body => json_fixture("user"))
23
- @server.should_receive(:send_message).with(":bob NICK blake")
24
- EM.run_block { @connection.fetch_my_user }
23
+ @connection.should_receive(:send_message).with(":bob NICK blake")
24
+ EM.run_block { @campfire_connection.fetch_my_user }
25
25
  end
26
26
  end
27
27
 
@@ -30,8 +30,8 @@ describe Flamethrower::Campfire::Connection do
30
30
  stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
31
31
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
32
32
  to_return(:status => 200, :body => json_fixture("rooms"))
33
- EM.run_block { @connection.fetch_rooms }
34
- room = @server.irc_channels.first.to_campfire
33
+ EM.run_block { @campfire_connection.fetch_rooms }
34
+ room = @connection.irc_channels.first.to_campfire
35
35
  room.number.should == 347348
36
36
  room.name.should == "Room 1"
37
37
  room.topic.should == "some topic"
@@ -41,7 +41,7 @@ describe Flamethrower::Campfire::Connection do
41
41
  stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
42
42
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
43
43
  to_return(:status => 200, :body => json_fixture("rooms"))
44
- EM.run_block { @connection.fetch_rooms }
44
+ EM.run_block { @campfire_connection.fetch_rooms }
45
45
  assert_requested(:get, "https://mydomain.campfirenow.com/rooms.json") {|req| req.headers['Authorization'].should == ["mytoken", "x"]}
46
46
  end
47
47
 
@@ -49,14 +49,17 @@ describe Flamethrower::Campfire::Connection do
49
49
  stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
50
50
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
51
51
  to_return(:status => 400)
52
- EM.run_block { @connection.fetch_rooms }
53
- @server.irc_channels.should == []
52
+ EM.run_block { @campfire_connection.fetch_rooms }
53
+ @connection.irc_channels.should == []
54
54
  end
55
55
 
56
- xit "sends a motd error message if unable to fetch room list" do
57
- @connection.should_receive(:campfire_get).and_raise(SocketError)
58
- @server.should_receive(:send_message).with(@server.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to fetch room list! Check your connection?"))
59
- @connection.rooms.should == []
56
+ it "sends a motd error message if unable to fetch room list" do
57
+ stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
58
+ with(:headers => {'Authorization'=>['mytoken', 'x']}).
59
+ to_timeout
60
+ @connection.should_receive(:send_message).with(@connection.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to make API call GET /rooms.json. Check your connection?"))
61
+ EM.run_block { @campfire_connection.fetch_rooms }
62
+ @connection.irc_channels.should == []
60
63
  end
61
64
  end
62
65
 
@@ -75,6 +75,72 @@ describe Flamethrower::Campfire::Message do
75
75
  end
76
76
  end
77
77
 
78
+ describe "#image_urls" do
79
+ it "returns a standalone image url" do
80
+ @message.body = "http://example.com/kitties.jpg"
81
+ @message.image_urls.should == ["http://example.com/kitties.jpg"]
82
+ end
83
+
84
+ it "supports jpeg" do
85
+ @message.body = "http://example.com/kitties.jpeg"
86
+ @message.image_urls.should == ["http://example.com/kitties.jpeg"]
87
+ end
88
+
89
+ it "supports gif" do
90
+ @message.body = "http://example.com/kitties.gif"
91
+ @message.image_urls.should == ["http://example.com/kitties.gif"]
92
+ end
93
+
94
+ it "supports png" do
95
+ @message.body = "http://example.com/kitties.png"
96
+ @message.image_urls.should == ["http://example.com/kitties.png"]
97
+ end
98
+
99
+ it "supports multiple images" do
100
+ @message.body = "http://example.com/kitties.png http://blah.com/duppy-pogs.png"
101
+ @message.image_urls.should == ["http://example.com/kitties.png", "http://blah.com/duppy-pogs.png"]
102
+ end
103
+
104
+ it "supports interleaved urls with messages" do
105
+ @message.body = "check this out: http://example.com/kitties.png"
106
+ @message.image_urls.should == ["http://example.com/kitties.png"]
107
+ end
108
+
109
+ it "supports upcased image extensions" do
110
+ @message.body = "check this out: http://example.com/kitties.PNG"
111
+ @message.image_urls.should == ["http://example.com/kitties.PNG"]
112
+ end
113
+
114
+ it "supports https image links" do
115
+ @message.body = "check this out: https://example.com/kitties.png"
116
+ @message.image_urls.should == ["https://example.com/kitties.png"]
117
+ end
118
+ end
119
+
120
+ describe "#has_images?" do
121
+ it "returns true if there are images present in the body" do
122
+ @message.body = "look ma! kitties! http://example.com/kitties.jpg"
123
+ @message.should have_images
124
+ end
125
+
126
+ it "returns false if there are no images present in the body" do
127
+ @message.body = "i love lamp, i really do"
128
+ @message.should_not have_images
129
+ end
130
+ end
131
+
132
+ describe "#needs_conversion?" do
133
+ it "returns true if the image hasn't been converted yet" do
134
+ @message.body = "look ma! kitties! http://example.com/kitties.jpg"
135
+ @message.should be_needs_image_conversion
136
+ end
137
+
138
+ it "returns false if the image has already been converted" do
139
+ @message.set_ascii_image("LOLCATS ASCII HERE!")
140
+ @message.should_not be_needs_image_conversion
141
+ end
142
+ end
143
+
78
144
  describe "#mark_delivered!" do
79
145
  it "sets the status to delivered" do
80
146
  @message.status.should_not == "delivered"
@@ -2,9 +2,9 @@ require File.join(File.dirname(__FILE__), "../../spec_helper")
2
2
 
3
3
  describe Flamethrower::Campfire::Room do
4
4
  before do
5
- @server = Flamethrower::MockServer.new
5
+ @connection = Flamethrower::MockConnection.new
6
6
  @room = Flamethrower::Campfire::Room.new("mydomain", "mytoken", "id" => 347348, "topic" => "some topic", "name" => "some name")
7
- @room.server = @server
7
+ @room.connection = @connection
8
8
  @user = Flamethrower::Campfire::User.new('name' => "bob", 'id' => 489198)
9
9
  @user2 = Flamethrower::Campfire::User.new('name' => "bill", 'id' => 123456)
10
10
  end
@@ -30,6 +30,38 @@ describe Flamethrower::Campfire::Room do
30
30
  end
31
31
  end
32
32
 
33
+ describe "#on_reconnect" do
34
+ it "writes to the log that it reconnected" do
35
+ message = "Reconnected to some name stream"
36
+ ::FLAMETHROWER_LOGGER.should_receive(:debug).with(message)
37
+
38
+ @room.on_reconnect
39
+ end
40
+ end
41
+
42
+ describe "#on_max_reconnects" do
43
+ before do
44
+ @room.instance_variable_set("@stream", mock(:stream))
45
+ end
46
+
47
+ it "writes to the log that it has failed to reconnect" do
48
+ @room.stub(:setup_reconnect)
49
+ message = "Failed to reconnect to some name, restarting room in 20 seconds"
50
+ ::FLAMETHROWER_LOGGER.should_receive(:debug).with(message)
51
+
52
+ @room.on_max_reconnects
53
+ end
54
+ end
55
+
56
+ describe "#on_error" do
57
+ it "writes to the log that there was an error" do
58
+ message = "There was an error connecting to some name stream"
59
+ ::FLAMETHROWER_LOGGER.should_receive(:debug).with(message)
60
+
61
+ @room.on_error
62
+ end
63
+ end
64
+
33
65
  describe "#send_topic!" do
34
66
  it "sets the topic when the campfire API returns 200" do
35
67
  stub_request(:put, "https://mydomain.campfirenow.com/room/347348.json").
@@ -47,6 +79,40 @@ describe Flamethrower::Campfire::Room do
47
79
  EM.run_block { @room.send_topic("some updated topic") }
48
80
  @room.topic.should == "some old topic"
49
81
  end
82
+
83
+ it "sends a motd error message if the send_topic call times out" do
84
+ stub_request(:put, "https://mydomain.campfirenow.com/room/347348.json").
85
+ with(:headers => {'Authorization'=>['mytoken', 'x'], 'Content-Type'=>'application/json'}).
86
+ to_timeout
87
+ @connection.should_receive(:send_message).with(@connection.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to make API call PUT /room/347348.json. Check your connection?"))
88
+ @room.instance_variable_set("@topic", "some old topic")
89
+ EM.run_block { @room.send_topic("some updated topic") }
90
+ @room.topic.should == "some old topic"
91
+ end
92
+ end
93
+
94
+ describe "#stop" do
95
+ it "should stop the stream" do
96
+ EventMachine.stub(:cancel_timer)
97
+ @room.instance_variable_set("@stream", mock(:stream, :stop => nil))
98
+ @room.stream.should_receive(:stop)
99
+ @room.stop
100
+ end
101
+
102
+ it "should cancel the timers" do
103
+ timer = mock(:timer)
104
+ @room.instance_variable_set("@polling_timer", timer)
105
+ @room.instance_variable_set("@periodic_timer", timer)
106
+ EventMachine.should_receive(:cancel_timer).with(timer).twice
107
+ @room.stop
108
+ end
109
+
110
+ it "should flip all the appropriate stop booleans" do
111
+ EventMachine.stub(:cancel_timer)
112
+ @room.stop
113
+ @room.should_not be_alive
114
+ @room.instance_variable_get("@room_info_set").should be_false
115
+ end
50
116
  end
51
117
 
52
118
  describe "#fetch_room_info" do
@@ -54,6 +120,7 @@ describe Flamethrower::Campfire::Room do
54
120
  stub_request(:get, "https://mydomain.campfirenow.com/room/347348.json").
55
121
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
56
122
  to_return(:status => 200, :body => json_fixture("room"))
123
+ @room.stub(:fetch_recent_messages)
57
124
  end
58
125
 
59
126
  it "retrieves a list of users and stores them as user objects" do
@@ -71,6 +138,31 @@ describe Flamethrower::Campfire::Room do
71
138
  EM.run_block { @room.fetch_room_info }
72
139
  assert_requested(:get, "https://mydomain.campfirenow.com/room/347348.json") {|req| req.headers['Authorization'].should == ["mytoken", "x"]}
73
140
  end
141
+
142
+ it "calls fetch_recent_messages if the room_info_set is false" do
143
+ @room.instance_variable_set("@room_info_sent", false)
144
+ @room.should_receive(:fetch_recent_messages)
145
+ EM.run_block { @room.fetch_room_info }
146
+ end
147
+
148
+ it "doesn't call fetch_recent_messages if the room_info_sent = true" do
149
+ @room.instance_variable_set("@room_info_sent", true)
150
+ @room.should_not_receive(:fetch_recent_messages)
151
+ EM.run_block { @room.fetch_room_info }
152
+ end
153
+ end
154
+
155
+ describe "#fetch_recent_messages" do
156
+ before do
157
+ stub_request(:get, "https://mydomain.campfirenow.com/room/347348/recent.json?limit=10").
158
+ with(:headers => {'Authorization'=>['mytoken', 'x']}).
159
+ to_return(:status => 200, :body => json_fixture("recent_messages"))
160
+ end
161
+
162
+ it "retrieves the most recent 10 messages and sends them to the inbound message queue" do
163
+ EM.run_block { @room.fetch_recent_messages }
164
+ @room.instance_variable_get("@users_to_fetch").size.should == 7
165
+ end
74
166
  end
75
167
 
76
168
  describe "#resolve renames" do
@@ -87,12 +179,48 @@ describe Flamethrower::Campfire::Room do
87
179
  bob2.name = "Bob Hope"
88
180
  new_users = [blake2, bob2, bill]
89
181
 
90
- @room.server.should_receive(:send_rename).with("blake", "Blake_Smith")
91
- @room.server.should_receive(:send_rename).with("bob", "Bob_Hope")
182
+ @room.connection.should_receive(:send_rename).with("blake", "Blake_Smith")
183
+ @room.connection.should_receive(:send_rename).with("bob", "Bob_Hope")
184
+ @room.resolve_renames(old_users, new_users)
185
+ end
186
+
187
+ it "doesn't rename if old_users has a user that new_users doesn't" do
188
+ blake = Flamethrower::Campfire::User.new('id' => 1, 'name' => 'blake')
189
+ bob = Flamethrower::Campfire::User.new('id' => 2, 'name' => 'bob')
190
+ bill = Flamethrower::Campfire::User.new('id' => 3, 'name' => 'bill')
191
+ old_users = [blake, bob, bill]
192
+ new_users = [blake, bob]
193
+
194
+ @room.connection.should_not_receive(:send_rename)
92
195
  @room.resolve_renames(old_users, new_users)
93
196
  end
94
197
  end
95
198
 
199
+ describe "#fetch_images" do
200
+ it "makes a call to the image ascii service to convert the image" do
201
+ stub_request(:get, "http://skeeter.blakesmith.me/?image_url=http://example.com/kitties.jpg&width=80").
202
+ to_return(:status => 200, :body => "LOLCAT ASCII ART HERE!")
203
+ @message = Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("streaming_image_message")))
204
+ @room.instance_variable_get("@images_to_fetch") << @message
205
+ EM.run_block { @room.fetch_images }
206
+ expected_body = "http://example.com/kitties.jpg\n"
207
+ expected_body << "LOLCAT ASCII ART HERE!"
208
+ @message.body.should == expected_body
209
+ end
210
+
211
+ context "when the image get call fails" do
212
+ it "marks the message as failed and puts it into the failed messages" do
213
+ stub_request(:get, "http://skeeter.blakesmith.me/?image_url=http://example.com/kitties.jpg&width=80").
214
+ to_return(:status => 400, :body => "An error has occured")
215
+ @message = Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("streaming_image_message")))
216
+ @message.user = mock('user')
217
+ @room.instance_variable_get("@images_to_fetch") << @message
218
+ EM.run_block { @room.fetch_images }
219
+ @room.instance_variable_get("@failed_messages").size.should == 1
220
+ end
221
+ end
222
+ end
223
+
96
224
  describe "#fetch_users" do
97
225
  it "makes a call to the campfire api to fetch user information" do
98
226
  stub_request(:get, "https://mydomain.campfirenow.com/users/734581.json").
@@ -104,9 +232,8 @@ describe Flamethrower::Campfire::Room do
104
232
  end
105
233
 
106
234
  it "fetches using the 'user_id' field if a streaming message" do
107
- stub_request(:get, "https://mytoken:x@mydomain.campfirenow.com/users/734581.json").to_return(:body => json_fixture("user"), :status => 200)
108
235
  @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
109
- @room.should_receive(:campfire_get).with("/users/734581.json").and_return(mock(:post, :callback => nil))
236
+ @room.should_receive(:campfire_get).with("/users/734581.json").and_return(mock(:get, :callback => nil))
110
237
  EM.run_block { @room.fetch_users }
111
238
  end
112
239
 
@@ -115,7 +242,9 @@ describe Flamethrower::Campfire::Room do
115
242
  stub_request(:get, "https://mydomain.campfirenow.com/users/734581.json").
116
243
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
117
244
  to_return(:status => 200, :body => json_fixture("user"))
118
- @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
245
+ json = JSON.parse(json_fixture('enter_message'))
246
+ json['direction'] = 'inbound'
247
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(json)
119
248
  EM.run_block { @room.fetch_users }
120
249
  message = @room.inbound_messages.pop.user.number.should == 734581
121
250
  end
@@ -130,6 +259,15 @@ describe Flamethrower::Campfire::Room do
130
259
  EM.run_block { @room.fetch_users }
131
260
  message = @room.inbound_messages.size.should == 0
132
261
  end
262
+
263
+ it "marks the message as failed and puts it into failed messages" do
264
+ stub_request(:get, "https://mydomain.campfirenow.com/users/734581.json").
265
+ with(:headers => {'Authorization'=>['mytoken', 'x']}).
266
+ to_return(:status => 400, :body => json_fixture("user"))
267
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
268
+ EM.run_block { @room.fetch_users }
269
+ message = @room.instance_variable_get("@failed_messages").size.should == 1
270
+ end
133
271
  end
134
272
  end
135
273
 
@@ -149,18 +287,37 @@ describe Flamethrower::Campfire::Room do
149
287
  EM.run_block { @room.join }
150
288
  @room.joined.should be_false
151
289
  end
290
+
291
+ it "sends a motd error message if the join call times out" do
292
+ stub_request(:post, "https://mydomain.campfirenow.com/room/347348/join.json").
293
+ with(:headers => {'Authorization'=>['mytoken', 'x'], 'Content-Type'=>'application/json'}).
294
+ to_timeout
295
+ @connection.should_receive(:send_message).with(@connection.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to make API call POST /room/347348/join.json. Check your connection?"))
296
+ EM.run_block { @room.join }
297
+ @room.joined.should be_false
298
+ end
152
299
  end
153
300
 
154
301
  describe "#connect" do
155
302
  it "initializes the twitter jsonstream with the right options" do
156
- Twitter::JSONStream.should_receive(:connect).with(:path => "/room/347348/live.json", :host => "streaming.campfirenow.com", :auth => "mytoken:x")
303
+ stream = mock(:stream, :on_reconnect => nil, :on_error => nil, :on_max_reconnects => nil)
304
+ Twitter::JSONStream.should_receive(:connect).with(:path => "/room/347348/live.json", :host => "streaming.campfirenow.com", :auth => "mytoken:x").and_return(stream)
305
+ @room.connect
306
+ end
307
+
308
+ it "sets up the stream callbacks" do
309
+ stream = mock(:stream, :on_reconnect => nil, :on_error => nil, :on_max_reconnects => nil)
310
+ Twitter::JSONStream.should_receive(:connect).with(:path => "/room/347348/live.json", :host => "streaming.campfirenow.com", :auth => "mytoken:x").and_return(stream)
311
+
312
+ @room.should_receive(:setup_stream_callbacks)
157
313
  @room.connect
158
314
  end
159
315
  end
160
316
 
161
317
  describe "#fetch_messages" do
162
318
  before do
163
- Twitter::JSONStream.stub(:connect).and_return("stream")
319
+ stream = mock(:stream, :on_reconnect => nil, :on_error => nil, :on_max_reconnects => nil)
320
+ Twitter::JSONStream.stub(:connect).and_return(stream)
164
321
  @item = json_fixture("streaming_message")
165
322
  @room.users << @user
166
323
  @room.connect
@@ -188,6 +345,11 @@ describe Flamethrower::Campfire::Room do
188
345
  @room.inbound_messages.pop.room.should == @room
189
346
  end
190
347
 
348
+ it "marks the message as inbound" do
349
+ @room.fetch_messages
350
+ @room.inbound_messages.pop.should be_inbound
351
+ end
352
+
191
353
  it "discards timestamp messages altogether" do
192
354
  item = json_fixture("timestamp_message")
193
355
  @room.stream.stub(:each_item).and_yield(item)
@@ -202,23 +364,46 @@ describe Flamethrower::Campfire::Room do
202
364
  @room.stream.stub(:each_item).and_yield(enter_message.to_json)
203
365
  @room.fetch_messages
204
366
  @room.instance_variable_get("@users_to_fetch").size.should == 1
367
+ @room.instance_variable_get("@inbound_messages").size.should == 0
368
+ end
369
+
370
+ it "puts messages that have an image url in the into the images_to_fetch queue" do
371
+ image_message = json_fixture("streaming_image_message")
372
+ @room.stream.stub(:each_item).and_yield(image_message)
373
+ @room.fetch_messages
374
+ @room.instance_variable_get("@inbound_messages").size.should == 0
375
+ @room.instance_variable_get("@images_to_fetch").size.should == 1
376
+ end
377
+
378
+ it "doesn't make the call to the image ascii service if the option is disabled" do
379
+ @room.connection.server.ascii_conversion['enabled'] = false
380
+ image_message = json_fixture("streaming_image_message")
381
+ @room.stream.stub(:each_item).and_yield(image_message)
382
+ @room.fetch_messages
383
+ @room.instance_variable_get("@users_to_fetch").size.should == 0
384
+ @room.instance_variable_get("@images_to_fetch").size.should == 0
385
+ @room.instance_variable_get("@inbound_messages").size.should == 1
205
386
  end
206
387
  end
207
388
 
208
389
  describe "#say" do
209
390
  it "queues a campfire message given a message body" do
210
- message = Flamethrower::Campfire::Message.new('body' => 'Hello there', 'user' => @user, 'room' => @room)
211
391
  @room.say('Hello there')
212
392
  popped_message = @room.outbound_messages.pop
213
393
  popped_message.body.should == 'Hello there'
214
394
  end
215
395
 
216
396
  it "takes an optional message type" do
217
- message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room)
218
397
  @room.say('Hello there', 'TextMessage')
219
398
  popped_message = @room.outbound_messages.pop
220
399
  popped_message.message_type.should == 'TextMessage'
221
400
  end
401
+
402
+ it "marks the message as an outbound message" do
403
+ @room.say('Hello there', 'TextMessage')
404
+ popped_message = @room.outbound_messages.pop
405
+ popped_message.should be_outbound
406
+ end
222
407
  end
223
408
 
224
409
  describe "#translate_nicknames" do
@@ -240,25 +425,47 @@ describe Flamethrower::Campfire::Room do
240
425
  end
241
426
 
242
427
  describe "#requeue_failed_messages" do
243
- it "queues a message whos retry_at is greater than now" do
428
+ it "queues an outbound message whos retry_at is greater than now" do
244
429
  Time.stub(:now).and_return(Time.parse("9:00AM"))
245
- message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room)
430
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'outbound')
246
431
  message.retry_at = Time.parse("9:00:01AM")
432
+ message.status = "failed"
247
433
  @room.failed_messages << message
248
434
  @room.requeue_failed_messages
249
435
  @room.outbound_messages.size.should == 1
250
436
  @room.failed_messages.size.should == 0
251
437
  end
252
438
 
439
+ it "queues an inbound message whos retry_at is greater than now" do
440
+ Time.stub(:now).and_return(Time.parse("9:00AM"))
441
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'inbound')
442
+ message.retry_at = Time.parse("9:00:01AM")
443
+ message.status = "failed"
444
+ @room.failed_messages << message
445
+ @room.requeue_failed_messages
446
+ @room.inbound_messages.size.should == 1
447
+ @room.failed_messages.size.should == 0
448
+ end
449
+
253
450
  it "doesn't queue a message whos retry_at is less than now" do
254
451
  Time.stub(:now).and_return(Time.parse("9:00AM"))
255
- message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room)
452
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'outbound')
256
453
  message.retry_at = Time.parse("8:59AM")
454
+ message.status = "failed"
257
455
  @room.failed_messages << message
258
456
  @room.requeue_failed_messages
259
457
  @room.outbound_messages.size.should == 0
260
458
  @room.failed_messages.size.should == 1
261
459
  end
460
+
461
+ it "marks the message as pending when it requeues" do
462
+ Time.stub(:now).and_return(Time.parse("9:00AM"))
463
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'inbound')
464
+ message.mark_failed!
465
+ @room.failed_messages << message
466
+ @room.requeue_failed_messages
467
+ message.should be_pending
468
+ end
262
469
  end
263
470
 
264
471
  describe "#post_messages" do