spqr 0.2.4 → 0.3.0
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/CHANGES +12 -3
- data/VERSION +1 -1
- data/lib/spqr/app.rb +47 -53
- data/lib/spqr/codegen.rb +1 -1
- data/lib/spqr/constants.rb +11 -0
- data/lib/spqr/event.rb +159 -0
- data/lib/spqr/manageable.rb +10 -0
- data/lib/spqr/spqr.rb +1 -0
- data/lib/spqr/utils.rb +42 -3
- data/ruby-spqr.spec.in +5 -0
- data/test/example-apps.rb +109 -0
- data/test/helper.rb +15 -3
- data/test/standalone-test.rb +330 -0
- data/test/test_events.rb +45 -0
- data/test/test_user_and_context.rb +31 -0
- metadata +15 -21
- data/examples/codegen/EchoAgent.rb +0 -33
data/CHANGES
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
version 0.
|
|
1
|
+
version 0.3.0 (04c1eb70855b6382925c65f350fbb69e9eb58c88)
|
|
2
|
+
|
|
3
|
+
* first-class QMF event support via the SPQR::Raiseable mixin.
|
|
4
|
+
* several small fixes to QMF interoperability (thanks to Ken Giusti
|
|
5
|
+
for observations and help)
|
|
6
|
+
* the current QMF user and context are available to SPQR methods
|
|
7
|
+
via Manageable#qmf_user_id and Manageable#qmf_context methods.
|
|
8
|
+
* various usability improvements to the test suite
|
|
9
|
+
|
|
10
|
+
version 0.2.4 (f2159d62949e5ed0f0e853bcef28dc4a7e986e48)
|
|
2
11
|
|
|
3
12
|
* Workaround for a crash in qmfengine when running on 32-bit machines
|
|
4
13
|
|
|
5
|
-
version 0.2.3
|
|
14
|
+
version 0.2.3 (ed9a92d249156b57f9d788047f3250b27811fbc8)
|
|
6
15
|
|
|
7
16
|
* Fixed a crash that occurred sometimes when attempting to return a
|
|
8
17
|
value from a failing method.
|
|
9
18
|
|
|
10
|
-
version 0.2.2
|
|
19
|
+
version 0.2.2 (d6b77f3ca349fe2c9221db5cb796bed1268982e5)
|
|
11
20
|
|
|
12
21
|
* Methods on manageable objects now can call fail(status, message) to
|
|
13
22
|
signal failure in the QMF method response.
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.3.0
|
data/lib/spqr/app.rb
CHANGED
|
@@ -45,6 +45,7 @@ module SPQR
|
|
|
45
45
|
|
|
46
46
|
@log.info("initializing SPQR app....")
|
|
47
47
|
|
|
48
|
+
@event_classes = []
|
|
48
49
|
@classes_by_name = {}
|
|
49
50
|
@classes_by_id = {}
|
|
50
51
|
@pipe = options[:notifier]
|
|
@@ -71,11 +72,17 @@ module SPQR
|
|
|
71
72
|
|
|
72
73
|
klass.log = @log
|
|
73
74
|
|
|
75
|
+
# XXX
|
|
76
|
+
if klass.included_modules.include?(::SPQR::Manageable)
|
|
77
|
+
@classes_by_id[klass.class_id] = klass
|
|
78
|
+
@classes_by_name[klass.spqr_meta.classname.to_s] = ClassMeta.new(klass, schemaclass)
|
|
79
|
+
else
|
|
80
|
+
@log.info "NOT registering query/lookup info for #{klass}; is it an event class?"
|
|
81
|
+
@event_classes << klass
|
|
82
|
+
end
|
|
83
|
+
|
|
74
84
|
@log.info("SETTING #{klass.spqr_meta.classname}.app to #{self.inspect}")
|
|
75
|
-
klass.app = self
|
|
76
|
-
|
|
77
|
-
@classes_by_id[klass.class_id] = klass
|
|
78
|
-
@classes_by_name[klass.spqr_meta.classname.to_s] = ClassMeta.new(klass, schemaclass)
|
|
85
|
+
klass.app = self
|
|
79
86
|
end
|
|
80
87
|
|
|
81
88
|
unmanageable_ks.each do |klass|
|
|
@@ -93,6 +100,9 @@ module SPQR
|
|
|
93
100
|
class_id = obj_id.object_num_high
|
|
94
101
|
obj_id = obj_id.object_num_low
|
|
95
102
|
|
|
103
|
+
Thread.current[:qmf_user_id] = user_id
|
|
104
|
+
Thread.current[:qmf_context] = context
|
|
105
|
+
|
|
96
106
|
@log.debug "calling method: context=#{context} method=#{name} object_id=#{obj_id}, user=#{user_id}"
|
|
97
107
|
|
|
98
108
|
managed_object = find_object(context, class_id, obj_id)
|
|
@@ -204,16 +214,25 @@ module SPQR
|
|
|
204
214
|
|
|
205
215
|
@agent = Qmf::Agent.new(self, @app_name)
|
|
206
216
|
@log.debug(" +-- @agent created: #{@agent}")
|
|
217
|
+
|
|
218
|
+
object_class_count = @classes_by_name.size
|
|
219
|
+
event_class_count = @event_classes.size
|
|
207
220
|
|
|
208
|
-
@
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
@log.info(" +-- registering #{object_class_count} object #{pluralize(object_class_count, "class", "classes")} and #{event_class_count} event #{pluralize(event_class_count, "class", "classes")}....")
|
|
222
|
+
|
|
223
|
+
all_schemas = @classes_by_name.values + @event_classes
|
|
224
|
+
|
|
225
|
+
all_schemas.each do |km|
|
|
226
|
+
identifier = ("object #{km.schema_class.package_name}.#{km.schema_class.class_name}" rescue "#{km.class.to_s}")
|
|
227
|
+
|
|
228
|
+
@log.debug(" +--+-- TRYING to register #{identifier}")
|
|
213
229
|
@agent.register_class(km.schema_class)
|
|
214
|
-
@log.
|
|
230
|
+
@log.info(" +--+-- #{identifier} REGISTERED")
|
|
215
231
|
end
|
|
216
232
|
|
|
233
|
+
@agent.set_connection(@connection)
|
|
234
|
+
@log.debug(" +-- @agent.set_connection called")
|
|
235
|
+
|
|
217
236
|
@log.debug("entering orbit....")
|
|
218
237
|
|
|
219
238
|
sleep
|
|
@@ -221,6 +240,11 @@ module SPQR
|
|
|
221
240
|
|
|
222
241
|
private
|
|
223
242
|
|
|
243
|
+
def pluralize(count, singular, plural=nil)
|
|
244
|
+
plural ||= "#{singular}s"
|
|
245
|
+
count == 1 ? singular : plural
|
|
246
|
+
end
|
|
247
|
+
|
|
224
248
|
def result_valid(actuals, mm)
|
|
225
249
|
(actuals.kind_of?(Array) and mm.formals_out.size == actuals.size) or mm.formals_out.size <= 1
|
|
226
250
|
end
|
|
@@ -249,6 +273,16 @@ module SPQR
|
|
|
249
273
|
def schematize(klass)
|
|
250
274
|
@log.info("Making a QMF schema for #{klass.spqr_meta.classname}")
|
|
251
275
|
|
|
276
|
+
if klass.respond_to? :schematize
|
|
277
|
+
@log.info("#{klass.spqr_meta.classname} knows how to schematize itself; it's probably an event class")
|
|
278
|
+
return klass.schematize
|
|
279
|
+
else
|
|
280
|
+
@log.info("#{klass.spqr_meta.classname} doesn't know how to schematize itself; it's probably an object class")
|
|
281
|
+
return schematize_object_class(klass)
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def schematize_object_class(klass)
|
|
252
286
|
meta = klass.spqr_meta
|
|
253
287
|
package = meta.package.to_s
|
|
254
288
|
classname = meta.classname.to_s
|
|
@@ -266,19 +300,7 @@ module SPQR
|
|
|
266
300
|
mm.args.each do |arg|
|
|
267
301
|
@log.info("| +-- creating a QMF schema for arg #{arg}")
|
|
268
302
|
|
|
269
|
-
|
|
270
|
-
arg_opts[:desc] ||= arg.description if (arg.description and arg.description.is_a? String)
|
|
271
|
-
arg_opts[:dir] ||= get_xml_constant(arg.direction.to_s, ::SPQR::XmlConstants::Direction)
|
|
272
|
-
arg_name = arg.name.to_s
|
|
273
|
-
arg_type = get_xml_constant(arg.kind.to_s, ::SPQR::XmlConstants::Type)
|
|
274
|
-
|
|
275
|
-
if @log.level <= Logger::DEBUG
|
|
276
|
-
local_variables.grep(/^arg_/).each do |local|
|
|
277
|
-
@log.debug(" #{local} --> #{(eval local).inspect}")
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
method.add_argument(Qmf::SchemaArgument.new(arg_name, arg_type, arg_opts))
|
|
303
|
+
encode_argument(arg, method)
|
|
282
304
|
end
|
|
283
305
|
|
|
284
306
|
sc.add_method(method)
|
|
@@ -300,36 +322,8 @@ module SPQR
|
|
|
300
322
|
end
|
|
301
323
|
end
|
|
302
324
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
k.is_a? Class and k.included_modules.include? ::SPQR::Manageable
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def get_xml_constant(xml_key, dictionary)
|
|
309
|
-
# FIXME: move out of App, into a utils module?
|
|
310
|
-
string_val = dictionary[xml_key]
|
|
311
|
-
return xml_key unless string_val
|
|
312
|
-
|
|
313
|
-
actual_val = const_lookup(string_val)
|
|
314
|
-
return string_val unless actual_val
|
|
315
|
-
|
|
316
|
-
return actual_val
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
# turns a string name of a constant into the value of that
|
|
320
|
-
# constant; returns that value, or nil if fqcn doesn't correspond
|
|
321
|
-
# to a valid constant
|
|
322
|
-
def const_lookup(fqcn)
|
|
323
|
-
# FIXME: move out of App, into a utils module?
|
|
324
|
-
hierarchy = fqcn.split("::")
|
|
325
|
-
const = hierarchy.pop
|
|
326
|
-
mod = Kernel
|
|
327
|
-
hierarchy.each do |m|
|
|
328
|
-
mod = mod.const_get(m)
|
|
329
|
-
end
|
|
330
|
-
mod.const_get(const) rescue nil
|
|
331
|
-
end
|
|
332
|
-
|
|
325
|
+
include ::SPQR::Util
|
|
326
|
+
|
|
333
327
|
# turns an instance of a managed object into a QmfObject
|
|
334
328
|
def qmfify(obj)
|
|
335
329
|
@log.debug("trying to qmfify #{obj}: qmf_oid is #{obj.qmf_oid} and class_id is #{obj.class.class_id}")
|
data/lib/spqr/codegen.rb
CHANGED
data/lib/spqr/constants.rb
CHANGED
|
@@ -59,6 +59,17 @@ module SPQR
|
|
|
59
59
|
"out" => 'Qmf::DIR_OUT',
|
|
60
60
|
"inout" => 'Qmf::DIR_IN_OUT'
|
|
61
61
|
}
|
|
62
|
+
|
|
63
|
+
Severity = {
|
|
64
|
+
"emerg" => "Qmf::SEV_EMERG",
|
|
65
|
+
"error" => "Qmf::SEV_ERROR",
|
|
66
|
+
"notice" => "Qmf::SEV_NOTICE",
|
|
67
|
+
"crit" => "Qmf::SEV_CRIT",
|
|
68
|
+
"debug" => "Qmf::SEV_DEBUG",
|
|
69
|
+
"inform" => "Qmf::SEV_INFORM",
|
|
70
|
+
"alert" => "Qmf::SEV_ALERT",
|
|
71
|
+
"warn" => "Qmf::SEV_WARN"
|
|
72
|
+
}
|
|
62
73
|
end
|
|
63
74
|
|
|
64
75
|
end
|
data/lib/spqr/event.rb
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# SPQR: Schema Processor for QMF/Ruby agents
|
|
2
|
+
#
|
|
3
|
+
# Manageable object mixin and support classes.
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2009--2010 Red Hat, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Author: William Benton (willb@redhat.com)
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
|
|
15
|
+
module SPQR
|
|
16
|
+
class EventMeta < Struct.new(:package, :classname, :args, :severity)
|
|
17
|
+
def initialize(*a)
|
|
18
|
+
super *a
|
|
19
|
+
self.args ||= []
|
|
20
|
+
self.severity ||= :alert
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class EventArgMeta < Struct.new(:name, :kind, :description, :options)
|
|
25
|
+
def initialize(*a)
|
|
26
|
+
super *a
|
|
27
|
+
self.options = ((!self.options && {}) || self.options.dup)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module Raiseable
|
|
32
|
+
module ClassMixins
|
|
33
|
+
include ::SPQR::Util
|
|
34
|
+
|
|
35
|
+
def arg(name, kind, description=nil, options=nil)
|
|
36
|
+
@spqr_event_meta ||= EventMeta.new
|
|
37
|
+
@spqr_event_meta.args << EventArgMeta.new(name.to_sym,kind,description,options)
|
|
38
|
+
attr_accessor name.to_sym
|
|
39
|
+
attr_setters << "#{name.to_s}="
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def spqr_meta
|
|
43
|
+
@spqr_event_meta ||= EventMeta.new
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def log=(logger)
|
|
48
|
+
@spqr_log = logger
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def log
|
|
52
|
+
@spqr_log || ::SPQR::Sink.new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def app=(app)
|
|
56
|
+
@spqr_app = app
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def app
|
|
60
|
+
@spqr_app
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def attr_setters
|
|
64
|
+
@attr_setters ||= []
|
|
65
|
+
@attr_setters
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def schematize
|
|
69
|
+
severity = get_xml_constant(spqr_meta.severity.to_s, ::SPQR::XmlConstants::Severity)
|
|
70
|
+
|
|
71
|
+
@spqr_schema_class = Qmf::SchemaEventClass.new(spqr_meta.package.to_s, spqr_meta.classname.to_s, severity)
|
|
72
|
+
|
|
73
|
+
spqr_meta.args.each do |arg|
|
|
74
|
+
encode_argument(arg, @spqr_schema_class)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
@spqr_schema_class
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def schema_class
|
|
81
|
+
@spqr_schema_class
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def qmf_package_name(nm)
|
|
85
|
+
spqr_meta.package = nm
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def qmf_class_name(nm)
|
|
89
|
+
spqr_meta.classname = nm
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def qmf_severity(sev)
|
|
93
|
+
raise ArgumentError.new("Invalid event severity '#{sev.inspect}'") unless ::SPQR::XmlConstants::Severity.keys.include? sev.to_s
|
|
94
|
+
spqr_meta.severity = sev
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
alias severity qmf_severity
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
module InstanceMixins
|
|
101
|
+
def initialize(*args)
|
|
102
|
+
if args.size > self.class.attr_setters.size
|
|
103
|
+
msg = "Too many arguments (max #{self.class.attr_setters.size}) to #{self.class.name}#initialize: #{args}"
|
|
104
|
+
log.error msg
|
|
105
|
+
raise ArgumentError.new(msg)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
message_pairs = self.class.attr_setters.zip(args).reject {|setter,val| val==nil}
|
|
109
|
+
message_pairs.each {|message| self.send *message}
|
|
110
|
+
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def app
|
|
114
|
+
self.class.app
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def schema_class
|
|
118
|
+
self.class.schema_class
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def log
|
|
122
|
+
self.class.log
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def bang!
|
|
126
|
+
unless schema_class
|
|
127
|
+
log.fatal("No schema class defined for SPQR event class #{self.class.name}; will not raise event. Did you register this event class?")
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
log.info("Raising an event of class #{self.class.name}")
|
|
132
|
+
|
|
133
|
+
event = Qmf::QmfEvent.new(schema_class)
|
|
134
|
+
log.debug "Created QmfEvent is #{event.inspect}"
|
|
135
|
+
|
|
136
|
+
self.class.spqr_meta.args.each do |arg|
|
|
137
|
+
val = self.send arg.name
|
|
138
|
+
log.debug "setting #{arg.name} of event to #{val}"
|
|
139
|
+
event.send "#{arg.name}=", val
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
log.debug "event to raise is #{event.inspect} (#{event})"
|
|
143
|
+
log.debug "arguments are #{event.arguments.inspect} (#{event.arguments})"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
app.agent.raise_event(event)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def self.included(receiver)
|
|
151
|
+
receiver.extend ClassMixins
|
|
152
|
+
receiver.send :include, InstanceMixins
|
|
153
|
+
|
|
154
|
+
name_components = receiver.name.to_s.split("::")
|
|
155
|
+
receiver.qmf_class_name name_components.pop
|
|
156
|
+
receiver.qmf_package_name name_components.join(".").downcase
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
data/lib/spqr/manageable.rb
CHANGED
|
@@ -245,6 +245,16 @@ module SPQR
|
|
|
245
245
|
raise ManageableObjectError.new(*args)
|
|
246
246
|
end
|
|
247
247
|
|
|
248
|
+
# Returns the user ID of the QMF user invoking this method
|
|
249
|
+
def qmf_user_id
|
|
250
|
+
Thread.current[:qmf_user_id]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Returns QMF context of the current method invocation
|
|
254
|
+
def qmf_context
|
|
255
|
+
Thread.current[:qmf_context]
|
|
256
|
+
end
|
|
257
|
+
|
|
248
258
|
def qmf_oid
|
|
249
259
|
result = 0
|
|
250
260
|
if self.respond_to? :spqr_object_id
|
data/lib/spqr/spqr.rb
CHANGED
data/lib/spqr/utils.rb
CHANGED
|
@@ -72,17 +72,56 @@ module SPQR
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
|
-
|
|
76
|
-
module
|
|
75
|
+
|
|
76
|
+
module Util
|
|
77
77
|
def symbolize_dict(k, kz=nil)
|
|
78
78
|
k2 = {}
|
|
79
79
|
kz ||= k.keys
|
|
80
80
|
|
|
81
81
|
k.keys.each do |key|
|
|
82
|
-
k2[key.to_sym] = k[key] if (kz.include?(key)
|
|
82
|
+
k2[key.to_sym] = k[key] if (kz.include?(key) || kz.include?(key.to_sym))
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
k2
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
def get_xml_constant(xml_key, dictionary)
|
|
89
|
+
string_val = dictionary[xml_key]
|
|
90
|
+
return xml_key unless string_val
|
|
91
|
+
|
|
92
|
+
actual_val = const_lookup(string_val)
|
|
93
|
+
return string_val unless actual_val
|
|
94
|
+
|
|
95
|
+
return actual_val
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# turns a string name of a constant into the value of that
|
|
99
|
+
# constant; returns that value, or nil if fqcn doesn't correspond
|
|
100
|
+
# to a valid constant
|
|
101
|
+
def const_lookup(fqcn)
|
|
102
|
+
# FIXME: move out of App, into a utils module?
|
|
103
|
+
hierarchy = fqcn.split("::")
|
|
104
|
+
const = hierarchy.pop
|
|
105
|
+
mod = Kernel
|
|
106
|
+
hierarchy.each do |m|
|
|
107
|
+
mod = mod.const_get(m)
|
|
108
|
+
end
|
|
109
|
+
mod.const_get(const) rescue nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def encode_argument(arg, destination)
|
|
113
|
+
arg_opts = arg.options
|
|
114
|
+
arg_opts[:desc] ||= arg.description if (arg.description && arg.description.is_a?(String))
|
|
115
|
+
arg_opts[:dir] ||= get_xml_constant(arg.direction.to_s, ::SPQR::XmlConstants::Direction) if arg.respond_to? :direction
|
|
116
|
+
arg_name = arg.name.to_s
|
|
117
|
+
arg_type = get_xml_constant(arg.kind.to_s, ::SPQR::XmlConstants::Type)
|
|
118
|
+
|
|
119
|
+
destination.add_argument(Qmf::SchemaArgument.new(arg_name, arg_type, arg_opts))
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def manageable?(k)
|
|
123
|
+
k.is_a?(Class) && (k.included_modules.include?(::SPQR::Manageable) || k.included_modules.include?(::SPQR::Raiseable))
|
|
124
|
+
end
|
|
125
|
+
|
|
87
126
|
end
|
|
88
127
|
end
|
data/ruby-spqr.spec.in
CHANGED
|
@@ -41,6 +41,7 @@ mkdir -p %{buildroot}/%{ruby_sitelib}/spqr
|
|
|
41
41
|
cp -f lib/spqr/app.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
42
42
|
cp -f lib/spqr/codegen.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
43
43
|
cp -f lib/spqr/constants.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
44
|
+
cp -f lib/spqr/event.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
44
45
|
cp -f lib/spqr/manageable.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
45
46
|
cp -f lib/spqr/spqr.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
46
47
|
cp -f lib/spqr/utils.rb %{buildroot}/%{ruby_sitelib}/spqr
|
|
@@ -56,6 +57,7 @@ rm -rf %{buildroot}
|
|
|
56
57
|
%{ruby_sitelib}/spqr/app.rb
|
|
57
58
|
%{ruby_sitelib}/spqr/codegen.rb
|
|
58
59
|
%{ruby_sitelib}/spqr/constants.rb
|
|
60
|
+
%{ruby_sitelib}/spqr/event.rb
|
|
59
61
|
%{ruby_sitelib}/spqr/manageable.rb
|
|
60
62
|
%{ruby_sitelib}/spqr/spqr.rb
|
|
61
63
|
%{ruby_sitelib}/spqr/utils.rb
|
|
@@ -68,6 +70,9 @@ rm -rf %{buildroot}
|
|
|
68
70
|
|
|
69
71
|
%changelog
|
|
70
72
|
|
|
73
|
+
* Mon May 10 2010 <willb@redhat> - 0.3.0-1
|
|
74
|
+
- updated to version 0.3.0-1
|
|
75
|
+
|
|
71
76
|
* Mon Apr 12 2010 <willb@redhat> - 0.2.4-1
|
|
72
77
|
- updated to version 0.2.4-1
|
|
73
78
|
|
data/test/example-apps.rb
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
class QmfUserAndContext
|
|
2
|
+
include ::SPQR::Manageable
|
|
3
|
+
|
|
4
|
+
def QmfUserAndContext.find_by_id(oid)
|
|
5
|
+
@singleton ||= QmfUserAndContext.new
|
|
6
|
+
@singleton
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def QmfUserAndContext.find_all
|
|
10
|
+
@singleton ||= QmfUserAndContext.new
|
|
11
|
+
[@singleton]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
expose :qmf_user_id do |args|
|
|
15
|
+
args.declare :uid, :sstr, :out
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
expose :qmf_context do |args|
|
|
19
|
+
args.declare :ctx, :uint64, :out
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
1
23
|
class QmfClicker
|
|
2
24
|
include ::SPQR::Manageable
|
|
3
25
|
|
|
@@ -233,3 +255,90 @@ class QmfListArg
|
|
|
233
255
|
qmf_class_name :QmfListArg
|
|
234
256
|
qmf_package_name :example
|
|
235
257
|
end
|
|
258
|
+
|
|
259
|
+
class DummyEvent
|
|
260
|
+
include ::SPQR::Raiseable
|
|
261
|
+
|
|
262
|
+
qmf_class_name :DummyEvent
|
|
263
|
+
qmf_package_name :example
|
|
264
|
+
qmf_severity :notice
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
class QmfDummyEventer
|
|
268
|
+
include ::SPQR::Manageable
|
|
269
|
+
|
|
270
|
+
def qmf_oid
|
|
271
|
+
1234
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def spqr_object_id
|
|
275
|
+
1234
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def QmfDummyEventer.find_by_id(oid)
|
|
279
|
+
@objs ||= [QmfDummyEventer.new]
|
|
280
|
+
@objs[0]
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def QmfDummyEventer.find_all
|
|
284
|
+
@objs ||= [QmfDummyEventer.new]
|
|
285
|
+
@objs
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def party_on
|
|
289
|
+
DummyEvent.new.bang!
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
expose :party_on do |args|
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
qmf_class_name :QmfDummyEventer
|
|
296
|
+
qmf_package_name :example
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class ArgEvent
|
|
301
|
+
include ::SPQR::Raiseable
|
|
302
|
+
|
|
303
|
+
arg :arg, :map, "A map from the name of the party_on method to the first count even numbers"
|
|
304
|
+
|
|
305
|
+
qmf_class_name :ArgEvent
|
|
306
|
+
qmf_package_name :example
|
|
307
|
+
qmf_severity :notice
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
class QmfArgEventer
|
|
311
|
+
include ::SPQR::Manageable
|
|
312
|
+
|
|
313
|
+
def qmf_oid
|
|
314
|
+
1234
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def spqr_object_id
|
|
318
|
+
1234
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def QmfArgEventer.find_by_id(oid)
|
|
322
|
+
@objs ||= [QmfArgEventer.new]
|
|
323
|
+
@objs[0]
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def QmfArgEventer.find_all
|
|
327
|
+
@objs ||= [QmfArgEventer.new]
|
|
328
|
+
@objs
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def party_on_one(name, count)
|
|
332
|
+
ls = (1..count).to_a.map {|x| x*2}
|
|
333
|
+
# ArgEvent.new({name=>ls}).bang!
|
|
334
|
+
ArgEvent.new({name=>count}).bang!
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
expose :party_on_one do |args|
|
|
338
|
+
args.declare :name, :sstr, :in
|
|
339
|
+
args.declare :count, :uint64, :in
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
qmf_class_name :QmfArgEventer
|
|
343
|
+
qmf_package_name :example
|
|
344
|
+
end
|
data/test/helper.rb
CHANGED
|
@@ -10,22 +10,34 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
|
10
10
|
require 'spqr/spqr'
|
|
11
11
|
require 'spqr/app'
|
|
12
12
|
|
|
13
|
+
$QMFENGINE_CONSOLE_SUPPORTS_EVENTS = (::ENV["QMFENGINE_CONSOLE_SUPPORTS_EVENTS"] && ::ENV["QMFENGINE_CONSOLE_SUPPORTS_EVENTS"] == "1")
|
|
14
|
+
|
|
13
15
|
module QmfTestHelpers
|
|
14
|
-
DEBUG = (::ENV["SPQR_TESTS_DEBUG"]
|
|
16
|
+
DEBUG = (::ENV["SPQR_TESTS_DEBUG"] && ((::ENV["SPQR_TESTS_DEBUG"].downcase == "yes" && "yes") || (::ENV["SPQR_TESTS_DEBUG"].downcase == "trace" && "trace")))
|
|
15
17
|
|
|
16
18
|
class AgentNotifyHandler < Qmf::ConsoleHandler
|
|
17
19
|
def initialize
|
|
18
20
|
@q = Queue.new
|
|
21
|
+
@eq = Queue.new
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
def queue
|
|
22
25
|
@q
|
|
23
26
|
end
|
|
27
|
+
|
|
28
|
+
def event_queue
|
|
29
|
+
@eq
|
|
30
|
+
end
|
|
24
31
|
|
|
25
32
|
def agent_added(agent)
|
|
26
33
|
puts "GOT AN AGENT: #{agent} at #{Time.now.utc}" if DEBUG
|
|
27
34
|
@q << agent
|
|
28
35
|
end
|
|
36
|
+
|
|
37
|
+
def event_received(event)
|
|
38
|
+
puts "GOT AN EVENT: #{event} at #{Time.now.utc}"
|
|
39
|
+
@eq << event
|
|
40
|
+
end
|
|
29
41
|
end
|
|
30
42
|
|
|
31
43
|
def app_setup(*classes)
|
|
@@ -47,14 +59,14 @@ module QmfTestHelpers
|
|
|
47
59
|
$stdout.reopen("/dev/null", "w")
|
|
48
60
|
$stderr.reopen("/dev/null", "w")
|
|
49
61
|
else
|
|
50
|
-
ENV['QPID_TRACE'] = "1"
|
|
62
|
+
ENV['QPID_TRACE'] = "1" if DEBUG == "trace"
|
|
51
63
|
end
|
|
52
64
|
|
|
53
65
|
exec("#{File.dirname(__FILE__)}/generic-agent.rb", *classes.map {|cl| cl.to_s})
|
|
54
66
|
exit! 127
|
|
55
67
|
|
|
56
68
|
@app = SPQR::App.new(:loglevel => (DEBUG ? :debug : :fatal), :appname=>"#{classes.join("")}[#{Process.pid}]")
|
|
57
|
-
@app.register
|
|
69
|
+
@app.register(*classes)
|
|
58
70
|
|
|
59
71
|
@app.main
|
|
60
72
|
end
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
require 'qmf'
|
|
2
|
+
|
|
3
|
+
class App < Qmf::AgentHandler
|
|
4
|
+
class ClassMeta < Struct.new(:object_class, :schema_class) ; end
|
|
5
|
+
|
|
6
|
+
attr_reader :agent
|
|
7
|
+
|
|
8
|
+
def initialize(options=nil)
|
|
9
|
+
defaults = {:logfile=>STDERR, :loglevel=>Logger::WARN, :notifier=>nil, :server=>"localhost", :port=>5672}
|
|
10
|
+
|
|
11
|
+
# convenient shorthands for log levels
|
|
12
|
+
loglevels = {:debug => Logger::DEBUG, :info => Logger::INFO, :warn => Logger::WARN, :error => Logger::ERROR, :fatal => Logger::FATAL}
|
|
13
|
+
|
|
14
|
+
options = defaults unless options
|
|
15
|
+
|
|
16
|
+
# set unsupplied options to defaults
|
|
17
|
+
defaults.each do |k,v|
|
|
18
|
+
options[k] = v unless options[k]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# fix up shorthands
|
|
22
|
+
options[:loglevel] = loglevels[options[:loglevel]] if loglevels[options[:loglevel]]
|
|
23
|
+
|
|
24
|
+
logger_opts = ([options[:logfile]] + [options[:logoptions]]).flatten.compact
|
|
25
|
+
|
|
26
|
+
@log = Logger.new(*logger_opts)
|
|
27
|
+
@log.level = options[:loglevel]
|
|
28
|
+
|
|
29
|
+
@log.info("initializing SPQR app....")
|
|
30
|
+
|
|
31
|
+
@classes_by_name = {}
|
|
32
|
+
@classes_by_id = {}
|
|
33
|
+
@pipe = options[:notifier]
|
|
34
|
+
@app_name = (options[:appname] or "SPQR application [#{Process.pid}]")
|
|
35
|
+
@qmf_host = options[:server]
|
|
36
|
+
@qmf_port = options[:port]
|
|
37
|
+
@qmf_sendUserId = if options.has_key?(:send_user_id)
|
|
38
|
+
options[:send_user_id]
|
|
39
|
+
else
|
|
40
|
+
(options.has_key?(:user) || options.has_key?(:password))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@qmf_user = options[:user]
|
|
44
|
+
@qmf_password = options[:password]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def register(*ks)
|
|
48
|
+
manageable_ks = ks.select {|kl| manageable? kl}
|
|
49
|
+
unmanageable_ks = ks.select {|kl| not manageable? kl}
|
|
50
|
+
manageable_ks.each do |klass|
|
|
51
|
+
schemaclass = schematize(klass)
|
|
52
|
+
|
|
53
|
+
klass.log = @log
|
|
54
|
+
|
|
55
|
+
# XXX
|
|
56
|
+
if klass.included_modules.include?(::SPQR::Manageable)
|
|
57
|
+
@classes_by_id[klass.class_id] = klass
|
|
58
|
+
@classes_by_name[klass.spqr_meta.classname.to_s] = ClassMeta.new(klass, schemaclass)
|
|
59
|
+
else
|
|
60
|
+
@log.info "NOT registering query/lookup info for #{klass}; is it an event class?"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
@log.info("SETTING #{klass.spqr_meta.classname}.app to #{self.inspect}")
|
|
64
|
+
klass.app = self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
unmanageable_ks.each do |klass|
|
|
68
|
+
@log.warn("SPQR can't manage #{klass}, which was registered")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def method_call(context, name, obj_id, args, user_id)
|
|
74
|
+
begin
|
|
75
|
+
status = 0
|
|
76
|
+
message = "OK"
|
|
77
|
+
failed = false
|
|
78
|
+
|
|
79
|
+
class_id = obj_id.object_num_high
|
|
80
|
+
obj_id = obj_id.object_num_low
|
|
81
|
+
|
|
82
|
+
Thread.current[:qmf_user_id] = user_id
|
|
83
|
+
Thread.current[:qmf_context] = context
|
|
84
|
+
|
|
85
|
+
@log.debug "calling method: context=#{context} method=#{name} object_id=#{obj_id}, user=#{user_id}"
|
|
86
|
+
|
|
87
|
+
managed_object = find_object(context, class_id, obj_id)
|
|
88
|
+
@log.debug("managed object is #{managed_object}")
|
|
89
|
+
managed_method = managed_object.class.spqr_meta.mmethods[name.to_sym]
|
|
90
|
+
|
|
91
|
+
raise RuntimeError.new("#{managed_object.class} does not have #{name} exposed as a manageable method; has #{managed_object.class.spqr_meta.mmethods.inspect}") unless managed_method
|
|
92
|
+
|
|
93
|
+
# Extract actual parameters from the Qmf::Arguments structure into a proper ruby list
|
|
94
|
+
@log.debug("actual params are: #{args.instance_variable_get(:@by_hash).inspect}") rescue nil
|
|
95
|
+
actuals_in = managed_method.formals_in.inject([]) {|acc,nm| acc << args[nm]}
|
|
96
|
+
actual_count = actuals_in.size
|
|
97
|
+
|
|
98
|
+
@log.debug("managed_object.respond_to? #{managed_method.name.to_sym} ==> #{managed_object.respond_to? managed_method.name.to_sym}")
|
|
99
|
+
@log.debug("managed_object.class.spqr_meta.mmethods.include? #{name.to_sym} ==> #{managed_object.class.spqr_meta.mmethods.include? name.to_sym}")
|
|
100
|
+
@log.debug("formals: #{managed_method.formals_in.inspect}")
|
|
101
|
+
@log.debug("actuals: #{actuals_in.inspect}")
|
|
102
|
+
|
|
103
|
+
actuals_out = []
|
|
104
|
+
|
|
105
|
+
begin
|
|
106
|
+
actuals_out = case actual_count
|
|
107
|
+
when 0 then managed_object.send(name.to_sym)
|
|
108
|
+
when 1 then managed_object.send(name.to_sym, actuals_in[0])
|
|
109
|
+
else managed_object.send(name.to_sym, *actuals_in)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
raise RuntimeError.new("#{managed_object.class} did not return the appropriate number of return values; got '#{actuals_out.inspect}', but expected #{managed_method.types_out.inspect}") unless result_valid(actuals_out, managed_method)
|
|
113
|
+
|
|
114
|
+
rescue ::SPQR::ManageableObjectError => failure
|
|
115
|
+
@log.info "#{name} called SPQR::Manageable#fail: #{failure}"
|
|
116
|
+
status = failure.status
|
|
117
|
+
message = failure.message || "ERROR"
|
|
118
|
+
# XXX: failure.result is currently ignored
|
|
119
|
+
actuals_out = failure.result || managed_method.formals_out.inject([]) {|acc, val| acc << args[val]; acc}
|
|
120
|
+
failed = true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if managed_method.formals_out.size == 0
|
|
124
|
+
actuals_out = [] # ignore return value in this case
|
|
125
|
+
elsif managed_method.formals_out.size == 1
|
|
126
|
+
actuals_out = [actuals_out] # wrap this up in a list
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
@log.debug("formals_out == #{managed_method.formals_out.inspect}")
|
|
130
|
+
@log.debug("actuals_out == #{actuals_out.inspect}")
|
|
131
|
+
|
|
132
|
+
unless failed
|
|
133
|
+
# Copy any out parameters from return value to the
|
|
134
|
+
# Qmf::Arguments structure; see XXX above
|
|
135
|
+
managed_method.formals_out.zip(actuals_out).each do |k,v|
|
|
136
|
+
@log.debug("fixing up out params: #{k.inspect} --> #{v.inspect}")
|
|
137
|
+
encoded_val = encode_object(v)
|
|
138
|
+
args[k] = encoded_val
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
@agent.method_response(context, status, message, args)
|
|
143
|
+
rescue Exception => ex
|
|
144
|
+
@log.error "Error calling #{name}: #{ex}"
|
|
145
|
+
@log.error " " + ex.backtrace.join("\n ")
|
|
146
|
+
@agent.method_response(context, 1, "ERROR: #{ex}", args)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def get_query(context, query, user_id)
|
|
151
|
+
@log.debug "query: user=#{user_id} context=#{context} class=#{query.class_name} object_num=#{query.object_id.object_num_low if query.object_id} details=#{query} haveSelect=#{query.impl and query.impl.haveSelect} getSelect=#{query.impl and query.impl.getSelect} (#{query.impl and query.impl.getSelect and query.impl.getSelect.methods.inspect})"
|
|
152
|
+
|
|
153
|
+
cmeta = @classes_by_name[query.class_name]
|
|
154
|
+
objs = []
|
|
155
|
+
|
|
156
|
+
# XXX: are these cases mutually exclusive?
|
|
157
|
+
|
|
158
|
+
# handle queries for a certain class
|
|
159
|
+
if cmeta
|
|
160
|
+
objs = objs + cmeta.object_class.find_all.collect {|obj| qmfify(obj)}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# handle queries for a specific object
|
|
164
|
+
o = find_object(context, query.object_id.object_num_high, query.object_id.object_num_low) rescue nil
|
|
165
|
+
if o
|
|
166
|
+
objs << qmfify(o)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
objs.each do |obj|
|
|
170
|
+
@log.debug("query_response of: #{obj.inspect}")
|
|
171
|
+
@agent.query_response(context, obj) rescue @log.error($!.inspect)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
@log.debug("completing query....")
|
|
175
|
+
@agent.query_complete(context)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def main
|
|
179
|
+
settings = Qmf::ConnectionSettings.new
|
|
180
|
+
settings.host = @qmf_host
|
|
181
|
+
settings.port = @qmf_port
|
|
182
|
+
settings.sendUserId = @qmf_sendUserId
|
|
183
|
+
|
|
184
|
+
settings.username = @qmf_user if @qmf_sendUserId
|
|
185
|
+
settings.password = @qmf_password if @qmf_sendUserId
|
|
186
|
+
|
|
187
|
+
@schemaclass = Qmf::SchemaObjectClass.new("test", "testclass")
|
|
188
|
+
|
|
189
|
+
@connection = Qmf::Connection.new(settings)
|
|
190
|
+
@log.debug(" +-- @connection created: #{@connection}")
|
|
191
|
+
@log.debug(" +-- app name is '#{@app_name}'")
|
|
192
|
+
|
|
193
|
+
@agent = Qmf::Agent.new(self, @app_name)
|
|
194
|
+
@log.debug(" +-- @agent created: #{@agent}")
|
|
195
|
+
|
|
196
|
+
@agent.set_connection(@connection)
|
|
197
|
+
@log.debug(" +-- @agent.set_connection called")
|
|
198
|
+
|
|
199
|
+
@log.debug(" +-- registering classes...")
|
|
200
|
+
@classes_by_name.values.each do |km|
|
|
201
|
+
@agent.register_class(km.schema_class)
|
|
202
|
+
@log.debug(" +--+-- #{km.schema_class.package_name} #{km.schema_class.class_name} registered")
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
@log.debug("entering orbit....")
|
|
206
|
+
|
|
207
|
+
sleep
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
private
|
|
211
|
+
|
|
212
|
+
def result_valid(actuals, mm)
|
|
213
|
+
(actuals.kind_of?(Array) and mm.formals_out.size == actuals.size) or mm.formals_out.size <= 1
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def qmf_arguments_to_hash(args)
|
|
217
|
+
result = {}
|
|
218
|
+
args.each do |k,v|
|
|
219
|
+
result[k] = v
|
|
220
|
+
end
|
|
221
|
+
result
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def encode_object(o)
|
|
225
|
+
return o unless o.kind_of? ::SPQR::Manageable
|
|
226
|
+
@agent.alloc_object_id(*(o.qmf_id))
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def find_object(ctx, c_id, obj_id)
|
|
230
|
+
# XXX: context is currently ignored
|
|
231
|
+
@log.debug("in find_object; class ID is #{c_id}, object ID is #{obj_id}...")
|
|
232
|
+
klass = @classes_by_id[c_id]
|
|
233
|
+
@log.debug("found class #{klass.inspect}")
|
|
234
|
+
klass.find_by_id(obj_id) if klass
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def schematize(klass)
|
|
238
|
+
@log.info("Making a QMF schema for #{klass.spqr_meta.classname}")
|
|
239
|
+
|
|
240
|
+
if klass.respond_to? :schematize
|
|
241
|
+
@log.info("#{klass.spqr_meta.classname} knows how to schematize itself; it's probably an event class")
|
|
242
|
+
return klass.schematize
|
|
243
|
+
else
|
|
244
|
+
@log.info("#{klass.spqr_meta.classname} doesn't know how to schematize itself; it's probably an object class")
|
|
245
|
+
return schematize_object_class(klass)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def schematize_object_class(klass)
|
|
250
|
+
meta = klass.spqr_meta
|
|
251
|
+
package = meta.package.to_s
|
|
252
|
+
classname = meta.classname.to_s
|
|
253
|
+
@log.info("+-- class #{classname} is in package #{package}")
|
|
254
|
+
|
|
255
|
+
sc = Qmf::SchemaObjectClass.new(package, classname)
|
|
256
|
+
|
|
257
|
+
meta.manageable_methods.each do |mm|
|
|
258
|
+
@log.info("+-- creating a QMF schema for method #{mm}")
|
|
259
|
+
m_opts = mm.options
|
|
260
|
+
m_opts[:desc] ||= mm.description if mm.description
|
|
261
|
+
|
|
262
|
+
method = Qmf::SchemaMethod.new(mm.name.to_s, m_opts)
|
|
263
|
+
|
|
264
|
+
mm.args.each do |arg|
|
|
265
|
+
@log.info("| +-- creating a QMF schema for arg #{arg}")
|
|
266
|
+
|
|
267
|
+
encode_argument(arg, method)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
sc.add_method(method)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
add_attributes(sc, meta.properties, :add_property, Qmf::SchemaProperty)
|
|
274
|
+
add_attributes(sc, meta.statistics, :add_statistic, Qmf::SchemaStatistic)
|
|
275
|
+
|
|
276
|
+
sc
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def add_attributes(sc, collection, msg, klass, what=nil)
|
|
280
|
+
what ||= (msg.to_s.split("_").pop rescue "property or statistic")
|
|
281
|
+
collection.each do |basic|
|
|
282
|
+
basic_name = basic.name.to_s
|
|
283
|
+
basic_type = get_xml_constant(basic.kind.to_s, ::SPQR::XmlConstants::Type)
|
|
284
|
+
@log.debug("+-- creating a QMF schema for #{what} #{basic_name} (#{basic_type}) with options #{basic.options.inspect}")
|
|
285
|
+
sc.send(msg, klass.new(basic_name, basic_type, basic.options))
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
include ::SPQR::Util
|
|
290
|
+
|
|
291
|
+
# turns an instance of a managed object into a QmfObject
|
|
292
|
+
def qmfify(obj)
|
|
293
|
+
@log.debug("trying to qmfify #{obj}: qmf_oid is #{obj.qmf_oid} and class_id is #{obj.class.class_id}")
|
|
294
|
+
cm = @classes_by_name[obj.class.spqr_meta.classname.to_s]
|
|
295
|
+
return nil unless cm
|
|
296
|
+
|
|
297
|
+
qmfobj = Qmf::AgentObject.new(cm.schema_class)
|
|
298
|
+
|
|
299
|
+
set_attrs(qmfobj, obj)
|
|
300
|
+
|
|
301
|
+
@log.debug("calling alloc_object_id(#{obj.qmf_oid}, #{obj.class.class_id})")
|
|
302
|
+
oid = @agent.alloc_object_id(obj.qmf_oid, obj.class.class_id)
|
|
303
|
+
|
|
304
|
+
@log.debug("calling qmfobj.set_object_id(#{oid})")
|
|
305
|
+
qmfobj.set_object_id(oid)
|
|
306
|
+
|
|
307
|
+
@log.debug("returning from qmfify")
|
|
308
|
+
qmfobj
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def set_attrs(qo, o)
|
|
312
|
+
return unless o.class.respond_to? :spqr_meta
|
|
313
|
+
|
|
314
|
+
attrs = o.class.spqr_meta.properties + o.class.spqr_meta.statistics
|
|
315
|
+
|
|
316
|
+
attrs.each do |a|
|
|
317
|
+
getter = a.name.to_s
|
|
318
|
+
@log.debug("setting property/statistic #{getter} to its value from #{o}: #{o.send(getter) if o.respond_to?(getter)}")
|
|
319
|
+
value = o.send(getter) if o.respond_to?(getter)
|
|
320
|
+
|
|
321
|
+
if value || a.kind == :bool
|
|
322
|
+
# XXX: remove this line when/if Manageable includes an
|
|
323
|
+
# appropriate impl method
|
|
324
|
+
value = encode_object(value) if value.kind_of?(::SPQR::Manageable)
|
|
325
|
+
qo[getter] = value
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
data/test/test_events.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
require 'set'
|
|
3
|
+
require 'example-apps'
|
|
4
|
+
|
|
5
|
+
class TestEvents < Test::Unit::TestCase
|
|
6
|
+
include QmfTestHelpers
|
|
7
|
+
|
|
8
|
+
def setup
|
|
9
|
+
@child_pid = nil
|
|
10
|
+
$notify_handler.event_queue.clear if $notify_handler
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_dummy_event
|
|
14
|
+
app_setup DummyEvent, QmfDummyEventer
|
|
15
|
+
de = $console.object(:class=>"QmfDummyEventer", :agent=>@ag)
|
|
16
|
+
method_response = de.party_on
|
|
17
|
+
assert_equal 0, method_response.status
|
|
18
|
+
|
|
19
|
+
sleep 2
|
|
20
|
+
|
|
21
|
+
if $QMFENGINE_CONSOLE_SUPPORTS_EVENTS
|
|
22
|
+
ev = Timeout::timeout(5) do
|
|
23
|
+
$notify_handler.event_queue.pop
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# XXX: make an appropriate assertion about ev here
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_arg_event
|
|
31
|
+
app_setup ArgEvent, QmfArgEventer
|
|
32
|
+
de = $console.object(:class=>"QmfArgEventer", :agent=>@ag)
|
|
33
|
+
method_response = de.party_on_one("foobar", 5)
|
|
34
|
+
assert_equal 0, method_response.status
|
|
35
|
+
sleep 2
|
|
36
|
+
|
|
37
|
+
if $QMFENGINE_CONSOLE_SUPPORTS_EVENTS
|
|
38
|
+
ev = Timeout::timeout(5) do
|
|
39
|
+
$notify_handler.event_queue.pop
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# XXX: make an appropriate assertion about ev here
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
require 'set'
|
|
3
|
+
require 'example-apps'
|
|
4
|
+
|
|
5
|
+
class TestUserAndContext < Test::Unit::TestCase
|
|
6
|
+
include QmfTestHelpers
|
|
7
|
+
|
|
8
|
+
def setup
|
|
9
|
+
@child_pid = nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_user_id
|
|
13
|
+
app_setup QmfUserAndContext
|
|
14
|
+
|
|
15
|
+
uac = $console.object(:class=>"QmfUserAndContext", :agent=>@ag)
|
|
16
|
+
userid = uac.qmf_user_id.uid
|
|
17
|
+
assert_equal(::ENV['SPQR_TESTS_QMF_USER_ID'] || "anonymous", userid)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_context
|
|
21
|
+
app_setup QmfUserAndContext
|
|
22
|
+
|
|
23
|
+
uac = $console.object(:class=>"QmfUserAndContext", :agent=>@ag)
|
|
24
|
+
ctx = uac.qmf_context.ctx
|
|
25
|
+
|
|
26
|
+
9.times do
|
|
27
|
+
old_ctx = ctx
|
|
28
|
+
assert(old_ctx < uac.qmf_context.ctx)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
metadata
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spqr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
5
|
-
segments:
|
|
6
|
-
- 0
|
|
7
|
-
- 2
|
|
8
|
-
- 4
|
|
9
|
-
version: 0.2.4
|
|
4
|
+
version: 0.3.0
|
|
10
5
|
platform: ruby
|
|
11
6
|
authors:
|
|
12
7
|
- William Benton
|
|
@@ -14,23 +9,19 @@ autorequire:
|
|
|
14
9
|
bindir: bin
|
|
15
10
|
cert_chain: []
|
|
16
11
|
|
|
17
|
-
date: 2010-
|
|
12
|
+
date: 2010-05-10 00:00:00 -05:00
|
|
18
13
|
default_executable: spqr-gen.rb
|
|
19
14
|
dependencies:
|
|
20
15
|
- !ruby/object:Gem::Dependency
|
|
21
16
|
name: rspec
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
type: :development
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
20
|
requirements:
|
|
25
21
|
- - ">="
|
|
26
22
|
- !ruby/object:Gem::Version
|
|
27
|
-
segments:
|
|
28
|
-
- 1
|
|
29
|
-
- 2
|
|
30
|
-
- 9
|
|
31
23
|
version: 1.2.9
|
|
32
|
-
|
|
33
|
-
version_requirements: *id001
|
|
24
|
+
version:
|
|
34
25
|
description: SPQR makes it very simple to expose methods on Ruby objects over QMF. You must install ruby-qmf in order to use SPQR.
|
|
35
26
|
email: willb@redhat.com
|
|
36
27
|
executables:
|
|
@@ -57,6 +48,7 @@ files:
|
|
|
57
48
|
- lib/spqr/app.rb
|
|
58
49
|
- lib/spqr/codegen.rb
|
|
59
50
|
- lib/spqr/constants.rb
|
|
51
|
+
- lib/spqr/event.rb
|
|
60
52
|
- lib/spqr/manageable.rb
|
|
61
53
|
- lib/spqr/spqr.rb
|
|
62
54
|
- lib/spqr/utils.rb
|
|
@@ -68,6 +60,7 @@ files:
|
|
|
68
60
|
- test/example-apps.rb
|
|
69
61
|
- test/generic-agent.rb
|
|
70
62
|
- test/helper.rb
|
|
63
|
+
- test/test_events.rb
|
|
71
64
|
- test/test_failbot.rb
|
|
72
65
|
- test/test_spqr_boolprop.rb
|
|
73
66
|
- test/test_spqr_clicker.rb
|
|
@@ -75,6 +68,7 @@ files:
|
|
|
75
68
|
- test/test_spqr_hello.rb
|
|
76
69
|
- test/test_spqr_integerprop.rb
|
|
77
70
|
- test/test_spqr_listarg.rb
|
|
71
|
+
- test/test_user_and_context.rb
|
|
78
72
|
has_rdoc: true
|
|
79
73
|
homepage: http://git.fedorahosted.org/git/grid/spqr.git
|
|
80
74
|
licenses: []
|
|
@@ -88,20 +82,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
88
82
|
requirements:
|
|
89
83
|
- - ">="
|
|
90
84
|
- !ruby/object:Gem::Version
|
|
91
|
-
segments:
|
|
92
|
-
- 0
|
|
93
85
|
version: "0"
|
|
86
|
+
version:
|
|
94
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
88
|
requirements:
|
|
96
89
|
- - ">="
|
|
97
90
|
- !ruby/object:Gem::Version
|
|
98
|
-
segments:
|
|
99
|
-
- 0
|
|
100
91
|
version: "0"
|
|
92
|
+
version:
|
|
101
93
|
requirements: []
|
|
102
94
|
|
|
103
95
|
rubyforge_project:
|
|
104
|
-
rubygems_version: 1.3.
|
|
96
|
+
rubygems_version: 1.3.5
|
|
105
97
|
signing_key:
|
|
106
98
|
specification_version: 3
|
|
107
99
|
summary: "SPQR: {Schema Processor|Straightforward Publishing} for QMF agents in Ruby"
|
|
@@ -112,12 +104,14 @@ test_files:
|
|
|
112
104
|
- test/test_spqr_dummyprop.rb
|
|
113
105
|
- test/test_spqr_listarg.rb
|
|
114
106
|
- test/generic-agent.rb
|
|
107
|
+
- test/test_events.rb
|
|
115
108
|
- test/helper.rb
|
|
116
109
|
- test/test_failbot.rb
|
|
117
110
|
- test/test_spqr_boolprop.rb
|
|
111
|
+
- test/standalone-test.rb
|
|
118
112
|
- test/test_spqr_clicker.rb
|
|
119
113
|
- test/test_spqr_integerprop.rb
|
|
114
|
+
- test/test_user_and_context.rb
|
|
120
115
|
- test/test_spqr_hello.rb
|
|
121
116
|
- examples/hello.rb
|
|
122
|
-
- examples/codegen/EchoAgent.rb
|
|
123
117
|
- examples/logservice.rb
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
module Examples
|
|
2
|
-
module Codegen
|
|
3
|
-
class EchoAgent
|
|
4
|
-
include SPQR::Manageable
|
|
5
|
-
|
|
6
|
-
spqr_package 'examples.codegen'
|
|
7
|
-
spqr_class 'EchoAgent'
|
|
8
|
-
# Find method (NB: you must implement this)
|
|
9
|
-
def EchoAgent.find_by_id(objid)
|
|
10
|
-
EchoAgent.new
|
|
11
|
-
end
|
|
12
|
-
# Find-all method (NB: you must implement this)
|
|
13
|
-
def EchoAgent.find_all
|
|
14
|
-
[EchoAgent.new]
|
|
15
|
-
end
|
|
16
|
-
### Schema method declarations
|
|
17
|
-
|
|
18
|
-
# echo returns its argument
|
|
19
|
-
# * arg (lstr/IO)
|
|
20
|
-
#
|
|
21
|
-
def echo(args)
|
|
22
|
-
# Print values of in/out parameters
|
|
23
|
-
log.debug "arg => #{args["arg"]}" #
|
|
24
|
-
# Assign values to in/out parameters
|
|
25
|
-
args["arg"] = args["arg"]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
spqr_expose :echo do |args|
|
|
29
|
-
args.declare :arg, :lstr, :inout, {}
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|