STart refactoring out the Sauce API code into its own module to make it more testable and extendable

This is a precursor to the bug fix for #2 but will also lay the ground work for
the more complex user-creation API calls required by #1
This commit is contained in:
R. Tyler Croy 2012-12-17 23:24:53 -08:00
parent b3fd19e0af
commit 500a941d84
8 changed files with 167 additions and 64 deletions

2
lib/sauce/heroku/api.rb Normal file
View File

@ -0,0 +1,2 @@
require 'sauce/heroku/api/sauce'

View File

@ -0,0 +1,44 @@
require 'httparty'
require 'json'
module Sauce
module Heroku
module API
class Sauce
attr_reader :config
def initialize(config)
@config = config
end
def create_scout_session(body)
if body.nil? || body.empty?
raise Errors::InvalidParametersError, 'body cannot be empty!'
end
unless config.configured?
raise Errors::SauceNotConfiguredError, 'we do not have a valid config loaded'
end
response = HTTParty.post(scout_url,
:body => body.to_json,
:basic_auth => {:username => config.username,
:password => config.access_key},
:headers => {'Content-Type' => 'application/json'})
return nil unless (response && response.code == 200)
response = JSON.parse(response.body)
# The response should contain the attribute `embed` which is the
# usable scout session URL
return response['embed']
end
def scout_url
return nil unless config.configured?
"https://saucelabs.com/rest/v1/users/#{config.username}/scout"
end
end
end
end
end

View File

@ -1,10 +1,9 @@
require 'heroku'
require 'heroku/command/base'
require 'httparty'
require 'json'
#require 'sauce'
require 'sauce/heroku/api'
require 'sauce/heroku/config'
require 'sauce/heroku/errors'
module Heroku
module Command
@ -13,6 +12,7 @@ module Heroku
super(*args)
@config = ::Sauce::Heroku::Config.new
@config.load!
@sauceapi = ::Sauce::Heroku::API::Sauce.new(@config)
end
def index
@ -115,26 +115,17 @@ access_key: #{apikey}
:'browser-version' => @browserversion,
:url => @url}
response = HTTParty.post(scout_url,
:body => body.to_json,
:basic_auth => {:username => @config.username,
:password => @config.access_key},
:headers => {'Content-Type' => 'application/json'})
return false unless (response && response.code == 200)
response = JSON.parse(response.body)
if response['embed']
launchy('Firing up Scout in your browser!', response['embed'])
url = nil
begin
url = @sauceapi.create_scout_session(body)
rescue ::Sauce::Heroku::Errors::SauceAuthenticationError
puts 'Auth error!'
end
return true
end
def scout_url
return nil unless @config.configured?
"https://saucelabs.com/rest/v1/users/#{@config.username}/scout"
unless url.nil?
launchy('Firing up Scout in your browser!', url)
end
end
end
end

View File

@ -0,0 +1,9 @@
module Sauce
module Heroku
module Errors
class SauceAuthenticationError < StandardError; end;
class InvalidParametersError < StandardError; end;
class SauceNotConfiguredError < StandardError; end;
end
end
end

83
spec/api_spec.rb Normal file
View File

@ -0,0 +1,83 @@
require 'spec_helper'
describe Sauce::Heroku::API::Sauce do
let(:config) { mock('Sauce::Heroku::Config Mock') }
# NOTE: The `config` variable is lazily evaluated and the shared context
# 'valid config' will overwrite the variable to make `api` contain a valid
# config
let(:api) { described_class.new(config) }
subject { api }
describe '#initialize' do
context 'with no parameters' do
end
context 'with a valid config' do
end
end
describe '#create_scout_session' do
context 'when passed an empty body' do
it 'should raise an error' do
expect {
api.create_scout_session({})
}.to raise_error(Sauce::Heroku::Errors::InvalidParametersError)
end
end
context 'when we are not configured' do
before :each do
config.stub(:configured? => false)
end
it 'should raise an error' do
expect {
api.create_scout_session({:foo => :bar})
}.to raise_error(Sauce::Heroku::Errors::SauceNotConfiguredError)
end
end
context 'when passed a valid body' do
include_context 'valid config'
let(:url) { 'http://fake/scout/url' }
let(:body) { {:url => 'http://saucelabs.com/'} }
before :each do
config.stub(:configured? => true)
api.should_receive(:scout_url).and_return(url)
end
it 'should POST to Sauce Labs properly' do
headers = {'Content-Type' => 'application/json'}
HTTParty.should_receive(:post).with(url,
hash_including(:headers => headers))
api.create_scout_session(body)
end
end
end
describe '#scout_url' do
subject { api.scout_url }
context 'when not configured' do
let(:config) { mock('Mock Config', :configured? => false) }
before :each do
api.stub(:config => config)
end
it { should be_nil }
end
context 'when configured' do
let(:config) do
c = mock('Mock Config', :username => 'rspec')
c.stub(:configured? => true)
c
end
before :each do
api.stub(:config => config)
end
it { should_not be_nil }
it { should_not be_empty }
end
end
end

View File

@ -5,52 +5,11 @@ describe Heroku::Command::Sauce do
describe '#scoutup!' do
context 'when configured' do
let(:config) do
c = mock('Sauce::Heroku::Config Mock')
c.stub(:configured? => true)
c.stub(:username => 'rspec')
c.stub(:access_key => 'rspec')
c
end
let(:scouturl) { 'http://fakeurl' }
before :each do
command.stub(:scout_url).and_return(scouturl)
command.instance_variable_set(:@config, config)
end
it 'should post to Sauce Labs' do
HTTParty.should_receive(:post).with(scouturl,
hash_including(:headers => {'Content-Type' => 'application/json'}))
it 'should create a scout session' do
api = command.instance_variable_get(:@sauceapi)
api.should_receive(:create_scout_session)
command.send(:scoutup!)
end
end
end
describe '#scout_url' do
subject { command.send(:scout_url) }
context 'when not configured' do
let(:config) { mock('Mock Config', :configured? => false) }
before :each do
command.instance_variable_set(:@config, config)
end
it { should be_nil }
end
context 'when configured' do
let(:config) do
c = mock('Mock Config', :username => 'rspec')
c.stub(:configured? => true)
c
end
before :each do
command.instance_variable_set(:@config, config)
end
it { should_not be_nil }
it { should_not be_empty }
end
end
end

View File

@ -3,3 +3,9 @@ require 'rspec'
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
require 'sauce/heroku/cli'
contexts = File.expand_path(File.dirname(__FILE__) + '/support/contexts')
Dir["#{contexts}/**.rb"].each do |f|
require f
end

View File

@ -0,0 +1,9 @@
require 'sauce/heroku/config'
shared_context 'valid config' do
let(:config) do
config = Sauce::Heroku::Config.new
config.config = {'username' => 'rspec', 'access_key' => 'rspec'}
config
end
end