omf_common 6.0.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|