Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add cf-runtime clients

- Add classes to create Mongo, Redis, AMQP, Carrot,
MySQL, and Postgresql connections to CF services

- Fix auto-reconfig log messages if 0 or more than
one services of a type are found

- Add cfruntime rdoc

- Move supported version constants to AutoReconfiguration module

- Remove complex passing of URL argument during AMQP auto-config

- Null path option during Redis auto-config

Change-Id: Iccab8a424dbb6e73b94feb6057859e17020005c5
  • Loading branch information...
commit af4661218c4f7d4c079c397fa8b7801515af53ea 1 parent 25777a8
Jennifer Hickey authored
Showing with 1,042 additions and 202 deletions.
  1. +1 −0  auto-reconfiguration/cf-autoconfig.gemspec
  2. +0 −1  auto-reconfiguration/lib/cfautoconfig.rb
  3. +9 −7 auto-reconfiguration/lib/cfautoconfig/document/mongodb.rb
  4. +3 −3 auto-reconfiguration/lib/cfautoconfig/document/mongodb_configurer.rb
  5. +19 −24 auto-reconfiguration/lib/cfautoconfig/keyvalue/redis.rb
  6. +2 −3 auto-reconfiguration/lib/cfautoconfig/keyvalue/redis_configurer.rb
  7. +25 −34 auto-reconfiguration/lib/cfautoconfig/messaging/amqp.rb
  8. +3 −3 auto-reconfiguration/lib/cfautoconfig/messaging/amqp_configurer.rb
  9. +19 −22 auto-reconfiguration/lib/cfautoconfig/messaging/carrot.rb
  10. +3 −3 auto-reconfiguration/lib/cfautoconfig/messaging/carrot_configurer.rb
  11. +6 −9 auto-reconfiguration/lib/cfautoconfig/relational/mysql.rb
  12. +34 −22 auto-reconfiguration/lib/cfautoconfig/relational/postgres.rb
  13. +6 −6 auto-reconfiguration/lib/cfautoconfig/relational/postgres_configurer.rb
  14. +35 −0 auto-reconfiguration/spec/unit/document/mongo_configurer_spec.rb
  15. +18 −1 auto-reconfiguration/spec/unit/keyvalue/redis_configurer_spec.rb
  16. +17 −7 auto-reconfiguration/spec/unit/messaging/amqp_configurer_spec.rb
  17. +16 −17 auto-reconfiguration/spec/unit/messaging/carrot_configurer_spec.rb
  18. +22 −0 auto-reconfiguration/spec/unit/relational/mysql_configurer_spec.rb
  19. +17 −8 auto-reconfiguration/spec/unit/relational/postgres_configurer_spec.rb
  20. +7 −0 cfruntime/cf-runtime.gemspec
  21. +8 −5 cfruntime/lib/cfruntime.rb
  22. +43 −0 cfruntime/lib/cfruntime/amqp.rb
  23. +44 −0 cfruntime/lib/cfruntime/carrot.rb
  24. +58 −0 cfruntime/lib/cfruntime/mongodb.rb
  25. +44 −0 cfruntime/lib/cfruntime/mysql.rb
  26. +50 −0 cfruntime/lib/cfruntime/postgres.rb
  27. +26 −10 cfruntime/lib/cfruntime/properties.rb
  28. +44 −0 cfruntime/lib/cfruntime/redis.rb
  29. +0 −2  cfruntime/lib/cfruntime/version.rb
  30. +82 −0 cfruntime/spec/amqp_spec.rb
  31. +66 −0 cfruntime/spec/carrot_spec.rb
  32. +78 −0 cfruntime/spec/mongodb_spec.rb
  33. +74 −0 cfruntime/spec/mysql_spec.rb
  34. +61 −0 cfruntime/spec/postgres_spec.rb
  35. +6 −8 cfruntime/spec/properties_spec.rb
  36. +73 −0 cfruntime/spec/redis_spec.rb
  37. +23 −7 cfruntime/spec/spec_helper.rb
View
1  auto-reconfiguration/cf-autoconfig.gemspec
@@ -13,6 +13,7 @@ spec = Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.extra_rdoc_files = ["LICENSE"]
+ s.rdoc_options = ["-N", "--tab-width=2", "--exclude='cf-autoconfig.gemspec|spec'"]
s.add_dependency "cf-runtime"
View
1  auto-reconfiguration/lib/cfautoconfig.rb
@@ -1,3 +1,2 @@
-# Copyright (c) 2009-2011 VMware, Inc.
require 'cfautoconfig/configurer'
require 'cfautoconfig/version'
View
16 auto-reconfiguration/lib/cfautoconfig/document/mongodb.rb
@@ -1,6 +1,7 @@
require 'cfruntime/properties'
module AutoReconfiguration
+ SUPPORTED_MONGO_VERSION = '1.2.0'
module Mongo
def self.included( base )
@@ -11,19 +12,20 @@ def self.included( base )
base.send( :alias_method, :original_shortcut, :[])
base.send( :alias_method, :[], :shortcut_with_cf )
end
-
+
def initialize_with_cf(host = nil, port = nil, opts = {})
- @service_props = CFRuntime::CloudApp.service_props('mongodb')
- if @service_props.nil?
- puts "No MongoDB service bound to app. Skipping auto-reconfiguration."
- @auto_config = false
- original_initialize host, port, opts
- else
+ service_names = CFRuntime::CloudApp.service_names_of_type('mongodb')
+ if service_names.length == 1
+ @service_props = CFRuntime::CloudApp.service_props('mongodb')
puts "Auto-reconfiguring MongoDB"
@auto_config = true
mongo_host = @service_props[:host]
mongo_port = @service_props[:port]
original_initialize mongo_host, mongo_port, opts
+ else
+ puts "Found #{service_names.length} mongo services. Skipping auto-reconfiguration."
+ @auto_config = false
+ original_initialize host, port, opts
end
end
View
6 auto-reconfiguration/lib/cfautoconfig/document/mongodb_configurer.rb
@@ -1,10 +1,9 @@
require 'cfautoconfig/configuration_helper'
-SUPPORTED_MONGO_VERSION = '1.2.0'
begin
#Require mongo here is mandatory for configurer to ensure class is loaded before applying OpenClass
require "mongo"
require File.join(File.dirname(__FILE__), 'mongodb')
- if Gem::Version.new(Mongo::VERSION) >= Gem::Version.new(SUPPORTED_MONGO_VERSION)
+ if Gem::Version.new(Mongo::VERSION) >= Gem::Version.new(AutoReconfiguration::SUPPORTED_MONGO_VERSION)
if AutoReconfiguration::ConfigurationHelper.disabled? :mongodb
puts "MongoDB auto-reconfiguration disabled."
module Mongo
@@ -26,6 +25,7 @@ class Connection
puts "MongoDB AutoReconfiguration already included."
else
module Mongo
+ #Introduce around alias into Mongo Connection class
class Connection
include AutoReconfiguration::Mongo
end
@@ -33,7 +33,7 @@ class Connection
end
else
puts "Auto-reconfiguration not supported for this Redis version. " +
- "Found: #{Mongo::VERSION}. Required: #{SUPPORTED_MONGO_VERSION} or higher."
+ "Found: #{Mongo::VERSION}. Required: #{AutoReconfiguration::SUPPORTED_MONGO_VERSION} or higher."
end
rescue LoadError
puts "No MongoDB Library Found. Skipping auto-reconfiguration."
View
43 auto-reconfiguration/lib/cfautoconfig/keyvalue/redis.rb
@@ -1,29 +1,24 @@
require 'cfruntime/properties'
+require 'cfruntime/redis'
module AutoReconfiguration
- module Redis
- def self.included( base )
- base.send( :alias_method, :original_initialize, :initialize)
- base.send( :alias_method, :initialize, :initialize_with_cf )
- end
+ SUPPORTED_REDIS_VERSION = '2.0'
+ module Redis
+ def self.included( base )
+ base.send( :alias_method, :original_initialize, :initialize)
+ base.send( :alias_method, :initialize, :initialize_with_cf )
+ end
- def initialize_with_cf(options = {})
- service_props = CFRuntime::CloudApp.service_props('redis')
- if(service_props.nil?)
- puts "No Redis service bound to app. Skipping auto-reconfiguration."
- original_initialize options
- else
- puts "Auto-reconfiguring Redis."
- cfoptions = options
- if !cfoptions[:path].nil?
- #Host and port are ignored if a path is specified
- cfoptions[:path] = "#{service_props[:host]}:#{service_props[:port]}"
- end
- cfoptions[:host] = service_props[:host]
- cfoptions[:port] = service_props[:port]
- cfoptions[:password] = service_props[:password]
- original_initialize cfoptions
- end
- end
- end
+ def initialize_with_cf(options = {})
+ service_names = CFRuntime::CloudApp.service_names_of_type('redis')
+ if service_names.length == 1
+ puts "Auto-reconfiguring Redis."
+ cfoptions = CFRuntime::RedisClient.options_for_svc(service_names[0],options)
+ original_initialize cfoptions
+ else
+ puts "Found #{service_names.length} redis services. Skipping auto-reconfiguration."
+ original_initialize options
+ end
+ end
+ end
end
View
5 auto-reconfiguration/lib/cfautoconfig/keyvalue/redis_configurer.rb
@@ -1,9 +1,8 @@
require 'cfautoconfig/configuration_helper'
-SUPPORTED_REDIS_VERSION = '2.0'
begin
require 'redis'
require File.join(File.dirname(__FILE__), 'redis')
- if Gem::Version.new(Redis::VERSION) >= Gem::Version.new(SUPPORTED_REDIS_VERSION)
+ if Gem::Version.new(Redis::VERSION) >= Gem::Version.new(AutoReconfiguration::SUPPORTED_REDIS_VERSION)
if AutoReconfiguration::ConfigurationHelper.disabled? :redis
puts "Redis auto-reconfiguration disabled."
class Redis
@@ -26,7 +25,7 @@ class Redis
end
else
puts "Auto-reconfiguration not supported for this Redis version. " +
- "Found: #{Redis::VERSION}. Required: #{SUPPORTED_REDIS_VERSION} or higher."
+ "Found: #{Redis::VERSION}. Required: #{AutoReconfiguration::SUPPORTED_REDIS_VERSION} or higher."
end
rescue LoadError
puts "No Redis Library Found. Skipping auto-reconfiguration."
View
59 auto-reconfiguration/lib/cfautoconfig/messaging/amqp.rb
@@ -1,39 +1,30 @@
require 'cfruntime/properties'
+require 'cfruntime/amqp'
module AutoReconfiguration
- module AMQP
- def self.included( base )
- base.send( :alias_method, :original_connect, :connect)
- base.send( :alias_method, :connect, :connect_with_cf )
- end
+ SUPPORTED_AMQP_VERSION = '0.8'
+ module AMQP
+ def self.included( base )
+ base.send( :alias_method, :original_connect, :connect)
+ base.send( :alias_method, :connect, :connect_with_cf )
+ end
- def connect_with_cf(connection_options_or_string = {}, other_options = {}, &block)
- service_props = CFRuntime::CloudApp.service_props('rabbitmq')
- if(service_props.nil?)
- puts "No RabbitMQ service bound to app. Skipping auto-reconfiguration."
- original_connect(connection_options_or_string, other_options, &block)
- else
- puts "Auto-reconfiguring AMQP."
- url_provided = false
- case connection_options_or_string
- when String then
- url_provided = true
- cfoptions = {}
- else
- cfoptions = connection_options_or_string
- end
- if service_props[:url] && url_provided
- #If user passed in a URL and we have a URL for service, use it
- original_connect(service_props[:url], other_options, &block)
- else
- cfoptions[:host] = service_props[:host]
- cfoptions[:port] = service_props[:port]
- cfoptions[:user] = service_props[:username]
- cfoptions[:pass] = service_props[:password]
- cfoptions[:vhost] = service_props[:vhost]
- original_connect(cfoptions, other_options, &block)
- end
- end
- end
- end
+ def connect_with_cf(connection_options_or_string = {}, other_options = {}, &block)
+ service_names = CFRuntime::CloudApp.service_names_of_type('rabbitmq')
+ if service_names.length == 1
+ puts "Auto-reconfiguring AMQP."
+ case connection_options_or_string
+ when String then
+ cfoptions = {}
+ else
+ cfoptions = connection_options_or_string
+ end
+ original_connect(CFRuntime::AMQPClient.options_for_svc(service_names[0],cfoptions),
+ other_options, &block)
+ else
+ puts "Found #{service_names.length} rabbitmq services. Skipping auto-reconfiguration."
+ original_connect(connection_options_or_string, other_options, &block)
+ end
+ end
+ end
end
View
6 auto-reconfiguration/lib/cfautoconfig/messaging/amqp_configurer.rb
@@ -1,10 +1,9 @@
require 'cfautoconfig/configuration_helper'
-SUPPORTED_AMQP_VERSION = '0.8'
begin
#Require amqp here is mandatory for configurer to ensure class is loaded before applying OpenClass
require "amqp"
require File.join(File.dirname(__FILE__), 'amqp')
- if Gem::Version.new(AMQP::VERSION) >= Gem::Version.new(SUPPORTED_AMQP_VERSION)
+ if Gem::Version.new(AMQP::VERSION) >= Gem::Version.new(AutoReconfiguration::SUPPORTED_AMQP_VERSION)
if AutoReconfiguration::ConfigurationHelper.disabled? :rabbitmq
puts "RabbitMQ auto-reconfiguration disabled."
class << AMQP
@@ -19,13 +18,14 @@ class << AMQP
elsif AMQP.public_methods.index :connect_with_cf
puts "AMQP AutoReconfiguration already included."
else
+ #Introduce around alias into AMQP class
class << AMQP
include AutoReconfiguration::AMQP
end
end
else
puts "Auto-reconfiguration not supported for this AMQP version. " +
- "Found: #{AMQP::VERSION}. Required: #{SUPPORTED_AMQP_VERSION} or higher."
+ "Found: #{AMQP::VERSION}. Required: #{AutoReconfiguration::SUPPORTED_AMQP_VERSION} or higher."
end
rescue LoadError
puts "No AMQP Library Found. Skipping auto-reconfiguration."
View
41 auto-reconfiguration/lib/cfautoconfig/messaging/carrot.rb
@@ -1,27 +1,24 @@
require 'cfruntime/properties'
+require 'cfruntime/carrot'
module AutoReconfiguration
- module Carrot
- def self.included( base )
- base.send( :alias_method, :original_initialize, :initialize)
- base.send( :alias_method, :initialize, :initialize_with_cf )
- end
+ SUPPORTED_CARROT_VERSION = '1.0'
+ module Carrot
+ def self.included( base )
+ base.send( :alias_method, :original_initialize, :initialize)
+ base.send( :alias_method, :initialize, :initialize_with_cf )
+ end
- def initialize_with_cf(opts = {})
- service_props = CFRuntime::CloudApp.service_props('rabbitmq')
- if(service_props.nil?)
- puts "No RabbitMQ service bound to app. Skipping auto-reconfiguration."
- original_initialize opts
- else
- puts "Auto-reconfiguring Carrot."
- cfoptions = opts
- cfoptions[:host] = service_props[:host]
- cfoptions[:port] = service_props[:port]
- cfoptions[:user] = service_props[:username]
- cfoptions[:pass] = service_props[:password]
- cfoptions[:vhost] = service_props[:vhost]
- original_initialize opts
- end
- end
- end
+ def initialize_with_cf(opts = {})
+ service_names = CFRuntime::CloudApp.service_names_of_type('rabbitmq')
+ if service_names.length == 1
+ puts "Auto-reconfiguring Carrot."
+ cfopts = CFRuntime::CarrotClient.options_for_svc(service_names[0],opts)
+ original_initialize cfopts
+ else
+ puts "Found #{service_names.length} rabbitmq services. Skipping auto-reconfiguration."
+ original_initialize opts
+ end
+ end
+ end
end
View
6 auto-reconfiguration/lib/cfautoconfig/messaging/carrot_configurer.rb
@@ -1,11 +1,10 @@
require 'cfautoconfig/configuration_helper'
-SUPPORTED_CARROT_VERSION = '1.0'
begin
#Require carrot here is mandatory for configurer to ensure class is loaded before applying OpenClass
require "carrot"
require File.join(File.dirname(__FILE__), 'carrot')
carrot_version = Gem.loaded_specs['carrot'].version
- if carrot_version >= Gem::Version.new(SUPPORTED_CARROT_VERSION)
+ if carrot_version >= Gem::Version.new(AutoReconfiguration::SUPPORTED_CARROT_VERSION)
if AutoReconfiguration::ConfigurationHelper.disabled? :rabbitmq
puts "RabbitMQ auto-reconfiguration disabled."
class Carrot
@@ -20,13 +19,14 @@ class Carrot
elsif Carrot.public_instance_methods.index :initialize_with_cf
puts "Carrot AutoReconfiguration already included."
else
+ #Introduce around alias into Carrot class
class Carrot
include AutoReconfiguration::Carrot
end
end
else
puts "Auto-reconfiguration not supported for this Carrot version. " +
- "Found: #{carrot_version}. Required: #{SUPPORTED_CARROT_VERSION} or higher."
+ "Found: #{carrot_version}. Required: #{AutoReconfiguration::SUPPORTED_CARROT_VERSION} or higher."
end
rescue LoadError
puts "No Carrot Library Found. Skipping auto-reconfiguration."
View
15 auto-reconfiguration/lib/cfautoconfig/relational/mysql.rb
@@ -1,4 +1,5 @@
require 'cfruntime/properties'
+require 'cfruntime/mysql'
module AutoReconfiguration
SUPPORTED_MYSQL2_VERSION = '0.2.7'
@@ -10,17 +11,13 @@ def self.included( base )
end
def initialize_with_cf(opts = {})
- @service_props = CFRuntime::CloudApp.service_props('mysql')
- if @service_props.nil?
- @auto_config = false
- else
+ service_names = CFRuntime::CloudApp.service_names_of_type('mysql')
+ if service_names.length == 1
puts "Auto-reconfiguring MySQL"
- @auto_config = true
- end
- if @auto_config
- original_initialize @service_props
+ original_initialize(CFRuntime::Mysql2Client.options_for_svc(service_names[0],opts))
else
- original_initialize opts
+ puts "Found #{service_names.length} mysql services. Skipping auto-reconfiguration."
+ original_initialize opts
end
end
end
View
56 auto-reconfiguration/lib/cfautoconfig/relational/postgres.rb
@@ -1,5 +1,6 @@
require 'cfruntime/properties'
module AutoReconfiguration
+ SUPPORTED_PG_VERSION = '0.11.0'
module Postgres
def self.included( base )
base.send( :alias_method, :original_open, :open)
@@ -10,19 +11,37 @@ def self.included( base )
base.send( :alias_method, :connect_start, :connect_start_with_cf )
end
- def open_with_cf(*args,&block)
- connection_string = parse_cf_connection_args(*args,&block)
- original_open(connection_string)
+ def open_with_cf(*args)
+ connection_string = parse_cf_connection_args(*args)
+ if connection_string
+ #Send the new connection string to passed block for verification.
+ yield connection_string if block_given?
+ original_open(connection_string)
+ else
+ original_open(*args)
+ end
end
- def connect_with_cf(*args,&block)
- connection_string = parse_cf_connection_args(*args,&block)
- original_connect(connection_string)
+ def connect_with_cf(*args)
+ connection_string = parse_cf_connection_args(*args)
+ if connection_string
+ #Send the new connection string to passed block for verification.
+ yield connection_string if block_given?
+ original_connect(connection_string)
+ else
+ original_connect(*args)
+ end
end
- def connect_start_with_cf(*args,&block)
- connection_string = parse_cf_connection_args(*args,&block)
- original_connect_start(connection_string)
+ def connect_start_with_cf(*args)
+ connection_string = parse_cf_connection_args(*args)
+ if connection_string
+ #Send the new connection string to passed block for verification.
+ yield connection_string if block_given?
+ original_connect_start(connection_string)
+ else
+ original_connect_start(*args)
+ end
end
private
@@ -33,13 +52,14 @@ def connect_start_with_cf(*args,&block)
# (connection_hash)
# (connection_string)
# (host, port, options, tty, dbname, user, password)
- def parse_cf_connection_args(*args,&block)
- service_props = CFRuntime::CloudApp.service_props('postgresql')
- if(service_props.nil?)
- puts "No PostgreSQL service bound to app. Skipping auto-reconfiguration."
- return args
+ def parse_cf_connection_args(*args)
+ service_names = CFRuntime::CloudApp.service_names_of_type('postgresql')
+ if service_names.length != 1
+ puts "Found #{service_names.length} postgresql services. Skipping auto-reconfiguration."
+ return
end
puts "Auto-reconfiguring PostgreSQL."
+ service_props = CFRuntime::CloudApp.service_props('postgresql')
#Use the parse_connect_args method from pg to process all possible formats into a single connection string
conn_string= parse_connect_args(*args)
sub_or_append_cf_arg(conn_string,'dbname',service_props[:database])
@@ -47,14 +67,6 @@ def parse_cf_connection_args(*args,&block)
sub_or_append_cf_arg(conn_string,'port',service_props[:port])
sub_or_append_cf_arg(conn_string,'user',service_props[:username])
sub_or_append_cf_arg(conn_string,'password',service_props[:password])
-
- #Send the new connection string to passed block for verification.
- #Block should only be passed by tests. User code never sends a block.
- #This is done b/c Postgres conn timeout Exception msg doesn't tell you
- #what server it is trying to connect to
- if(block)
- block.yield(conn_string)
- end
conn_string
end
View
12 auto-reconfiguration/lib/cfautoconfig/relational/postgres_configurer.rb
@@ -1,16 +1,15 @@
require 'cfautoconfig/configuration_helper'
-SUPPORTED_PG_VERSION = '0.11.0'
begin
#Require pg here is mandatory for configurer to ensure class is loaded before applying OpenClass
require "pg"
require File.join(File.dirname(__FILE__), 'postgres')
- if Gem::Version.new(PGconn::VERSION) >= Gem::Version.new(SUPPORTED_PG_VERSION)
+ if Gem::Version.new(PGconn::VERSION) >= Gem::Version.new(AutoReconfiguration::SUPPORTED_PG_VERSION)
if AutoReconfiguration::ConfigurationHelper.disabled? :postgresql
puts "PostgreSQL auto-reconfiguration disabled."
- #Remove introduced aliases and methods.
- #This is mostly for testing, as we don't expect this script
- #to run twice during a single app startup
class << PGconn
+ #Remove introduced aliases and methods.
+ #This is mostly for testing, as we don't expect this script
+ #to run twice during a single app startup
if method_defined?(:open_with_cf)
undef_method :open_with_cf
alias :open :original_open
@@ -27,13 +26,14 @@ class << PGconn
elsif PGconn.public_methods.index :open_with_cf
puts "PostgreSQL AutoReconfiguration already included."
else
+ #Introduce around alias into PGconn class
class << PGconn
include AutoReconfiguration::Postgres
end
end
else
puts "Auto-reconfiguration not supported for this PG version. " +
- "Found: #{PGconn::VERSION}. Required: #{SUPPORTED_PG_VERSION} or higher."
+ "Found: #{PGconn::VERSION}. Required: #{AutoReconfiguration::SUPPORTED_PG_VERSION} or higher."
end
rescue LoadError
puts "No PostgreSQL Library Found. Skipping auto-reconfiguration."
View
35 auto-reconfiguration/spec/unit/document/mongo_configurer_spec.rb
@@ -98,6 +98,17 @@ def authenticate(username, password, save_auth=true)
mongo.host_to_try.should == mongo.send(:format_pair, '127.0.0.1', 27017)
end
+ it 'does not auto-configure Mongo if multiple mongo services found' do
+ ENV['VCAP_SERVICES'] = '{"mongodb-1.8":[{"name": "mongo-1","label": "mongodb-1.8",' +
+ '"plan": "free", "credentials": {"hostname": "10.20.30.40","port": 12345, ' +
+ '"username": "8d93ae0a", "password": "7cf3c0e3","name": "m1", "db": "db"}},' +
+ '{"name": "mongo-2","label": "mongodb-1.8",' +
+ '"plan": "free", "credentials": {"hostname": "10.20.30.40","port": 12345, ' +
+ '"username": "8d93ae0a", "password": "7cf3c0e3","name": "m1", "db": "db"}}]}'
+ mongo = Mongo::Connection.new('127.0.0.1', 27017, {:connect => false})
+ mongo.host_to_try.should == mongo.send(:format_pair, '127.0.0.1', 27017)
+ end
+
it 'does not auto-configure DB if VCAP_SERVICES not set' do
ENV['VCAP_SERVICES'] = nil
module Mongo
@@ -117,6 +128,30 @@ def authenticate(username, password, save_auth=true)
db = mongo.db('test')
end
+ it 'does not auto-configure DB if multiple mongo services found' do
+ ENV['VCAP_SERVICES'] = '{"mongodb-1.8":[{"name": "mongo-1","label": "mongodb-1.8",' +
+ '"plan": "free", "credentials": {"hostname": "10.20.30.40","port": 12345, ' +
+ '"username": "8d93ae0a", "password": "7cf3c0e3","name": "m1", "db": "db"}},' +
+ '{"name": "mongo-2","label": "mongodb-1.8",' +
+ '"plan": "free", "credentials": {"hostname": "10.20.30.40","port": 12345, ' +
+ '"username": "8d93ae0a", "password": "7cf3c0e3","name": "m1", "db": "db"}}]}'
+ module Mongo
+ module Support
+ def validate_db_name(db_name)
+ db_name.should == 'test'
+ db_name
+ end
+ end
+ class DB
+ def authenticate(username, password, save_auth=true)
+ raise(Mongo::AuthenticationError, "Authenticate should not have been called!")
+ end
+ end
+ end
+ mongo = Mongo::Connection.new('127.0.0.1', 27017, {:connect => false})
+ db = mongo.db('test')
+ end
+
it 'disables Mongo auto-reconfig if DISABLE_AUTO_CONFIG includes mongodb' do
ENV['DISABLE_AUTO_CONFIG'] = "redis:mongodb"
load 'cfautoconfig/document/mongodb_configurer.rb'
View
19 auto-reconfiguration/spec/unit/keyvalue/redis_configurer_spec.rb
@@ -24,7 +24,9 @@
it 'auto-configures Redis on initialize with path' do
redis = Redis.new(:path => '127.0.0.1:6321',
:password => 'mypw')
- redis.client.path.should == '10.20.30.40:1234'
+ redis.client.host.should == '10.20.30.40'
+ redis.client.port.should == 1234
+ redis.client.path.should == nil
redis.client.password.should == 'mypass'
end
@@ -38,6 +40,21 @@
redis.client.password.should == 'mypw'
end
+ it 'does not auto-configure Redis if multiple Redis services found' do
+ ENV['VCAP_SERVICES'] = '{"redis-2.2":[{"name": "redis-1","label": "redis-2.2",' +
+ '"plan": "free", "credentials": {"node_id": "redis_node_8","hostname": ' +
+ '"10.20.30.40","port": 1234,"password": "mypass","name": "r1"}},' +
+ '{"name": "redis-2","label": "redis-2.2",' +
+ '"plan": "free", "credentials": {"node_id": "redis_node_8","hostname": ' +
+ '"10.20.30.40","port": 1234,"password": "mypass","name": "r1"}}]}'
+ redis = Redis.new(:host => '127.0.0.1',
+ :port => '6321',
+ :password => 'mypw')
+ redis.client.host.should == '127.0.0.1'
+ redis.client.port.should == 6321
+ redis.client.password.should == 'mypw'
+ end
+
it 'does not open Redis class to apply methods twice' do
load 'cfautoconfig/keyvalue/redis_configurer.rb'
#This would blow up massively (stack trace too deep) if we
View
24 auto-reconfiguration/spec/unit/messaging/amqp_configurer_spec.rb
@@ -26,7 +26,6 @@
ENV['VCAP_SERVICES'] = '{"rabbitmq-2.4":[{"name": "rabbit-1","label": "rabbitmq-2.4",' +
'"plan": "free", "credentials": {"hostname": "10.20.30.40", "port": 12345, "user": "username",
"pass":"password", "vhost" : "virtualHost"}}]}'
- load 'cfruntime/properties.rb'
mock_client = mock("client")
AMQP.client = mock_client
mock_client.should_receive(:connect).with({:host => '10.20.30.40', :port =>12345, :user=>'username',
@@ -39,8 +38,8 @@
it 'auto-configures AMQP on connect with url and new format (srs)' do
mock_client = mock("client")
AMQP.client = mock_client
- mock_client.should_receive(:connect).with(:scheme=>"amqp", :user=>"username", :pass=>"password",
- :host=>"10.20.30.40", :port=>12345, :ssl=>false, :vhost=>"virtualHost").and_return(@mock_connection)
+ mock_client.should_receive(:connect).with({:host => '10.20.30.40', :port =>12345, :user=>'username',
+ :pass=>'password', :vhost=>'virtualHost'}).and_return(@mock_connection)
@mock_connection.should_receive(:on_open)
AMQP.connect("amqp://testuser:testpass@127.0.0.1:1234/testvhost")
end
@@ -49,7 +48,6 @@
ENV['VCAP_SERVICES'] = '{"rabbitmq-2.4":[{"name": "rabbit-1","label": "rabbitmq-2.4",' +
'"plan": "free", "credentials": {"hostname": "10.20.30.40", "port": 12345, "user": "username",
"pass":"password", "vhost" : "virtualHost"}}]}'
- load 'cfruntime/properties.rb'
mock_client = mock("client")
AMQP.client = mock_client
mock_client.should_receive(:connect).with({:host => '10.20.30.40', :port =>12345, :user=>'username',
@@ -60,7 +58,19 @@
it 'does not auto-configure AMQP if VCAP_SERVICES not set' do
ENV['VCAP_SERVICES'] = nil
- load 'cfruntime/properties.rb'
+ mock_client = mock("client")
+ AMQP.client = mock_client
+ mock_client.should_receive(:connect).with(:scheme=>"amqp", :user=>"testuser", :pass=>"testpass",
+ :host=>"127.0.0.1", :port=>1234, :ssl=>false, :vhost=>"testvhost").and_return(@mock_connection)
+ @mock_connection.should_receive(:on_open)
+ AMQP.connect("amqp://testuser:testpass@127.0.0.1:1234/testvhost")
+ end
+
+ it 'does not auto-configure AMQP if multiple Rabbit services found' do
+ ENV['VCAP_SERVICES'] = '{"rabbitmq-2.4":[{"name": "rabbit-1","label": "rabbitmq-2.4",' +
+ '"plan": "free", "credentials": {"url": "amqp://username:password@10.20.30.40:12345/virtualHost"}},' +
+ '{"name": "rabbit-2","label": "rabbitmq-2.4",' +
+ '"plan": "free", "credentials": {"url": "amqp://username:password@10.20.30.40:12345/virtualHost"}}]}'
mock_client = mock("client")
AMQP.client = mock_client
mock_client.should_receive(:connect).with(:scheme=>"amqp", :user=>"testuser", :pass=>"testpass",
@@ -75,8 +85,8 @@
#aliased the connect methods twice
mock_client = mock("client")
AMQP.client = mock_client
- mock_client.should_receive(:connect).with(:scheme=>"amqp", :user=>"username", :pass=>"password",
- :host=>"10.20.30.40", :port=>12345, :ssl=>false, :vhost=>"virtualHost").and_return(@mock_connection)
+ mock_client.should_receive(:connect).with({:host => '10.20.30.40', :port =>12345, :user=>'username',
+ :pass=>'password', :vhost=>'virtualHost'}).and_return(@mock_connection)
@mock_connection.should_receive(:on_open)
AMQP.connect("amqp://testuser:testpass@127.0.0.1:1234/testvhost")
end
View
33 auto-reconfiguration/spec/unit/messaging/carrot_configurer_spec.rb
@@ -9,24 +9,12 @@
ENV['VCAP_SERVICES'] = '{"rabbitmq-2.4":[{"name": "rabbit-1","label": "rabbitmq-2.4",' +
'"plan": "free", "credentials": {"url": "amqp://username:password@10.20.30.40:12345/virtualHost"}}]}'
ENV['DISABLE_AUTO_CONFIG'] = nil
- #Add access to the opts variable stored on new
- class Carrot
- def opts_for_cf
- @opts
- end
- end
- end
-
- after(:each) do
- class Carrot
- undef_method :opts_for_cf
- end
end
it 'auto-configures Carrot on connect with new format (srs)' do
carrot = Carrot.new({:host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'})
- carrot.opts_for_cf.should == { :host => '10.20.30.40', :port =>12345, :user=>'username',
+ carrot.instance_variable_get("@opts").should == { :host => '10.20.30.40', :port =>12345, :user=>'username',
:pass=>'password', :vhost=>'virtualHost'}
end
@@ -36,7 +24,7 @@ class Carrot
"pass":"password", "vhost" : "virtualHost"}}]}'
carrot = Carrot.new({:host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'})
- carrot.opts_for_cf.should == { :host => '10.20.30.40', :port =>12345, :user=>'username',
+ carrot.instance_variable_get("@opts").should == { :host => '10.20.30.40', :port =>12345, :user=>'username',
:pass=>'password', :vhost=>'virtualHost'}
end
@@ -44,7 +32,18 @@ class Carrot
ENV['VCAP_SERVICES'] = nil
carrot = Carrot.new({:host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'})
- carrot.opts_for_cf.should == { :host => '127.0.0.1', :port =>1234, :user=>'testuser',
+ carrot.instance_variable_get("@opts").should == { :host => '127.0.0.1', :port =>1234, :user=>'testuser',
+ :pass=>'testpass', :vhost=>'testvhost'}
+ end
+
+ it 'does not auto-configure Carrot if multiple Rabbit services found' do
+ ENV['VCAP_SERVICES'] = '{"rabbitmq-2.4":[{"name": "rabbit-1","label": "rabbitmq-2.4",' +
+ '"plan": "free", "credentials": {"url": "amqp://username:password@10.20.30.40:12345/virtualHost"}},' +
+ '{"name": "rabbit-2","label": "rabbitmq-2.4",' +
+ '"plan": "free", "credentials": {"url": "amqp://username:password@10.20.30.40:12345/virtualHost"}}]}'
+ carrot = Carrot.new({:host => '127.0.0.1', :port =>1234, :user=>'testuser',
+ :pass=>'testpass', :vhost=>'testvhost'})
+ carrot.instance_variable_get("@opts").should == { :host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'}
end
@@ -54,7 +53,7 @@ class Carrot
#aliased the connect methods twice
carrot = Carrot.new({:host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'})
- carrot.opts_for_cf.should == { :host => '10.20.30.40', :port =>12345, :user=>'username',
+ carrot.instance_variable_get("@opts").should == { :host => '10.20.30.40', :port =>12345, :user=>'username',
:pass=>'password', :vhost=>'virtualHost'}
end
@@ -63,7 +62,7 @@ class Carrot
load 'cfautoconfig/messaging/carrot_configurer.rb'
carrot = Carrot.new({:host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'})
- carrot.opts_for_cf.should == { :host => '127.0.0.1', :port =>1234, :user=>'testuser',
+ carrot.instance_variable_get("@opts").should == { :host => '127.0.0.1', :port =>1234, :user=>'testuser',
:pass=>'testpass', :vhost=>'testvhost'}
end
end
View
22 auto-reconfiguration/spec/unit/relational/mysql_configurer_spec.rb
@@ -58,6 +58,28 @@ def connect user, pass, host, port, database, socket, flags
db = Mysql2::Client.new(@dbopts)
end
+ it 'does not auto-configure Mysql if multiple mysql services are found' do
+ ENV['VCAP_SERVICES'] = '{"mysql-5.1":[{"name": "mysql-1","label": "mysql-5.1",' +
+ '"plan": "free", "credentials": { "hostname": "10.20.30.40",' +
+ '"port": 1234,"name": "cfdb","user": "cfuser","username": "cfuser","password": "cfpasswd"}},'+
+ '{"name": "mysql-2","label": "mysql-5.1",' +
+ '"plan": "free", "credentials": { "hostname": "10.20.30.40",' +
+ '"port": 1234,"name": "cfdb","user": "cfuser","username": "cfuser","password": "cfpasswd"}}]}'
+ module Mysql2
+ class Client
+ def connect user, pass, host, port, database, socket, flags
+ user.should == 'user'
+ pass.should == 'passwd'
+ host.should == 'localhost'
+ port.should == 3306
+ database.should == 'test'
+ end
+ end
+ end
+ db = Mysql2::Client.new(@dbopts)
+ end
+
+
it 'disables Mysql auto-reconfig if DISABLE_AUTO_CONFIG includes mysql' do
ENV['DISABLE_AUTO_CONFIG'] = "redis:mysql:mongodb"
load 'cfautoconfig/relational/mysql_configurer.rb'
View
25 auto-reconfiguration/spec/unit/relational/postgres_configurer_spec.rb
@@ -9,7 +9,6 @@
'"plan": "free", "credentials": { "node_id": "postgresql_node_4","hostname": "10.20.30.40",' +
'"port": 8552,"password": "svcpw","name": "svcdb","username": "svcuser"}}]}'
ENV['DISABLE_AUTO_CONFIG'] = nil
- load 'cfruntime/properties.rb'
end
it 'auto-configures PGConn.open with Array arguments' do
@@ -48,18 +47,28 @@
end
it 'auto-configures PGConn.connect' do
- expected_conn_string= attempt_pg_connect('localhost','5689', {:foo=>'bar'},nil,'testdb','testuser','testpw',:connect_timeout=>1)
- expected_conn_string.should == "connect_timeout='1' host='10.20.30.40' port='8552' options='{:foo=>\"bar\"}' dbname='svcdb' user='svcuser' password='svcpw'"
+ expected_conn_string= attempt_pg_connect('localhost','5689', {:foo=>'bar'},nil,'testdb','testuser','testpw',:connect_timeout=>1)
+ expected_conn_string.should == "connect_timeout='1' host='10.20.30.40' port='8552' options='{:foo=>\"bar\"}' dbname='svcdb' user='svcuser' password='svcpw'"
end
- it 'auto-configures PGConn.connect_start' do
- expected_conn_string= attempt_pg_connect_start('localhost','5689', {:foo=>'bar'},nil,'testdb','testuser','testpw',:connect_timeout=>1)
- expected_conn_string.should == "connect_timeout='1' host='10.20.30.40' port='8552' options='{:foo=>\"bar\"}' dbname='svcdb' user='svcuser' password='svcpw'"
- end
+ it 'auto-configures PGConn.connect_start' do
+ expected_conn_string= attempt_pg_connect_start('localhost','5689', {:foo=>'bar'},nil,'testdb','testuser','testpw',:connect_timeout=>1)
+ expected_conn_string.should == "connect_timeout='1' host='10.20.30.40' port='8552' options='{:foo=>\"bar\"}' dbname='svcdb' user='svcuser' password='svcpw'"
+ end
it 'does not auto-configure PGConn.open if VCAP_SERVICES not set' do
ENV['VCAP_SERVICES'] = nil
- load 'cfruntime/properties.rb'
+ expected_conn_string=attempt_pg_open("host=localhost port=8552 user=testuser connect_timeout=1")
+ expected_conn_string.should == ""
+ end
+
+ it 'does not auto-configure PGConn.open if multiple postgres services found' do
+ ENV['VCAP_SERVICES'] = '{"postgresql-9.0":[{"name": "postgres-1","label": "postgresql-9.0",' +
+ '"plan": "free", "credentials": { "node_id": "postgresql_node_4","hostname": "10.20.30.40",' +
+ '"port": 8552,"password": "svcpw","name": "svcdb","username": "svcuser"}},' +
+ '{"name": "postgres-2","label": "postgresql-9.0",' +
+ '"plan": "free", "credentials": { "node_id": "postgresql_node_4","hostname": "10.20.30.40",' +
+ '"port": 8552,"password": "svcpw","name": "svcdb","username": "svcuser"}}]}'
expected_conn_string=attempt_pg_open("host=localhost port=8552 user=testuser connect_timeout=1")
expected_conn_string.should == ""
end
View
7 cfruntime/cf-runtime.gemspec
@@ -12,9 +12,16 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.extra_rdoc_files = ["LICENSE"]
+ s.rdoc_options = ["-N", "--tab-width=2", "--exclude='cf-runtime.gemspec|spec'"]
s.add_dependency "crack", "~> 0.3.1"
+ s.add_development_dependency "redis", "~> 2.0"
+ s.add_development_dependency "amqp", "~> 0.8"
+ s.add_development_dependency "carrot", "~> 1.0"
+ s.add_development_dependency "mongo", "~> 1.2.0"
+ s.add_development_dependency "pg", "~> 0.11.0"
+ s.add_development_dependency "mysql2", "~> 0.2.7"
s.add_development_dependency "rake", "~> 0.9.2"
s.add_development_dependency "rcov", "~> 0.9.10"
s.add_development_dependency "rack-test", "~> 0.6.1"
View
13 cfruntime/lib/cfruntime.rb
@@ -1,5 +1,8 @@
-require "cfruntime/version"
-
-module CFRuntime
- # Your code goes here...
-end
+require 'cfruntime/amqp'
+require 'cfruntime/carrot'
+require 'cfruntime/mongodb'
+require 'cfruntime/mysql'
+require 'cfruntime/postgres'
+require 'cfruntime/properties'
+require 'cfruntime/redis'
+require 'cfruntime/version'
View
43 cfruntime/lib/cfruntime/amqp.rb
@@ -0,0 +1,43 @@
+require 'amqp'
+module CFRuntime
+ class AMQPClient
+
+ # Creates and returns an +AMQP+ connection to a single rabbitmq service.
+ # Passes optional other_options and block arguments to +AMQP.connect+.
+ # Raises +ArgumentError+ If zero or multiple rabbitmq services are found.
+ def self.create(other_options = {}, &block)
+ service_names = CloudApp.service_names_of_type('rabbitmq')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of rabbitmq type, " +
+ "but found #{service_names.length}. " +
+ "Consider using create_from_svc(service_name) instead.")
+ end
+ create_from_svc(service_names[0],other_options,&block)
+ end
+
+ # Creates and returns an +AMQP+ connection to a rabbitmq service with the
+ # specified name.
+ # Passes optional other_options and block arguments to +AMQP.connect+.
+ # Raises +ArgumentError+ If specified rabbitmq service is not found.
+ def self.create_from_svc(service_name, other_options = {}, &block)
+ AMQP.connect(options_for_svc(service_name), other_options, &block)
+ end
+
+ # Merges provided options with connection options for specified rabbitmq service.
+ # Returns merged Hash containing (:user, :pass, :vhost, :host, :port).
+ # Raises +ArgumentError+ If specified rabbitmq service is not found.
+ def self.options_for_svc(service_name,options={})
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ cfoptions = options
+ cfoptions[:host] = service_props[:host]
+ cfoptions[:port] = service_props[:port]
+ cfoptions[:user] = service_props[:username]
+ cfoptions[:pass] = service_props[:password]
+ cfoptions[:vhost] = service_props[:vhost]
+ cfoptions
+ end
+ end
+end
View
44 cfruntime/lib/cfruntime/carrot.rb
@@ -0,0 +1,44 @@
+require 'carrot'
+require 'cfruntime/properties'
+module CFRuntime
+ class CarrotClient
+
+ # Creates and returns a +Carrot+ instance connected to a single rabbitmq service.
+ # Passes optional Hash of non-connection-related options to +Carrot.new+.
+ # Raises +ArgumentError+ If zero or multiple rabbitmq services are found.
+ def self.create(options={})
+ service_names = CloudApp.service_names_of_type('rabbitmq')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of rabbitmq type, " +
+ "but found #{service_names.length}. " +
+ "Consider using create_from_svc(service_name) instead.")
+ end
+ create_from_svc(service_names[0],options)
+ end
+
+ # Creates and returns a +Carrot+ instance connected to a rabbitmq service with the
+ # specified name.
+ # Passes optional Hash of non-connection-related options to +Carrot.new+.
+ # Raises +ArgumentError+ If specified rabbitmq service is not found.
+ def self.create_from_svc(service_name, options={})
+ Carrot.new(options_for_svc(service_name,options))
+ end
+
+ # Merges provided options with connection options for specified rabbitmq service.
+ # Returns merged Hash containing (:user, :pass, :vhost, :host, :port).
+ # Raises +ArgumentError+ If specified rabbitmq service is not found.
+ def self.options_for_svc(service_name,options={})
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ cfoptions = options
+ cfoptions[:host] = service_props[:host]
+ cfoptions[:port] = service_props[:port]
+ cfoptions[:user] = service_props[:username]
+ cfoptions[:pass] = service_props[:password]
+ cfoptions[:vhost] = service_props[:vhost]
+ cfoptions
+ end
+ end
+end
View
58 cfruntime/lib/cfruntime/mongodb.rb
@@ -0,0 +1,58 @@
+require 'mongo'
+require 'cfruntime/properties'
+module CFRuntime
+ class MongoClient
+
+ # Creates and returns a Mongo +Connection+ to a single mongodb service.
+ # Passes optional Hash of non-connection-related options to +Mongo::Connection.new+.
+ # Raises +ArgumentError+ If zero or multiple mongodb services are found.
+ def self.create(options={})
+ service_names = CloudApp.service_names_of_type('mongodb')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of mongodb type, " +
+ "but found #{service_names.length}. " +
+ "Consider using create_from_svc(service_name) instead.")
+ end
+ create_from_svc(service_names[0],options)
+ end
+
+ # Creates and returns a Mongo +Connection+ to a mongodb service with the
+ # specified name.
+ # Passes optional Hash of non-connection-related options to +Mongo::Connection.new+.
+ # Raises +ArgumentError+ If specified mongodb service is not found.
+ def self.create_from_svc(service_name,options={})
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ Mongo::Connection.new(service_props[:host], service_props[:port],options)
+ end
+
+ # Creates and returns an authenticated Mongo +DB+ instance connected to a single mongodb service
+ # Raises +ArgumentError+ If zero or multiple mongodb services are found.
+ def self.db(connection)
+ service_names = CloudApp.service_names_of_type('mongodb')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of mongodb type, " +
+ "but found #{service_names.length}. " +
+ "Consider using db_from_svc(service_name) instead.")
+ end
+ db_from_svc(service_names[0],connection)
+ end
+
+ # Creates and returns an authenticated Mongo +DB+ instance connected to a mongodb service with the
+ # specified name.
+ # Raises +ArgumentError+ If specified mongodb service is not found.
+ def self.db_from_svc(service_name,connection)
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ db = connection.db(service_props[:db])
+ db.authenticate(service_props[:username],service_props[:password])
+ db
+ end
+
+
+ end
+end
View
44 cfruntime/lib/cfruntime/mysql.rb
@@ -0,0 +1,44 @@
+require 'mysql2'
+require 'cfruntime/properties'
+module CFRuntime
+ class Mysql2Client
+
+ # Creates and returns a Mysql2 +Client+ instance connected to a single mysql service.
+ # Passes optional Hash of non-connection-related options to +Mysql2::Client.new+.
+ # Raises +ArgumentError+ If zero or multiple mysql services are found.
+ def self.create(options={})
+ service_names = CloudApp.service_names_of_type('mysql')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of mysql type, " +
+ "but found #{service_names.length}. " +
+ "Consider using create_from_svc(service_name) instead.")
+ end
+ create_from_svc(service_names[0],options)
+ end
+
+ # Creates and returns a Mysql2 +Client+ instance connected to a mysql service with the
+ # specified name.
+ # Passes optional Hash of non-connection-related options to +Mysql2::Client.new+.
+ # Raises +ArgumentError+ If specified mysql service is not found.
+ def self.create_from_svc(service_name, options={})
+ Mysql2::Client.new(options_for_svc(service_name,options))
+ end
+
+ # Merges provided options with connection options for specified mysql service.
+ # Returns merged Hash containing (:username, :password, :database, :host, :port).
+ # Raises +ArgumentError+ If specified mysql service is not found.
+ def self.options_for_svc(service_name,options={})
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ cfoptions = options
+ cfoptions[:host] = service_props[:host]
+ cfoptions[:port] = service_props[:port]
+ cfoptions[:username] = service_props[:username]
+ cfoptions[:password] = service_props[:password]
+ cfoptions[:database] = service_props[:database]
+ cfoptions
+ end
+ end
+end
View
50 cfruntime/lib/cfruntime/postgres.rb
@@ -0,0 +1,50 @@
+require 'pg'
+require 'cfruntime/properties'
+module CFRuntime
+ class PGClient
+
+ # Creates and returns a +PGconn+ connecting to a single postgresql service.
+ # Passes optional Hash of non-connection-related options to +PGconn.open+.
+ # Raises +ArgumentError+ If zero or multiple postgresql services are found.
+ def self.create(options={})
+ service_names = CloudApp.service_names_of_type('postgresql')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of postgresql type, " +
+ "but found #{service_names.length}. " +
+ "Consider using create_from_svc(service_name) instead.")
+ end
+ cfoptions = options_for_svc(service_names[0],options)
+ #Pass back the options for verification
+ yield cfoptions if block_given?
+ PGconn.open(cfoptions)
+ end
+
+ # Creates and returns a +PGconn+ connecting to a postgresql service with the
+ # specified name.
+ # Passes optional Hash of non-connection-related options to +PGconn.open+.
+ # Raises +ArgumentError+ If specified postgresql service is not found.
+ def self.create_from_svc(service_name,options={})
+ cfoptions = options_for_svc(service_name,options)
+ #Pass back the options for verification
+ yield cfoptions if block_given?
+ PGconn.open(cfoptions)
+ end
+
+ # Merges provided options with connection options for specified postgresql service.
+ # Returns merged Hash containing (:user, :password, :dbname, :host, :port).
+ # Raises +ArgumentError+ If specified postgresql service is not found.
+ def self.options_for_svc(service_name,options={})
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ cfoptions = options
+ cfoptions[:host] = service_props[:host]
+ cfoptions[:port] = service_props[:port]
+ cfoptions[:user] = service_props[:username]
+ cfoptions[:password] = service_props[:password]
+ cfoptions[:dbname] = service_props[:database]
+ cfoptions
+ end
+ end
+end
View
36 cfruntime/lib/cfruntime/properties.rb
@@ -1,5 +1,3 @@
-# Copyright (c) 2009-2011 VMware, Inc.
-
module CFRuntime
require 'crack/json'
@@ -8,18 +6,27 @@ module CFRuntime
class CloudApp
class << self
+ # Returns true if this code is running on Cloud Foundry
def running_in_cloud?()
!ENV['VCAP_APPLICATION'].nil?
end
+ # Returns the application host name
def host
ENV['VCAP_APP_HOST']
end
+ # Returns the port bound to the application
def port
ENV['VCAP_APP_PORT']
end
+ # Parses the VCAP_SERVICES environment variable and returns a Hash of properties
+ # for the specified service name. If only one service of a particular type is bound
+ # to the application, service_props(type) will also work.
+ # Example: service_props('mysql').
+ # Returns nil if service with specified name is not found or if zero or multiple services
+ # of a specified type are found.
def service_props(service_name)
registered_svcs = {}
if ENV['VCAP_SERVICES']
@@ -79,23 +86,32 @@ def service_props(service_name)
registered_svcs[service_name]
end
+ # Parses the VCAP_SERVICES environment variable and returns an array of Service
+ # names bound to the current application.
def service_names
service_names = []
- Crack::JSON.parse(ENV['VCAP_SERVICES']).each do |key,list|
- list.each do |svc|
- service_names << svc["name"]
+ if ENV['VCAP_SERVICES']
+ Crack::JSON.parse(ENV['VCAP_SERVICES']).each do |key,list|
+ list.each do |svc|
+ service_names << svc["name"]
+ end
end
end
service_names
end
+ # Parses the VCAP_SERVICES environment variable and returns an array of Service
+ # names of the specified type bound to the current application.
+ # Example: service_names_of_type('mysql')
def service_names_of_type(type)
service_names = []
- Crack::JSON.parse(ENV['VCAP_SERVICES']).each do |key,list|
- label, version = key.split('-')
- list.each do |svc|
- if label == type
- service_names << svc["name"]
+ if ENV['VCAP_SERVICES']
+ Crack::JSON.parse(ENV['VCAP_SERVICES']).each do |key,list|
+ label, version = key.split('-')
+ list.each do |svc|
+ if label == type
+ service_names << svc["name"]
+ end
end
end
end
View
44 cfruntime/lib/cfruntime/redis.rb
@@ -0,0 +1,44 @@
+require 'redis'
+require 'cfruntime/properties'
+module CFRuntime
+ class RedisClient
+
+ # Creates and returns a +Redis+ instance connected to a single redis service.
+ # Passes optional Hash of non-connection-related options to +Redis.new+.
+ # Raises +ArgumentError+ If zero or multiple redis services are found.
+ def self.create(options={})
+ service_names = CloudApp.service_names_of_type('redis')
+ if service_names.length != 1
+ raise ArgumentError.new("Expected 1 service of redis type, " +
+ "but found #{service_names.length}. " +
+ "Consider using create_from_svc(service_name) instead.")
+ end
+ create_from_svc(service_names[0],options)
+ end
+
+ # Creates and returns a +Redis+ instance connected to a redis service with the
+ # specified name.
+ # Passes optional Hash of non-connection-related options to +Redis.new+.
+ # Raises +ArgumentError+ If specified redis service is not found.
+ def self.create_from_svc(service_name, options={})
+ Redis.new(options_for_svc(service_name,options))
+ end
+
+ # Merges provided options with connection options for specified redis service.
+ # Returns merged Hash containing (password, :host, :port)
+ # Raises +ArgumentError+ If specified redis service is not found.
+ def self.options_for_svc(service_name,options={})
+ service_props = CFRuntime::CloudApp.service_props(service_name)
+ if service_props.nil?
+ raise ArgumentError.new("Service with name #{service_name} not found")
+ end
+ cfoptions = options
+ cfoptions[:host] = service_props[:host]
+ cfoptions[:port] = service_props[:port]
+ cfoptions[:password] = service_props[:password]
+ #host and port are ignored if path is provided, so we null it out
+ cfoptions[:path] = nil
+ cfoptions
+ end
+ end
+end
View
2  cfruntime/lib/cfruntime/version.rb
@@ -1,5 +1,3 @@
-# Copyright (c) 2009-2011 VMware, Inc.
-
module CFRuntime
VERSION = "0.0.1"
end
View
82 cfruntime/spec/amqp_spec.rb
@@ -0,0 +1,82 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+require 'cfruntime/amqp'
+
+describe 'CFRuntime::AMQPClient' do
+ include CFRuntime::Test
+
+ before(:each) do
+ @mock_connection = mock("connection")
+ end
+
+ it 'creates a client with a Rabbit service by type and no additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ with_vcap_services(svcs) do
+ mock_client = mock("client")
+ AMQP.client = mock_client
+ mock_client.should_receive(:connect).with({:host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost'}).and_return(@mock_connection)
+ @mock_connection.should_receive(:on_open)
+ CFRuntime::AMQPClient.create
+ end
+ end
+
+ it 'creates a client with a Rabbit service by type and additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ addl_opts = {:some=>'thing'}
+ with_vcap_services(svcs) do
+ mock_client = mock("client")
+ AMQP.client = mock_client
+ mock_client.should_receive(:connect).with({:host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost', :some=>'thing'}).and_return(@mock_connection)
+ @mock_connection.should_receive(:on_open)
+ CFRuntime::AMQPClient.create(addl_opts)
+ end
+ end
+
+ it 'creates a client with a Rabbit service by name and no additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ with_vcap_services(svcs) do
+ mock_client = mock("client")
+ AMQP.client = mock_client
+ mock_client.should_receive(:connect).with({:host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost'}).and_return(@mock_connection)
+ @mock_connection.should_receive(:on_open)
+ CFRuntime::AMQPClient.create_from_svc('rabbit-test')
+ end
+ end
+
+ it 'creates a client with a Rabbit service by name and additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ addl_opts = {:some=>'thing'}
+ with_vcap_services(svcs) do
+ mock_client = mock("client")
+ AMQP.client = mock_client
+ mock_client.should_receive(:connect).with({:host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost', :some=>'thing'}).and_return(@mock_connection)
+ @mock_connection.should_receive(:on_open)
+ CFRuntime::AMQPClient.create_from_svc('rabbit-test',addl_opts)
+ end
+ end
+
+ it 'raises an ArgumentError if no service of Rabbit type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::AMQPClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of rabbitmq type, but found 0. Consider using create_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError if multiple services of Rabbit type found' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost'),
+ create_rabbit_srs_service('rabbit-test2','testvhost')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::AMQPClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of rabbitmq type, but found 2. Consider using create_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError if Rabbit service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::AMQPClient.create_from_svc('non-existent-rabbit')}.to raise_error(ArgumentError,
+ 'Service with name non-existent-rabbit not found')
+ end
+
+end
View
66 cfruntime/spec/carrot_spec.rb
@@ -0,0 +1,66 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+require 'cfruntime/carrot'
+
+describe 'CFRuntime::CarrotClient' do
+ include CFRuntime::Test
+
+ it 'creates a client with a Rabbit service by type and no additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ with_vcap_services(svcs) do
+ carrot = CFRuntime::CarrotClient.create
+ carrot.instance_variable_get("@opts").should == { :host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost'}
+ end
+ end
+
+ it 'creates a client with a Rabbit service by type and additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ opts = {:some=>'thing'}
+ with_vcap_services(svcs) do
+ carrot = CFRuntime::CarrotClient.create(opts)
+ carrot.instance_variable_get("@opts").should == { :host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost', :some=>'thing'}
+ end
+ end
+
+ it 'creates a client with a Rabbit service by name and no additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ with_vcap_services(svcs) do
+ carrot = CFRuntime::CarrotClient.create_from_svc('rabbit-test')
+ carrot.instance_variable_get("@opts").should == { :host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost'}
+ end
+ end
+
+ it 'creates a client with a Rabbit service by name and additional options' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost')]}
+ opts = {:some=>'thing'}
+ with_vcap_services(svcs) do
+ carrot = CFRuntime::CarrotClient.create_from_svc('rabbit-test',opts)
+ carrot.instance_variable_get("@opts").should == { :host => "#{SOME_SERVER}", :port =>SOME_SERVICE_PORT, :user=>'rabbituser',
+ :pass=>'rabbitpass', :vhost=>'testvhost', :some=>'thing'}
+ end
+ end
+
+ it 'raises an ArgumentError if no service of Rabbit type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::CarrotClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of rabbitmq type, but found 0. Consider using create_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError if multiple services of Rabbit type found' do
+ svcs = {"rabbitmq-#{rabbit_version}"=>[create_rabbit_srs_service('rabbit-test','testvhost'),
+ create_rabbit_srs_service('rabbit-test2','testvhost')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::CarrotClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of rabbitmq type, but found 2. Consider using create_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError if Rabbit service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::CarrotClient.create_from_svc('non-existent-rabbit')}.to raise_error(ArgumentError,
+ 'Service with name non-existent-rabbit not found')
+ end
+
+end
View
78 cfruntime/spec/mongodb_spec.rb
@@ -0,0 +1,78 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+require 'cfruntime/mongodb'
+
+describe 'CFRuntime::MongoClient' do
+ include CFRuntime::Test
+
+ before(:each) do
+ module Mongo
+ class DB
+ def authenticate(username,password)
+ username.should == "testuser"
+ password.should == "testpw"
+ end
+ end
+ end
+ end
+
+ it 'creates a client with a Mongo service by type and additional options' do
+ svcs = {"mongodb-#{mongo_version}"=>[create_mongo_service('mongo-test')]}
+ with_vcap_services(svcs) do
+ conn = CFRuntime::MongoClient.create(:connect=>false)
+ db = CFRuntime::MongoClient.db(conn)
+ db.name.should == "db"
+ db.connection.host_to_try.should == [SOME_SERVER,SOME_SERVICE_PORT]
+ end
+ end
+
+ it 'creates a client with a Mongo service by name and additional options' do
+ svcs = {"mongodb-#{mongo_version}"=>[create_mongo_service('mongo-test')]}
+ with_vcap_services(svcs) do
+ conn = CFRuntime::MongoClient.create_from_svc('mongo-test',:connect=>false)
+ db = CFRuntime::MongoClient.db_from_svc('mongo-test',conn)
+ db.name.should == "db"
+ db.connection.host_to_try.should == [SOME_SERVER,SOME_SERVICE_PORT]
+ end
+ end
+
+ it 'raises an ArgumentError on create if no service of Mongo type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::MongoClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of mongodb type, but found 0. Consider using create_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError on create if multiple services of Mongo type found' do
+ svcs = {"mongodb-#{mongo_version}"=>[create_mongo_service('mongo-test'),
+ create_mongo_service('mongo-test2')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::MongoClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of mongodb type, but found 2. Consider using create_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError on create if Mongo service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::MongoClient.create_from_svc('non-existent-mongo')}.to raise_error(ArgumentError,
+ 'Service with name non-existent-mongo not found')
+ end
+ it 'raises an ArgumentError on db if no service of Mongo type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::MongoClient.db(mock("connection"))}.to raise_error(ArgumentError,
+ 'Expected 1 service of mongodb type, but found 0. Consider using db_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError on db if multiple services of Mongo type found' do
+ svcs = {"mongodb-#{mongo_version}"=>[create_mongo_service('mongo-test'),
+ create_mongo_service('mongo-test2')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::MongoClient.db(mock("connection"))}.to raise_error(ArgumentError,
+ 'Expected 1 service of mongodb type, but found 2. Consider using db_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError on db if Mongo service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::MongoClient.db_from_svc('non-existent-mongo',mock("connection"))}.to raise_error(ArgumentError,
+ 'Service with name non-existent-mongo not found')
+ end
+end
View
74 cfruntime/spec/mysql_spec.rb
@@ -0,0 +1,74 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+require 'cfruntime/mysql'
+
+describe 'CFRuntime::Mysql2Client' do
+ include CFRuntime::Test
+
+ before(:each) do
+ module Mysql2
+ class Client
+ attr_accessor :opts
+ def connect(user, pass, host, port, database, socket, flags)
+ @opts = {:user=>user,:pass=>pass, :host=>host, :port=>port, :database=>database, :socket=>socket}
+ end
+ end
+ end
+ end
+
+ it 'creates a client with a MySQL service by type and no additional options' do
+ svcs = {"mysql-#{mysql_version}"=>[create_mysql_service('mysql-test')]}
+ with_vcap_services(svcs) do
+ client = CFRuntime::Mysql2Client.create
+ client.opts.should=={:user=>"testuser",:pass=>"testpw", :host=>SOME_SERVER, :port=>SOME_SERVICE_PORT,
+ :database=>"mysqldatabase", :socket=>nil}
+ end
+ end
+
+ it 'creates a client with a MySQL service by type and additional options' do
+ svcs = {"mysql-#{mysql_version}"=>[create_mysql_service('mysql-test')]}
+ with_vcap_services(svcs) do
+ client = CFRuntime::Mysql2Client.create({:socket=>"sock"})
+ client.opts.should=={:user=>"testuser",:pass=>"testpw", :host=>SOME_SERVER, :port=>SOME_SERVICE_PORT,
+ :database=>"mysqldatabase", :socket=>"sock"}
+ end
+ end
+
+ it 'creates a client with a MySQL service by name and no additional options' do
+ svcs = {"mysql-#{mysql_version}"=>[create_mysql_service('mysql-test')]}
+ with_vcap_services(svcs) do
+ client = CFRuntime::Mysql2Client.create_from_svc('mysql-test')
+ client.opts.should=={:user=>"testuser",:pass=>"testpw", :host=>SOME_SERVER, :port=>SOME_SERVICE_PORT,
+ :database=>"mysqldatabase", :socket=>nil}
+ end
+ end
+
+ it 'creates a client with a MySQL service by name and additional options' do
+ svcs = {"mysql-#{mysql_version}"=>[create_mysql_service('mysql-test')]}
+ with_vcap_services(svcs) do
+ client = CFRuntime::Mysql2Client.create_from_svc('mysql-test',{:socket=>"sock"})
+ client.opts.should=={:user=>"testuser",:pass=>"testpw", :host=>SOME_SERVER, :port=>SOME_SERVICE_PORT,
+ :database=>"mysqldatabase", :socket=>"sock"}
+ end
+ end
+
+ it 'raises an ArgumentError if no service of MySQL type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::Mysql2Client.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of mysql type, but found 0. Consider using create_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError if multiple services of MySQL type found' do
+ svcs = {"mysql-#{mysql_version}"=>[create_mysql_service('mysql-test'),
+ create_mysql_service('mysql-test2')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::Mysql2Client.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of mysql type, but found 2. Consider using create_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError if MySQL service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::Mysql2Client.create_from_svc('non-existent-mysql')}.to raise_error(ArgumentError,
+ 'Service with name non-existent-mysql not found')
+ end
+end
View
61 cfruntime/spec/postgres_spec.rb
@@ -0,0 +1,61 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+require 'cfruntime/postgres'
+
+describe 'CFRuntime::PGClient' do
+ include CFRuntime::Test
+
+ it 'creates a client with a Postgres service by type and additional options' do
+ svcs = {"postgresql-#{postgres_version}"=>[create_postgres_service('pg-test')]}
+ with_vcap_services(svcs) do
+ begin
+ CFRuntime::PGClient.create(:connect_timeout=>1) do|cfopts|
+ cfopts.should == {:connect_timeout=>1, :host=>SOME_SERVER, :port=>SOME_SERVICE_PORT, :user=>"testuser",
+ :password=>"testpw", :dbname=>"pgdatabase"}
+ end
+ rescue PGError=>e
+ #Excepted connection timeout
+ if !e.message=~"timeout expired"
+ raise e
+ end
+ end
+ end
+ end
+
+ it 'creates a client with a Postgres service by name and additional options' do
+ svcs = {"postgresql-#{postgres_version}"=>[create_postgres_service('pg-test')]}
+ with_vcap_services(svcs) do
+ begin
+ CFRuntime::PGClient.create_from_svc('pg-test',:connect_timeout=>1) do|cfopts|
+ cfopts.should == {:connect_timeout=>1, :host=>SOME_SERVER, :port=>SOME_SERVICE_PORT, :user=>"testuser",
+ :password=>"testpw", :dbname=>"pgdatabase"}
+ end
+ rescue PGError=>e
+ #Excepted connection timeout
+ if !e.message=~"timeout expired"
+ raise e
+ end
+ end
+ end
+ end
+
+ it 'raises an ArgumentError if no service of Postgresql type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::PGClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of postgresql type, but found 0. Consider using create_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError if multiple services of Postgresql type found' do
+ svcs = {"postgresql-#{postgres_version}"=>[create_postgres_service('pg-test'),
+ create_postgres_service('pg-test2')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::PGClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of postgresql type, but found 2. Consider using create_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError if Postgres service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::PGClient.create_from_svc('non-existent-postgres')}.to raise_error(ArgumentError,
+ 'Service with name non-existent-postgres not found')
+ end
+end
View
14 cfruntime/spec/properties_spec.rb
@@ -1,5 +1,3 @@
-# Copyright (c) 2009-2011 VMware, Inc.
-
require File.join(File.dirname(__FILE__), 'spec_helper')
require 'cfruntime/properties.rb'
@@ -100,9 +98,9 @@
CFRuntime::CloudApp.service_props('rabbit-test')[:name].should == "rabbit-test"
CFRuntime::CloudApp.service_props('rabbit-test')[:host].should == SOME_SERVER
CFRuntime::CloudApp.service_props('rabbit-test')[:port].should == 25046
- CFRuntime::CloudApp.service_props('rabbit-test')[:username].should_not == nil
- CFRuntime::CloudApp.service_props('rabbit-test')[:password].should_not == nil
- CFRuntime::CloudApp.service_props('rabbit-test')[:url].should_not == nil
+ CFRuntime::CloudApp.service_props('rabbit-test')[:username].should == "rabbituser"
+ CFRuntime::CloudApp.service_props('rabbit-test')[:password].should == "rabbitpass"
+ CFRuntime::CloudApp.service_props('rabbit-test')[:url].should == "amqp://rabbituser:rabbitpass@#{SOME_SERVER}:#{SOME_SERVICE_PORT}/testvhost"
CFRuntime::CloudApp.service_props('rabbit-test')[:vhost].should == "testvhost"
end
end
@@ -114,9 +112,9 @@
CFRuntime::CloudApp.service_props('rabbit-test')[:name].should == "rabbit-test"
CFRuntime::CloudApp.service_props('rabbit-test')[:host].should == SOME_SERVER
CFRuntime::CloudApp.service_props('rabbit-test')[:port].should == 25046
- CFRuntime::CloudApp.service_props('rabbit-test')[:username].should_not == nil
- CFRuntime::CloudApp.service_props('rabbit-test')[:password].should_not == nil
- CFRuntime::CloudApp.service_props('rabbit-test')[:url].should_not == nil
+ CFRuntime::CloudApp.service_props('rabbit-test')[:username].should == "rabbituser"
+ CFRuntime::CloudApp.service_props('rabbit-test')[:password].should == "rabbitpass"
+ CFRuntime::CloudApp.service_props('rabbit-test')[:url].should == "amqp://rabbituser:rabbitpass@#{SOME_SERVER}:#{SOME_SERVICE_PORT}"
CFRuntime::CloudApp.service_props('rabbit-test')[:vhost].should == '/'
end
end
View
73 cfruntime/spec/redis_spec.rb
@@ -0,0 +1,73 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+require 'cfruntime/redis'
+
+describe 'CFRuntime::RedisClient' do
+ include CFRuntime::Test
+
+ it 'creates a client with a Redis service by type and no additional options' do
+ svcs = {
+ "redis-#{redis_version}"=>[create_redis_service('redis-test')]}
+ with_vcap_services(svcs) do
+ redis = CFRuntime::RedisClient.create
+ redis.client.host.should == SOME_SERVER
+ redis.client.port.should == SOME_SERVICE_PORT
+ redis.client.password.should_not == nil
+ end
+ end
+
+ it 'creates a client with a Redis service by type and additional options' do
+ svcs = {
+ "redis-#{redis_version}"=>[create_redis_service('redis-test')]}
+ with_vcap_services(svcs) do
+ redis = CFRuntime::RedisClient.create({:timeout=>1})
+ redis.client.host.should == SOME_SERVER
+ redis.client.port.should == SOME_SERVICE_PORT
+ redis.client.password.should_not == nil
+ redis.client.timeout.should == 1
+ end
+ end
+
+ it 'creates a client with a Redis service by name and no additional options' do
+ svcs = {
+ "redis-#{redis_version}"=>[create_redis_service('redis-test')]}
+ with_vcap_services(svcs) do
+ redis = CFRuntime::RedisClient.create_from_svc('redis-test')
+ redis.client.host.should == SOME_SERVER
+ redis.client.port.should == SOME_SERVICE_PORT
+ redis.client.password.should_not == nil
+ end
+ end
+
+ it 'creates a client with a Redis service by name and additional options' do
+ svcs = {
+ "redis-#{redis_version}"=>[create_redis_service('redis-test')]}
+ with_vcap_services(svcs) do
+ redis = CFRuntime::RedisClient.create_from_svc('redis-test',:timeout=>1)
+ redis.client.host.should == SOME_SERVER
+ redis.client.port.should == SOME_SERVICE_PORT
+ redis.client.password.should_not == nil
+ redis.client.timeout.should == 1
+ end
+ end
+
+ it 'raises an ArgumentError if no service of Redis type found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::RedisClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of redis type, but found 0. Consider using create_from_svc(service_name) instead.')
+ end
+
+ it 'raises an ArgumentError if multiple services of Redis type found' do
+ svcs = {"redis-#{redis_version}"=>[create_redis_service('redis-test'),
+ create_redis_service('redis-test2')]}
+ with_vcap_services(svcs) do
+ expect{CFRuntime::RedisClient.create}.to raise_error(ArgumentError,
+ 'Expected 1 service of redis type, but found 2. Consider using create_from_svc(service_name) instead.')
+ end
+ end
+
+ it 'raises an ArgumentError if Redis service of specified name is not found' do
+ ENV['VCAP_SERVICES'] = nil
+ expect{CFRuntime::RedisClient.create_from_svc('nonexistent-redis')}.to raise_error(ArgumentError,
+ 'Service with name nonexistent-redis not found')
+ end
+end
View
30 cfruntime/spec/spec_helper.rb
@@ -1,4 +1,3 @@
-# Copyright (c) 2009-2011 VMware, Inc.
$:.unshift File.join(File.dirname(__FILE__), '..')
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
@@ -16,6 +15,7 @@ module Test
SOME_SERVER = '172.30.48.73'
SOME_PORT = 56789
+ SOME_SERVICE_PORT = 25046
def self.host
SOME_SERVER
@@ -77,6 +77,14 @@ def rabbit_version
"2.4"
end
+ def mysql_version
+ "0.3.11"
+ end
+
+ def postgres_version
+ "0.11.0"
+ end
+
def create_mongo_service(name)
create_service(name, "mongodb", mongo_version,"db")
end
@@ -85,29 +93,37 @@ def create_redis_service(name)
create_service(name, "redis", redis_version)
end
+ def create_mysql_service(name)
+ create_service(name, "mysql", mysql_version,nil,"mysqldatabase")
+ end
+
+ def create_postgres_service(name)
+ create_service(name, "postgresql", postgres_version,nil,"pgdatabase")
+ end
+
def create_rabbit_service(name, vhost=nil)
"{\"name\":\"#{name}\",\"label\":\"rabbitmq-#{rabbit_version}\"," +
"\"plan\":\"free\",\"tags\":[\"rabbitmq\",\"rabbitmq-#{rabbit_version}\"]," +
- "\"credentials\":{\"hostname\":\"#{SOME_SERVER}\",\"port\":25046,\"user\":\"#{secure_uuid}\"," +
+ "\"credentials\":{\"hostname\":\"#{SOME_SERVER}\",\"port\":#{SOME_SERVICE_PORT},\"user\":\"#{secure_uuid}\"," +
"\"pass\":\"#{secure_uuid}\",\"vhost\":\"#{vhost}\"}}"
end
def create_rabbit_srs_service(name, vhost=nil)
if vhost
- url = "amqp://#{secure_uuid}:#{secure_uuid}@#{SOME_SERVER}:25046/#{vhost}"
+ url = "amqp://rabbituser:rabbitpass@#{SOME_SERVER}:#{SOME_SERVICE_PORT}/#{vhost}"
else
- url = "amqp://#{secure_uuid}:#{secure_uuid}@#{SOME_SERVER}:25046"
+ url = "amqp://rabbituser:rabbitpass@#{SOME_SERVER}:#{SOME_SERVICE_PORT}"
end
"{\"name\":\"#{name}\",\"label\":\"rabbitmq-#{rabbit_version}\"," +
"\"plan\":\"free\",\"tags\":[\"rabbitmq\",\"rabbitmq-#{rabbit_version}\"]," +
"\"credentials\":{\"url\":\"#{url}\"}}"
end
- def create_service(name, type, version, db=nil)
+ def create_service(name, type, version, db=nil, cred_name=secure_uuid)
svc = "{\"name\":\"#{name}\",\"label\":\"#{type}-#{version}\",\"plan\":\"free\"," +
"\"tags\":[\"#{type}\",\"#{type}-#{version}\"],\"credentials\":{\"hostname\":\"#{SOME_SERVER}\"," +
- "\"host\":\"#{SOME_SERVER}\",\"port\":25046,\"username\":\"#{secure_uuid}\",\"password\":\"#{secure_uuid}\"," +
- "\"name\":\"#{secure_uuid}\""
+ "\"host\":\"#{SOME_SERVER}\",\"port\":#{SOME_SERVICE_PORT},\"username\":\"testuser\",\"password\":\"testpw\"," +
+ "\"name\":\"#{cred_name}\""
if db
svc = svc + ", \"db\":\"#{db}\""
end
Please sign in to comment.
Something went wrong with that request. Please try again.