[ibm] Added Mocking and Tests

This commit is contained in:
Carl Hicks 2011-12-02 10:27:44 -08:00 committed by Decklin Foster
parent 402d42ced7
commit 019e536312
46 changed files with 1505 additions and 3 deletions

View File

@ -64,6 +64,7 @@ require 'fog/bin/ecloud'
require 'fog/bin/glesys'
require 'fog/bin/go_grid'
require 'fog/bin/google'
require 'fog/bin/ibm'
require 'fog/bin/joyent'
require 'fog/bin/libvirt'
require 'fog/bin/linode'

30
lib/fog/bin/ibm.rb Normal file
View File

@ -0,0 +1,30 @@
class IBM < Fog::Bin
class << self
def class_for(key)
case key
when :compute
Fog::Compute::IBM
else
raise ArgumentError, "Unsupported #{self} service: #{key}"
end
end
def [](service)
@@connections ||= Hash.new do |hash, key|
hash[key] = case key
when :compute
Fog::Compute.new(:provider => 'IBM')
else
raise ArgumentError, "Unrecognized service: #{service}"
end
end
@@connections[service]
end
def services
Fog::IBM.services
end
end
end

View File

@ -47,5 +47,126 @@ module Fog
end
end
class Mock
class << self
def id
Fog::Mock.random_numbers(7).to_i.to_s
end
alias :instance_id :id
alias :request_id :id
def primary_ip
{ "type" => 0, "ip" => Fog::IBM::Mock.ip_address, "hostname" => Fog::IBM::Mock.hostname }
end
def ip_address
ip = []
4.times do
ip << Fog::Mock.random_numbers(rand(3) + 1).to_i.to_s # remove leading 0
end
ip.join('.')
end
def hostname
"vhost" + Fog::Mock.random_numbers(3).to_i.to_s + ".fake.compute.ihost.com"
end
# Miliseconds since epoch
def launch_time
(Time.now.tv_sec * 1000).to_i
end
# 1 year from now, in miliseconds since epoch
def expiry_time
((Time.now.tv_sec + 31556926) * 1000).to_i
end
def owner
"user" + Fog::Mock.random_numbers(3).to_i.to_s + "@company.com"
end
def key_material
OpenSSL::PKey::RSA.generate(1024)
end
def private_image(name, description)
{
"name" => name,
"createdTime" => Fog::IBM::Mock.launch_time,
"productCodes"=> [],
"id" => Fog::IBM::Mock.instance_id,
"description" => description,
"visibility" => "PRIVATE",
"state" => 0
}
end
def create_instance(name, image_id, instance_type, location, public_key, options)
{
"name" => name,
"location" => location,
"keyName" => public_key,
"primaryIP" => Fog::IBM::Mock.primary_ip,
"productCodes" => [],
"requestId" => Fog::IBM::Mock.request_id,
"imageId" => image_id,
"launchTime" => Fog::IBM::Mock.launch_time,
"id" => Fog::IBM::Mock.instance_id,
"volumes" => [],
"root-only" => "false",
"instanceType" => instance_type,
"diskSize" => "60",
"requestName" => "",
"secondaryIP" => [],
"status" => 1,
"software" => [
{ "name"=>"SUSE Linux Enterprise Server",
"type"=>"OS",
"version"=>"11 SP1" }
],
"expirationTime"=> Fog::IBM::Mock.expiry_time,
"owner" => Fog::IBM::Mock.owner
}
end
def create_volume(name, format, location_id, size, offering_id)
{
"instanceId" => "0",
"state" => 1,
"size" => size,
"offeringId" => offering_id,
"ioPrice" => {
"rate" => 0.11,
"unitOfMeasure" => "CNT",
"countryCode" => "897",
"effectiveDate" => Fog::IBM::Mock.launch_time,
"currencyCode" => "USD",
"pricePerQuantity" => 1
},
"owner" => Fog::IBM::Mock.owner,
"createdTime" => Fog::IBM::Mock.launch_time,
"location" => location_id,
"productCodes"=> [],
"format" => format,
"name" => name,
"id" => Fog::IBM::Mock.id,
}
end
def create_address(location_id, offering_id, vlan_id)
# TODO: Figure out vlan handling
{
"id" => Fog::IBM::Mock.id,
"location" => location_id,
"offeringId"=> offering_id,
"ip" => "",
"state" => 0
}
end
end
end
end
end

View File

@ -81,8 +81,144 @@ module Fog
class Mock
def request(options)
Fog::Mock.not_implemented
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {
:instances => {},
:images => populate_images,
:keys => {},
:locations => populate_locations,
:private_keys => {},
:volumes => {},
:addresses => {}
}
end
end
def self.reset
@data = nil
end
def data
self.class.data[@ibm_user_id]
end
def reset_data
self.class.data.delete(@ibm_user_id)
@data = self.class.data[@ibm_user_id]
end
def initialize(options={})
@ibm_user_id = options[:ibm_user_id]
@ibm_password = options[:ibm_password]
@data = self.class.data[@ibm_user_id]
end
def self.populate_images
images = {}
images["20015393"] = {
"name"=>"SUSE Linux Enterprise Server 11 SP1 for x86 (TOR)",
"manifest"=>"https://www-147.ibm.com/cloud/enterprise/ram.ws/RAMSecure/artifact/{53575245-38D1-A40F-D8E0-8106DC68047D}/1.0/parameters.xml",
"state"=>1,
"visibility"=>"PUBLIC",
"owner"=>"SYSTEM",
"architecture"=>"i386",
"platform"=>"SUSE Linux Enterprise Server/11 SP1",
"createdTime"=>1296361572466,
"location"=>"101",
# HOLY METADATA BATMAN!
"supportedInstanceTypes"=>[
{"detail"=>"Silver - 32 bit (vCPU: 2, RAM: 4 GiB, Disk: 410 GiB)", "label"=>"Silver 32 bit",
"price"=>{"rate"=>0.2, "unitOfMeasure"=>"UHR", "countryCode"=>"897", "effectiveDate"=>1313107200000, "currencyCode"=>"USD", "pricePerQuantity"=>1}, "id"=>"SLV32.2/4096/60*350"},
{"detail"=>"Bronze - 32 bit (vCPU: 1, RAM: 2 GiB, Disk: 235 GiB)", "label"=>"Bronze 32 bit",
"price"=>{"rate"=>0.115, "unitOfMeasure"=>"UHR", "countryCode"=>"897", "effectiveDate"=>1313107200000, "currencyCode"=>"USD", "pricePerQuantity"=>1}, "id"=>"BRZ32.1/2048/60*175"},
{"detail"=>"Gold - 32 bit (vCPU: 4, RAM: 4 GiB, Disk: 410 GiB)", "label"=>"Gold 32 bit",
"price"=>{"rate"=>0.33, "unitOfMeasure"=>"UHR", "countryCode"=>"897", "effectiveDate"=>1313107200000, "currencyCode"=>"USD", "pricePerQuantity"=>1}, "id"=>"GLD32.4/4096/60*350"},
{"detail"=>"Copper - 32 bit (vCPU: 1, RAM: 2 GiB, Disk: 60 GiB)", "label"=>"Copper 32 bit",
"price"=>{"rate"=>0.095, "unitOfMeasure"=>"UHR", "countryCode"=>"897", "effectiveDate"=>1313107200000, "currencyCode"=>"USD", "pricePerQuantity"=>1}, "id"=>"COP32.1/2048/60"}],
"productCodes"=>["caondc1Sr7dKs9ARDmuPy6WPgV"],
"documentation"=>"https://www-147.ibm.com/cloud/enterprise/ram.ws/RAMSecure/artifact/{53575245-38D1-A40F-D8E0-8106DC68047D}/1.0/GettingStarted.html",
"id"=>"20015393",
"description"=>"Suse Linux 32 bit - for TOR datacenter"
}
images
end
def self.populate_locations
locations = {}
locations["41"] = {
"state"=>1,
"location"=>"RTP",
"capabilities"=>[
{"entries"=>{"EXT3"=>["ext3"], "RAW"=>["raw"]}, "id"=>"oss.storage.format"},
{"entries"=>{}, "id"=>"oss.instance.spec.i386"},
{"entries"=>{}, "id"=>"oss.instance.spec.x86_64"},
{"entries"=>{}, "id"=>"oss.storage.availabilityarea"}],
"name"=>"Raleigh, U.S.A",
"id"=>"41",
"description"=>"This data center is located in Raleigh, North Carolina, U.S.A. The services provided are: Guest Instances, Image Capture, Persistent Storage, Reserved IP, Private VLAN/VPN."
}
locations["61"] = {
"state"=>1,
"location"=>"EHN",
"capabilities"=>[
{"entries"=>{"EXT3"=>["ext3"], "RAW"=>["raw"]}, "id"=>"oss.storage.format"},
{"entries"=>{}, "id"=>"oss.instance.spec.i386"},
{"entries"=>{}, "id"=>"oss.instance.spec.x86_64"},
{"entries"=>{}, "id"=>"oss.storage.availabilityarea"}],
"name"=>"Ehningen, Germany",
"id"=>"61",
"description"=>"This data center is located in Ehningen(near Baden-Wurttemberg), Germany. The services provided are: Guest Instances, Image Capture, Persistent Storage, Reserved IP, Private VLAN/VPN."
}
locations["82"] = {
"state"=>1,
"location"=>"us-co-dc1",
"capabilities"=>[
{"entries"=>{"EXT3"=>["ext3"], "RAW"=>["raw"]}, "id"=>"oss.storage.format"},
{"entries"=>{}, "id"=>"oss.instance.spec.i386"},
{"entries"=>{}, "id"=>"oss.instance.spec.x86_64"},
{"entries"=>{}, "id"=>"oss.storage.availabilityarea"}],
"name"=>"Boulder1, U.S.A",
"id"=>"82",
"description"=>"This data center is located in Boulder(near Denver), Colorado, U.S.A. The services provided are: Guest Instances, Image Capture, Persistent Storage, Reserved IP, Private VLAN/VPN."
}
locations["101"] = {
"state"=>1,
"location"=>"ca-on-dc1",
"capabilities"=>[
{"entries"=>{"EXT3"=>["ext3"], "RAW"=>["raw"]}, "id"=>"oss.storage.format"},
{"entries"=>{}, "id"=>"oss.instance.spec.i386"},
{"entries"=>{}, "id"=>"oss.instance.spec.x86_64"},
{"entries"=>{}, "id"=>"oss.storage.availabilityarea"}],
"name"=>"Markham, Canada",
"id"=>"101",
"description"=>"This data center is located in Markham(near Toronto), Ontario, Canada. The services provided are: Guest Instances, Image Capture, Persistent Storage, Reserved IP, Private VLAN/VPN."
}
locations["121"] = {
"state"=>1,
"location"=>"ap-jp-dc1",
"capabilities"=>[
{"entries"=>{"EXT3"=>["ext3"], "RAW"=>["raw"]}, "id"=>"oss.storage.format"},
{"entries"=>{}, "id"=>"oss.instance.spec.i386"},
{"entries"=>{}, "id"=>"oss.instance.spec.x86_64"},
{"entries"=>{}, "id"=>"oss.storage.availabilityarea"}],
"name"=>"Makuhari, Japan",
"id"=>"121",
"description"=>"This data center is located in Makuhari(near Tokoyo), Japan. The services provided are: Guest Instances, Image Capture, Persistent Storage, Reserved IP, Private VLAN/VPN."
}
locations["141"] = {
"state"=>1,
"location"=>"ap-sg-dc1",
"capabilities"=>[
{"entries"=>{"EXT3"=>["ext3"], "RAW"=>["raw"]}, "id"=>"oss.storage.format"},
{"entries"=>{}, "id"=>"oss.instance.spec.i386"},
{"entries"=>{}, "id"=>"oss.instance.spec.x86_64"},
{"entries"=>{}, "id"=>"oss.storage.availabilityarea"}],
"name"=>"Singapore, Singapore",
"id"=>"141",
"description"=>"This data center is located in Singapore. The services provided are: Guest Instances, Image Capture, Persistent Storage, Reserved IP, Private VLAN/VPN."
}
locations
end
end

View File

@ -22,6 +22,22 @@ module Fog
end
end
class Mock
def clone_image(image_id, name, description)
response = Excon::Response.new
if image_exists? image_id
id = Fog::IBM::Mock.instance_id
self.data[:images][id] = self.data[:images][image_id].dup
response.status = 200
response.body = { "ImageID" => id }
else
response.status = 404
end
response
end
end
end
end
end

View File

@ -23,6 +23,19 @@ module Fog
end
end
class Mock
def create_address(location_id, offering_id="20001223", vlan_id=nil)
address = Fog::IBM::Mock.create_address(location_id, offering_id, vlan_id)
self.data[:addresses][address['id']] = address
response = Excon::Response.new
response.status = 200
response.body = address
response
end
end
end
end
end

View File

@ -22,6 +22,23 @@ module Fog
end
end
class Mock
def create_image(instance_id, name, description)
response = Excon::Response.new
if instance_exists? instance_id
image = Fog::IBM::Mock.private_image(name, description)
self.data[:images][image["id"]] = image
response.status = 200
response.body = image
else
response.status = 404
end
response
end
end
end
end
end

View File

@ -32,6 +32,26 @@ module Fog
end
end
class Mock
def create_instance(name="fog instance", image_id="20018425", instance_type="COP32.1/2048/60", location="101", public_key="fog", options={})
response = Excon::Response.new
# Since we want to test error conditions, we have a little regex that traps specially formed
# instance type strings.
case name
when /FAIL:\ (\d{3})/
response.status = $1
else
instance = Fog::IBM::Mock.create_instance(name, image_id, instance_type, location, public_key, options)
self.data[:instances][instance['id']] = instance
response.status = 200
response.body = {"instances" => [ instance ]}
end
response
end
end
end
end
end

View File

@ -22,6 +22,33 @@ module Fog
end
end
class Mock
# SmartCloud returns the private key when create_key is called
# We need to store both the private and public key for later use
def create_key(name, public_key=nil)
response = Excon::Response.new
response.status = 200
attributes = {
"keyName" => name,
"lastModifiedTime" => Fog::IBM::Mock.launch_time,
"default" => false,
"instanceIds" => [],
}
if public_key.nil?
private_key = Fog::IBM::Mock.key_material
public_key = private_key.public_key
public_key = { "keyMaterial" => public_key.to_s }.merge(attributes.dup)
self.data[:keys][name] = public_key
private_key = { "keyMaterial" => private_key.to_s }.merge(attributes.dup)
self.data[:private_keys][name] = private_key
response.body = private_key
end
response
end
end
end
end
end

View File

@ -18,6 +18,26 @@ module Fog
end
end
class Mock
def delete_address(address_id)
response = Excon::Response.new
if address_exists? address_id
self.data[:addresses].delete address_id
response.status = 200
response.body = { "success" => true }
else
response.status = 404
end
response
end
def address_exists?(address_id)
self.data[:addresses].key? address_id
end
end
end
end
end

View File

@ -18,6 +18,23 @@ module Fog
end
end
class Mock
def delete_image(image_id)
response = Excon::Response.new
# TODO: We should probably check that an image is deleteable.
# i.e. that the user has appropriate permissions
if image_exists? image_id
self.data[:images].delete image_id
response.status = 200
response.body = {"success"=>true}
else
response.status = 404
end
response
end
end
end
end
end

View File

@ -18,6 +18,31 @@ module Fog
end
end
class Mock
def delete_instance(instance_id)
response = Excon::Response.new
if deleteable? instance_id
# remove from memoreeeez.
self.data[:instances].delete instance_id
response.status = 200
else
# TODO: we should really return a 412 if the instance is in an invalid state, and a 404 if it doesn't exist.
response.status = 404
end
response
end
# we can't delete the instance if it doesn't exist, or is in an invalid state.
def deleteable?(instance_id)
return false unless instance_exists? instance_id
instance = self.data[:instances][instance_id]
return false if [0, 1, 7, 14, 15].include?(instance["status"].to_i)
true
end
end
end
end
end

View File

@ -18,6 +18,21 @@ module Fog
end
end
class Mock
def delete_key(key_name)
response = Excon::Response.new
if key_exists? key_name
self.data[:keys].delete(key_name)
response.status = 200
response.body = {"success"=>true}
else
response.status = 404
end
response
end
end
end
end
end

View File

@ -18,6 +18,27 @@ module Fog
end
end
class Mock
def get_image(image_id)
response = Excon::Response.new
if image_exists? image_id
response.status = 200
response.body = self.data[:images][image_id]
else
response.status = 404
end
response
end
private
def image_exists?(image_id)
self.data[:images].key? image_id
end
end
end
end
end

View File

@ -18,6 +18,41 @@ module Fog
end
end
class Mock
# TODO: Fix this so they work.
def get_image_agreement(image_id)
response = Excon::Response.new
response.status = 200
response.body = {"text"=>
"test, operating system is SUSE Linux Enterprise Server/11 SP1 - English\n\nYour access to and use of the Service, including all selected options, are governed by the terms of the Agreement signed between your Enterprise and IBM. Each Service is also governed by one or more Attachments (including, for example, Image Terms Attachments). Applicable Attachments are part of the Agreement between you and IBM and include Attachments for Services you acquire after the Agreement was signed. The Agreement also references applicable IBM and third party end user license agreements that govern the use of IBM software and operating system software provided as part of an Image.\n\nYou are responsible for complying with the terms of the Agreement (including applicable Attachments) and applicable license agreements. You may review the terms for the Service by 1) obtaining information regarding the Agreement from your Account Administrator and 2) accessing the Asset Catalog to review specific Image Terms and end user license agreements for IBM and third party software provided as part of an Image. ",
"id"=>"20020159",
"attachments"=>
[{"label"=>"Service Description for Developement & Test Service",
"url"=>
"https://www-147.ibm.com/cloud/enterprise/static/internal_user_agreement.pdf",
"type"=>0},
{"label"=>"Smart Business on the IBM Public Cloud Agreement",
"url"=>
"https://www-147.ibm.com/cloud/enterprise/static/internal_user_agreement.pdf",
"type"=>1},
{"label"=>
"End User License for SUSE 10.2 Linux Enterprise Server software",
"url"=>
"https://www.novell.com/licensing/eula/sles_10/sles_10_english.pdf",
"type"=>2},
{"label"=>
"End User License for SUSE 11.0 Linux Enterprise Server software",
"url"=>"https://www.novell.com/licensing/eula/sles_11/sles_11_en.pdf",
"type"=>2},
{"label"=>"End User License for RedHat Linux RHEL software",
"url"=>"https://www.redhat.com/licenses/",
"type"=>2}]}
response
end
end
end
end
end

View File

@ -18,6 +18,19 @@ module Fog
end
end
class Mock
# TODO: Create a data store for this.
def get_image_manifest(image_id)
response = Excon::Response.new
response.status = 200
response.body = {"manifest"=>
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><parameters xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"platform:/resource/com.ibm.ccl.devcloud.client/schema/parameters.xsd\">\n\t<firewall>\n\t\t<rule>\n\t\t\t<source>0.0.0.0/0</source>\n\t\t\t<minport>1</minport>\n\t\t\t<maxport>65535</maxport>\n\t\t</rule>\n\t</firewall>\n</parameters>"}
response
end
end
end
end
end

View File

@ -18,6 +18,37 @@ module Fog
end
end
class Mock
def get_instance(instance_id)
response = Excon::Response.new
if instance_exists? instance_id
activate_instance(instance_id) # Set it to Active if it's not running
response.status = 200
response.body = self.data[:instances][instance_id]
else
response.status = 404
end
response
end
# Checks if an instance exists
def instance_exists?(instance_id)
self.data[:instances].key? instance_id
end
# Sets instance status to Active if it's not already set.
def activate_instance(instance_id)
self.data[:instances][instance_id]["status"] = 5 unless instance_active? instance_id
end
# Checks if an instance is Active
def instance_active?(instance_id)
self.data[:instances][instance_id]["status"] == 5
end
end
end
end
end

View File

@ -18,6 +18,25 @@ module Fog
end
end
class Mock
def get_key(key_name)
response = Excon::Response.new
if key_exists? key_name
response.status = 200
response.body = self.data[:keys][key_name]
else
response.status = 404
end
response
end
def key_exists?(name)
self.data[:keys].key? name
end
end
end
end
end

View File

@ -18,6 +18,25 @@ module Fog
end
end
class Mock
def get_location(location_id)
response = Excon::Response.new
if location_exists? location_id
response.status = 200
response.body = self.data[:locations][location_id]
else
response.status = 404
end
response
end
def location_exists?(location_id)
self.data[:locations].key? location_id
end
end
end
end
end

View File

@ -22,6 +22,37 @@ module Fog
end
class Mock
def get_request(request_id)
response = Excon::Response.new
response.status = 200
response.body = {"instances"=>
[{"name"=>"test from fog",
"location"=>"101",
"keyName"=>"mykey",
"primaryIP"=>
{"type"=>0, "ip"=>"42.42.42.42 ", "hostname"=>"42.42.42.42 "},
"productCodes"=>[],
"requestId"=>"75364",
"imageId"=>"20020159",
"launchTime"=>1304012220770,
"id"=>"75064",
"volumes"=>[],
"instanceType"=>"SLV32.2/4096/60*350",
"requestName"=>"test from fog",
"secondaryIP"=>[],
"status"=>1,
"software"=>
[{"name"=>"SUSE Linux Enterprise Server",
"type"=>"OS",
"version"=>"11 SP1"}],
"expirationTime"=>1367084229205,
"owner"=>"user@example.com"}]}
response
end
end
end
end
end

View File

@ -21,6 +21,27 @@ module Fog
end
end
class Mock
def list_address_offerings
response = Excon::Response.new
response.status = 200
response.body = {"addresses"=>
[{"price"=>
{"pricePerQuantity"=>1,
"effectiveDate"=>1302566400000,
"rate"=>0.01,
"countryCode"=>"897",
"unitOfMeasure"=>"UHR",
"currencyCode"=>"USD"},
"location"=>"101",
"ipType"=>0,
"id"=>"20001223"}]}
response
end
end
end
end
end

View File

@ -18,6 +18,17 @@ module Fog
end
end
class Mock
def list_locations
response = Excon::Response.new
response.status = 200
response.body = { "locations" => self.data[:locations].values }
response
end
end
end
end
end

View File

@ -19,6 +19,24 @@ module Fog
end
end
class Mock
def list_vlans
response = Excon::Response.new
response.status = 200
response.body = {"addresses"=>
[{"location"=>"101",
"mode"=>0,
"offeringId"=>"20001223",
"id"=>"75321",
"type"=>1,
"ip"=>"170.224.192.210 ",
"hostname"=>"170.224.192.210 ",
"state"=>2}]},
response
end
end
end
end
end

View File

@ -17,6 +17,41 @@ module Fog
:body => options
)
end
end
class Mock
def modify_instance(instance_id, options={})
response = Excon::Response.new
if params['state'] = 'restart'
if instance_exists? instance_id
self.data[:instances][instance_id]["status"] = "8"
self.data[:instances][instance_id]["keyName"] = key_name
response.status = 200
response.body = { "success" => true }
else
response.status = 404
end
elsif params['type'] == 'attach' || params['type'] == 'detach'
if (instance_exists?(instance_id) && volume_exists?(volume_id))
# TODO: Update the instance in the data hash, assuming IBM ever gets this feature working properly.
response.status = 415
else
response.status = 404
end
elsif params['name']
if instance_exists?(instance_id)
self.data[:instances][instance_id]["name"] = name
response.status = 200
response.body = { "success" => true }
else
response.status = 404
end
else
Fog::Mock.not_implemented
end
response
end
end
end

View File

@ -19,6 +19,26 @@ module Fog
end
end
class Mock
def modify_key(key_name, params={})
response = Excon::Response.new
if params['public_key']
if key_exists? key_name
self.data[:keys][key_name]['keyMaterial'] = public_key
self.data[:keys][key_name]['lastModifiedTime'] = Fog::IBM::Mock.launch_time,
response.status = 200
response.body = {"success"=>true}
else
response.status = 404
end
else
Fog::Mock.not_implemented
end
response
end
end
end
end
end

View File

@ -23,6 +23,18 @@ module Fog
}
)
end
end
class Mock
def create_volume(name, offering_id, format, location_id, size)
volume = Fog::IBM::Mock.create_volume(name, format, location_id, size, offering_id)
self.data[:volumes][volume['id']] = volume
response = Excon::Response.new
response.status = 200
response.body = format_get_volume_response_for(volume['id'])
response
end
end
end

View File

@ -18,6 +18,22 @@ module Fog
end
end
class Mock
def delete_volume(volume_id)
response = Excon::Response.new
if volume_exists? volume_id
self.data[:volumes].delete volume_id
response.status = 200
response.body = {"success"=>true}
else
response.status = 404
end
response
end
end
end
end
end

View File

@ -18,6 +18,53 @@ module Fog
end
end
class Mock
# For whatever reason, get_volume returns different data than an entry in list_volumes
def get_volume(volume_id)
response = Excon::Response.new
if volume_exists? volume_id
response.status = 200
response.body = format_get_volume_response_for(volume_id)
else
response.status = 404
end
response
end
# get_volume response doesn't contain instanceId
def format_get_volume_response_for(volume_id)
# If we aren't attached/ready, make us ready
ready_volume(volume_id) unless volume_attached? volume_id
self.data[:volumes][volume_id].reject { |k,v| k == 'instanceId' }
end
# The list_volumes response doesn't contain ioPrice
def format_list_volumes_response
self.data[:volumes].values.dup.map { |volume| volume.reject { |k,v| k == 'ioPrice'} }
end
def volume_exists?(volume_id)
self.data[:volumes].key? volume_id
end
# Checks if an volume is Active
def volume_ready?(volume_id)
self.data[:volumes][volume_id]['state'] == 4
end
def volume_attached?(volume_id)
self.data[:volumes][volume_id]['instanceId'] != "0"
end
# Sets volume status to Detached if it's not already set, and or attached
def ready_volume(volume_id)
# If not ready, make ready
self.data[:volumes][volume_id]['state'] = 4
end
end
end
end
end

View File

@ -19,6 +19,43 @@ module Fog
end
end
class Mock
def list_offerings
response = Excon::Response.new
response.status = 200
response.body = {"volumes"=>
[{"name"=>"Small",
"price"=>
{"pricePerQuantity"=>1,
"effectiveDate"=>-1,
"rate"=>0.0384,
"countryCode"=>"897",
"unitOfMeasure"=>"UHR",
"currencyCode"=>"USD"},
"location"=>"61",
"id"=>"20001208",
"formats"=>
[{"label"=>"ext3", "id"=>"EXT3"}, {"label"=>"raw", "id"=>"RAW"}],
"capacity"=>256},
{"name"=>"Small",
"price"=>
{"pricePerQuantity"=>1,
"effectiveDate"=>-1,
"rate"=>0.0384,
"countryCode"=>"897",
"unitOfMeasure"=>"UHR",
"currencyCode"=>"USD"},
"location"=>"141",
"id"=>"20001208",
"formats"=>
[{"label"=>"ext3", "id"=>"EXT3"}, {"label"=>"raw", "id"=>"RAW"}],
"capacity"=>256}]},
response
end
end
end
end
end

View File

@ -19,6 +19,17 @@ module Fog
end
end
class Mock
def list_volumes
response = Excon::Response.new
response.status = 200
response.body = { 'volumes' => format_list_volumes_response }
response
end
end
end
end
end

View File

@ -22,6 +22,10 @@ def compute_providers
:glesys => {
:mocked => false
},
:ibm => {
:server_attributes => {},
:mocked => true
},
:joyent => {
:mocked => false
},

View File

@ -12,7 +12,7 @@ def array_differences(array_a, array_b)
end
# check to see which credentials are available and add others to the skipped tags list
all_providers = ['aws', 'bluebox', 'brightbox', 'dnsimple', 'dnsmadeeasy', 'dynect', 'ecloud', 'glesys', 'gogrid', 'google', 'joyent', 'linode', 'local', 'ninefold', 'baremetalcloud', 'openstack', 'ovirt', 'rackspace', 'slicehost', 'stormondemand', 'voxel', 'vsphere', 'zerigo']
all_providers = ['aws', 'bluebox', 'brightbox', 'dnsimple', 'dnsmadeeasy', 'dynect', 'ecloud', 'glesys', 'gogrid', 'google', 'ibm', 'joyent', 'linode', 'local', 'ninefold', 'baremetalcloud', 'openstack', 'ovirt', 'rackspace', 'slicehost', 'stormondemand', 'voxel', 'vsphere', 'zerigo']
available_providers = Fog.available_providers.map {|provider| provider.downcase}
for provider in (all_providers - available_providers)
Formatador.display_line("[yellow]Skipping tests for [bold]#{provider}[/] [yellow]due to lacking credentials (add some to '~/.fog' to run them)[/]")

View File

@ -30,6 +30,8 @@ if Fog.mock?
:go_grid_shared_secret => 'go_grid_shared_secret',
:google_storage_access_key_id => 'google_storage_access_key_id',
:google_storage_secret_access_key => 'google_storage_secret_access_key',
:ibm_user_id => 'ibm_user_id',
:ibm_password => 'ibm_password',
:joyent_username => "joyentuser",
:joyent_password => "joyentpass",
:linode_api_key => 'linode_api_key',

View File

@ -0,0 +1,10 @@
Shindo.tests('Fog::Compute[:ibm] | image', ['ibm']) do
@image_id = "20015393"
@image = Fog::Compute[:ibm].images.get(@image_id)
tests('success') do
end
end

View File

@ -0,0 +1,23 @@
Shindo.tests('Fog::Compute[:ibm] | key', ['ibm']) do
tests('success') do
@key_name = "fog test key"
@key = nil
tests("Fog::Compute::IBM::Key.new('#{@key_name}')") do
@key = Fog::Compute[:ibm].keys.new({:name => @key_name})
returns(true) { @key.save }
end
tests("Fog::Compute::IBM::Key#instances") do
returns([]) { @key.instances }
end
tests('Fog::Compute::IBM::Key#destroy') do
returns(true) { @key.destroy }
end
end
end

View File

@ -0,0 +1,35 @@
Shindo.tests('Fog::Compute[:ibm] | keys', ['ibm']) do
tests('success') do
@key_name = "fog test key"
@key = nil
tests("Fog::Compute[:ibm].keys.create('#{@key_name}')") do
@key = Fog::Compute[:ibm].keys.create(@key_name)
returns(@key_name) { @key.name }
end
tests('Fog::Compute[:ibm].keys') do
returns(true) { Fog::Compute[:ibm].keys.length > 0 }
end
tests("Fog::Compute[:ibm].keys.default = '#{@key_name}'") do
returns(@key_name) { Fog::Compute[:ibm].keys.default = @key_name }
end
tests("Fog::Compute[:ibm].keys.default") do
@key = Fog::Compute[:ibm].keys.get(@key_name)
returns(@key.name) { Fog::Compute[:ibm].keys.default.name }
end
tests("Fog::Compute[:ibm].keys.get('#{@key_name}')") do
key = Fog::Compute[:ibm].keys.get(@key_name)
returns(@key_name) { key.name }
end
@key.destroy
end
end

View File

@ -0,0 +1,18 @@
Shindo.tests('Fog::Compute[:ibm] | locations', ['ibm']) do
tests('success') do
@location_id = "101"
tests('Fog::Compute[:ibm].locations') do
returns(true) { Fog::Compute[:ibm].locations.length > 0 }
end
tests('Fog::Compute[:ibm].locations.get("#{@location_id}")') do
@location = Fog::Compute[:ibm].locations.get(@location_id)
returns(@location_id) { @location.id }
end
end
end

View File

@ -0,0 +1,78 @@
Shindo.tests('Fog::Compute[:ibm] | server', ['ibm']) do
tests('success') do
# TODO: Fix this for non-mock tests
@server = nil
@instance_id = nil
@name = "Fog Test Instance"
@image_id = "20015393"
@instance_type = "BRZ32.1/2048/60*175"
@location_id = "101"
@key_name = "test"
tests('Fog::Compute::IBM::Server.new') do
@server = Fog::Compute[:ibm].servers.new(
:name => @name,
:image_id => @image_id,
:instance_type => @instance_type,
:location_id => @location,
:key_name => @key_name
)
returns(@name) { @server.name }
end
tests('Fog::Compute::IBM::Server#save') do
returns(true) { @server.save }
returns(String) { @server.id.class }
@instance_id = @server.id
end
tests('Fog::Compute::IBM::Server#wait_for { ready? }') do
Fog::Compute[:ibm].servers.get(@instance_id).wait_for { ready? }
@server = Fog::Compute[:ibm].servers.last
end
tests('Fog::Compute::IBM::Server#id') do
returns(@instance_id) { @server.id }
end
tests('Fog::Compute::IBM::Server#ready?') do
returns(true) { @server.ready? }
end
tests('Fog::Compute::IBM::Server#status') do
returns("Active") { @server.status }
end
tests('Fog::Compute::IBM::Server#reboot') do
returns(true) { @server.reboot }
end
tests('Fog::Compute::IBM::Server#rename("name")') do
name = @server.name + "-rename"
returns(true) { @server.rename(name) }
returns(name) { @server.name }
end
tests('Fog::Compute::IBM::Server#image') do
returns(@image_id) { @server.image.id }
end
tests('Fog::Compute::IBM::Server#to_image') do
data = @server.to_image(:name => @server.name)
returns(@server.name) { data['name'] }
returns(true) { Fog::Compute[:ibm].delete_image(data['id']).body['success'] }
end
tests('Fog::Compute::IBM::Server#expire!') do
returns(true) { @server.expire! }
end
tests('Fog::Compute::IBM::Server#destroy') do
returns(true) { @server.destroy }
end
end
end

View File

@ -0,0 +1,19 @@
Shindo.tests('Fog::Compute[:ibm] | servers', ['ibm']) do
tests('success') do
@instance_id = Fog::Compute[:ibm].create_instance.body["instances"][0]["id"]
@server = nil
tests('Fog::Compute[:ibm].servers') do
returns(1) { Fog::Compute[:ibm].servers.length }
end
tests('Fog::Compute[:ibm].servers.get("#{@instance_id}")') do
@server = Fog::Compute[:ibm].servers.get(@instance_id)
returns(@instance_id) { @server.id }
end
end
end

View File

@ -0,0 +1,59 @@
Shindo.tests('Fog::Compute[:ibm] | volume', ['ibm']) do
tests('success') do
@volume = nil
@volume_id = nil
@name = "fog test volume"
@format = "raw"
@location_id = "101"
@size = "256"
@offering_id = "20001208"
tests('Fog::Compute::IBM::Volume.new') do
@volume = Fog::Compute[:ibm].volumes.new(
:name => @name,
:format => @image_id,
:location_id => @location_id,
:size => @size,
:offering_id => @offering_id
)
returns(@name) { @volume.name }
end
tests('Fog::Compute::IBM::Volume#save') do
returns(true) { @volume.save }
returns(String) { @volume.id.class }
@volume_id = @volume.id
end
tests("Fog::Compute::IBM::Volume#instance") do
returns(nil) { @volume.instance }
end
tests("Fog::Compute::IBM::Volume#location") do
returns(Fog::Compute::IBM::Location) { @volume.location.class }
end
tests('Fog::Compute::IBM::Volume#id') do
returns(@volume_id) { @volume.id }
end
tests('Fog::Compute::IBM::Volume#ready?') do
# We do a "get" to advance the state if we are mocked.
# TODO: Fix this for real connections
Fog::Compute[:ibm].get_volume(@volume_id)
returns(true) { @volume.ready? }
end
tests('Fog::Compute::IBM::Volume#status') do
returns("Detached") { @volume.status }
end
tests('Fog::Compute::IBM::Volume#destroy') do
returns(true) { @volume.destroy }
end
end
end

View File

@ -0,0 +1,41 @@
Shindo.tests('Fog::Compute[:ibm] | address requests', ['ibm']) do
@address_format = {
"state" => Integer,
"offeringId"=> String,
"location" => String,
"ip" => String,
"id" => String,
"mode" => Integer,
"hostname" => String,
"type" => Integer
}
# create_address doesn't return mode, hostname or type attributes
@create_address_format = @address_format.reject { |k,v| ["mode", "hostname", "type"].include? k }
# list_address returns everything
@list_address_format = { 'addresses' => [ @address_format ] }
@address_id = nil
@location_id = "101"
@offering_id = "20001223"
tests('success') do
tests("#create_address('#{@location_id}')").formats(@create_address_format) do
data = Fog::Compute[:ibm].create_address(@location_id).body
@address_id = data['id']
data
end
tests("#list_addresses").formats(@list_address_format) do
Fog::Compute[:ibm].list_addresses.body
end
tests("#delete_address('#{@address_id}')") do
returns(true) { Fog::Compute[:ibm].delete_address(@address_id).body['success'] }
end
end
end

View File

@ -0,0 +1,101 @@
Shindo.tests('Fog::Compute[:ibm] | image requests', ['ibm']) do
@image_format = {
'state' => Integer,
'visibility' => String,
'platform' => String,
'architecture' => String,
'owner' => String,
'createdTime' => Integer,
'location' => String,
'productCodes' => Array,
'name' => String,
'id' => String,
'description' => String,
'supportedInstanceTypes' => Array,
'manifest' => String,
'documentation' => String
}
# TODO: Actually check this format
@product_code_format = {
'detail' => String,
'label' => String,
'price' => @price_format,
'id' => String
}
# TODO: Actually check this format
@price_format = {
'rate' => Float,
'unitOfMeasure' => String,
'effectiveDate' => Integer,
'currencyCode' => String,
'pricePerQuantity' => Integer
}
@images_format = {
'images' => [ @image_format ]
}
@create_image_format = {
"name" => String,
"createdTime" => Integer,
"productCodes"=> Array,
"id" => String,
"description" => String,
"visibility" => String,
"state" => Integer
}
@instance_id = nil
@name = "fog test image instance"
@image_id = "20015393"
@instance_type = "BRZ32.1/2048/60*175"
@location = "101"
@public_key = "test"
@id = nil
@cloned_id = nil
@image_name = "fog test create image"
tests('success') do
tests("#list_images").formats(@images_format) do
Fog::Compute[:ibm].list_images.body
end
tests('#get_image').formats(@image_format) do
Fog::Compute[:ibm].get_image("20015393").body
end
tests('#create_image').formats(@create_image_format) do
response = Fog::Compute[:ibm].create_instance(
@name,
@image_id,
@instance_type,
@location,
@public_key,
@options
).body
@instance_id = response['instances'][0]['id']
data = Fog::Compute[:ibm].create_image(@instance_id, @image_name, "").body
@id = data['id']
data
end
tests('#clone_image') do
data = Fog::Compute[:ibm].clone_image(@image_id, "fog test clone image", "").body
@cloned_id = data['ImageID']
returns(String) { data['ImageID'].class }
end
tests('#delete_image') do
returns(true) { Fog::Compute[:ibm].delete_image(@id).body['success'] }
returns(true) { Fog::Compute[:ibm].delete_image(@cloned_id).body['success'] }
end
end
end

View File

@ -0,0 +1,87 @@
Shindo.tests('Fog::Compute[:ibm] | instance requests', ['ibm']) do
@instance_format = {
'name' => String,
'location' => String,
'keyName' => String,
'primaryIP' => {
'type' => Integer,
'ip' => String,
'hostname' => String,
},
'productCodes' => Array,
'requestId' => String,
'imageId' => String,
'launchTime' => Integer,
'id' => String,
'volumes' => Array,
'root-only' => String,
'instanceType' => String,
'diskSize' => String,
'requestName' => String,
'secondaryIP' => Array,
'status' => Integer,
'software' => Array,
'expirationTime'=> Integer,
'owner' => String
}
@instances_format = {
'instances' => [ @instance_format ]
}
tests('success') do
@instance_id = nil
@name = "fog test instance"
@image_id = "20018425"
@instance_type = "COP32.1/2048/60"
@location = "101"
@public_key = "test"
@expiration_time= (Time.now.tv_usec + 10000).to_f * 1000
@options = {}
tests("#create_instance('#{@name}', '#{@image_id}', '#{@instance_type}', '#{@location}', '#{@public_key}', options)").formats(@instances_format) do
response = Fog::Compute[:ibm].create_instance(@name, @image_id, @instance_type, @location, @public_key, @options).body
@instance_id = response['instances'][0]['id']
response
end
tests("#get_instance('#{@instance_id}')").formats(@instance_format) do
response = Fog::Compute[:ibm].get_instance(@instance_id).body
end
Fog::Compute[:ibm].servers.get(@instance_id).wait_for { ready? }
tests("#list_instances").formats(@instances_format) do
instances = Fog::Compute[:ibm].list_instances.body
end
tests("#restart_instance('#{@instance_id}', '#{@public_key}')") do
returns(true) { Fog::Compute[:ibm].restart_instance(@instance_id, @public_key).body["success"] }
end
tests("#rename_instance('#{@instance_id}', '#{@name} 2')") do
returns(true) { Fog::Compute[:ibm].rename_instance(@instance_id, @name + " 2").body["success"] }
end
tests("#set_instance_expiration('#{@instance_id}', '#{@expiration_time}')") do
returns(@expiration_time) { Fog::Compute[:ibm].set_instance_expiration(@instance_id, @expiration_time).body["expirationTime"] }
end
tests("#delete_instance('#{@instance_id}')") do
data = Fog::Compute[:ibm].delete_instance(@instance_id)
end
end
tests('failures') do
tests('#create_instance => 401') do
response = Fog::Compute[:ibm].create_instance("FAIL: 401", "123456", "12345", "101", "invalid")
returns("401") { response.status }
end
end
end

View File

@ -0,0 +1,57 @@
Shindo.tests('Fog::Compute[:ibm] | key requests', ['ibm']) do
@key_format = {
'default' => Fog::Boolean,
'instanceIds' => Array,
'keyMaterial' => String,
'keyName' => String,
'lastModifiedTime' => Integer
}
@keys_format = {
'keys' => [ @key_format ]
}
tests('success') do
@key_name = "fog test key"
@public_key = <<-EOF
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAL2nePLzDy1Z2Y64/Dz5QMmJN4S9xc6D8TbiKVe5YHeuNt3fCSYDJl9x
d/V5r2mUo4nGrEhum1ooX0rdk5CPugVxd3Tgovj87y3NRw9zAdeCB8omfrRwG4yu
x1z+ejqX1BSKYy+KvOT2RKiuLdIiodLsps5epovQFZmlymTIg/ODAgMBAAE=
-----END RSA PUBLIC KEY-----
EOF
@public_key.gsub!(/^\s{4}/, '')
tests("#create_key('#{@key_name}')").formats(@key_format) do
Fog::Compute[:ibm].create_key(@key_name).body
end
tests("#list_keys").formats(@keys_format) do
Fog::Compute[:ibm].list_keys.body
end
tests("#get_key('#{@key_name}')").formats(@key_format) do
Fog::Compute[:ibm].get_key(@key_name).body
end
tests("#set_default_key('#{@key_name}')") do
returns(@key_name) { Fog::Compute[:ibm].set_default_key(@key_name).body }
end
tests("#update_key('#{@key_name}', '#{@public_key}')") do
returns(true) { Fog::Compute[:ibm].update_key(@key_name, @public_key).body['success'] }
end
tests("#delete_key('#{@key_name}')") do
returns(true) { Fog::Compute[:ibm].delete_key(@key_name).body['success'] }
end
tests("#upload_key('#{@key_name}', '#{@public_key}')") do
returns(true) { Fog::Compute[:ibm].upload_key(@key_name, @public_key).body['success'] }
end
end
end

View File

@ -0,0 +1,28 @@
Shindo.tests('Fog::Compute[:ibm] | location requests', ['ibm']) do
@location_format = {
'state' => Integer,
'location' => String,
'capabilities' => Array,
'name' => String,
'id' => String,
'description' => String
}
@locations_format = {
'locations' => [ @location_format ]
}
tests('success') do
tests("#list_locations").formats(@locations_format) do
Fog::Compute[:ibm].list_locations.body
end
tests('#get_locations').formats(@location_format) do
Fog::Compute[:ibm].get_location("101").body
end
end
end

View File

@ -0,0 +1,85 @@
Shindo.tests('Fog::Compute[:ibm] | volume requests', ['ibm']) do
@combined_volume_format = {
"id" => String,
"instanceId" => String,
"name" => String,
"format" => String,
"state" => Integer,
"size" => String,
"offeringId" => String,
"owner" => String,
"createdTime" => Integer,
"location" => String,
"productCodes" => Array,
"ioPrice" => {
"rate" => Float,
"unitOfMeasure" => String,
"countryCode" => String,
"effectiveDate" => Integer,
"currencyCode" => String,
"pricePerQuantity" => Integer,
}
}
@volumes_format = {
'volumes' => [ @combined_volume_format.reject { |k,v| k == "ioPrice" } ]
}
@volume_format = @combined_volume_format.reject { |k,v| k == "instanceId" }
tests('success') do
@volume_id = nil
@name = "fog test volume"
@format = "raw"
@location_id = "101"
@size = "256"
@offering_id = "20001208"
@instance_id = nil
@image_id = "20015393"
@instance_type = "BRZ32.1/2048/60*175"
@location = "101"
@public_key = "test"
tests("#create_volume('#{@name}', '#{@format}', '#{@location_id}', '#{@size}', '#{@offering_id}')").formats(@volume_format) do
data = Fog::Compute[:ibm].create_volume(@name, @format, @location_id, @size, @offering_id).body
@volume_id = data['id']
data
end
tests("#list_volumes").formats(@volumes_format) do
Fog::Compute[:ibm].list_volumes.body
end
tests("#get_volume('#{@volume_id}')").formats(@volume_format) do
Fog::Compute[:ibm].get_volume(@volume_id).body
end
tests("#attach_volume('#{@instance_id}','#{@volume_id}')") do
@instance_id = Fog::Compute[:ibm].create_instance(
"fog test volume instance",
@image_id,
@instance_type,
@location,
@public_key,
@options
).body['instances'][0]['id']
# TODO: Add assertions for this whenever it is properly supported
Fog::Compute[:ibm].attach_volume(@instance_id, @volume_id)
end
tests("#detach_volume('#{@instance_id}','#{@volume_id}')") do
# TODO: Add assertions for this whenever it is properly supported
Fog::Compute[:ibm].detach_volume(@instance_id, @volume_id)
Fog::Compute[:ibm].delete_instance(@instance_id)
end
tests("#delete_volume('#{@volume_id}')") do
returns(true) { Fog::Compute[:ibm].delete_volume(@volume_id).body['success'] }
end
end
end