omf_common 6.0.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +10 -0
- data/lib/omf_common/comm.rb +9 -0
- data/lib/omf_common/command.rb +33 -0
- data/lib/omf_common/core_ext/blather/dsl/pubsub.rb +11 -0
- data/lib/omf_common/core_ext/blather/dsl.rb +8 -0
- data/lib/omf_common/core_ext/blather/stanza/registration.rb +18 -0
- data/lib/omf_common/core_ext/string.rb +13 -0
- data/lib/omf_common/dsl/xmpp_blather.rb +99 -0
- data/lib/omf_common/message.rb +118 -0
- data/lib/omf_common/protocol.rnc +42 -0
- data/lib/omf_common/protocol.rng +141 -0
- data/lib/omf_common/version.rb +4 -0
- data/lib/omf_common.rb +19 -0
- data/omf_common.gemspec +26 -0
- data/test/omf_common/comm_spec.rb +17 -0
- data/test/omf_common/command_spec.rb +14 -0
- data/test/omf_common/core_ext/string_spec.rb +16 -0
- data/test/omf_common/message_spec.rb +85 -0
- data/test/test_helper.rb +9 -0
- metadata +132 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module OmfCommon::Command
|
4
|
+
# Execute a system command and use Open3 to capture exit status, stdout, stderr
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# OmfRc::Command.execute("uname -a")
|
9
|
+
def self.execute(*cmd, &block)
|
10
|
+
result = nil
|
11
|
+
begin
|
12
|
+
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
|
13
|
+
case wait_thread.value.exitstatus
|
14
|
+
when 0
|
15
|
+
# Exit status 0, all good, read stdout
|
16
|
+
result = stdout.read.chomp
|
17
|
+
when 1
|
18
|
+
# Exit status 1, log minor error as warning
|
19
|
+
logger.warn stderr.read.chomp
|
20
|
+
when 2
|
21
|
+
# Exit status 2, log standard error
|
22
|
+
logger.error stderr.read.chomp
|
23
|
+
else
|
24
|
+
# Exit status greater than 2, log fatal error
|
25
|
+
logger.fatal stderr.read.chomp
|
26
|
+
end
|
27
|
+
end
|
28
|
+
rescue Errno::ENOENT => e
|
29
|
+
logger.fatal e.message
|
30
|
+
end
|
31
|
+
result
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Blather
|
2
|
+
module DSL
|
3
|
+
class PubSub
|
4
|
+
def create_with_configuration(node, configuration, host = nil)
|
5
|
+
stanza = Stanza::PubSub::Create.new(:set, send_to(host), node)
|
6
|
+
stanza.configure_node << configuration
|
7
|
+
request(stanza) { |n| yield n if block_given? }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'blather/stanza/iq'
|
2
|
+
|
3
|
+
module Blather
|
4
|
+
class Stanza
|
5
|
+
class Registration < Iq
|
6
|
+
def self.new(username, password)
|
7
|
+
node = super :set
|
8
|
+
Nokogiri::XML::Builder.with(node) do |xml|
|
9
|
+
xml.query('xmlns' => 'jabber:iq:register') do
|
10
|
+
xml.username username
|
11
|
+
xml.password password
|
12
|
+
end
|
13
|
+
end
|
14
|
+
node
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
def ducktype
|
3
|
+
Integer(self) rescue Float(self) rescue self
|
4
|
+
end
|
5
|
+
|
6
|
+
def camelcase
|
7
|
+
self.split('_').map(&:capitalize).join('')
|
8
|
+
end
|
9
|
+
|
10
|
+
def constant
|
11
|
+
self.split('::').inject(Object) { |obj, name| obj = obj.const_get(name); obj }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'blather/client/dsl'
|
2
|
+
require 'omf_common/core_ext/blather/dsl'
|
3
|
+
require 'omf_common/core_ext/blather/dsl/pubsub'
|
4
|
+
require 'omf_common/core_ext/blather/stanza/registration'
|
5
|
+
|
6
|
+
module OmfCommon
|
7
|
+
module DSL
|
8
|
+
module XmppBlather
|
9
|
+
include Blather::DSL
|
10
|
+
|
11
|
+
PUBSUB_CONFIGURE = Blather::Stanza::X.new({
|
12
|
+
:type => :submit,
|
13
|
+
:fields => [
|
14
|
+
{ :var => "FORM_TYPE", :type => 'hidden', :value => "http://jabber.org/protocol/pubsub#node_config" },
|
15
|
+
{ :var => "pubsub#persist_items", :value => "0" },
|
16
|
+
{ :var => "pubsub#max_items", :value => "0" },
|
17
|
+
{ :var => "pubsub#notify_retract", :value => "0" },
|
18
|
+
{ :var => "pubsub#publish_model", :value => "open" }]
|
19
|
+
})
|
20
|
+
|
21
|
+
# Set up XMPP options and start the Eventmachine, connect to XMPP server
|
22
|
+
#
|
23
|
+
def connect(username, password, server)
|
24
|
+
jid = "#{username}@#{server}"
|
25
|
+
client.setup(jid, password)
|
26
|
+
client.run
|
27
|
+
end
|
28
|
+
|
29
|
+
# Shut down XMPP connection
|
30
|
+
#
|
31
|
+
# @param [String] host Host represents the pubsub address, e.g. pubsub.norbit.npc.nicta.com.au
|
32
|
+
def disconnect(host)
|
33
|
+
shutdown
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a new pubsub node with additional configuration
|
37
|
+
#
|
38
|
+
# @param [String] node Pubsub node name
|
39
|
+
# @param [String] host Pubsub host address
|
40
|
+
def create_node(node, host, &block)
|
41
|
+
pubsub.create_with_configuration(node, PUBSUB_CONFIGURE, host, &callback_logging(__method__, node, &block))
|
42
|
+
end
|
43
|
+
|
44
|
+
# Delete a pubsub node
|
45
|
+
#
|
46
|
+
# @param [String] node Pubsub node name
|
47
|
+
# @param [String] host Pubsub host address
|
48
|
+
def delete_node(node, host, &block)
|
49
|
+
pubsub.delete(node, host, &callback_logging(__method__, node, &block))
|
50
|
+
end
|
51
|
+
|
52
|
+
# Subscribe to a pubsub node
|
53
|
+
#
|
54
|
+
# @param [String] node Pubsub node name
|
55
|
+
# @param [String] host Pubsub host address
|
56
|
+
def subscribe(node, host, &block)
|
57
|
+
pubsub.subscribe(node, nil, host, &callback_logging(__method__, node, &block))
|
58
|
+
end
|
59
|
+
|
60
|
+
# Un-subscribe all existing subscriptions from all pubsub nodes.
|
61
|
+
#
|
62
|
+
# @param [String] host Pubsub host address
|
63
|
+
def unsubscribe(host)
|
64
|
+
pubsub.subscriptions(host) do |m|
|
65
|
+
m[:subscribed] && m[:subscribed].each do |s|
|
66
|
+
pubsub.unsubscribe(s[:node], nil, s[:subid], host, &callback_logging(__method__, s[:node], s[:subid]))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Publish to a pubsub node
|
72
|
+
#
|
73
|
+
# @param [String] node Pubsub node name
|
74
|
+
# @param [String] message Any XML fragment to be sent as payload
|
75
|
+
# @param [String] host Pubsub host address
|
76
|
+
def publish(node, message, host, &block)
|
77
|
+
pubsub.publish(node, message, host, &callback_logging(__method__, node, message.operation, &block))
|
78
|
+
end
|
79
|
+
|
80
|
+
# Event callback for pubsub node event(item published)
|
81
|
+
#
|
82
|
+
def node_event(*args, &block)
|
83
|
+
pubsub_event(:items?, *args, &callback_logging(__method__, &block))
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# Provide a new block wrap to automatically log errors
|
89
|
+
def callback_logging(*args, &block)
|
90
|
+
m = args.empty? ? "OPERATION" : args.map {|v| v.to_s.upcase }.join(" ")
|
91
|
+
proc do |callback|
|
92
|
+
logger.error callback if callback.respond_to?(:error?) && callback.error?
|
93
|
+
logger.debug "#{m} SUCCEED" if callback.respond_to?(:result?) && callback.result?
|
94
|
+
block.call(callback) if block
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'niceogiri'
|
2
|
+
require 'hashie'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
module OmfCommon
|
7
|
+
# Refer to resource life cycle, instance methods are basically construct & parse XML fragment
|
8
|
+
#
|
9
|
+
# @example To create a valid omf message, e.g. a 'configure' message:
|
10
|
+
#
|
11
|
+
# Message.request do |message|
|
12
|
+
# message.property('os', 'debian')
|
13
|
+
# message.property('memory', 2) do |p|
|
14
|
+
# p.element('unit', 'gb')
|
15
|
+
# end
|
16
|
+
# end.sign
|
17
|
+
#
|
18
|
+
class Message < Niceogiri::XML::Node
|
19
|
+
OMF_NAMESPACE = "http://schema.mytestbed.net/#{OmfCommon::PROTOCOL_VERSION}/protocol"
|
20
|
+
SCHEMA_FILE = "#{File.dirname(__FILE__)}/protocol.rng"
|
21
|
+
OPERATION = %w(create configure request release inform)
|
22
|
+
|
23
|
+
class << self
|
24
|
+
OPERATION.each do |operation|
|
25
|
+
define_method(operation) do |*args, &block|
|
26
|
+
xml = new(operation, nil, OMF_NAMESPACE)
|
27
|
+
xml.element('context_id', operation == 'inform' ? args[0] : SecureRandom.uuid)
|
28
|
+
xml.element('publish_to', args[0]) if operation == 'request'
|
29
|
+
xml.element('inform_type', args[1]) if operation == 'inform'
|
30
|
+
block.call(xml) if block
|
31
|
+
xml
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse(xml)
|
36
|
+
xml_root = Nokogiri::XML(xml).root
|
37
|
+
new(xml_root.element_name, nil, xml_root.namespace.href).inherit(xml_root)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def property(key, value = nil, &block)
|
42
|
+
key_node = Message.new('property')
|
43
|
+
key_node.write_attr('key', key)
|
44
|
+
add_child(key_node)
|
45
|
+
if block
|
46
|
+
key_node.element('value', value) if value
|
47
|
+
block.call(key_node)
|
48
|
+
else
|
49
|
+
key_node.content = value if value
|
50
|
+
end
|
51
|
+
key_node
|
52
|
+
end
|
53
|
+
|
54
|
+
# Generate SHA1 of canonicalised xml and write into the ID attribute of the message
|
55
|
+
#
|
56
|
+
def sign
|
57
|
+
write_attr('msg_id', OpenSSL::Digest::SHA1.new(canonicalize)) if read_attr('id').nil? || read_attr('id').empty?
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def valid?
|
62
|
+
validation = Nokogiri::XML::RelaxNG(File.open(SCHEMA_FILE)).validate(document)
|
63
|
+
if validation.empty?
|
64
|
+
true
|
65
|
+
else
|
66
|
+
logger.error validation.map(&:message).join("\n")
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def element(key, value)
|
72
|
+
key_node = Niceogiri::XML::Node.new(key)
|
73
|
+
key_node.content = value
|
74
|
+
add_child(key_node)
|
75
|
+
end
|
76
|
+
|
77
|
+
# The root element_name represents operation
|
78
|
+
#
|
79
|
+
def operation
|
80
|
+
element_name.to_sym
|
81
|
+
end
|
82
|
+
|
83
|
+
def element_by_xpath_with_default_namespace(xpath_without_ns)
|
84
|
+
xpath(xpath_without_ns.gsub(/(\/+)(\w+)/, '\1xmlns:\2'), :xmlns => OMF_NAMESPACE)
|
85
|
+
end
|
86
|
+
|
87
|
+
# In case you think method :element_by_xpath_with_default_namespace is too long
|
88
|
+
#
|
89
|
+
alias_method :read_element, :element_by_xpath_with_default_namespace
|
90
|
+
|
91
|
+
# We just want to know the content of an non-repeatable element
|
92
|
+
#
|
93
|
+
def read_content(element_name)
|
94
|
+
read_element("//#{element_name}").first.content rescue nil
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get a property by key
|
98
|
+
#
|
99
|
+
# @param [String] key name of the property element
|
100
|
+
# @return [Object] the content of the property, as string, integer, float, or mash(hash with indifferent access)
|
101
|
+
#
|
102
|
+
def read_property(key)
|
103
|
+
key = key.to_s
|
104
|
+
e = read_element("//property[@key='#{key}']").first
|
105
|
+
if e
|
106
|
+
if e.children.size == 1
|
107
|
+
e.content.ducktype
|
108
|
+
else
|
109
|
+
Hashie::Mash.new.tap do |mash|
|
110
|
+
e.element_children.each do |child|
|
111
|
+
mash[child.element_name] ||= child.content.ducktype
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
default namespace = "http://schema.mytestbed.net/6.0/protocol"
|
2
|
+
|
3
|
+
element (create | configure) {
|
4
|
+
attribute msg_id { text },
|
5
|
+
element context_id { text },
|
6
|
+
element property {
|
7
|
+
(attribute key { text } | element key { text }),
|
8
|
+
(attribute type { text } | element type { text })?,
|
9
|
+
(element value { text } | text),
|
10
|
+
element unit { text }?,
|
11
|
+
element precision { text }?
|
12
|
+
}*
|
13
|
+
} |
|
14
|
+
element request {
|
15
|
+
attribute msg_id { text },
|
16
|
+
element context_id { text },
|
17
|
+
element publish_to { text }?,
|
18
|
+
element property {
|
19
|
+
(attribute key { text } | element key { text }),
|
20
|
+
element min_value { text }?,
|
21
|
+
element max_value { text }?
|
22
|
+
}*
|
23
|
+
} |
|
24
|
+
element inform {
|
25
|
+
attribute msg_id { text },
|
26
|
+
element context_id { text },
|
27
|
+
element inform_type { "CREATED" | "FAILED" | "STATUS" | "RELEASED" },
|
28
|
+
element resource_id { text }?,
|
29
|
+
element resource_address { text }?,
|
30
|
+
element error_message { text }?,
|
31
|
+
element property {
|
32
|
+
(attribute key { text } | element key { text }),
|
33
|
+
element current { text },
|
34
|
+
element target { text }?,
|
35
|
+
element msg { text }?,
|
36
|
+
element progress { text }?
|
37
|
+
}*
|
38
|
+
} |
|
39
|
+
element release {
|
40
|
+
attribute msg_id { text },
|
41
|
+
element context_id { text }
|
42
|
+
}
|
@@ -0,0 +1,141 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<choice ns="http://schema.mytestbed.net/6.0/protocol" xmlns="http://relaxng.org/ns/structure/1.0">
|
3
|
+
<element>
|
4
|
+
<choice>
|
5
|
+
<name>create</name>
|
6
|
+
<name>configure</name>
|
7
|
+
</choice>
|
8
|
+
<attribute name="msg_id"/>
|
9
|
+
<element name="context_id">
|
10
|
+
<text/>
|
11
|
+
</element>
|
12
|
+
<zeroOrMore>
|
13
|
+
<element name="property">
|
14
|
+
<choice>
|
15
|
+
<attribute name="key"/>
|
16
|
+
<element name="key">
|
17
|
+
<text/>
|
18
|
+
</element>
|
19
|
+
</choice>
|
20
|
+
<optional>
|
21
|
+
<choice>
|
22
|
+
<attribute name="type"/>
|
23
|
+
<element name="type">
|
24
|
+
<text/>
|
25
|
+
</element>
|
26
|
+
</choice>
|
27
|
+
</optional>
|
28
|
+
<choice>
|
29
|
+
<element name="value">
|
30
|
+
<text/>
|
31
|
+
</element>
|
32
|
+
<text/>
|
33
|
+
</choice>
|
34
|
+
<optional>
|
35
|
+
<element name="unit">
|
36
|
+
<text/>
|
37
|
+
</element>
|
38
|
+
</optional>
|
39
|
+
<optional>
|
40
|
+
<element name="precision">
|
41
|
+
<text/>
|
42
|
+
</element>
|
43
|
+
</optional>
|
44
|
+
</element>
|
45
|
+
</zeroOrMore>
|
46
|
+
</element>
|
47
|
+
<element name="request">
|
48
|
+
<attribute name="msg_id"/>
|
49
|
+
<element name="context_id">
|
50
|
+
<text/>
|
51
|
+
</element>
|
52
|
+
<optional>
|
53
|
+
<element name="publish_to">
|
54
|
+
<text/>
|
55
|
+
</element>
|
56
|
+
</optional>
|
57
|
+
<zeroOrMore>
|
58
|
+
<element name="property">
|
59
|
+
<choice>
|
60
|
+
<attribute name="key"/>
|
61
|
+
<element name="key">
|
62
|
+
<text/>
|
63
|
+
</element>
|
64
|
+
</choice>
|
65
|
+
<optional>
|
66
|
+
<element name="min_value">
|
67
|
+
<text/>
|
68
|
+
</element>
|
69
|
+
</optional>
|
70
|
+
<optional>
|
71
|
+
<element name="max_value">
|
72
|
+
<text/>
|
73
|
+
</element>
|
74
|
+
</optional>
|
75
|
+
</element>
|
76
|
+
</zeroOrMore>
|
77
|
+
</element>
|
78
|
+
<element name="inform">
|
79
|
+
<attribute name="msg_id"/>
|
80
|
+
<element name="context_id">
|
81
|
+
<text/>
|
82
|
+
</element>
|
83
|
+
<element name="inform_type">
|
84
|
+
<choice>
|
85
|
+
<value>CREATED</value>
|
86
|
+
<value>FAILED</value>
|
87
|
+
<value>STATUS</value>
|
88
|
+
<value>RELEASED</value>
|
89
|
+
</choice>
|
90
|
+
</element>
|
91
|
+
<optional>
|
92
|
+
<element name="resource_id">
|
93
|
+
<text/>
|
94
|
+
</element>
|
95
|
+
</optional>
|
96
|
+
<optional>
|
97
|
+
<element name="resource_address">
|
98
|
+
<text/>
|
99
|
+
</element>
|
100
|
+
</optional>
|
101
|
+
<optional>
|
102
|
+
<element name="error_message">
|
103
|
+
<text/>
|
104
|
+
</element>
|
105
|
+
</optional>
|
106
|
+
<zeroOrMore>
|
107
|
+
<element name="property">
|
108
|
+
<choice>
|
109
|
+
<attribute name="key"/>
|
110
|
+
<element name="key">
|
111
|
+
<text/>
|
112
|
+
</element>
|
113
|
+
</choice>
|
114
|
+
<element name="current">
|
115
|
+
<text/>
|
116
|
+
</element>
|
117
|
+
<optional>
|
118
|
+
<element name="target">
|
119
|
+
<text/>
|
120
|
+
</element>
|
121
|
+
</optional>
|
122
|
+
<optional>
|
123
|
+
<element name="msg">
|
124
|
+
<text/>
|
125
|
+
</element>
|
126
|
+
</optional>
|
127
|
+
<optional>
|
128
|
+
<element name="progress">
|
129
|
+
<text/>
|
130
|
+
</element>
|
131
|
+
</optional>
|
132
|
+
</element>
|
133
|
+
</zeroOrMore>
|
134
|
+
</element>
|
135
|
+
<element name="release">
|
136
|
+
<attribute name="msg_id"/>
|
137
|
+
<element name="context_id">
|
138
|
+
<text/>
|
139
|
+
</element>
|
140
|
+
</element>
|
141
|
+
</choice>
|
data/lib/omf_common.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'logging'
|
2
|
+
|
3
|
+
require "omf_common/version"
|
4
|
+
require "omf_common/message"
|
5
|
+
require "omf_common/comm"
|
6
|
+
require "omf_common/command"
|
7
|
+
require "omf_common/core_ext/string"
|
8
|
+
|
9
|
+
include Logging.globally
|
10
|
+
|
11
|
+
Logging.appenders.stdout('stdout',
|
12
|
+
:layout => Logging.layouts.pattern(:date_pattern => '%F %T %z',
|
13
|
+
:pattern => '[%d] %-5l %m\n',
|
14
|
+
:color_scheme => 'default'))
|
15
|
+
Logging.logger.root.appenders = 'stdout'
|
16
|
+
Logging.logger.root.level = :info
|
17
|
+
|
18
|
+
module OmfCommon
|
19
|
+
end
|
data/omf_common.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "omf_common/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "omf_common"
|
7
|
+
s.version = OmfCommon::VERSION
|
8
|
+
s.authors = ["NICTA"]
|
9
|
+
s.email = ["omf-user@lists.nicta.com.au"]
|
10
|
+
s.homepage = "https://www.mytestbed.net"
|
11
|
+
s.summary = %q{Common library of OMF}
|
12
|
+
s.description = %q{Common library of OMF, a generic framework for controlling and managing networking testbeds.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "omf_common"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "minitest", "~> 2.11.3"
|
23
|
+
s.add_runtime_dependency "blather", "~> 0.7"
|
24
|
+
s.add_runtime_dependency "logging", "~> 1.7.1"
|
25
|
+
s.add_runtime_dependency "hashie", "~> 1.2.0"
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe OmfCommon::Comm do
|
4
|
+
describe 'when initialised with a pubsub implementation' do
|
5
|
+
it 'must return a instance with all methods defined in corresponding module loaded' do
|
6
|
+
@comm = OmfCommon::Comm.new(:xmpp_blather)
|
7
|
+
%w(connect disconnect create_node delete_node subscribe unsubscribe publish).each do |m|
|
8
|
+
@comm.must_respond_to m
|
9
|
+
end
|
10
|
+
|
11
|
+
# also existing blather DSL should work too
|
12
|
+
%w(when_ready shutdown).each do |m|
|
13
|
+
@comm.must_respond_to m
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'omf_common/command'
|
3
|
+
|
4
|
+
describe OmfCommon::Command do
|
5
|
+
describe "when use util file to execute a system command" do
|
6
|
+
it "must not print anything to stdout if executed successfully" do
|
7
|
+
OmfCommon::Command.execute("date").must_match /^.+/
|
8
|
+
end
|
9
|
+
|
10
|
+
it "must capture and log errors if command not found" do
|
11
|
+
OmfCommon::Command.execute("dte -z").must_be_nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe String do
|
4
|
+
describe "when given a string" do
|
5
|
+
it "must response to to_n, camelcase, constant" do
|
6
|
+
"100.0".ducktype.must_equal 100.0
|
7
|
+
"i_am_a_string".ducktype.must_equal "i_am_a_string"
|
8
|
+
"i_am_a_string".camelcase.must_equal "IAmAString"
|
9
|
+
module IAmAString; end
|
10
|
+
"i_am_a_string".camelcase.constant.must_equal IAmAString
|
11
|
+
module IAmAString::Test; end
|
12
|
+
"IAmAString::Test".constant.must_equal IAmAString::Test
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
include OmfCommon
|
4
|
+
|
5
|
+
PROP_ELEMENTS = %w(p1 p2 p3)
|
6
|
+
|
7
|
+
describe OmfCommon::Message do
|
8
|
+
describe "when constructing valid messages" do
|
9
|
+
it "must return a create or configure XML element without failing" do
|
10
|
+
%w(create configure).each do |msg_name|
|
11
|
+
message = Message.send(msg_name) do |m|
|
12
|
+
PROP_ELEMENTS.each_with_index do |prop_element, index|
|
13
|
+
if index == 0
|
14
|
+
m.property(prop_element, rand(100))
|
15
|
+
else
|
16
|
+
m.property(prop_element, rand(100)) do |p|
|
17
|
+
p.element('unit', 'test')
|
18
|
+
p.element('precision', 'test')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end.sign
|
23
|
+
message.valid?.must_equal true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must return a request XML element without failing" do
|
28
|
+
request = Message.request('foo@bar') do |m|
|
29
|
+
PROP_ELEMENTS.each do |prop_element|
|
30
|
+
m.property(prop_element) do |p|
|
31
|
+
p.element('min_value', 'test')
|
32
|
+
p.element('max_value', 'test')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end.sign
|
36
|
+
request.valid?.must_equal true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "must return a release XML element without failing" do
|
40
|
+
release = Message.release.sign
|
41
|
+
release.valid?.must_equal true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "must return a inform XML element without failing" do
|
45
|
+
inform = Message.inform('9012c3bc-68de-459a-ac9f-530cc7168e22', 'CREATED') do |m|
|
46
|
+
m.element('resource_id', 'test')
|
47
|
+
m.element('resource_address', 'test')
|
48
|
+
PROP_ELEMENTS.each do |prop_element|
|
49
|
+
m.property(prop_element) do |p|
|
50
|
+
p.element('current', 'test')
|
51
|
+
p.element('target', 'test')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end.sign
|
55
|
+
inform.valid?.must_equal true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "must be able to parse a XML element into Message object" do
|
60
|
+
it "must behave" do
|
61
|
+
xml = Message.create do |m|
|
62
|
+
m.property('type', 'vm')
|
63
|
+
m.property('os', 'debian')
|
64
|
+
m.property('memory', 1024) do |p|
|
65
|
+
p.element('unit', 'mb')
|
66
|
+
p.element('precision', '0')
|
67
|
+
end
|
68
|
+
end.sign.to_xml
|
69
|
+
|
70
|
+
message = Message.parse(xml)
|
71
|
+
|
72
|
+
message.must_be_kind_of Message
|
73
|
+
message.operation.must_equal :create
|
74
|
+
message.read_element("//property").size.must_equal 3
|
75
|
+
message.read_content("unit").must_equal 'mb'
|
76
|
+
message.read_element("/create/property").size.must_equal 3
|
77
|
+
message.read_property("type").must_equal 'vm'
|
78
|
+
message.read_property(:type).must_equal 'vm'
|
79
|
+
memory = message.read_property(:memory)
|
80
|
+
memory.value.must_equal 1024
|
81
|
+
memory.unit.must_equal 'mb'
|
82
|
+
memory.precision.must_equal 0
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omf_common
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 6.0.0.pre.1
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- NICTA
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: minitest
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.11.3
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.11.3
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: blather
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0.7'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.7'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: logging
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.7.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.7.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: hashie
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.2.0
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.2.0
|
78
|
+
description: Common library of OMF, a generic framework for controlling and managing
|
79
|
+
networking testbeds.
|
80
|
+
email:
|
81
|
+
- omf-user@lists.nicta.com.au
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- Rakefile
|
89
|
+
- lib/omf_common.rb
|
90
|
+
- lib/omf_common/comm.rb
|
91
|
+
- lib/omf_common/command.rb
|
92
|
+
- lib/omf_common/core_ext/blather/dsl.rb
|
93
|
+
- lib/omf_common/core_ext/blather/dsl/pubsub.rb
|
94
|
+
- lib/omf_common/core_ext/blather/stanza/registration.rb
|
95
|
+
- lib/omf_common/core_ext/string.rb
|
96
|
+
- lib/omf_common/dsl/xmpp_blather.rb
|
97
|
+
- lib/omf_common/message.rb
|
98
|
+
- lib/omf_common/protocol.rnc
|
99
|
+
- lib/omf_common/protocol.rng
|
100
|
+
- lib/omf_common/version.rb
|
101
|
+
- omf_common.gemspec
|
102
|
+
- test/omf_common/comm_spec.rb
|
103
|
+
- test/omf_common/command_spec.rb
|
104
|
+
- test/omf_common/core_ext/string_spec.rb
|
105
|
+
- test/omf_common/message_spec.rb
|
106
|
+
- test/test_helper.rb
|
107
|
+
homepage: https://www.mytestbed.net
|
108
|
+
licenses: []
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ! '>'
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.3.1
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project: omf_common
|
127
|
+
rubygems_version: 1.8.23
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Common library of OMF
|
131
|
+
test_files: []
|
132
|
+
has_rdoc:
|