You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2009/09/21 18:24:38 UTC

svn commit: r817312 - in /qpid/trunk/qpid/cpp: bindings/qmf/ruby/ bindings/qmf/tests/ src/qmf/

Author: tross
Date: Mon Sep 21 16:24:38 2009
New Revision: 817312

URL: http://svn.apache.org/viewvc?rev=817312&view=rev
Log:
Added Ruby test infrastructure and Console tests in Ruby
Fixed issues identified by the new tests:
  - Improper formatting of object-id in get-query
  - Remote (non-broker-resident) agents not visible to the console
  - object.update() and object.merge() not implemented

Added:
    qpid/trunk/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb   (with props)
    qpid/trunk/qpid/cpp/bindings/qmf/tests/test_base.rb
Modified:
    qpid/trunk/qpid/cpp/bindings/qmf/ruby/qmf.rb
    qpid/trunk/qpid/cpp/bindings/qmf/tests/run_interop_tests
    qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.cpp
    qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.h
    qpid/trunk/qpid/cpp/src/qmf/Object.h
    qpid/trunk/qpid/cpp/src/qmf/ObjectIdImpl.cpp
    qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.cpp
    qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.h

Modified: qpid/trunk/qpid/cpp/bindings/qmf/ruby/qmf.rb
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/bindings/qmf/ruby/qmf.rb?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/bindings/qmf/ruby/qmf.rb (original)
+++ qpid/trunk/qpid/cpp/bindings/qmf/ruby/qmf.rb Mon Sep 21 16:24:38 2009
@@ -402,13 +402,18 @@
     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 @@
       @impl.getException
     end
 
-    def arguments
+    def text
+      exception.asString
+    end
+
+    def args
       Arguments.new(@impl.getArgs)
     end
   end
@@ -542,13 +551,13 @@
         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 @@
 
   class Broker < ConnectionHandler
     include MonitorMixin
-    attr_reader :impl, :conn
+    attr_reader :impl, :conn, :console
 
     def initialize(console, conn)
       super()

Added: qpid/trunk/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb?rev=817312&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb (added)
+++ qpid/trunk/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb Mon Sep 21 16:24:38 2009
@@ -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
+
+
+

Propchange: qpid/trunk/qpid/cpp/bindings/qmf/tests/ruby_console_test.rb
------------------------------------------------------------------------------
    svn:executable = *

Modified: qpid/trunk/qpid/cpp/bindings/qmf/tests/run_interop_tests
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/bindings/qmf/tests/run_interop_tests?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/bindings/qmf/tests/run_interop_tests (original)
+++ qpid/trunk/qpid/cpp/bindings/qmf/tests/run_interop_tests Mon Sep 21 16:24:38 2009
@@ -88,11 +88,19 @@
         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:

Added: qpid/trunk/qpid/cpp/bindings/qmf/tests/test_base.rb
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/bindings/qmf/tests/test_base.rb?rev=817312&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/bindings/qmf/tests/test_base.rb (added)
+++ qpid/trunk/qpid/cpp/bindings/qmf/tests/test_base.rb Mon Sep 21 16:24:38 2009
@@ -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

Modified: qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.cpp?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.cpp Mon Sep 21 16:24:38 2009
@@ -113,7 +113,7 @@
     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 @@
 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 @@
         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::eventStable()
 {
+    QPID_LOG(trace, "Console Link to Broker Stable");
     BrokerEventImpl::Ptr event(new BrokerEventImpl(BrokerEvent::STABLE));
     return event;
 }
@@ -432,7 +433,7 @@
         // 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 @@
         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()

Modified: qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.h?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.h (original)
+++ qpid/trunk/qpid/cpp/src/qmf/BrokerProxyImpl.h Mon Sep 21 16:24:38 2009
@@ -146,7 +146,7 @@
         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 @@
         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();
     };

Modified: qpid/trunk/qpid/cpp/src/qmf/Object.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qmf/Object.h?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qmf/Object.h (original)
+++ qpid/trunk/qpid/cpp/src/qmf/Object.h Mon Sep 21 16:24:38 2009
@@ -37,8 +37,10 @@
         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;

Modified: qpid/trunk/qpid/cpp/src/qmf/ObjectIdImpl.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qmf/ObjectIdImpl.cpp?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qmf/ObjectIdImpl.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qmf/ObjectIdImpl.cpp Mon Sep 21 16:24:38 2009
@@ -115,7 +115,7 @@
 {
     stringstream val;
 
-    val << getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" <<
+    val << (int) getFlags() << "-" << getSequence() << "-" << getBrokerBank() << "-" <<
         getAgentBank() << "-" << getObjectNum();
     return val.str();
 }

Modified: qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.cpp?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.cpp Mon Sep 21 16:24:38 2009
@@ -118,6 +118,16 @@
         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 @@
 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); }
 

Modified: qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.h?rev=817312&r1=817311&r2=817312&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.h (original)
+++ qpid/trunk/qpid/cpp/src/qmf/ObjectImpl.h Mon Sep 21 16:24:38 2009
@@ -59,6 +59,8 @@
         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;



---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org