Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit a6a4ad6b704b0ef4eaceb4f66be9ac4f96f53553 @wjessop committed Jan 18, 2012
2 Gemfile
@@ -0,0 +1,2 @@
+source :rubygems
+gemspec
51 Gemfile.lock
@@ -0,0 +1,51 @@
+PATH
+ remote: .
+ specs:
+ em-campfire (0.0.1)
+ em-http-request (~> 1.0.0.beta.4)
+ eventmachine (~> 1.0.0.beta.4)
+ yajl-ruby (~> 0.8.3)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ addressable (2.2.6)
+ cookiejar (0.3.0)
+ crack (0.3.1)
+ diff-lcs (1.1.3)
+ em-http-request (1.0.1)
+ addressable (>= 2.2.3)
+ cookiejar
+ em-socksify
+ eventmachine (>= 1.0.0.beta.4)
+ http_parser.rb (>= 0.5.3)
+ em-socksify (0.1.0)
+ eventmachine
+ eventmachine (1.0.0.beta.4)
+ http_parser.rb (0.5.3)
+ metaclass (0.0.1)
+ mocha (0.10.0)
+ metaclass (~> 0.0.1)
+ rake (0.9.2.2)
+ rspec (2.6.0)
+ rspec-core (~> 2.6.0)
+ rspec-expectations (~> 2.6.0)
+ rspec-mocks (~> 2.6.0)
+ rspec-core (2.6.4)
+ rspec-expectations (2.6.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.6.0)
+ webmock (1.7.10)
+ addressable (~> 2.2, > 2.2.5)
+ crack (>= 0.1.7)
+ yajl-ruby (0.8.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ em-campfire!
+ mocha (~> 0.10.0)
+ rake (~> 0.9.2)
+ rspec (~> 2.6.0)
+ webmock (~> 1.7.6)
19 LICENSE.md
@@ -0,0 +1,19 @@
+Copyright (C) 2011 by Will Jessop
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
6 README.md
@@ -0,0 +1,6 @@
+
+This isn't ready for production use yet, so don't use it!
+
+## Example
+
+See examples/simple.rb
13 Rakefile
@@ -0,0 +1,13 @@
+require 'bundler/gem_tasks'
+
+begin
+ require 'rspec/core/rake_task'
+ RSpec::Core::RakeTask.new(:spec)
+rescue LoadError => e
+ task "spec" do
+ puts "RSpec not loaded - make sure it's installed and you're using bundle exec"
+ exit 1
+ end
+end
+
+task :default => :spec
27 em-campfire.gemspec
@@ -0,0 +1,27 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "em-campfire/version"
+
+Gem::Specification.new do |s|
+ s.name = "em-campfire"
+ s.version = EventMachine::Campfire::VERSION
+ s.authors = ["Will Jessop"]
+ s.email = ["will@willj.net"]
+ s.homepage = "https://github.com/wjessop/em-campfire"
+ s.summary = %q{Eventmachine campfire API lib}
+ s.description = %q{Eventmachine campfire API lib}
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ s.add_dependency('eventmachine', '~> 1.0.0.beta.4')
+ s.add_dependency('yajl-ruby', '~> 0.8.3')
+ s.add_dependency('em-http-request', '~> 1.0.0.beta.4')
+
+ s.add_development_dependency "rake", "~> 0.9.2"
+ s.add_development_dependency "rspec", "~> 2.6.0"
+ s.add_development_dependency "mocha", "~> 0.10.0"
+ s.add_development_dependency "webmock", "~> 1.7.6"
+end
19 examples/simple.rb
@@ -0,0 +1,19 @@
+$:.unshift File.join(File.dirname(__FILE__), '../lib')
+
+require 'em-campfire'
+
+EM.run {
+ connection = EM::Campfire.new(:subdomain => "foo", :api_key => "foo")
+ connection.join 293788 # Robot Army
+ connection.join 401839 # Monitoring
+
+ connection.on_message do |msg|
+ puts msg.inspect
+ end
+
+ # Give lib a chance to connect
+ EM::Timer.new(10) do
+ # Say something on a specific channel
+ connection.say "foofoofoo", "Robot Army"
+ end
+}
57 lib/em-campfire.rb
@@ -0,0 +1,57 @@
+require 'eventmachine'
+require 'em-http-request'
+require 'yajl'
+require "logger"
+
+require "em-campfire/version"
+require "em-campfire/connection"
+require "em-campfire/rooms"
+require "em-campfire/users"
+require "em-campfire/messages"
+
+module EventMachine
+ class Campfire
+ attr_accessor :logger, :verbose, :subdomain, :api_key
+
+ include Connection
+ include Rooms
+ include Users
+ include Messages
+
+ def initialize(options = {})
+ raise ArgumentError, "You must pass an API key" unless options[:api_key]
+ raise ArgumentError, "You must pass a subdomain" unless options[:subdomain]
+
+ options.each do |k,v|
+ s = "#{k}="
+ if respond_to?(s)
+ send(s, v)
+ else
+ logger.warn "em-campfire initialized with #{k.inspect} => #{v.inspect} but NO UNDERSTAND!"
+ end
+ end
+
+ # @rooms = {}
+# @user_cache = {}
+ @room_cache = {}
+
+ populate_room_list
+
+# # populate bot data separately, in case we are ignoring ourselves
+# fetch_data_for('me')
+ end
+
+ def logger
+ unless @logger
+ @logger = Logger.new(STDOUT)
+ @logger.level = (verbose ? Logger::DEBUG : Logger::INFO)
+ end
+ @logger
+ end
+
+ def verbose=(is_verbose)
+ @verbose = is_verbose
+ logger.level = Logger::DEBUG if is_verbose
+ end
+ end # Campfire
+end # EventMachine
28 lib/em-campfire/connection.rb
@@ -0,0 +1,28 @@
+module EventMachine
+ class Campfire
+ module Connection
+
+ attr_accessor :ignore_self
+
+ def on_message &blk
+ @on_message_block = blk
+ end
+
+ private
+
+ attr_accessor :on_message_block
+
+ def process_message(msg)
+ logger.debug "Received message #{msg.inspect}"
+ return false if ignore_self && is_me?(msg[:user_id])
+ if on_message_block
+ logger.debug "on_message callback exists, calling it #{msg.inspect}"
+ on_message_block.call(msg)
+ else
+ logger.debug "on_message callback does not exist"
+ end
+ end
+
+ end
+ end
+end
39 lib/em-campfire/messages.rb
@@ -0,0 +1,39 @@
+module EventMachine
+ class Campfire
+ module Messages
+ def say(message, room_id_or_name)
+ send_message(room_id_or_name, message, "Textmessage")
+ end
+
+ def paste(message, room_id_or_name)
+ send_message(room_id_or_name, message, "PasteMessage")
+ end
+
+ def play(sound, room_id_or_name)
+ send_message(room_id_or_name, sound, "SoundMessage")
+ end
+
+ private
+
+ # curl -vvv -H 'Content-Type: application/json' -d '{"message":{"body":"Yeeeeeaaaaaahh", "type":"Textmessage"}}' -u API_KEY:X https://something.campfirenow.com/room/2345678/speak.json
+ def send_message(room_id_or_name, payload, type)
+ if room_cache.size < 1
+ logger.error "Couldn't post message \"#{payload}\" to room #{room_id_or_name} as no rooms have been joined"
+ return
+ end
+
+ room_id = room_id(room_id_or_name)
+ url = "https://#{subdomain}.campfirenow.com/room/#{room_id}/speak.json"
+ http = EventMachine::HttpRequest.new(url).post :head => {'Content-Type' => 'application/json', 'authorization' => [api_key, 'X']}, :body => Yajl::Encoder.encode({:message => {:body => payload, :type => type}})
+ http.errback { logger.error "Couldn't connect to #{url} to post message \"#{payload}\" to room #{room_id}" }
+ http.callback {
+ if [200,201].include? http.response_header.status
+ logger.debug "Posted #{type} \"#{payload}\" to room #{room_id}"
+ else
+ logger.error "Couldn't post message \"#{payload}\" to room #{room_id} using url #{url}, http response from the API was #{http.response_header.status}"
+ end
+ }
+ end
+ end
+ end
+end
122 lib/em-campfire/rooms.rb
@@ -0,0 +1,122 @@
+module EventMachine
+ class Campfire
+ module Rooms
+
+# attr_accessor :rooms
+ attr_accessor :room_cache
+
+ def join(room, &blk)
+ id = room_id(room)
+ # logger.info "Joining room #{id}"
+ if id
+ url = "https://#{subdomain}.campfirenow.com/room/#{id}/join.json"
+ http = EventMachine::HttpRequest.new(url).post :head => {'Content-Type' => 'application/json', 'authorization' => [api_key, 'X']}
+ http.errback { logger.error "Error joining room: #{id}" }
+ http.callback {
+ if http.response_header.status == 200
+ logger.info "Joined room #{id} successfully"
+ # fetch_room_data(id)
+ stream(id)
+ else
+ logger.error "Error joining room: #{id}"
+ end
+ }
+ end
+ end
+
+ private
+
+ attr_accessor :populating_room_list
+
+ def stream(room_id)
+ json_parser = Yajl::Parser.new :symbolize_keys => true
+ json_parser.on_parse_complete = method(:process_message)
+
+ url = "https://streaming.campfirenow.com/room/#{room_id}/live.json"
+ # Timeout per https://github.com/igrigorik/em-http-request/wiki/Redirects-and-Timeouts
+ http = EventMachine::HttpRequest.new(url, :connect_timeout => 20, :inactivity_timeout => 0).get :head => {'authorization' => [api_key, 'X']}
+ http.errback { logger.error "Couldn't stream room #{room_id} at url #{url}" }
+ http.callback { logger.info "Disconnected from #{url}"; join(room_id) if rooms[room_id] }
+ http.stream {|chunk| json_parser << chunk }
+ end
+
+
+ def room_id(room_id_or_name)
+ if room_id_or_name.is_a? Integer
+ return room_id_or_name
+ else
+ return room_id_from_room_name(room_id_or_name)
+ end
+ end
+
+ def room_id_from_room_name(room_name)
+ logger.debug "Looking for room id for #{room_name}"
+
+ if room_cache.has_key? room_name
+ return room_cache[room_name]["id"]
+ else
+ logger.warn "Attempted to join #{room_name} but could not find an ID for it"
+ return false
+ end
+ end
+
+ # curl -vvv -H 'Content-Type: application/json' -u API_KEY:X https://something.campfirenow.com/rooms.json
+ def populate_room_list
+ url = "https://#{subdomain}.campfirenow.com/rooms.json"
+ http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
+ http.errback { logger.error "Couldn't connect to url #{url} to fetch room list"; puts http.inspect }
+ http.callback {
+ if http.response_header.status == 200
+ logger.debug "Fetched room list"
+ new_rooms = {}
+ Yajl::Parser.parse(http.response)['rooms'].each do |c|
+ new_rooms[c["name"]] = c
+ end
+ @room_cache = new_rooms # replace existing room list
+ else
+ logger.error "Couldn't fetch room list with url #{url}, http response from API was #{http.response_header.status}"
+ end
+ }
+ end
+
+ # def fetch_room_data(room_id)
+ # url = "https://#{subdomain}.campfirenow.com/room/#{room_id}.json"
+ # http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
+ # http.errback { logger.error "Couldn't connect to #{url} to fetch room data for room #{room_id}" }
+ # http.callback {
+ # if http.response_header.status == 200
+ # logger.debug "Fetched room data for #{room_id}"
+ # room = Yajl::Parser.parse(http.response)['room']
+ # room_cache[room["id"]] = room
+ #
+ # room['users'].each do |u|
+ # update_user_cache_with(u["id"], u)
+ # end
+ # else
+ # logger.error "Couldn't fetch room data for room #{room_id} with url #{url}, http response from API was #{http.response_header.status}"
+ # end
+ # }
+ # end
+
+ def fetch_room_data(room_id)
+ url = "https://#{subdomain}.campfirenow.com/room/#{room_id}.json"
+ http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
+ http.errback { logger.error "Couldn't connect to #{url} to fetch room data for room #{room_id}" }
+ http.callback {
+ if http.response_header.status == 200
+ logger.debug "Fetched room data for #{room_id}"
+ room = Yajl::Parser.parse(http.response)['room']
+ room_cache[room["id"]] = room
+
+ room['users'].each do |u|
+ update_user_cache_with(u["id"], u)
+ end
+ else
+ logger.error "Couldn't fetch room data for room #{room_id} with url #{url}, http response from API was #{http.response_header.status}"
+ end
+ }
+ end
+
+ end # Rooms
+ end # Campfire
+end # EventMachine
56 lib/em-campfire/users.rb
@@ -0,0 +1,56 @@
+module EventMachine
+ class Campfire
+ module Users
+
+# attr_accessor :user_cache
+
+ private
+
+ # Return the user_id if we haven't got the real name and
+ # kick off a user data fetch
+ def username_for(user_id)
+# if cached_user?(user_id)
+# user_cache[user_id]["name"]
+# else
+ fetch_data_for(user_id)
+# user_id.to_s
+# end
+ end
+
+# def is_me?(user_id)
+# if user_cache['me']
+# user_cache['me']['id'] == user_id
+# else
+# fetch_data_for('me')
+# false
+# end
+# end
+#
+# def cached_user? user_id
+# user_cache[user_id] != nil
+# end
+
+ def fetch_data_for(user_id)
+ return unless user_id
+ url = "https://#{subdomain}.campfirenow.com/users/#{user_id}.json"
+ http = EventMachine::HttpRequest.new(url).get(:head => {'authorization' => [api_key, 'X'], "Content-Type" => "application/json"})
+ http.callback do
+ if http.response_header.status == 200
+ logger.debug "Got the data for #{user_id}"
+ update_user_cache_with(user_id, Yajl::Parser.parse(http.response)['user'])
+ else
+ logger.error "Couldn't fetch user data for user #{user_id} with url #{url}, http response from API was #{http.response_header.status}"
+ end
+ end
+ http.errback do
+ logger.error "Couldn't connect to #{url} to fetch user data for user #{user_id}"
+ end
+ end
+
+# def update_user_cache_with(user_id, data)
+# logger.debug "Updated user cache for #{data['name']}"
+# user_cache[user_id] = data
+# end
+ end
+ end
+end
5 lib/em-campfire/version.rb
@@ -0,0 +1,5 @@
+module EventMachine
+ class Campfire
+ VERSION = "0.0.1"
+ end
+end
12 spec/lib/connection_spec.rb
@@ -0,0 +1,12 @@
+require "spec_helper"
+
+describe EventMachine::Campfire::Connection do
+
+ context "#on_message" do
+ before :each do
+ EM.run_block { @adaptor = a EM::Campfire }
+ end
+
+ it "run a block when it receives a message"
+ end
+end
253 spec/lib/em-campfire_spec.rb
@@ -0,0 +1,253 @@
+require "spec_helper"
+
+describe EventMachine::Campfire do
+
+ before :each do
+ stub_rooms_data_request
+ end
+
+ describe "#initialize" do
+ it "should work with valid params" do
+ EM.run_block { a(EM::Campfire).should be_a(EM::Campfire) }
+ end
+
+ it "should warn if given an option it doesn't know" do
+ mock_logger
+ EM.run_block { a(EM::Campfire, :fred => "estaire").should be_a(EM::Campfire) }
+ logger_output.should =~ /WARN.*em-campfire initialized with :fred => "estaire" but NO UNDERSTAND!/
+ end
+
+ it "should require essential parameters" do
+ lambda { EM::Campfire.new }.should raise_error(ArgumentError, "You must pass an API key")
+ lambda { EM::Campfire.new(:api_key => "foo") }.should raise_error(ArgumentError, "You must pass a subdomain")
+ end
+ end
+
+ describe "#verbose" do
+ it "should default to false" do
+ EM.run_block { a(EM::Campfire).verbose.should be_false }
+ end
+
+ it "should be overridable at initialization" do
+ EM.run_block { a(EM::Campfire, :verbose => true).verbose.should be_true }
+ end
+ end
+
+ describe "#logger" do
+ context "default logger" do
+ before { EM.run_block { @adaptor = a EM::Campfire } }
+
+ it { @adaptor.logger.should be_a(Logger) }
+ it { @adaptor.logger.level.should be == Logger::INFO }
+ end
+
+ context "default logger in verbose mode" do
+ before { EM.run_block { @adaptor = a EM::Campfire, :verbose => true } }
+
+ it { @adaptor.logger.level.should be == Logger::DEBUG }
+ end
+
+ context "overriding default" do
+ before do
+ @custom_logger = Logger.new("/dev/null")
+ EM.run_block { @adaptor = a EM::Campfire, :logger => @custom_logger }
+ end
+
+ it { @adaptor.logger.should be == @custom_logger }
+ end
+
+
+
+ #
+ # it "should handle HTTP errors fetching individual room data" do
+ # mock_logger
+ # bot = a Scamp
+ #
+ # EM.run_block {
+ # stub_request(:post, @message_post_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type' => 'application/json'}).
+ # to_return(:status => 502, :body => "", :headers => {'Content-Type'=>'text/html'})
+ # lambda {bot.send(:send_message, 123, "Hi", "Textmessage")}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't post message "Hi" to room 123 using url #{@message_post_url}, http response from the API was 502/
+ # end
+ #
+ # it "should handle network errors fetching individual room data" do
+ # mock_logger
+ # bot = a Scamp
+ #
+ # EM.run_block {
+ # stub_request(:post, @message_post_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type' => 'application/json'}).to_timeout
+ # lambda {bot.send(:send_message, 123, "Hi", "Textmessage")}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't connect to #{@message_post_url} to post message "Hi" to room 123/
+ # end
+ #
+
+
+
+ # context "user operations" do
+ # it "should fetch user data" do
+ # adaptor = a EM::Campfire
+ #
+ # EM.run_block {
+ # stub_request(:get, "https://#{valid_params[:subdomain]}.campfirenow.com/users/123.json").
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).
+ # to_return(:status => 200, :body => Yajl::Encoder.encode(:user => valid_user_cache_data[123]), :headers => {})
+ # adaptor.send(:username_for, 123)
+ # stub.should have_been_requested
+ # }
+ # end
+
+ # it "should handle HTTP errors fetching user data" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # url = "https://#{valid_params[:subdomain]}.campfirenow.com/users/123.json"
+ # EM.run_block {
+ # stub_request(:get, url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).
+ # to_return(:status => 502, :body => "", :headers => {'Content-Type'=>'text/html'})
+ # lambda {bot.username_for(123)}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't fetch user data for user 123 with url #{url}, http response from API was 502/
+ # end
+ #
+ # it "should handle network errors fetching user data" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # url = "https://#{valid_params[:subdomain]}.campfirenow.com/users/123.json"
+ # EM.run_block {
+ # stub_request(:get, url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).to_timeout
+ # lambda {bot.username_for(123)}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't connect to #{url} to fetch user data for user 123/
+ # end
+ end
+
+ context "room operations" do
+ before do
+ @room_list_url = "https://#{valid_params[:subdomain]}.campfirenow.com/rooms.json"
+ @me_list_url = "https://#{valid_params[:subdomain]}.campfirenow.com/users/me.json"
+ @room_url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/123.json"
+ @stream_url = "https://streaming.campfirenow.com/room/123/live.json"
+ end
+
+ # it "should fetch a room list" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # EM.run_block {
+ # stub_request(:get, @room_list_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).
+ # to_return(:status => 200, :body => Yajl::Encoder.encode(:rooms => valid_room_cache_data.values), :headers => {})
+ # bot.send(:populate_room_list)
+ # stub.should have_been_requested
+ # }
+ # logger_output.should =~ /DEBUG.*Fetched room list/
+ # end
+
+ # it "should invoke the post connection callback" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # invoked_cb = false
+ #
+ # EM.run_block {
+ # stub_request(:get, @room_list_url).
+ # with(:headers => {
+ # 'Authorization'=>[valid_params[:api_key], 'X'],
+ # 'Content-Type' => 'application/json'
+ # }).
+ # to_return(:status => 200, :body => Yajl::Encoder.encode(:rooms => valid_room_cache_data.values), :headers => {})
+ #
+ # stub_request(:get, @room_list_url).
+ # with(:headers => {
+ # 'Authorization'=>[valid_params[:api_key], 'X']
+ # }).
+ # to_return(:status => 200, :body => Yajl::Encoder.encode(:rooms => valid_room_cache_data.values), :headers => {})
+ #
+ # # Disable fetch_data_for, not important to this test.
+ # EM::Campfire.any_instance.expects(:fetch_data_for).returns(nil)
+ #
+ # bot.send(:connect!, [valid_room_cache_data.keys.first]) do
+ # invoked_cb = true
+ # end
+ # }
+ # invoked_cb.should be_true
+ # end
+ #
+ # it "should handle HTTP errors fetching the room list" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # EM.run_block {
+ # # stub_request(:get, url).
+ # # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).
+ # # to_return(:status => 502, :body => "", :headers => {'Content-Type'=>'text/html'})
+ # stub_request(:get, @room_list_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).
+ # to_return(:status => 502, :body => "", :headers => {'Content-Type'=>'text/html'})
+ # lambda {bot.send(:populate_room_list)}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't fetch room list with url #{@room_list_url}, http response from API was 502/
+ # end
+ #
+ # it "should handle network errors fetching the room list" do
+ # mock_logger
+ # bot = a EM::Campfire
+ # EM.run_block {
+ # stub_request(:get, @room_list_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).to_timeout
+ # lambda {bot.send(:populate_room_list)}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't connect to url #{@room_list_url} to fetch room list/
+ # end
+ #
+ # it "should fetch individual room data" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # EM.run_block {
+ # stub_request(:get, @room_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).
+ # to_return(:status => 200, :body => Yajl::Encoder.encode(:room => valid_room_cache_data[123]), :headers => {})
+ # bot.room_name_for(123)
+ # }
+ # logger_output.should =~ /DEBUG.*Fetched room data for 123/
+ # end
+ #
+ # it "should handle HTTP errors fetching individual room data" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # EM.run_block {
+ # stub_request(:get, @room_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).
+ # to_return(:status => 502, :body => "", :headers => {'Content-Type'=>'text/html'})
+ # lambda {bot.room_name_for(123)}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't fetch room data for room 123 with url #{@room_url}, http response from API was 502/
+ # end
+ #
+ # it "should handle network errors fetching individual room data" do
+ # mock_logger
+ # bot = a EM::Campfire
+ #
+ # EM.run_block {
+ # stub_request(:get, @room_url).
+ # with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).to_timeout
+ # lambda {bot.room_name_for(123)}.should_not raise_error
+ # }
+ # logger_output.should =~ /ERROR.*Couldn't connect to #{@room_url} to fetch room data for room 123/
+ # end
+ #
+ # it "should stream a room"
+ # it "should handle HTTP errors streaming a room"
+ # it "should handle network errors streaming a room"
+ end
+end
+
47 spec/lib/messages_spec.rb
@@ -0,0 +1,47 @@
+require "spec_helper"
+
+describe EventMachine::Campfire::Messages do
+
+ before :each do
+ stub_rooms_data_request
+ stub_join_room_request(123)
+ stub_stream_room_request(123)
+ EM.run_block { @adaptor = a(EM::Campfire) }
+ end
+
+ it "should say a message" do
+ mock_logger
+ stub = stub_message_post_request
+
+ EM.run_block {
+ @adaptor.join 123
+ @adaptor.say "Hi", 123
+ }
+ stub.should have_been_requested
+ logger_output.should =~ /DEBUG.*Posted Textmessage "Hi" to room 123/
+ end
+
+ it "should paste a message" do
+ mock_logger
+ stub = stub_message_post_request
+
+ EM.run_block {
+ @adaptor.join 123
+ @adaptor.paste "Hi", 123
+ }
+ stub.should have_been_requested
+ logger_output.should =~ /DEBUG.*Posted PasteMessage "Hi" to room 123/
+ end
+
+ it "should play a sound" do
+ mock_logger
+ stub = stub_message_post_request
+
+ EM.run_block {
+ @adaptor.join 123
+ @adaptor.play "nyan", 123
+ }
+ stub.should have_been_requested
+ logger_output.should =~ /DEBUG.*Posted SoundMessage "nyan" to room 123/
+ end
+end
47 spec/lib/rooms_spec.rb
@@ -0,0 +1,47 @@
+require "spec_helper"
+
+describe EventMachine::Campfire::Rooms do
+
+ before :each do
+ @message_post_url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/123/speak.json"
+ stub_rooms_data_request
+ EM.run_block { @adaptor = a(EM::Campfire) }
+ end
+
+ context "#join" do
+ before :each do
+ EM.run_block { @adaptor = a EM::Campfire }
+ end
+
+ it "should allow joining by id" do
+ mock_logger
+
+ join_stub = stub_join_room_request(123)
+ stream_stub = stub_stream_room_request(123)
+ EM.run_block { @adaptor.join(123) }
+ logger_output.should =~ /INFO.*Joined room 123 successfully/
+ join_stub.should have_been_requested
+ end
+
+ it "should allow joining by name" do
+ join_stub = stub_join_room_request(123)
+ stream_stub = stub_stream_room_request(123)
+ EM.run_block { @adaptor.join("foo") }
+ join_stub.should have_been_requested
+ end
+
+ it "should not be able to join an invalid room" do
+ mock_logger
+ stream_stub = stub_stream_room_request(9999999999999999)
+ url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/9999999999999999/join.json"
+ join_stub = stub_request(:post, url).
+ with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).
+ to_return(:status => 302, :body => "", :headers => {})
+
+ EM.run_block { @adaptor.join(9999999999999999) }
+ logger_output.should =~ /Error joining room: 9999999999999999/
+ join_stub.should have_been_requested
+ stream_stub.should_not have_been_requested
+ end
+ end
+end
78 spec/spec_helper.rb
@@ -0,0 +1,78 @@
+require File.expand_path("../lib/em-campfire", File.dirname(__FILE__))
+
+require 'mocha'
+require 'webmock/rspec'
+
+RSpec.configure do |config|
+ config.color_enabled = true
+ config.mock_framework = :mocha
+end
+
+def a klass, params={}
+ params ||= {}
+ params = valid_params.merge(params) if klass == EM::Campfire
+ klass.new(params)
+end
+
+# Urg
+def mock_logger
+ @logger_string = StringIO.new
+ @fake_logger = Logger.new(@logger_string)
+ EM::Campfire.any_instance.expects(:logger).at_least(1).returns(@fake_logger)
+end
+
+# Bleurgh
+def logger_output
+ str = @logger_string.dup
+ str.rewind
+ str.read
+end
+
+def valid_user_cache_data
+ {123 => {"name" => "foo"}, 456 => {"name" => "bar"}, 'me' => {"name" => "bot", "id" => 123}}
+end
+
+def valid_room_cache_data
+ {
+ 123 => {
+ "id" => 123,
+ "name" => "foo",
+ "users" => []
+ },
+ 456 => {
+ "id" => 456,
+ "name" => "bar",
+ "users" => []
+ }
+ }
+end
+
+def valid_params
+ {:api_key => "6124d98749365e3db2c9e5b27ca04db6", :subdomain => "oxygen"}
+end
+
+def stub_join_room_request(room)
+ url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/#{room}/join.json"
+ stub_request(:post, url).
+ with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type'=>'application/json'}).
+ to_return(:status => 200, :body => "", :headers => {})
+end
+
+def stub_rooms_data_request
+ stub_request(:get, "https://#{valid_params[:subdomain]}.campfirenow.com/rooms.json").
+ with(:headers => {'Authorization'=>['6124d98749365e3db2c9e5b27ca04db6', 'X']}).
+ to_return(:status => 200, :body => Yajl::Encoder.encode(:rooms => valid_room_cache_data.values), :headers => {})
+end
+
+def stub_message_post_request
+ message_post_url = "https://#{valid_params[:subdomain]}.campfirenow.com/room/123/speak.json"
+ stub_request(:post, message_post_url).
+ with(:headers => {'Authorization'=>[valid_params[:api_key], 'X'], 'Content-Type' => 'application/json'}).
+ to_return(:status => 201, :body => "", :headers => {})
+end
+
+def stub_stream_room_request(room)
+ stub_request(:get, "https://streaming.campfirenow.com/room/#{room}/live.json").
+ with(:headers => {'Authorization'=>[valid_params[:api_key], 'X']}).
+ to_return(:status => 200, :body => "", :headers => {})
+end

0 comments on commit a6a4ad6

Please sign in to comment.