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

Sign up to get free protection for your applications and to get access to all the features.
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: