зеркало из
1
0
Форкнуть 0
This commit is contained in:
Maciej Skierkowski 2012-07-06 15:59:00 -07:00
Родитель aaa44fda2b
Коммит fdd5326dca
17 изменённых файлов: 643 добавлений и 235 удалений

Просмотреть файл

@ -1,3 +1,37 @@
Run "rake" to run all tests.
# Azure Ruby SDK
Run "gem build azure.gemspec" to build gem.
## Generating documentation
Run the following command:
rake doc
This will generate the API documentation in the `./doc` directory.
## Running tests
In order to run the tests, run `rake`.
This will run all the unit tests, and then attempt to run the integration tests,
which need a real azure server running.
In order for the integration tests to run, you need the following ENV variables:
* `AZURE_ACCOUNT_NAME`: The name of the storage account you're using.
- If testing against the emulator, this must be `devstoreaccount1`
* `AZURE_ACCESS_KEY`: The Base64-encoded Access Key for your storage account.
- If testing against the emulator, this must be
`Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==`
* `AZURE_BLOB_HOST`: Pointing to the server running the Azure platform.
- If testing against the real thing: `http://<account-name>.blob.core.windows.net`
- If testing against the emulator: `http://localhost:10000/<account-name>`
* `AZURE_QUEUE_HOST`: Pointing to the server running the Azure platform.
- If testing against the real thing: `http://<account-name>.queue.core.windows.net`
- If testing against the emulator: `http://localhost:10001/<account-name>`
* `AZURE_TABLE_HOST`: Pointing to the server running the Azure platform.
- If testing against the real thing: `http://<account-name>.table.core.windows.net`
- If testing against the emulator: `http://localhost:10002/<account-name>`
* `AZURE_ACS_NAMESPACE`: a ServiceBus management namespace.
* `AZURE_SB_ACCESS_KEY`: The Base64-encoded Access Key for your ServiceBus
namespace.
* `AZURE_SB_ISSUER`: The name of the issuer for the ServiceBus. This should be `owner`

Просмотреть файл

@ -1,6 +1,10 @@
require "rake/testtask"
require "rubygems/package_task"
task :doc do
system "yard --plugin yard-tomdoc -o doc/ -"
end
gem_spec = eval(File.read("./azure.gemspec"))
Gem::PackageTask.new(gem_spec) do |pkg|
pkg.need_zip = false
@ -8,6 +12,21 @@ Gem::PackageTask.new(gem_spec) do |pkg|
end
namespace :test do
task :require_environment do
unset_environment = [
ENV.fetch("AZURE_ACCOUNT_NAME", nil),
ENV.fetch("AZURE_ACCESS_KEY", nil),
ENV.fetch("AZURE_TABLE_HOST", nil),
ENV.fetch("AZURE_BLOB_HOST", nil),
ENV.fetch("AZURE_QUEUE_HOST", nil),
ENV.fetch("AZURE_ACS_NAMESPACE", nil),
ENV.fetch("AZURE_SB_ACCESS_KEY", nil),
ENV.fetch("AZURE_SB_ISSUER", nil)
].include?(nil)
abort "[ABORTING] Configure your environment to run the integration tests" if unset_environment
end
Rake::TestTask.new :unit do |t|
t.pattern = "test/unit/**/*_test.rb"
t.verbose = true
@ -20,6 +39,8 @@ namespace :test do
t.libs = ["lib", "test"]
end
task :integration => :require_environment
namespace :integration do
def component_task(component)
Rake::TestTask.new component do |t|
@ -27,32 +48,17 @@ namespace :test do
t.verbose = true
t.libs = ["lib", "test"]
end
task component => "test:require_environment"
end
component_task :tables
component_task :blobs
component_task :queues
component_task :service_bus
task :conditionally do
name = ENV.fetch("AZURE_ACCOUNT_NAME", nil)
key = ENV.fetch("AZURE_ACCESS_KEY", nil)
t_host = ENV.fetch("AZURE_TABLE_HOST", nil)
b_host = ENV.fetch("AZURE_BLOB_HOST", nil)
q_host = ENV.fetch("AZURE_QUEUE_HOST", nil)
acs_namespace = ENV.fetch("AZURE_ACS_NAMESPACE", nil)
sb_access_key = ENV.fetch("AZURE_SB_ACCESS_KEY", nil)
sb_issuer = ENV.fetch("AZURE_SB_ISSUER", nil)
if name && key && t_host && b_host && q_host && acs_namespace && sb_access_key && sb_issuer
Rake::Task["test:integration"].invoke
else
warn "[WARNING] Configure your environment to run the integration tests"
end
end
end
Rake::TestTask.new :cleanup do |t|
task :cleanup => :require_environment do
$:.unshift "lib"
require 'azure'
@ -76,6 +82,6 @@ namespace :test do
end
end
task :test => ["test:unit", "test:integration:conditionally"]
task :test => ["test:unit", "test:integration"]
task default: :test

Просмотреть файл

@ -2,22 +2,20 @@ require "date"
Gem::Specification.new do |s|
s.name = "azure"
s.version = "0.1.1"
s.date = Date.today.iso8601
s.version = "0.1.0"
s.authors = ["AppFog","Microsoft"]
s.authors = ["Microsoft"]
s.email = "azure@microsoft.com"
s.description = "Services and ruby SDKs to access the Windows Azure platform."
s.summary = "Implementation of several Windows Azure SDKs in ruby."
s.homepage = "http://azure.com"
s.files = `git ls-files | grep -v "^examples/"`.split("\n")
s.files = `git ls-files`.split("\n")
s.add_runtime_dependency("uuid", "~> 2.0")
s.add_runtime_dependency("ratom", "~> 0.6")
s.add_runtime_dependency("nokogiri", "~> 1.5")
s.add_runtime_dependency("mime-types", "~> 1.0")
s.add_development_dependency("rake")
s.add_development_dependency("minitest", "~> 3.0")
s.add_development_dependency("em-minitest-spec")
s.add_development_dependency("yard")
s.add_development_dependency("yard-tomdoc")
end

Просмотреть файл

@ -1,170 +1,173 @@
require "atom"
require "time"
require "delegate"
require "nokogiri"
require "azure/tables/types"
module Azure
# Collection of XML::Node extensions for generating Atom feeds.
# Public: The Atom module includes functionality to generate and parse Atom
# feeds and entries.
module Atom
Entry = ::Atom::Entry
Feed = ::Atom::Feed
# Generates a Data Property, making sure that it's in the correct namespace
# (dataservices).
class Property < XML::Node
# Public: Set up the property.
# Convenience module so abstract the logic of generating XML. The objects
# that include this module must implement #as_xml, such that it returns a
# Nokogiri::XML::Node.
module Serializable
# Public: Convert this object into XML.
#
# name - The property name, without the namespace qualification.
# value - The property's value.
def initialize(name, value)
super("d:#{name}")
self << value
end
# Public: Set the property's value, and sets the content type based on the
# value's type.
#
# value - The value of the property.
#
# Returns self.
def <<(value)
self["m:type"] = Azure::Tables::Types.type_of(value)
super(value)
end
def to_xml(*)
self
# Returns a String.
def to_xml
as_xml.to_xml
end
end
# Represent a list of properties in the proper namespace
# (dataservices/metadata).
class PropertyList < XML::Node
include ::Atom::Xml::Parseable
# Public: An Atom Entry corresponds to a representation of a single object.
#
# In order to parse an entry's XML into a more manageable object, call
# Entry.parse.
#
# In order to generate an XML string from an entry, call #to_xml (included
# from Serializable).
class Entry
include Serializable
add_extension_namespace "d", "http://schemas.microsoft.com/ado/2007/08/dataservices"
# Public: Initialize the property list.
# Public: Parses a string of XML, returning a new Entry.
#
# Yields the PropertyList.
def initialize(o=nil)
super("m:properties")
# xml - A String of XML data.
#
# Returns an Atom::Entry.
def self.parse(xml)
doc = Nokogiri::XML(xml)
new do |entry|
entry.id = (doc % "id").text
entry.updated = Time.parse((doc % "updated").text)
entry.content = (doc % "content").inner_html
yield entry, doc if block_given?
end
end
if o && o.is_a?(LibXML::XML::Reader)
o.node.children.each do |node|
self << node.copy(true) unless node.blank?
# Public: Initializes the Entry.
#
# Yields the new Entry.
def initialize
yield self if block_given?
end
# Public: Get/Set the Entry's id.
attr_accessor :id
# Public: Get/Set the Entry's content.
attr_accessor :content
# Public: Get the Entry's updated-at Time (defaults to now).
def updated
@updated || Time.now
end
# Public: Set the Entry's updated-at Time.
attr_writer :updated
# Convert this object into an XML node that can be serialized.
#
# xml - A Nokogiri::XML::Builder to use as the parent node (optional).
#
# Returns a Nokogiri::XML::Node.
def as_xml(xml=Nokogiri::XML::Builder.new)
as_xml = ->(obj, parent) do
if obj.respond_to?(:as_xml)
obj.as_xml(parent)
else
obj.to_s
end
end
yield self if block_given?
end
xml.entry("xmlns" => "http://www.w3.org/2005/Atom",
"xmlns:m" => "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata",
"xmlns:d" => "http://schemas.microsoft.com/ado/2007/08/dataservices") do |xml|
xml.id(self.id)
xml.updated(self.updated.xmlschema)
xml.title
xml.author do |xml|
xml.name
end
# Public: Add several properties at the same time.
#
# properties - A Hash of property name => property value pairs.
#
# Returns the passed properties.
def merge(properties)
properties.each do |name, value|
self[name] = value
if content.respond_to?(:as_xml)
xml.content("type" => "application/xml") do |xml|
content.as_xml(xml)
end
else
xml.content(content, "type" => "application/xml")
end
end
end
# Public: Add a property to this list. This will internally store a
# Atom::Nodes::Property object.
#
# property - The name of the property to be included.
# value - The value of the property.
#
# Returns nothing.
def []=(property, value)
self << Property.new(property, value)
end
def to_xml(*)
self
xml
end
end
# Represent an entry's <content/> tag, ensuring it has the correct content
# type and that it conforms to the Atom::Content interface so it can be used
# seamlessly with Atom::Entry objects.
class Content < XML::Node
include ::Atom::Xml::Parseable
# Public: An Atom Feed is a list of Entries.
#
# In order to parse a feed's XML into a more manageable object, call
# Feed.parse.
#
# In order to generate an XML string from a feed, call #to_xml (included
# from Serializable).
class Feed
include Serializable
add_extension_namespace "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
# Get the Array of entries in this feed.
attr :entries
element "m:properties", class: Azure::Atom::PropertyList
# Public: Initialize the content node.
# Public: Parses a string of XML, returning a new Feed.
#
# Yields self.
def initialize(o=nil)
super("content")
self["type"] = "application/xml"
if o && o.is_a?(LibXML::XML::Reader)
o.read_inner_xml
o.read
parse o
# xml - A String of XML data.
#
# Returns an Atom::Feed.
def self.parse(xml, entry_parser=Entry)
doc = Nokogiri::XML(xml)
new do |feed|
feed.id = (doc % "id").text
feed.updated = Time.parse((doc % "updated").text)
(doc / "entry").each do |entry|
feed.entries << entry_parser.parse(entry.to_xml)
end
end
end
# Public: Initialize the Feed.
#
# Yields the Feed.
def initialize
@entries = []
yield self if block_given?
end
# Public: Cast this object into something Atom::Entry can understand as
# content. By returning itself (as a Node) the Entry won't try to escape
# this as CDATA.
# Public: Get/Set the Feed's id.
attr_accessor :id
# Public: Get the Feed's updated-at Time (defaults to now).
def updated
@updated || Time.now
end
# Public: Set the Feed's updated-at Time.
attr_writer :updated
# Convert this object into an XML node that can be serialized.
#
# Returns self.
def to_xml(*)
self
# xml - A Nokogiri::XML::Builder to use as the parent node (optional).
#
# Returns a Nokogiri::XML::Node.
def as_xml(xml=Nokogiri::XML::Builder.new)
xml.entry("xmlns" => "http://www.w3.org/2005/Atom",
"xmlns:m" => "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata",
"xmlns:d" => "http://schemas.microsoft.com/ado/2007/08/dataservices") do |xml|
xml.id(self.id)
xml.updated(self.updated.xmlschema)
xml.title
entries.each do |entry|
entry.as_xml(xml)
end
end
xml
end
end
end
end
# FIXME: The rAtom gem doesn't play well when you extend your classes, raising
# weird errors, so we're monkeypatching their classes. This *sucks*.
module Atom
# Public: An Atom feed, that understands the Microsoft ADO namespaces for Data
# services.
class Feed
add_extension_namespace "d", "http://schemas.microsoft.com/ado/2007/08/dataservices"
add_extension_namespace "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
end
# Public: An Atom entry, that understands the Microsoft ADO namespaces for Data
# services.
class Entry
add_extension_namespace "d", "http://schemas.microsoft.com/ado/2007/08/dataservices"
add_extension_namespace "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
element "content", class: Azure::Atom::Content
# Public: Generate a list of data properties to include in this Entry's
# content.
# FIXME: This method isn't very confident as getter, use content.m_properties instead.
#
# Yields a Nodes::PropertyList.
#
# Example:
#
# entry.properties do |props|
# props["one"] = 1
# props["two"] = 2
# end
#
# Returns the XML node for entry's <m_properties/>.
def properties(&block)
if !@content
@content = Azure::Atom::Content.new
@m_properties = Azure::Atom::PropertyList.new
@content << @m_properties
end
yield @m_properties if block_given?
@m_properties
end
end
end

Просмотреть файл

@ -181,6 +181,8 @@ module Azure
def self.get_messages(queue, options = {}, service = Azure::Queues::Services::GetMessages.new)
response = service.call(queue.name, options)
options[:visibility_timeout] = options.fetch(:visibility_timeout, 1)
# FIXME: need error handling
document = Nokogiri::XML(response.body)
(document / "//QueueMessagesList/QueueMessage").map do |node|

Просмотреть файл

@ -3,7 +3,7 @@ require "azure/tables/table"
require "azure/tables/entity"
require "azure/tables/entities_collection"
require "azure/tables/tables_collection"
require "azure/atom"
require "azure/tables/atom"
module Azure
module Tables
@ -15,7 +15,7 @@ module Azure
# Returns an Array of Table elements.
def self.all(query = {}, service=Azure::Tables::Services::QueryTables.new)
response = service.call(query)
feed = Atom::Feed.load_feed(response.body)
feed = Atom::Feed.parse(response.body)
collection = Azure::Tables::TablesCollection.from_entries(feed.entries, query)
collection.continuation_token(
@ -36,7 +36,7 @@ module Azure
response = service.call(name)
if response.success?
Table.from_entry(Atom::Entry.load_entry(response.body))
Table.from_entry(Atom::Entry.parse(response.body))
else
Table.from_error(response.error)
end
@ -54,7 +54,7 @@ module Azure
response = service.call(name)
if response.success?
Table.from_entry(Atom::Entry.load_entry(response.body))
Table.from_entry(Atom::Entry.parse(response.body))
else
Table.from_error(response.error)
end
@ -85,7 +85,7 @@ module Azure
if response.success?
entity.reset(
Entity.from_entry(Azure::Atom::Entry.load_entry(response.body))
Entity.from_entry(Atom::Entry.parse(response.body))
)
entity.etag = response.headers["etag"]
else
@ -181,7 +181,7 @@ module Azure
response = service.call(table.name, query)
if response.success?
Entity.from_entry(Azure::Atom::Entry.load_entry(response.body))
Entity.from_entry(Atom::Entry.parse(response.body))
else
nil
end
@ -199,7 +199,7 @@ module Azure
response = service.call(table.name, query)
if response.success?
feed = Atom::Feed.load_feed(response.body)
feed = Atom::Feed.parse(response.body)
collection = Azure::Tables::EntitiesCollection.from_entries(table, feed.entries, query)
collection.continuation_token(
response.headers["x-ms-continuation-nextpartitionkey"],

197
lib/azure/tables/atom.rb Normal file
Просмотреть файл

@ -0,0 +1,197 @@
require "azure/atom"
module Azure
module Tables
# Specific group of extensions to simplify working with entries as used in
# the Table Service. See Azure::Atom for more information.
module Atom
# A table's or entity's entry has a list of properties that represent the
# object in question.
class Entry < Azure::Atom::Entry
def self.parse(xml) # :nodoc:
super(xml) do |entry, doc|
doc.remove_namespaces!
props = doc % "properties"
entry.properties.merge(PropertyList.parse(props.to_xml))
end
end
def initialize(*) # :nodoc:
@properties = PropertyList.new
super
end
# Public: Get the list of properties from this Entry.
#
# Yields the list of properties.
#
# Returns the list of properties.
def properties
yield @properties if block_given?
@properties
end
# Public: Get the content of this entry. Defaults to its properties.
def content
@content ||= properties
end
end
class Feed < Azure::Atom::Feed # :nodoc:
def self.parse(xml, entry_parser=Tables::Atom::Entry)
super(xml, entry_parser)
end
end
# A PropertyList is a hash-like object that groups the meta-properties
# than an Entry can have.
#
# It represents an <m:properties/> tag.
class PropertyList
include Azure::Atom::Serializable
include Enumerable
# Public: Parses a string of XML, returning a new PropertyList.
#
# xml - A String of XML data.
#
# Returns a Tables::Atom::PropertyList.
def self.parse(xml)
doc = Nokogiri::XML(xml)
doc.remove_namespaces!
new do |list|
doc.root.children.reject(&:text?).each do |property|
p = Property.parse(property.to_xml)
list[property.name] = p
end
end
end
# Public: Initialize the PropertyList.
#
# Yields the new PropertyList.
def initialize
@properties = {}
yield self if block_given?
end
# Public: Iterate over every property.
#
# Yields each name/value pair.
#
# Returns the list of properties.
def each
@properties.each do |name, property|
yield name, property.value
end
self
end
# Public: Access the value of a property, cast into the corresponding
# type. See Azure::Table::Types.
#
# name - The name of the property.
#
# Returns the property's value.
def [](name)
@properties[name].value
end
# Public: Set the value of a property.
#
# name - The name of the property.
# value - The object with this property's value.
#
# Returns the property's value.
def []=(name, value)
value = Property.new(name, value) unless value.respond_to?(:value)
@properties[name] = value
end
# Public: Merge a hash of name/value pairs into this list of properties.
#
# props - A Hash.
#
# Returns the passed Hash.
def merge(props)
props.each do |name, value|
self[name] = value
end
end
# Public: Get the size of the PropertyList.
#
# Returns a Fixnum.
def size
@properties.size
end
# Convert this object into an XML node that can be serialized.
#
# xml - A Nokogiri::XML::Builder to use as the parent node (optional).
#
# Returns a Nokogiri::XML::Node.
def as_xml(xml=Nokogiri::XML::Builder.new)
xml.send("m:properties") do |xml|
@properties.values.each do |property|
property.as_xml(xml)
end
end
xml
end
end
# A Property represents a single field of information. It has a name, a
# value, and a type (inferred from the value using Azure::Tables::Types).
class Property
include Azure::Atom::Serializable
# Public: Parses a string of XML, returning a new PropertyList.
#
# xml - A String of XML data.
#
# Returns a Tables::Atom::PropertyList.
def self.parse(xml)
doc = Nokogiri::XML(xml)
doc.remove_namespaces!
prop = doc.root
value = Azure::Tables::Types.cast(prop.text, prop["type"])
new(prop.name, value)
end
# Get the property's name.
attr :name
# Get the property's value.
attr :value
# Public: Initialize the Property.
#
# name - The property's name.
# value - The property's value.
def initialize(name, value)
@name = name
@value = value
end
# Public: Get the type of this property. See Azure::Tables::Types.
#
# Returns a String.
def type
Azure::Tables::Types.type_of(value)
end
# Convert this object into an XML node that can be serialized.
#
# xml - A Nokogiri::XML::Builder to use as the parent node (optional).
#
# Returns a Nokogiri::XML::Node.
def as_xml(xml=Nokogiri::XML::Builder.new)
xml.send("d:#{name}", value, "m:type" => type)
xml
end
end
end
end
end

Просмотреть файл

@ -1,4 +1,3 @@
require "azure/tables/types"
require "azure/tables"
require "azure/error"
@ -13,7 +12,7 @@ module Azure
# Public: Returns an Entity from an Atom::Entry object.
#
# entry - Atom::Entry object representing the Entity.
# entry - Tables::Atom::Entry object representing the Entity.
#
# Returns Azure::Entity
def self.from_entry(entry)
@ -21,13 +20,8 @@ module Azure
entity.url = URI(entry.id)
entry.content.m_properties.each do |property_node|
value = Types.cast(
property_node.content,
property_node.attributes["type"]
)
entity[property_node.name] = value
entry.properties.each do |name, value|
entity[name] = value
end
entity

Просмотреть файл

@ -3,7 +3,7 @@ require "azure/core/utils/queryable"
require "azure/tables/auth/shared_key"
require "azure/tables/auth/shared_key_lite"
require "azure/tables/uri"
require "azure/atom"
require "azure/tables/atom"
module Azure
module Tables
@ -59,7 +59,7 @@ module Azure
#
# Returns a Response.
def call(table_name)
body = Atom::Entry.new do |entry|
body = Tables::Atom::Entry.new do |entry|
entry.properties["TableName"] = table_name
end
@ -89,7 +89,7 @@ module Azure
#
# Returns a Response.
def call(table_name, attributes)
body = Atom::Entry.new do |entry|
body = Tables::Atom::Entry.new do |entry|
entry.updated = Time.now.utc
entry.properties.merge(attributes)
end
@ -116,7 +116,7 @@ module Azure
attributes.fetch("RowKey")
)
body = Atom::Entry.new do |entry|
body = Tables::Atom::Entry.new do |entry|
entry.id = uri
entry.updated = Time.now.utc
entry.properties.merge(attributes)
@ -139,7 +139,7 @@ module Azure
#
# Returns a Response.
def call(uri, attributes, etag)
body = Atom::Entry.new do |entry|
body = Tables::Atom::Entry.new do |entry|
entry.id = uri
entry.updated = Time.now.utc
entry.properties.merge(attributes)

Просмотреть файл

@ -25,7 +25,7 @@ module Azure
#
# Returns a Table.
def self.from_entry(entry)
name = entry.content.m_properties.children.first.content
name = entry.properties["TableName"]
new(name, ::URI.parse(entry.id))
end

Просмотреть файл

@ -44,6 +44,8 @@ module Azure
Integer(serialized)
when "Edm.Boolean"
/true/i === serialized
when "Edm.Guid"
GUID.new(serialized.to_s)
else
serialized.to_s
end

Просмотреть файл

@ -0,0 +1,44 @@
class NameGenerator
def initialize(&cleanup_proc)
@cleanup_proc = cleanup_proc
@names = []
end
def name
alpha = ("a".."z").to_a
name = 10.times.map { alpha[Random.rand(alpha.size)]}.join
@names << name
name
end
def clean
@names.reject! do |name|
@cleanup_proc.call(name)
end
end
end
TableNameHelper = NameGenerator.new do |name|
table = Azure::Tables::Table.new(name)
Azure::Tables.delete(table)
end
ContainerNameHelper = NameGenerator.new do |name|
container = Azure::Blobs::Container.new(name)
container.delete
end
QueueNameHelper = NameGenerator.new do |name|
queue = Azure::Queues::Queue.new(name)
queue.delete
end
ServiceBusQueueNameHelper = NameGenerator.new do |name|
queue = Azure::ServiceBus::Queues::Queue.new(name)
queue.delete
end
ServiceBusTopicNameHelper = NameGenerator.new do |name|
topic = Azure::ServiceBus::Topics::Topic.new(name)
topic.delete
end

Просмотреть файл

@ -1,58 +1,112 @@
require "test_helper"
require "azure/atom"
describe "Generating Atom entries with property lists" do
it "lists the properties in the node" do
entry = Atom::Entry.new do |entry|
entry.properties do |props|
props["Prop1Name"] = "Prop1Value"
props["Prop2Name"] = "Prop2Value"
end
end
entry.properties.first.name.must_equal "d:Prop1Name"
entry.properties.first.content.must_equal "Prop1Value"
entry.properties.last.name.must_equal "d:Prop2Name"
entry.properties.last.content.must_equal "Prop2Value"
describe "Parsing Atom" do
let :entry_xml do
<<-XML
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://myaccount.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<id>http://myaccount.table.core.windows.net/Tables('mytable')</id>
<title type="text"></title>
<updated>2009-01-04T17:18:54.7062347Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Tables" href="Tables('mytable')" />
<category term="myaccount.Tables" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:TableName>mytable</d:TableName>
</m:properties>
</content>
</entry>
XML
end
it "can bulk-update a property list" do
entry = Atom::Entry.new do |entry|
entry.properties.merge(a: 1, b: 2, c: 3)
end
doc = XML::Parser.string(entry.to_xml).parse
doc.find("//d:a[text() = '1']").wont_be_empty
doc.find("//d:b[text() = '2']").wont_be_empty
doc.find("//d:c[text() = '3']").wont_be_empty
let :feed_xml do
<<-XML
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="http://myaccount.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<id>http://myaccount.table.core.windows.net/Tables</id>
<title type="text">Tables</title>
<updated>2009-01-04T17:18:54.7062347Z</updated>
<link rel="self" title="Tables" href="Tables" />
<entry>
<id>http://myaccount.table.core.windows.net/Tables('mytable')</id>
<title type="text"></title>
<updated>2009-01-04T17:18:54.7062347Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Tables" href="Tables('mytable')" />
<category term="myaccount.Tables" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:TableName>mytable</d:TableName>
</m:properties>
</content>
</entry>
</feed>
XML
end
it "can set properties in several ways" do
entry = Atom::Entry.new do |entry|
entry.properties["a"] = 1
entry.properties.merge(b: 2, c: 3)
entry.properties do |props|
props["d"] = 4
end
end
doc = XML::Parser.string(entry.to_xml).parse
doc.find("//d:a[text() = '1']").wont_be_empty
doc.find("//d:b[text() = '2']").wont_be_empty
doc.find("//d:c[text() = '3']").wont_be_empty
doc.find("//d:d[text() = '4']").wont_be_empty
let :feeds_entry_xml do
(Nokogiri::XML(feed_xml) % "entry").to_xml
end
it "generates properties with the given data type" do
node = Azure::Atom::Property.new("name", "value")
node["m:type"].must_equal "Edm.String"
it "parses an entry correctly" do
entry = Azure::Atom::Entry.parse(entry_xml)
entry.id.must_equal "http://myaccount.table.core.windows.net/Tables('mytable')"
entry.updated.must_equal Time.parse("2009-01-04T17:18:54.7062347Z")
entry.content.must_match /d:TableName/
end
it "generates properties with the given data name" do
node = Azure::Atom::Property.new("firstName", "value")
node.name.must_equal "d:firstName"
node = Azure::Atom::Property.new(:firstName, "value")
node.name.must_equal "d:firstName"
it "parses a feed correctly" do
feed = Azure::Atom::Feed.parse(feed_xml)
feed.id.must_equal "http://myaccount.table.core.windows.net/Tables"
feed.updated.must_equal Time.parse("2009-01-04T17:18:54.7062347Z")
feed.entries.size.must_equal 1
entry = feed.entries.first
entry.id.must_equal "http://myaccount.table.core.windows.net/Tables('mytable')"
end
it "chooses the entry parser when parsing feeds" do
entry = double()
parser = MiniTest::Mock.new
parser.expect(:parse, entry, [feeds_entry_xml])
feed = Azure::Atom::Feed.parse(feed_xml, parser)
parser.verify
end
end
describe "Generating Atom" do
class ComplexContent
def as_xml(xml)
xml.foo("bar")
xml
end
end
it "includes the content of the entry when it's a string" do
entry = Azure::Atom::Entry.new do |entry|
entry.content = "FooBar"
end
doc = Nokogiri::XML(entry.to_xml)
content = doc % "content"
content.text.must_equal "FooBar"
end
it "includes the content of the entry when it's an XML structure" do
entry = Azure::Atom::Entry.new do |entry|
entry.content = ComplexContent.new
end
doc = Nokogiri::XML(entry.to_xml)
foo_in_content = doc % "content > foo"
foo_in_content.text.must_equal "bar"
end
end

Просмотреть файл

@ -0,0 +1,74 @@
require "test_helper"
require "azure/tables/atom"
describe "Generating Atom entries with property lists" do
it "can set the properties one by one" do
entry = Azure::Tables::Atom::Entry.new do |entry|
entry.properties["name1"] = "value"
entry.properties["name2"] = "value"
end
entry.properties.size.must_equal 2
end
it "can set the properties by merging a hash" do
entry = Azure::Tables::Atom::Entry.new do |entry|
entry.properties.merge("name1" => "value", "name2" => "value")
end
entry.properties.size.must_equal 2
end
it "overrides a previous property with the same name" do
entry = Azure::Tables::Atom::Entry.new do |entry|
entry.properties["name"] = "value1"
entry.properties["name"] = "value2"
end
entry.properties.size.must_equal 1
entry.properties["name"].must_equal "value2"
end
it "can pass the properties as a block" do
entry = Azure::Tables::Atom::Entry.new do |entry|
entry.properties do |props|
props["Prop1Name"] = "Prop1Value"
props["Prop2Name"] = "Prop2Value"
end
end
entry.properties.size.must_equal 2
end
it "can be serialized to xml" do
entry = Azure::Tables::Atom::Entry.new do |entry|
entry.properties do |props|
props["name"] = "value"
end
end
doc = Nokogiri::XML(entry.to_xml)
prop = doc.xpath("//d:name", doc.collect_namespaces).first
prop.text.must_equal "value"
end
end
describe "Parsing property lists" do
let :property_list do
<<-XML
<m:properties xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<d:Foo>bar</d:Foo>
<d:Bar>baz</d:Bar>
<d:Number m:type="Edm.Int32">20</d:Number>
</m:properties>
XML
end
it "can parse a simple property list" do
list = Azure::Tables::Atom::PropertyList.parse(property_list)
list["Foo"].must_equal "bar"
list["Bar"].must_equal "baz"
end
it "will cast properties to the corresponding class" do
list = Azure::Tables::Atom::PropertyList.parse(property_list)
list["Number"].must_equal 20
end
end

Просмотреть файл

@ -11,7 +11,7 @@ describe Azure::Tables::EntitiesCollection do
before do
@table = Azure::Tables::Table.new("table_name")
entries = Azure::Atom::Feed.load_feed(Fixtures[:query_entities_response]).entries
entries = Azure::Tables::Atom::Feed.parse(Fixtures[:query_entities_response]).entries
@collection = Azure::Tables::EntitiesCollection.from_entries(@table, entries, {}, service)
end

Просмотреть файл

@ -3,7 +3,7 @@ require 'azure/tables/entity'
describe Azure::Tables::Entity do
before do
@entry = Azure::Atom::Entry.load_entry(Fixtures[:insert_entity_response_entry])
@entry = Azure::Tables::Atom::Entry.parse(Fixtures[:insert_entity_response_entry])
end
it "should be able to instantiate an entity from an xml entry" do

Просмотреть файл

@ -3,7 +3,7 @@ require "azure/tables/table"
describe Azure::Tables::Table do
def entry
Atom::Entry.load_entry(Fixtures[:create_table_response_entry])
Azure::Tables::Atom::Entry.parse(Fixtures[:create_table_response_entry])
end
it "can be instantiated from an entry" do