omf_common 6.0.0.pre.7 → 6.0.0.pre.8

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/lib/omf_common.rb CHANGED
@@ -2,6 +2,7 @@ require 'logging'
2
2
  require 'active_support/inflector'
3
3
 
4
4
  require "omf_common/version"
5
+ require 'omf_common/measure'
5
6
  require "omf_common/message"
6
7
  require "omf_common/comm"
7
8
  require "omf_common/command"
@@ -1,4 +1,6 @@
1
1
  require 'omf_common/dsl/xmpp'
2
+ require 'omf_common/dsl/xmpp_mp'
3
+
2
4
 
3
5
  module OmfCommon
4
6
  # PubSub communication class, can be extended with different implementations
@@ -23,11 +23,13 @@ module OmfCommon
23
23
  jid = "#{username}@#{server}"
24
24
  client.setup(jid, password)
25
25
  client.run
26
+ MPConnection.inject(Time.now.to_f, jid, 'connect') if OmfCommon::Measure.enabled?
26
27
  end
27
28
 
28
29
  # Shut down XMPP connection
29
30
  def disconnect
30
31
  shutdown
32
+ OmfCommon::DSL::Xmpp::MPConnection.inject(Time.now.to_f, jid, 'disconnect') if OmfCommon::Measure.enabled?
31
33
  end
32
34
 
33
35
  # Create a new pubsub topic with additional configuration
@@ -49,6 +51,7 @@ module OmfCommon
49
51
  # @param [String] topic Pubsub topic name
50
52
  def subscribe(topic, &block)
51
53
  pubsub.subscribe(topic, nil, default_host, &callback_logging(__method__, topic, &block))
54
+ MPSubscription.inject(Time.now.to_f, jid, 'join', topic) if OmfCommon::Measure.enabled?
52
55
  end
53
56
 
54
57
  # Un-subscribe all existing subscriptions from all pubsub topics.
@@ -56,6 +59,7 @@ module OmfCommon
56
59
  pubsub.subscriptions(default_host) do |m|
57
60
  m[:subscribed] && m[:subscribed].each do |s|
58
61
  pubsub.unsubscribe(s[:node], nil, s[:subid], default_host, &callback_logging(__method__, s[:node], s[:subid]))
62
+ MPSubscription.inject(Time.now.to_f, jid, 'leave', s[:node]) if OmfCommon::Measure.enabled?
59
63
  end
60
64
  end
61
65
  end
@@ -71,6 +75,7 @@ module OmfCommon
71
75
  def publish(topic, message, &block)
72
76
  raise StandardError, "Invalid message" unless message.valid?
73
77
  pubsub.publish(topic, message, default_host, &callback_logging(__method__, topic, message.operation, &block))
78
+ MPPublished.inject(Time.now.to_f, jid, topic, message.to_s.gsub("\n",'')) if OmfCommon::Measure.enabled?
74
79
  end
75
80
 
76
81
  # Generate OMF related message
@@ -91,6 +96,8 @@ module OmfCommon
91
96
  end
92
97
  end
93
98
  end
99
+ else
100
+ Message.send(m_name)
94
101
  end
95
102
 
96
103
  OmfCommon::TopicMessage.new(message, self)
@@ -124,8 +131,13 @@ module OmfCommon
124
131
 
125
132
  # Event callback for pubsub topic event(item published)
126
133
  #
127
- def topic_event(*args, &block)
128
- pubsub_event(*args, &callback_logging(__method__, &block))
134
+ def topic_event(&block)
135
+ guard_block = proc do |event|
136
+ passed = (event.items?) && (!event.delayed?) && event.items.first.payload
137
+ MPReceived.inject(Time.now.to_f, jid, event.node, event.items.first.payload.to_s.gsub("\n",'')) if OmfCommon::Measure.enabled? && passed
138
+ passed
139
+ end
140
+ pubsub_event(guard_block, &callback_logging(__method__, &block))
129
141
  end
130
142
 
131
143
  # Return a topic object represents pubsub topic
@@ -0,0 +1,36 @@
1
+ module OmfCommon
2
+ module DSL
3
+ module Xmpp
4
+ class MPConnection < OML4R::MPBase
5
+ name :xmpp_connections
6
+ param :time, :type => :double
7
+ param :jid, :type => :string
8
+ param :operation, :type => :string
9
+ end
10
+
11
+ class MPPublished < OML4R::MPBase
12
+ name :xmpp_published
13
+ param :time, :type => :double
14
+ param :jid, :type => :string
15
+ param :topic, :type => :string
16
+ param :xml_stanza, :type => :string
17
+ end
18
+
19
+ class MPReceived < OML4R::MPBase
20
+ name :xmpp_received
21
+ param :time, :type => :double
22
+ param :jid, :type => :string
23
+ param :topic, :type => :string
24
+ param :xml_stanza, :type => :string
25
+ end
26
+
27
+ class MPSubscription < OML4R::MPBase
28
+ name :xmpp_subscriptions
29
+ param :time, :type => :double
30
+ param :jid, :type => :string
31
+ param :operation, :type => :string
32
+ param :topic, :type => :string
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,163 +1,163 @@
1
- #
2
- # Copyright (c) 2006-2012 National ICT Australia (NICTA), Australia
3
- #
4
- # Copyright (c) 2004-2009 WINLAB, Rutgers University, USA
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- # THE SOFTWARE.
23
- #
24
- #
25
- # Library of client side helpers
26
- #
27
- require 'fcntl'
28
-
29
- #
30
- # Run an application on the client.
31
- #
32
- # Borrows from Open3
33
- #
34
- class ExecApp
35
-
36
- # Holds the pids for all active apps
37
- @@all_apps = Hash.new
38
-
39
- # True if this active app is being killed by a proper
40
- # call to ExecApp.signal_all() or signal()
41
- # (i.e. when the caller of ExecApp decided to stop the application,
42
- # as far as we are concerned, this is a 'clean' exit)
43
- @clean_exit = false
44
-
45
- # Return an application instance based on its ID
46
- #
47
- # @param [String] id of the application to return
48
- def ExecApp.[](id)
49
- app = @@all_apps[id]
50
- logger.info "Unknown application '#{id}/#{id.class}'" if app.nil?
51
- return app
52
- end
53
-
54
- def ExecApp.signal_all(signal = 'KILL')
55
- @@all_apps.each_value { |app| app.signal(signal) }
56
- end
57
-
58
- def stdin(line)
59
- logger.debug "Writing '#{line}' to app '#{@id}'"
60
- @stdin.write("#{line}\n")
61
- @stdin.flush
62
- end
63
-
64
- def signal(signal = 'KILL')
65
- @clean_exit = true
66
- Process.kill(signal, @pid)
67
- end
68
-
69
- #
70
- # Run an application 'cmd' in a separate thread and monitor
71
- # its stdout. Also send status reports to the 'observer' by
72
- # calling its "on_app_event(eventType, appId, message")"
73
- #
74
- # @param id ID of application (used for reporting)
75
- # @param observer Observer of application's progress
76
- # @param cmd Command path and args
77
- # @param map_std_err_to_out If true report stderr as stdin [false]
78
- #
79
- def initialize(id, observer, cmd, map_std_err_to_out = false)
80
-
81
- @id = id
82
- @observer = observer
83
- @@all_apps[id] = self
84
-
85
- pw = IO::pipe # pipe[0] for read, pipe[1] for write
86
- pr = IO::pipe
87
- pe = IO::pipe
88
-
89
- logger.debug "Starting application '#{id}' - cmd: '#{cmd}'"
90
- @observer.on_app_event(:STARTED, id, cmd)
91
- @pid = fork {
92
- # child will remap pipes to std and exec cmd
93
- pw[1].close
94
- STDIN.reopen(pw[0])
95
- pw[0].close
96
-
97
- pr[0].close
98
- STDOUT.reopen(pr[1])
99
- pr[1].close
100
-
101
- pe[0].close
102
- STDERR.reopen(pe[1])
103
- pe[1].close
104
-
105
- begin
106
- exec(cmd)
107
- rescue => ex
108
- cmd = cmd.join(' ') if cmd.kind_of?(Array)
109
- STDERR.puts "exec failed for '#{cmd}' (#{$!}): #{ex}"
110
- end
111
- # Should never get here
112
- exit!
113
- }
114
-
115
- pw[0].close
116
- pr[1].close
117
- pe[1].close
118
- monitor_pipe(:stdout, pr[0])
119
- monitor_pipe(map_std_err_to_out ? :stdout : :stderr, pe[0])
120
- # Create thread which waits for application to exit
121
- Thread.new(id, @pid) do |id, pid|
122
- ret = Process.waitpid(pid)
123
- status = $?
124
- @@all_apps.delete(@id)
125
- # app finished
126
- if (status == 0) || @clean_exit
127
- s = "OK"
128
- logger.debug "Application '#{id}' finished"
129
- else
130
- s = "ERROR"
131
- logger.debug "Application '#{id}' failed (code=#{status})"
132
- end
133
- @observer.on_app_event("DONE.#{s}", @id, "status: #{status}")
134
- end
135
- @stdin = pw[1]
136
- end
137
-
138
- private
139
-
140
- #
141
- # Create a thread to monitor the process and its output
142
- # and report that back to the server
143
- #
144
- # @param name Name of app stream to monitor (should be :stdout, :stderr)
145
- # @param pipe Pipe to read from
146
- #
147
- def monitor_pipe(name, pipe)
148
- Thread.new() do
149
- begin
150
- while true do
151
- s = pipe.readline.chomp
152
- @observer.on_app_event(name.to_s.upcase, @id, s)
153
- end
154
- rescue EOFError
155
- # do nothing
156
- rescue Exception => err
157
- logger.error "monitorApp(#{@id}): #{err}"
158
- ensure
159
- pipe.close
160
- end
161
- end
162
- end
163
- end
1
+ #
2
+ # Copyright (c) 2006-2012 National ICT Australia (NICTA), Australia
3
+ #
4
+ # Copyright (c) 2004-2009 WINLAB, Rutgers University, USA
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #
24
+ #
25
+ # Library of client side helpers
26
+ #
27
+ require 'fcntl'
28
+
29
+ #
30
+ # Run an application on the client.
31
+ #
32
+ # Borrows from Open3
33
+ #
34
+ class ExecApp
35
+
36
+ # Holds the pids for all active apps
37
+ @@all_apps = Hash.new
38
+
39
+ # True if this active app is being killed by a proper
40
+ # call to ExecApp.signal_all() or signal()
41
+ # (i.e. when the caller of ExecApp decided to stop the application,
42
+ # as far as we are concerned, this is a 'clean' exit)
43
+ @clean_exit = false
44
+
45
+ # Return an application instance based on its ID
46
+ #
47
+ # @param [String] id of the application to return
48
+ def ExecApp.[](id)
49
+ app = @@all_apps[id]
50
+ logger.info "Unknown application '#{id}/#{id.class}'" if app.nil?
51
+ return app
52
+ end
53
+
54
+ def ExecApp.signal_all(signal = 'KILL')
55
+ @@all_apps.each_value { |app| app.signal(signal) }
56
+ end
57
+
58
+ def stdin(line)
59
+ logger.debug "Writing '#{line}' to app '#{@id}'"
60
+ @stdin.write("#{line}\n")
61
+ @stdin.flush
62
+ end
63
+
64
+ def signal(signal = 'KILL')
65
+ @clean_exit = true
66
+ Process.kill(signal, @pid)
67
+ end
68
+
69
+ #
70
+ # Run an application 'cmd' in a separate thread and monitor
71
+ # its stdout. Also send status reports to the 'observer' by
72
+ # calling its "on_app_event(eventType, appId, message")"
73
+ #
74
+ # @param id ID of application (used for reporting)
75
+ # @param observer Observer of application's progress
76
+ # @param cmd Command path and args
77
+ # @param map_std_err_to_out If true report stderr as stdin [false]
78
+ #
79
+ def initialize(id, observer, cmd, map_std_err_to_out = false)
80
+
81
+ @id = id
82
+ @observer = observer
83
+ @@all_apps[id] = self
84
+
85
+ pw = IO::pipe # pipe[0] for read, pipe[1] for write
86
+ pr = IO::pipe
87
+ pe = IO::pipe
88
+
89
+ logger.debug "Starting application '#{id}' - cmd: '#{cmd}'"
90
+ @observer.on_app_event(:STARTED, id, cmd)
91
+ @pid = fork {
92
+ # child will remap pipes to std and exec cmd
93
+ pw[1].close
94
+ STDIN.reopen(pw[0])
95
+ pw[0].close
96
+
97
+ pr[0].close
98
+ STDOUT.reopen(pr[1])
99
+ pr[1].close
100
+
101
+ pe[0].close
102
+ STDERR.reopen(pe[1])
103
+ pe[1].close
104
+
105
+ begin
106
+ exec(cmd)
107
+ rescue => ex
108
+ cmd = cmd.join(' ') if cmd.kind_of?(Array)
109
+ STDERR.puts "exec failed for '#{cmd}' (#{$!}): #{ex}"
110
+ end
111
+ # Should never get here
112
+ exit!
113
+ }
114
+
115
+ pw[0].close
116
+ pr[1].close
117
+ pe[1].close
118
+ monitor_pipe(:stdout, pr[0])
119
+ monitor_pipe(map_std_err_to_out ? :stdout : :stderr, pe[0])
120
+ # Create thread which waits for application to exit
121
+ Thread.new(id, @pid) do |id, pid|
122
+ ret = Process.waitpid(pid)
123
+ status = $?
124
+ @@all_apps.delete(@id)
125
+ # app finished
126
+ if (status == 0) || @clean_exit
127
+ s = "OK"
128
+ logger.debug "Application '#{id}' finished"
129
+ else
130
+ s = "ERROR"
131
+ logger.debug "Application '#{id}' failed (code=#{status})"
132
+ end
133
+ @observer.on_app_event("DONE.#{s}", @id, "status: #{status}")
134
+ end
135
+ @stdin = pw[1]
136
+ end
137
+
138
+ private
139
+
140
+ #
141
+ # Create a thread to monitor the process and its output
142
+ # and report that back to the server
143
+ #
144
+ # @param name Name of app stream to monitor (should be :stdout, :stderr)
145
+ # @param pipe Pipe to read from
146
+ #
147
+ def monitor_pipe(name, pipe)
148
+ Thread.new() do
149
+ begin
150
+ while true do
151
+ s = pipe.readline.chomp
152
+ @observer.on_app_event(name.to_s.upcase, @id, s)
153
+ end
154
+ rescue EOFError
155
+ # do nothing
156
+ rescue Exception => err
157
+ logger.error "monitorApp(#{@id}): #{err}"
158
+ ensure
159
+ pipe.close
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,8 @@
1
+ require 'oml4r'
2
+ module OmfCommon
3
+ class Measure
4
+ @@enabled = false
5
+ def Measure.enabled? ; @@enabled end
6
+ def Measure.enable ; @@enabled = true end
7
+ end
8
+ end
@@ -4,6 +4,16 @@ require 'securerandom'
4
4
  require 'openssl'
5
5
 
6
6
  module OmfCommon
7
+
8
+ class MPMessage < OML4R::MPBase
9
+ name :message
10
+ param :time, :type => :double
11
+ param :operation, :type => :string
12
+ param :msg_id, :type => :string
13
+ param :context_id, :type => :string
14
+ param :content, :type => :string
15
+ end
16
+
7
17
  # Refer to resource life cycle, instance methods are basically construct & parse XML fragment
8
18
  #
9
19
  # @example To create a valid omf message, e.g. a 'configure' message:
@@ -17,6 +27,11 @@ module OmfCommon
17
27
  OMF_NAMESPACE = "http://schema.mytestbed.net/#{OmfCommon::PROTOCOL_VERSION}/protocol"
18
28
  SCHEMA_FILE = "#{File.dirname(__FILE__)}/protocol/#{OmfCommon::PROTOCOL_VERSION}.rng"
19
29
  OPERATION = %w(create configure request release inform)
30
+ # When OML instrumentation is enabled, we do not want to send a the same
31
+ # measurement twice, once when a message is created for publishing to T,
32
+ # and once when this message comes back (as we are also a subscriber of T)
33
+ # Thus we keep track of message IDs here (again only when OML is enabled)
34
+ @@msg_id_list = []
20
35
 
21
36
  class << self
22
37
  OPERATION.each do |operation|
@@ -35,8 +50,13 @@ module OmfCommon
35
50
  end
36
51
 
37
52
  def parse(xml)
53
+ raise ArgumentError, 'Can not parse an empty XML into OMF message' if xml.nil? || xml.empty?
38
54
  xml_root = Nokogiri::XML(xml).root
39
- new(xml_root.element_name, nil, xml_root.namespace.href).inherit(xml_root)
55
+ result = new(xml_root.element_name, nil, xml_root.namespace.href).inherit(xml_root)
56
+ if OmfCommon::Measure.enabled? && !@@msg_id_list.include?(result.msg_id)
57
+ MPMessage.inject(Time.now.to_f, result.operation.to_s, result.msg_id, result.context_id, result.to_s.gsub("\n",''))
58
+ end
59
+ result
40
60
  end
41
61
  end
42
62
 
@@ -47,7 +67,7 @@ module OmfCommon
47
67
  key_node.write_attr('key', key)
48
68
 
49
69
  unless value.nil?
50
- key_node.write_attr('type', value.class.to_s.downcase)
70
+ key_node.write_attr('type', ruby_type_2_prop_type(value.class))
51
71
  c_node = value_node_set(value)
52
72
 
53
73
  if c_node.class == Array
@@ -66,7 +86,7 @@ module OmfCommon
66
86
  [].tap do |array|
67
87
  value.each_pair do |k, v|
68
88
  n = Message.new(k)
69
- n.write_attr('type', v.class.to_s.downcase)
89
+ n.write_attr('type', ruby_type_2_prop_type(v.class))
70
90
 
71
91
  c_node = value_node_set(v, k)
72
92
  if c_node.class == Array
@@ -80,7 +100,7 @@ module OmfCommon
80
100
  when Array
81
101
  value.map do |v|
82
102
  n = Message.new('item')
83
- n.write_attr('type', v.class.to_s.downcase)
103
+ n.write_attr('type', ruby_type_2_prop_type(v.class))
84
104
 
85
105
  c_node = value_node_set(v, 'item')
86
106
  if c_node.class == Array
@@ -104,9 +124,20 @@ module OmfCommon
104
124
  #
105
125
  def sign
106
126
  write_attr('msg_id', OpenSSL::Digest::SHA1.new(canonicalize)) if read_attr('id').nil? || read_attr('id').empty?
127
+ if OmfCommon::Measure.enabled?
128
+ MPMessage.inject(Time.now.to_f, operation.to_s, msg_id, context_id, self.to_s.gsub("\n",''))
129
+ @@msg_id_list << msg_id
130
+ end
107
131
  self
108
132
  end
109
133
 
134
+ # param :time, :type => :int32
135
+ # param :operation, :type => :string
136
+ # param :msg_id, :type => :string
137
+ # param :context_id, :type => :string
138
+ # param :content, :type => :string
139
+
140
+
110
141
  # Validate against relaxng schema
111
142
  #
112
143
  def valid?
@@ -151,7 +182,11 @@ module OmfCommon
151
182
  #
152
183
  def read_content(element_name)
153
184
  element_content = read_element("//#{element_name}").first.content rescue nil
154
- element_content.empty? ? nil : element_content
185
+ unless element_content.nil?
186
+ element_content.empty? ? nil : element_content
187
+ else
188
+ nil
189
+ end
155
190
  end
156
191
 
157
192
  # Context ID will be requested quite often
@@ -164,6 +199,14 @@ module OmfCommon
164
199
  read_property(:resource_id) || read_content(:resource_id)
165
200
  end
166
201
 
202
+ def publish_to
203
+ read_property(:publish_to) || read_content(:publish_to)
204
+ end
205
+
206
+ def msg_id
207
+ read_attr('msg_id')
208
+ end
209
+
167
210
  # Get a property by key
168
211
  #
169
212
  # @param [String] key name of the property element
@@ -178,17 +221,17 @@ module OmfCommon
178
221
  def reconstruct_data(node)
179
222
  case node.attr('type')
180
223
  when 'array'
181
- mash ||= Hashie::Mash.new
182
- mash[:items] = node.element_children.map do |child|
224
+ node.element_children.map do |child|
183
225
  reconstruct_data(child)
184
226
  end
185
- mash
186
227
  when /hash/
187
228
  mash ||= Hashie::Mash.new
188
229
  node.element_children.each do |child|
189
230
  mash[child.attr('key') || child.element_name] ||= reconstruct_data(child)
190
231
  end
191
232
  mash
233
+ when /boolean/
234
+ node.content == "true"
192
235
  else
193
236
  node.content.empty? ? nil : node.content.ducktype
194
237
  end
@@ -205,5 +248,16 @@ module OmfCommon
205
248
  def print_app_event
206
249
  "APP_EVENT (#{read_property(:app)}, ##{read_property(:seq)}, #{read_property(:event)}): #{read_property(:msg)}"
207
250
  end
251
+
252
+ private
253
+
254
+ def ruby_type_2_prop_type(ruby_class_type)
255
+ v_type = ruby_class_type.to_s.downcase
256
+ if %w(trueclass falseclass).include?(v_type)
257
+ 'boolean'
258
+ else
259
+ v_type
260
+ end
261
+ end
208
262
  end
209
263
  end
@@ -22,7 +22,7 @@ module OmfCommon
22
22
  event.node == self.id &&
23
23
  (valid_guard?(message_guard_proc) ? message_guard_proc.call(omf_message) : true)
24
24
  end
25
- comm.topic_event(guard_block, &event_block)
25
+ comm.pubsub_event(guard_block, &event_block)
26
26
  end
27
27
 
28
28
  private
@@ -1,4 +1,4 @@
1
1
  module OmfCommon
2
- VERSION = "6.0.0.pre.7"
2
+ VERSION = "6.0.0.pre.8"
3
3
  PROTOCOL_VERSION = "6.0"
4
4
  end
data/omf_common.gemspec CHANGED
@@ -26,4 +26,5 @@ Gem::Specification.new do |s|
26
26
  s.add_runtime_dependency "blather", "~> 0.8.0"
27
27
  s.add_runtime_dependency "logging", "~> 1.7.1"
28
28
  s.add_runtime_dependency "hashie", "~> 1.2.0"
29
+ s.add_runtime_dependency "oml4r", "~> 2.8.0"
29
30
  end
@@ -68,22 +68,25 @@ describe OmfCommon::Message do
68
68
  end
69
69
  end
70
70
 
71
- describe "must be able to parse a XML element into Message object" do
72
- it "must behave" do
71
+ describe "when asked to parse a XML element into Message object" do
72
+ it "must create the message object correctly " do
73
73
  xml = Message.create do |m|
74
74
  m.property('type', 'vm')
75
75
  m.property('os', 'debian')
76
76
  m.property('memory', { value: 1024, unit: 'mb', precision: 0 })
77
77
  m.property('devices', [{ name: 'w0', driver: 'mod_bob'}, { name: 'w1', driver: ['mod1', 'mod2']} ])
78
+ m.property('true', true)
79
+ m.property('false', false)
80
+ m.property('boolean_array', [false, true])
78
81
  end.canonicalize
79
82
 
80
83
  message = Message.parse(xml)
81
84
 
82
85
  message.must_be_kind_of Message
83
86
  message.operation.must_equal :create
84
- message.read_element("//property").size.must_equal 4
87
+ message.read_element("//property").size.must_equal 7
85
88
  message.read_content("unit").must_equal 'mb'
86
- message.read_element("/create/property").size.must_equal 4
89
+ message.read_element("/create/property").size.must_equal 7
87
90
  message.read_property("type").must_equal 'vm'
88
91
  message.read_property(:type).must_equal 'vm'
89
92
 
@@ -94,13 +97,22 @@ describe OmfCommon::Message do
94
97
  memory.precision.must_equal 0
95
98
 
96
99
  devices = message.read_property(:devices)
97
- devices.items.must_be_kind_of Array
98
- devices.items.size.must_equal 2
99
- devices.items.find { |v| v.name == 'w1'}.driver.items.size.must_equal 2
100
+ devices.must_be_kind_of Array
101
+ devices.size.must_equal 2
102
+ devices.find { |v| v.name == 'w1'}.driver.size.must_equal 2
100
103
  # Each property iterator
101
104
  message.each_property do |v|
102
- %w(type os memory devices).must_include v.attr('key')
105
+ %w(type os memory devices true false boolean_array).must_include v.attr('key')
103
106
  end
107
+
108
+ message.read_property(:true).must_equal true
109
+ message.read_property(:false).must_equal false
110
+ message.read_property('boolean_array').must_equal [false, true]
111
+ end
112
+
113
+ it "must fail if parse an empty xml" do
114
+ lambda { Message.parse("") }.must_raise ArgumentError
115
+ lambda { Message.parse(nil) }.must_raise ArgumentError
104
116
  end
105
117
  end
106
118
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omf_common
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.pre.7
4
+ version: 6.0.0.pre.8
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-02 00:00:00.000000000 Z
12
+ date: 2012-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -123,6 +123,22 @@ dependencies:
123
123
  - - ~>
124
124
  - !ruby/object:Gem::Version
125
125
  version: 1.2.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: oml4r
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 2.8.0
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: 2.8.0
126
142
  description: Common library of OMF, a generic framework for controlling and managing
127
143
  networking testbeds.
128
144
  email:
@@ -140,7 +156,9 @@ files:
140
156
  - lib/omf_common/core_ext/object.rb
141
157
  - lib/omf_common/core_ext/string.rb
142
158
  - lib/omf_common/dsl/xmpp.rb
159
+ - lib/omf_common/dsl/xmpp_mp.rb
143
160
  - lib/omf_common/exec_app.rb
161
+ - lib/omf_common/measure.rb
144
162
  - lib/omf_common/message.rb
145
163
  - lib/omf_common/protocol/6.0.rnc
146
164
  - lib/omf_common/protocol/6.0.rng
@@ -182,4 +200,3 @@ signing_key:
182
200
  specification_version: 3
183
201
  summary: Common library of OMF
184
202
  test_files: []
185
- has_rdoc: