diff options
Diffstat (limited to 'qpid/cpp')
-rw-r--r-- | qpid/cpp/bindings/qmf/ruby/qmf.rb | 19 | ||||
-rwxr-xr-x | qpid/cpp/bindings/qmf/tests/ruby_console_test.rb | 137 | ||||
-rwxr-xr-x | qpid/cpp/bindings/qmf/tests/run_interop_tests | 10 | ||||
-rw-r--r-- | qpid/cpp/bindings/qmf/tests/test_base.rb | 64 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/BrokerProxyImpl.cpp | 44 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/BrokerProxyImpl.h | 3 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/Object.h | 4 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/ObjectIdImpl.cpp | 2 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/ObjectImpl.cpp | 14 | ||||
-rw-r--r-- | qpid/cpp/src/qmf/ObjectImpl.h | 2 |
10 files changed, 282 insertions, 17 deletions
diff --git a/qpid/cpp/bindings/qmf/ruby/qmf.rb b/qpid/cpp/bindings/qmf/ruby/qmf.rb index 4a4c863521..cba9759135 100644 --- a/qpid/cpp/bindings/qmf/ruby/qmf.rb +++ b/qpid/cpp/bindings/qmf/ruby/qmf.rb @@ -402,13 +402,18 @@ module Qmf end def update() + raise "No linkage to broker" unless @broker + newer = @broker.console.get_objects(Query.new(:object_id => object_id)) + raise "Expected exactly one update for this object" unless newer.size == 1 + mergeUpdate(newer[0]) end def mergeUpdate(newObject) + @impl.merge(newObject.impl) end def deleted?() - @delete_time > 0 + @impl.isDeleted end def index() @@ -523,7 +528,11 @@ module Qmf @impl.getException end - def arguments + def text + exception.asString + end + + def args Arguments.new(@impl.getArgs) end end @@ -542,13 +551,13 @@ module Qmf if kwargs.include?(:key) @impl = Qmfengine::Query.new(kwargs[:key]) elsif kwargs.include?(:object_id) - @impl = Qmfengine::Query.new(kwargs[:object_id]) + @impl = Qmfengine::Query.new(kwargs[:object_id].impl) else package = kwargs[:package] if kwargs.include?(:package) if kwargs.include?(:class) @impl = Qmfengine::Query.new(kwargs[:class], package) else - raise ArgumentError, "Invalid arguments, use :key or :class[,:package]" + raise ArgumentError, "Invalid arguments, use :key, :object_id or :class[,:package]" end end end @@ -930,7 +939,7 @@ module Qmf class Broker < ConnectionHandler include MonitorMixin - attr_reader :impl, :conn + attr_reader :impl, :conn, :console def initialize(console, conn) super() diff --git a/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb new file mode 100755 index 0000000000..7779d2c70c --- /dev/null +++ b/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb @@ -0,0 +1,137 @@ +#!/usr/bin/ruby + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'test_base' + +class ConsoleTest < ConsoleTestBase + + def test_A_agent_presence + agents = [] + count = 0 + while agents.size == 0 + agents = @qmfc.get_objects(Qmf::Query.new(:class => "agent")) + sleep(1) + count += 1 + fail("Timed out waiting for remote agent") if count > 10 + end + + agentList = @qmfc.get_agents + assert_equal(agentList.size, 2, "Number of agents reported by Console") + end + + def test_B_basic_method_invocation + parents = @qmfc.get_objects(Qmf::Query.new(:class => "parent")) + assert_equal(parents.size, 1, "Number of 'parent' objects") + parent = parents[0] + for seq in 0...10 + result = parent.echo(seq) + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + assert_equal(result.args["sequence"], seq, "Echo Response Sequence") + end + + result = parent.set_numerics("bogus") + assert_equal(result.status, 1) + assert_equal(result.text, "Invalid argument value for test") + end + + def test_C_basic_types_numeric_big + parents = @qmfc.get_objects(Qmf::Query.new(:class =>"parent")) + assert_equal(parents.size, 1, "Number of parent objects") + parent = parents[0] + + result = parent.set_numerics("big") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + assert_equal(parent.uint64val, 0x9494949449494949) + assert_equal(parent.uint32val, 0xA5A55A5A) + assert_equal(parent.uint16val, 0xB66B) + assert_equal(parent.uint8val, 0xC7) + + assert_equal(parent.int64val, 1000000000000000000) + assert_equal(parent.int32val, 1000000000) + assert_equal(parent.int16val, 10000) + assert_equal(parent.int8val, 100) + end + + def test_C_basic_types_numeric_small + parents = @qmfc.get_objects(Qmf::Query.new(:class =>"parent")) + assert_equal(parents.size, 1, "Number of parent objects") + parent = parents[0] + + result = parent.set_numerics("small") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + assert_equal(parent.uint64val, 4) + assert_equal(parent.uint32val, 5) + assert_equal(parent.uint16val, 6) + assert_equal(parent.uint8val, 7) + + assert_equal(parent.int64val, 8) + assert_equal(parent.int32val, 9) + assert_equal(parent.int16val, 10) + assert_equal(parent.int8val, 11) + end + + def _test_C_basic_types_numeric_negative + parents = @qmfc.get_objects(Qmf::Query.new(:class =>"parent")) + assert_equal(parents.size, 1, "Number of parent objects") + parent = parents[0] + + result = parent.set_numerics("negative") + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.text, "OK", "Method Response Text") + + parent.update + + assert_equal(parent.uint64val, 0) + assert_equal(parent.uint32val, 0) + assert_equal(parent.uint16val, 0) + assert_equal(parent.uint8val, 0) + + assert_equal(parent.int64val, -10000000000) + assert_equal(parent.int32val, -100000) + assert_equal(parent.int16val, -1000) + assert_equal(parent.int8val, -100) + end + + def _test_D_userid_for_method + parents = @qmfc.get_objects(Qmf::Query.new(:class => "parent")) + assert_equal(parents.size, 1, "Number of parent objects") + parent = parents[0] + + result = parent.probe_userid + assert_equal(result.status, 0, "Method Response Status") + assert_equal(result.args["userid"], "guest") + end + +end + +app = ConsoleTest.new + + + diff --git a/qpid/cpp/bindings/qmf/tests/run_interop_tests b/qpid/cpp/bindings/qmf/tests/run_interop_tests index 01d7221ac6..b5545d736d 100755 --- a/qpid/cpp/bindings/qmf/tests/run_interop_tests +++ b/qpid/cpp/bindings/qmf/tests/run_interop_tests @@ -88,11 +88,19 @@ if test -d ${PYTHON_DIR} ; then echo " Ruby agent started at pid $AGENT_PID" ${PYTHON_DIR}/qpid-python-test -m python_console -b localhost:$BROKER_PORT $@ RETCODE=$? - stop_ruby_agent if test x$RETCODE != x0; then echo "FAIL qmf interop tests (Ruby Agent)"; TESTS_FAILED=1 fi + + echo " Ruby Agent (external storage) vs. Ruby Console" + ruby -I${MY_DIR} -I${MY_DIR}/../ruby -I${RUBY_LIB_DIR} ${MY_DIR}/ruby_console_test.rb localhost $BROKER_PORT $@ + RETCODE=$? + stop_ruby_agent + if test x$RETCODE != x0; then + echo "FAIL qmf interop tests (Ruby Console/Ruby Agent)"; + TESTS_FAILED=1 + fi fi # Also against the Pure-Python console: diff --git a/qpid/cpp/bindings/qmf/tests/test_base.rb b/qpid/cpp/bindings/qmf/tests/test_base.rb new file mode 100644 index 0000000000..18bf4c2649 --- /dev/null +++ b/qpid/cpp/bindings/qmf/tests/test_base.rb @@ -0,0 +1,64 @@ +#!/usr/bin/ruby + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +require 'qmf' +require 'socket' + +class ConsoleTestBase < Qmf::ConsoleHandler + def initialize + @settings = Qmf::ConnectionSettings.new + @settings.set_attr("host", ARGV[0]) if ARGV.size > 0 + @settings.set_attr("port", ARGV[1].to_i) if ARGV.size > 1 + @connection = Qmf::Connection.new(@settings) + @qmfc = Qmf::Console.new + + @broker = @qmfc.add_connection(@connection) + @broker.waitForStable + + tests = [] + methods.each do |m| + name = m.to_s + tests << name if name[0..4] == "test_" + end + + tests.sort.each do |t| + begin + print "#{t}..." + $stdout.flush + send(t) + puts " Pass" + rescue + puts " Fail: #{$!}" + end + end + + @qmfc.del_connection(@broker) + end + + def assert_equal(left, right, in_text=nil) + text = " (#{in_text})" if in_text + raise "Assertion failed: #{left} != #{right}#{text}" unless left == right + end + + def fail(text) + raise text + end +end diff --git a/qpid/cpp/src/qmf/BrokerProxyImpl.cpp b/qpid/cpp/src/qmf/BrokerProxyImpl.cpp index 29e51566b3..a66fa24834 100644 --- a/qpid/cpp/src/qmf/BrokerProxyImpl.cpp +++ b/qpid/cpp/src/qmf/BrokerProxyImpl.cpp @@ -113,7 +113,7 @@ void BrokerProxyImpl::startProtocol() char rawbuffer[512]; Buffer buffer(rawbuffer, 512); - agentList.push_back(AgentProxyPtr(AgentProxyImpl::factory(console, publicObject, 0, "Agent embedded in broker"))); + agentList[0] = AgentProxyPtr(AgentProxyImpl::factory(console, publicObject, 0, "Agent embedded in broker")); requestsOutstanding = 1; topicBound = false; @@ -189,10 +189,10 @@ uint32_t BrokerProxyImpl::agentCount() const const AgentProxy* BrokerProxyImpl::getAgent(uint32_t idx) const { Mutex::ScopedLock _lock(lock); - for (vector<AgentProxyPtr>::const_iterator iter = agentList.begin(); + for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin(); iter != agentList.end(); iter++) if (idx-- == 0) - return iter->get(); + return iter->second.get(); return 0; } @@ -204,9 +204,9 @@ void BrokerProxyImpl::sendQuery(const Query& query, void* context, const AgentPr sendGetRequestLH(queryContext, query, agent); } else { // TODO (optimization) only send queries to agents that have the requested class+package - for (vector<AgentProxyPtr>::const_iterator iter = agentList.begin(); + for (map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.begin(); iter != agentList.end(); iter++) { - sendGetRequestLH(queryContext, query, (*iter).get()); + sendGetRequestLH(queryContext, query, iter->second.get()); } } } @@ -317,6 +317,7 @@ BrokerEventImpl::Ptr BrokerProxyImpl::eventSetupComplete() BrokerEventImpl::Ptr BrokerProxyImpl::eventStable() { + QPID_LOG(trace, "Console Link to Broker Stable"); BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE)); return event; } @@ -432,7 +433,7 @@ void BrokerProxyImpl::handleSchemaResponse(Buffer& inBuffer, uint32_t seq) // request for the current list of agents so we can have it on-hand before we declare // this session "stable". // - if (key->getClassName() == AGENT_CLASS && key->getPackageName() == BROKER_PACKAGE) { + if (key->impl->getClassName() == AGENT_CLASS && key->impl->getPackageName() == BROKER_PACKAGE) { Mutex::ScopedLock _lock(lock); incOutstandingLH(); Buffer outBuffer(outputBuffer, MA_BUFFER_SIZE); @@ -467,7 +468,36 @@ ObjectPtr BrokerProxyImpl::handleObjectIndication(Buffer& inBuffer, uint32_t seq return ObjectPtr(); } - return ObjectPtr(ObjectImpl::factory(schema, this, inBuffer, prop, stat, true)); + ObjectPtr optr(ObjectImpl::factory(schema, this, inBuffer, prop, stat, true)); + if (prop && classKey->impl->getPackageName() == BROKER_PACKAGE && classKey->impl->getClassName() == AGENT_CLASS) { + // + // We've intercepted information about a remote agent... update the agent list accordingly + // + updateAgentList(optr); + } + return optr; +} + +void BrokerProxyImpl::updateAgentList(ObjectPtr obj) +{ + Value* value = obj->getValue("agentBank"); + if (value != 0 && value->isUint()) { + uint32_t agentBank = value->asUint(); + if (obj->isDeleted()) { + agentList.erase(agentBank); + QPID_LOG(trace, "Agent at bank " << agentBank << " removed from agent list"); + } else { + Value* str = obj->getValue("label"); + string label; + if (str != 0 && str->isString()) + label = str->asString(); + map<uint32_t, AgentProxyPtr>::const_iterator iter = agentList.find(agentBank); + if (iter == agentList.end()) { + agentList[agentBank] = AgentProxyPtr(AgentProxyImpl::factory(console, publicObject, agentBank, label)); + QPID_LOG(trace, "Agent '" << label << "' found at bank " << agentBank); + } + } + } } void BrokerProxyImpl::incOutstandingLH() diff --git a/qpid/cpp/src/qmf/BrokerProxyImpl.h b/qpid/cpp/src/qmf/BrokerProxyImpl.h index d98c28c32a..3b85191f85 100644 --- a/qpid/cpp/src/qmf/BrokerProxyImpl.h +++ b/qpid/cpp/src/qmf/BrokerProxyImpl.h @@ -146,7 +146,7 @@ namespace qmf { SequenceManager seqMgr; uint32_t requestsOutstanding; bool topicBound; - std::vector<AgentProxyPtr> agentList; + std::map<uint32_t, AgentProxyPtr> agentList; std::deque<MessageImpl::Ptr> xmtQueue; std::deque<BrokerEventImpl::Ptr> eventQueue; @@ -169,6 +169,7 @@ namespace qmf { void handleEventIndication(qpid::framing::Buffer& inBuffer, uint32_t seq); void handleSchemaResponse(qpid::framing::Buffer& inBuffer, uint32_t seq); ObjectPtr handleObjectIndication(qpid::framing::Buffer& inBuffer, uint32_t seq, bool prop, bool stat); + void updateAgentList(ObjectPtr obj); void incOutstandingLH(); void decOutstanding(); }; diff --git a/qpid/cpp/src/qmf/Object.h b/qpid/cpp/src/qmf/Object.h index ded6714429..58ab12365e 100644 --- a/qpid/cpp/src/qmf/Object.h +++ b/qpid/cpp/src/qmf/Object.h @@ -37,8 +37,10 @@ namespace qmf { const ObjectId* getObjectId() const; void setObjectId(ObjectId* oid); const SchemaObjectClass* getClass() const; - Value* getValue(char* key) const; + Value* getValue(const char* key) const; void invokeMethod(const char* methodName, const Value* inArgs, void* context) const; + bool isDeleted() const; + void merge(const Object& from); private: friend class ObjectImpl; diff --git a/qpid/cpp/src/qmf/ObjectIdImpl.cpp b/qpid/cpp/src/qmf/ObjectIdImpl.cpp index b993c2dbdf..90daf204c8 100644 --- a/qpid/cpp/src/qmf/ObjectIdImpl.cpp +++ b/qpid/cpp/src/qmf/ObjectIdImpl.cpp @@ -115,7 +115,7 @@ std::string ObjectIdImpl::asString() const { stringstream val; - val << getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" << + val << (int) getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" << getAgentBank() << "-" << getObjectNum(); return val.str(); } diff --git a/qpid/cpp/src/qmf/ObjectImpl.cpp b/qpid/cpp/src/qmf/ObjectImpl.cpp index f78808376f..99d1fb4354 100644 --- a/qpid/cpp/src/qmf/ObjectImpl.cpp +++ b/qpid/cpp/src/qmf/ObjectImpl.cpp @@ -118,6 +118,16 @@ void ObjectImpl::invokeMethod(const string& methodName, const Value* inArgs, voi broker->sendMethodRequest(objectId.get(), objectClass, methodName, inArgs, context); } +void ObjectImpl::merge(const Object& from) +{ + for (map<string, ValuePtr>::const_iterator piter = from.impl->properties.begin(); + piter != from.impl->properties.end(); piter++) + properties[piter->first] = piter->second; + for (map<string, ValuePtr>::const_iterator siter = from.impl->statistics.begin(); + siter != from.impl->statistics.end(); siter++) + statistics[siter->first] = siter->second; +} + void ObjectImpl::parsePresenceMasks(Buffer& buffer, set<string>& excludeList) { int propCount = objectClass->getPropertyCount(); @@ -215,6 +225,8 @@ void Object::destroy() { impl->destroy(); } const ObjectId* Object::getObjectId() const { return impl->getObjectId(); } void Object::setObjectId(ObjectId* oid) { impl->setObjectId(oid); } const SchemaObjectClass* Object::getClass() const { return impl->getClass(); } -Value* Object::getValue(char* key) const { return impl->getValue(key); } +Value* Object::getValue(const char* key) const { return impl->getValue(key); } void Object::invokeMethod(const char* m, const Value* a, void* c) const { impl->invokeMethod(m, a, c); } +bool Object::isDeleted() const { return impl->isDeleted(); } +void Object::merge(const Object& from) { impl->merge(from); } diff --git a/qpid/cpp/src/qmf/ObjectImpl.h b/qpid/cpp/src/qmf/ObjectImpl.h index 565e9a2704..0776aab8fa 100644 --- a/qpid/cpp/src/qmf/ObjectImpl.h +++ b/qpid/cpp/src/qmf/ObjectImpl.h @@ -59,6 +59,8 @@ namespace qmf { const SchemaObjectClass* getClass() const { return objectClass; } Value* getValue(const std::string& key) const; void invokeMethod(const std::string& methodName, const Value* inArgs, void* context) const; + bool isDeleted() const { return destroyTime != 0; } + void merge(const Object& from); void parsePresenceMasks(qpid::framing::Buffer& buffer, std::set<std::string>& excludeList); void encodeSchemaKey(qpid::framing::Buffer& buffer) const; |