You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kp...@apache.org on 2016/11/04 19:42:14 UTC
qpid-interop-test git commit: QPIDIT-47: Add Rhea javascript client.
Also includes minor adjustments to python and c++ shims owing to expended
tests and not using message ids as a part of the test.
Repository: qpid-interop-test
Updated Branches:
refs/heads/master 5579efd4b -> 156ac5a56
QPIDIT-47: Add Rhea javascript client. Also includes minor adjustments to python and c++ shims owing to expended tests and not using message ids as a part of the test.
Project: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/commit/156ac5a5
Tree: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/tree/156ac5a5
Diff: http://git-wip-us.apache.org/repos/asf/qpid-interop-test/diff/156ac5a5
Branch: refs/heads/master
Commit: 156ac5a56c2fdf88efb5ea5e5d43dbc313d3da76
Parents: 5579efd
Author: Kim van der Riet <kp...@apache.org>
Authored: Fri Nov 4 15:41:52 2016 -0400
Committer: Kim van der Riet <kp...@apache.org>
Committed: Fri Nov 4 15:41:52 2016 -0400
----------------------------------------------------------------------
.../src/qpidit/amqp_types_test/Receiver.cpp | 3 +-
.../src/qpidit/amqp_types_test/Receiver.hpp | 2 +-
.../src/amqp_types_test/Receiver.py | 2 +-
shims/rhea-js/amqp_types_test/.gitignore | 1 +
shims/rhea-js/amqp_types_test/README | 47 +++
shims/rhea-js/amqp_types_test/Receiver.js | 196 +++++++++++
shims/rhea-js/amqp_types_test/Sender.js | 340 +++++++++++++++++++
.../amqp_types_test/rhea-long-ulong.patch | 50 +++
src/python/qpid_interop_test/amqp_types_test.py | 127 +++++--
src/python/qpid_interop_test/shims.py | 9 +
10 files changed, 738 insertions(+), 39 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.cpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.cpp b/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.cpp
index 22f4aed..53819a7 100644
--- a/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.cpp
+++ b/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.cpp
@@ -60,7 +60,8 @@ namespace qpidit
}
void Receiver::on_message(proton::delivery &d, proton::message &m) {
- if (proton::get<uint64_t>(m.id()) < _received) return; // ignore duplicate
+ // TODO: Ignore m.id() if it does not exist on the message
+ //if (proton::get<uint64_t>(m.id()) < _received) return; // ignore duplicate
if (_received < _expected) {
if (_amqpType.compare("null") == 0) {
checkMessageType(m, proton::NULL_TYPE);
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.hpp
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.hpp b/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.hpp
index 3e180d3..9435a99 100644
--- a/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.hpp
+++ b/shims/qpid-proton-cpp/src/qpidit/amqp_types_test/Receiver.hpp
@@ -69,7 +69,7 @@ namespace qpidit
if (fillFlag) {
oss << std::setw(sizeof(T)*2) << std::setfill('0');
}
- oss << (sizeof(T) == 1 ? (int)val & 0xff : sizeof(T) == 2 ? val & 0xffff : sizeof(T) == 4 ? val & 0xffffffff : val);
+ oss << (sizeof(T) == 1 ? (int)val & 0xff : sizeof(T) == 2 ? val & 0xffff : /*sizeof(T) == 4 ? val & 0xffffffff :*/ val);
return oss.str();
}
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
----------------------------------------------------------------------
diff --git a/shims/qpid-proton-python/src/amqp_types_test/Receiver.py b/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
index f075977..4533124 100755
--- a/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
+++ b/shims/qpid-proton-python/src/amqp_types_test/Receiver.py
@@ -94,7 +94,7 @@ class AmqpTypesTestReceiver(MessagingHandler):
elif self.amqp_type == 'decimal128':
self.received_value_list.append('0x' + ''.join(['%02x' % ord(c) for c in event.message.body]).strip())
elif self.amqp_type == 'char':
- if ord(event.message.body) < 0x80 and event.message.body in digits + letters + punctuation:
+ if ord(event.message.body) < 0x80 and event.message.body in digits + letters + punctuation + " ":
self.received_value_list.append(event.message.body)
else:
self.received_value_list.append(hex(ord(event.message.body)))
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/rhea-js/amqp_types_test/.gitignore
----------------------------------------------------------------------
diff --git a/shims/rhea-js/amqp_types_test/.gitignore b/shims/rhea-js/amqp_types_test/.gitignore
new file mode 100644
index 0000000..2ccbe46
--- /dev/null
+++ b/shims/rhea-js/amqp_types_test/.gitignore
@@ -0,0 +1 @@
+/node_modules/
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/rhea-js/amqp_types_test/README
----------------------------------------------------------------------
diff --git a/shims/rhea-js/amqp_types_test/README b/shims/rhea-js/amqp_types_test/README
new file mode 100644
index 0000000..308a141
--- /dev/null
+++ b/shims/rhea-js/amqp_types_test/README
@@ -0,0 +1,47 @@
+These are the Sender and Receiver shims for qpid-interop-test AMQP types test.
+They send and receive messages via an AMQP broker which is assumed to be running
+at a well-known location/port.
+
+These are invoked on the command-line from the test program using the following
+command-line options:
+
+1. broker address (ip-addr:port)
+2. queue name
+3. AMQP type under test
+4. JSON list of stringified test values (Sender) "[\"val1\", \"val2\", ... ]"
+ or
+ A number indicating how many messages to expect (Receiver)
+
+Any errors/exceptions are sent to stderr.
+The Sender does not print anything onto stdout.
+The Receiver prints two items onto stdout:
+
+1. The AMQP type under test
+2. JSON list of stringified test values received (matching that sent to the
+ Sender)
+
+The top-level test program (amqp_types_test.py) will launch each shim as needed
+with its command-line parameters and will receive output from stdout and
+stderr. These outputs will be checked to determine pass/fail. By default, the
+JSON sequende sent to the Sender must match the JSON sequence received from the
+receiver for the test to pass.
+
+The AMQP types and test values are all set within the top-level test program.
+
+Required modules
+----------------
+ rhea (https://github.com/grs/rhea.git)
+ node-uuid (via npm)
+
+NOTE: For the tests to pass, a patch is needed for the Rhea javascript client.
+This patch is contained in the file rhea-long-ulong.patch. It addresses a
+problem in Javascript in which numbers are represented internally as floating
+point numbers. This means that the precision available for representing large
+integer values is limited, and can round up or down to a representation that
+is not exact and can cause tests to fail. (For example, the unsigned long
+number 0x7fffffffffffffff will round to 0x8000000000000000). The patch allows
+numbers stored in Buffer objects to be used to set a long or ulong values in
+message bodies, which avoids this problem. If the patch is not applied, the
+long and ulong tests will fail. (If this patch is accepted into Rhea, then
+this file will be removed.)
+
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/rhea-js/amqp_types_test/Receiver.js
----------------------------------------------------------------------
diff --git a/shims/rhea-js/amqp_types_test/Receiver.js b/shims/rhea-js/amqp_types_test/Receiver.js
new file mode 100755
index 0000000..dc4ec57
--- /dev/null
+++ b/shims/rhea-js/amqp_types_test/Receiver.js
@@ -0,0 +1,196 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+"use strict";
+
+//Check if the environment is Node.js and if not log an error and exit.
+if (typeof process !== 'object' || typeof require !== 'function') {
+ console.error("Receiver.js should be run in Node.js");
+ process.exit(-1);
+}
+
+var uuid = require("node-uuid");
+
+var args = process.argv.slice(2);
+if (args.length !== 4) {
+ console.error("ERROR: Sender.js needs 4 arguments:");
+ console.error(" 1. Broker address (ip-addr:port)");
+ console.error(" 2. Queue name");
+ console.error(" 3. AMQP type");
+ console.error(" 4. Number of expected values");
+ process.exit(-1);
+}
+
+function Receiver(brokerAddr, brokerPort, queueName, amqpType, numTestValues) {
+ this.amqpType = amqpType;
+ this.received = 0;
+ this.expected = numTestValues;
+ this.receivedValueList = [];
+ this.container = require('rhea');
+
+ this.container.connect({'host':brokerAddr, 'port':brokerPort}).open_receiver(queueName);
+
+ this.processMessage = function(msgBody) {
+// console.log("processMessage: amqpType=" + this.amqpType + "; msgBody=" + msgBody);
+ switch(this.amqpType) {
+ case "null": this.receivedValueList.push(this.decodeNull(msgBody)); break;
+ case "boolean": this.receivedValueList.push(this.decodeBoolean(msgBody)); break;
+ case "ubyte":
+ case "ushort":
+ case "uint":
+ case "ulong":
+ case "decimal32":
+ case "decimal64":
+ case "decimal128":
+ case "timestamp": this.receivedValueList.push(this.decodeUnsigned(msgBody)); break;
+ case "byte":
+ case "short":
+ case "int":
+ case "long": this.receivedValueList.push(this.decodeSigned(msgBody)); break;
+ case "float": this.receivedValueList.push(this.decodeFloat(msgBody)); break;
+ case "double": this.receivedValueList.push(this.decodeDouble(msgBody)); break;
+ case "char": this.receivedValueList.push(this.decodeChar(msgBody)); break;
+ case "uuid": this.receivedValueList.push(this.decodeUuid(msgBody)); break;
+ case "binary": this.receivedValueList.push(this.decodeBinary(msgBody)); break;
+ case "string": this.receivedValueList.push(this.decodeString(msgBody)); break;
+ case "symbol": this.receivedValueList.push(this.decodeSymbol(msgBody)); break;
+ case "list": this.receivedValueList.push(this.decodeList(msgBody)); break;
+ case "map": this.receivedValueList.push(this.decodeMap(msgBody)); break;
+ case "array": this.receivedValueList.push(this.decodeArray(msgBody)); break;
+ default: throw "Unknown AMQP type: " + this.amqpType;
+ }
+ };
+
+ this.decodeNull = function (msgBody) {
+ return "None";
+ };
+
+ this.decodeBoolean = function(msgBody) {
+ return msgBody ? "True" : "False";
+ };
+
+ this.decodeUnsigned = function(msgBody) {
+ return "0x" + msgBody.toString(Buffer.isBuffer(msgBody) ? 'hex' : 16);
+ };
+
+ this.decodeSigned = function(msgBody) {
+ if (Buffer.isBuffer(msgBody)) {
+ if (msgBody[0] & 0x80) { // sign bit set
+ msgBody[0] &= 0x80;
+ return "-0x" + msgBody.toString('hex');
+ } else {
+ return "0x" + msgBody.toString('hex');
+ }
+ } else {
+ if (msgBody < 0) {
+ return "-0x" + (-msgBody).toString(16);
+ } else {
+ return "0x" + msgBody.toString(16);
+ }
+ }
+ };
+
+ this.decodeFloat = function(msgBody) {
+ // Buffer.writeFloatBE() does not support -NaN (ignores sign)
+ var buf = new Buffer(4);
+ buf.writeFloatBE(msgBody);
+ return "0x" + buf.toString('hex');
+ };
+
+ this.decodeDouble = function(msgBody) {
+ // Buffer.writeDoubleBE() does not support -NaN (ignores sign)
+ var buf = new Buffer(8);
+ buf.writeDoubleBE(msgBody);
+ return "0x" + buf.toString('hex');
+ };
+
+ // UTF32LE char per AMQP spec
+ this.decodeChar = function(msgBody) {
+ if (Buffer.isBuffer(msgBody)) {
+ if (msgBody[0] === 0 && msgBody[1] === 0 && msgBody[2] === 0 && msgBody[3] >= 32 && msgBody[3] <= 126) {
+ // Printable single ASCII char - return just the char
+ return String.fromCharCode(msgBody[3]);
+ }
+ return "0x" + this.buffer2HexString(msgBody, false);
+ } else {
+ throw "AMQP type char message body is not Buffer";
+ }
+ };
+
+ this.decodeUuid = function(msgBody) {
+ return uuid.unparse(msgBody);
+ };
+
+ this.decodeBinary = function(msgBody) {
+ return msgBody.toString();
+ };
+
+ this.decodeString = function(msgBody) {
+ return msgBody;
+ };
+
+ this.decodeSymbol = function(msgBody) {
+ return msgBody;
+ };
+
+ this.decodeList = function(msgBody) {
+ return msgBody; // TODO: decode list
+ };
+
+ this.decodeMap = function(msgBody) {
+ return msgBody; // TODO: decode map
+ };
+
+ this.decodeArray = function(msgBody) {
+ return msgBody; // TODO: decode array
+ };
+
+ this.buffer2HexString = function(buff, pad) {
+ var hexStr = "";
+ var first = true;
+ for (var i = 0; i < buff.length; i++) {
+ if (pad || buff[i] > 0) {
+ hexStr += (pad || !first) ? ("0" + buff[i].toString(16)).substr(-2) : buff[i].toString(16);
+ first = false;
+ }
+ }
+ return hexStr;
+ };
+
+ this.printResult = function() {
+ console.log(this.amqpType);
+ console.log(JSON.stringify(this.receivedValueList));
+ };
+
+ this.container.on('message', function (context) {
+ if (receiver.expected === 0 || receiver.received < receiver.expected) {
+ receiver.processMessage(context.message.body);
+ if (++receiver.received === receiver.expected) {
+ context.receiver.detach();
+ context.connection.close();
+ receiver.printResult();
+ }
+ }
+ });
+}
+
+var colonPos = args[0].indexOf(":");
+var receiver = new Receiver(args[0].slice(0, colonPos), args[0].slice(colonPos+1), args[1], args[2], parseInt(args[3], 10));
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/rhea-js/amqp_types_test/Sender.js
----------------------------------------------------------------------
diff --git a/shims/rhea-js/amqp_types_test/Sender.js b/shims/rhea-js/amqp_types_test/Sender.js
new file mode 100755
index 0000000..475d6b5
--- /dev/null
+++ b/shims/rhea-js/amqp_types_test/Sender.js
@@ -0,0 +1,340 @@
+#!/usr/bin/env node
+/*
+ * 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.
+ *
+ */
+
+"use strict";
+
+var uuid = require("node-uuid");
+var amqp_types = require('rhea/lib/types.js');
+
+//Check if the environment is Node.js and if not log an error and exit.
+if (typeof process !== 'object' || typeof require !== 'function') {
+ console.error("Receiver.js should be run in Node.js");
+ process.exit(-1);
+}
+
+var args = process.argv.slice(2);
+if (args.length !== 4) {
+ console.error("ERROR: Sender.js needs 4 arguments:");
+ console.error(" 1. Broker address (ip-addr:port)");
+ console.error(" 2. Queue name");
+ console.error(" 3. AMQP type");
+ console.error(" 4. JSON string containing test values");
+ process.exit(-1);
+}
+
+var AmqpArrayTypes = {
+ "boolean": 0x56,
+ "ubyte": 0x50,
+ "ushort": 0x60,
+ "uint": 0x70,
+ "ulong": 0x80,
+ "byte": 0x51,
+ "short": 0x61,
+ "int": 0x71,
+ "long": 0x81,
+ "float": 0x72,
+ "double": 0x82,
+ "decimal32": 0x74,
+ "decimal64": 0x84,
+ "decimal128": 0x94,
+ "char": 0x73,
+ "timestamp": 0x83,
+ "uuid": 0x98,
+ "binary": 0xb0,
+ "string": 0xb1,
+ "symbol": 0xb3
+};
+
+function Sender(brokerAddr, brokerPort, queueName, amqpType, testValues) {
+ this.amqpType = amqpType;
+ this.testValues = testValues;
+ this.sent = 0;
+ this.confirmed = 0;
+ this.total = testValues.length;
+ this.container = require('rhea');
+
+ this.connection = this.container.connect({'host':brokerAddr, 'port':brokerPort}); //.open_sender(queueName);
+ this.connection.open_sender(queueName);
+
+ this.createMessage = function(testValue) {
+ //console.log("createMessage: amqpType=" + this.amqpType + "; testValue=" + testValue);
+ switch(this.amqpType) {
+ case "null": return {body: this.encodeNull(testValue)};
+ case "boolean": return {body: amqp_types.wrap_boolean(this.encodeBoolean(testValue))};
+ case "ubyte": return {body: amqp_types.wrap_ubyte(this.encodeUbyte(testValue))};
+ case "ushort": return {body: amqp_types.wrap_ushort(this.encodeUshort(testValue))};
+ case "uint": return {body: amqp_types.wrap_uint(this.encodeUint(testValue))};
+ case "ulong": return {body: amqp_types.wrap_ulong(this.encodeUlong(testValue))};
+ case "byte": return {body: amqp_types.wrap_byte(this.encodeByte(testValue))};
+ case "short": return {body: amqp_types.wrap_short(this.encodeShort(testValue))};
+ case "int": return {body: amqp_types.wrap_int(this.encodeInt(testValue))};
+ case "long": return {body: amqp_types.wrap_long(this.encodeLong(testValue))};
+ case "float": return {body: amqp_types.wrap_float(this.encodeFloat(testValue))};
+ case "double": return {body: amqp_types.wrap_double(this.encodeDouble(testValue))};
+ case "decimal32": return {body: new amqp_types.Decimal32(this.encodeDecimal32(testValue))};
+ case "decimal64": return {body: new amqp_types.Decimal64(this.encodeDecimal64(testValue))};
+ case "decimal128": return {body: new amqp_types.Decimal128(this.encodeDecimal128(testValue))};
+ case "char": return {body: new amqp_types.CharUTF32(this.encodeChar(testValue))};
+ case "timestamp": return {body: amqp_types.wrap_timestamp(this.encodeTimestamp(testValue))};
+ case "uuid": return {body: new amqp_types.Uuid(this.encodeUuid(testValue))};
+ case "binary": return {body: amqp_types.wrap_binary(this.encodeBinary(testValue))};
+ case "string": return {body: amqp_types.wrap_string(this.encodeString(testValue))};
+ case "symbol": return {body: amqp_types.wrap_symbol(this.encodeSymbol(testValue))};
+ case "list": return {body: amqp_types.wrap_list(this.encodeList(testValue))};
+ case "map": return {body: amqp_types.wrap_map(this.encodeMap(testValue))};
+ case "array": return {body: amqp_types.wrap_array(this.encodeArray(testValue.slice(1), AmqpArrayTypes[testValue[0]]))};
+ default: throw "Unknown AMQP type: \"" + this.amqpType + "\"";
+ }
+ };
+
+ // static
+ this.encodeAmqpType = function(amqpType, testValue) {
+ switch(amqpType) {
+ case "null": return this.encodeNull(testValue);
+ case "boolean": return this.encodeBoolean(testValue);
+ case "ubyte": return this.encodeUbyte(testValue);
+ case "ushort": return this.encodeUshort(testValue);
+ case "uint": return this.encodeUint(testValue);
+ case "ulong": return this.encodeUlong(testValue);
+ case "byte": return this.encodeByte(testValue);
+ case "short": return this.encodeShort(testValue);
+ case "int": return this.encodeInt(testValue);
+ case "long": return this.encodeLong(testValue);
+ case "float": return this.encodeFloat(testValue);
+ case "double": return this.encodeDouble(testValue);
+ case "decimal32": return this.encodeDecimal32(testValue);
+ case "decimal64": return this.encodeDecimal64(testValue);
+ case "decimal128": return this.encodeDecimal128(testValue);
+ case "char": return this.encodeChar(testValue);
+ case "timestamp": return this.encodeTimestamp(testValue);
+ case "uuid": return this.encodeUuid(testValue);
+ case "binary": return this.encodeBinary(testValue);
+ case "string": return this.encodeString(testValue);
+ case "symbol": return this.encodeSymbol(testValue);
+ case "list": return this.encodeList(testValue);
+ case "map": return this.encodeMap(testValue);
+ case "array": return this.encodeArray(testValue);
+ default: throw "Unknown AMQP type: \"" + this.amqpType + "\"";
+ }
+ };
+
+ // These functions encode the incoming JSON string representation
+ // of the test values into appropriate test values for the message
+ // bodies.
+
+ this.encodeNull = function(testValue) {
+ if (testValue === "None") return null;
+ this.handleEncodeError("null", testValue);
+ };
+
+ this.encodeBoolean = function(testValue) {
+ if (testValue === "True") return true;
+ if (testValue === "False") return false;
+ this.handleEncodeError("boolean", testValue);
+ };
+
+ this.encodeUbyte = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("ubyte", testValue); }
+ };
+
+ this.encodeUshort = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("ushort", testValue); }
+ };
+
+ this.encodeUint = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("uint", testValue); }
+ };
+
+ this.encodeUlong = function(testValue) {
+ try { return new Buffer(this.hexString2ByteArray(testValue.slice(2), 8)); }
+ catch (err) { this.handleEncodeError("ulong", testValue, err); }
+ };
+
+ this.encodeByte = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("byte", testValue); }
+ };
+
+ this.encodeShort = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("short", testValue); }
+ };
+
+ this.encodeInt = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("int", testValue); }
+ };
+
+ this.encodeLong = function(testValue) {
+ try {
+ var negFlag = testValue.charAt(0) === "-";
+ var ba = this.hexString2ByteArray(testValue.slice(negFlag ? 3 : 2), 8);
+ if (negFlag) this.byteArray2sCompl(ba);
+ return new Buffer(ba);
+ }
+ catch (err) { this.handleEncodeError("long", testValue); }
+ };
+
+ this.encodeFloat = function(testValue) {
+ // NOTE: Buffer.readFloatBE() does not support -NaN (ignores sign)
+// var buf = new Buffer(testValue.substr(2), "hex");
+// return buf.readFloatBE(0);
+ // This method gets the -NaN with sign onto the wire correctly.
+ var dv = new DataView(new ArrayBuffer(4));
+ dv.setUint32(0, parseInt(testValue.substr(2), 16));
+ return dv.getFloat32(0);
+ };
+
+ this.encodeDouble = function(testValue) {
+ // NOTE: Buffer.readDoubleBE() does not support -NaN (ignores sign)
+// var buf = new Buffer(testValue.substr(2), "hex");
+// return buf.readDoubleBE(0);
+ // This method gets the -NaN with sign onto the wire correctly.
+ var dv = new DataView(new ArrayBuffer(8));
+ dv.setUint32(0, parseInt(testValue.substr(2, 8), 16));
+ dv.setUint32(4, parseInt(testValue.substr(10), 16));
+ return dv.getFloat64(0);
+ };
+
+ this.encodeDecimal32 = function(testValue) {
+ try { return new Buffer(this.hexString2ByteArray(testValue.slice(2), 4)); }
+ catch (err) { this.handleEncodeError("decimal32", testValue, err); }
+ };
+
+ this.encodeDecimal64 = function(testValue) {
+ try { return new Buffer(this.hexString2ByteArray(testValue.slice(2), 8)); }
+ catch (err) { this.handleEncodeError("decimal64", testValue, err); }
+ };
+
+ this.encodeDecimal128 = function(testValue) {
+ try { return new Buffer(this.hexString2ByteArray(testValue.slice(2), 16)); }
+ catch (err) { this.handleEncodeError("decimal128", testValue, err); }
+ };
+
+ this.encodeChar = function(testValue) {
+ var val = null;
+ try {
+ if (testValue.length === 1) { // Single char format 'a'
+ val = [0, 0, 0, testValue.charCodeAt(0)];
+ } else { // Hex format '0xNNNN'
+ val = this.hexString2ByteArray(testValue.slice(2), 4);
+ }
+ }
+ catch (err) { this.handleEncodeError("char", testValue); }
+ return new Buffer(val);
+ };
+
+ this.encodeTimestamp = function(testValue) {
+ try { return parseInt(testValue, 16); }
+ catch (err) { this.handleEncodeError("timestamp", testValue); }
+ };
+
+ this.encodeUuid = function(testValue) {
+ var buff = new Buffer(16);
+ try { uuid.parse(testValue, buff); }
+ catch (err) { this.handleEncodeError("uuid", testValue); }
+ return buff;
+ };
+
+ this.encodeBinary = function(testValue) {
+ return testValue;
+ };
+
+ this.encodeString = function(testValue) {
+ return testValue;
+ };
+
+ this.encodeSymbol = function(testValue) {
+ return testValue;
+ };
+
+ this.encodeList = function(testValue) {
+ return testValue; // TODO: encode list
+ };
+
+ this.encodeMap = function(testValue) {
+ return testValue; // TODO: encode map
+ };
+
+ // testValue format for arrays: ['type', 'val1', 'val2', ... ]
+ this.encodeArray = function(testValue) {
+ return testValue.slice(1); // TODO: encode array
+ };
+
+ this.handleEncodeError = function(amqpType, testValue, err) {
+ var errStr = "Invalid string value for type " + amqpType + ": \"" + testValue + "\"";
+ if (err) {
+ errStr += " (" + err.message + ")";
+ }
+ throw new Error(errStr);
+ };
+
+ // NOTE: hexStr must not include '0x' prefix
+ this.hexString2ByteArray = function(hexStr, len) {
+ var result = [];
+ var oddFlag = hexStr.length !== 2*Math.round(hexStr.length/2.0); // odd number of hex digits
+ for (var i = len - 1; i >= 0; i--) {
+ if (2 * i < hexStr.length) {
+ var ssIndex = oddFlag ? 0 : hexStr.length - 2*(i+1);
+ var ssLen = oddFlag ? 1 : 2;
+ result.push(parseInt(hexStr.substr(ssIndex, ssLen), 16));
+ oddFlag = false;
+ } else {
+ result.push(0); // leading zeros
+ }
+ }
+ return result;
+ };
+
+ this.byteArray2sCompl = function(ba) {
+ var carry = 1;
+ for (var i=ba.length-1; i>=0; i--) {
+ var val = (ba[i] ^ 0xff) + carry;
+ ba[i] = val & 0xff;
+ carry = val >> 8;
+ }
+ };
+
+ this.container.on('sendable', function (context) {
+ while (context.sender.sendable() && sender.sent < sender.total) {
+ for (var i=0; i<sender.testValues.length; ++i) {
+ context.sender.send(sender.createMessage(sender.testValues[i]));
+ sender.sent++;
+ }
+ }
+ });
+
+ this.container.on('accepted', function (context) {
+ if (++sender.confirmed === sender.total) {
+ context.connection.close();
+ }
+ });
+
+ this.container.on('disconnected', function (context) {
+ sender.sent = sender.confirmed;
+ });
+}
+
+var colonPos = args[0].indexOf(":");
+var sender = new Sender(args[0].slice(0, colonPos), args[0].slice(colonPos+1), args[1], args[2], JSON.parse(args[3]));
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/shims/rhea-js/amqp_types_test/rhea-long-ulong.patch
----------------------------------------------------------------------
diff --git a/shims/rhea-js/amqp_types_test/rhea-long-ulong.patch b/shims/rhea-js/amqp_types_test/rhea-long-ulong.patch
new file mode 100644
index 0000000..c7497c3
--- /dev/null
+++ b/shims/rhea-js/amqp_types_test/rhea-long-ulong.patch
@@ -0,0 +1,50 @@
+diff --git lib/types.js lib/types.js
+index 985607f..f1d5514 100644
+--- lib/types.js
++++ lib/types.js
+@@ -270,6 +270,12 @@ function is_one_of(o, typelist) {
+ }
+ return false;
+ }
++function buffer_zero(b, len, neg) {
++ for (var i = 0; i < len && i < b.length; i++) {
++ if (b[i] !== (neg ? 0xff : 0)) return false;
++ }
++ return true;
++}
+ types.is_ulong = function(o) {
+ return is_one_of(o, [types.Ulong, types.Ulong0, types.SmallUlong]);
+ };
+@@ -290,8 +296,13 @@ types.wrap_boolean = function(v) {
+ return v ? new types.True() : new types.False();
+ };
+ types.wrap_ulong = function(l) {
+- if (l === 0) return new types.Ulong0();
+- else return l > 255 ? new types.Ulong(l) : new types.SmallUlong(l);
++ if (Buffer.isBuffer(l)) {
++ if (buffer_zero(l, 8, false)) return new types.Ulong0();
++ return buffer_zero(l, 7, false) ? new types.SmallUlong(l[7]) : new types.Ulong(l);
++ } else {
++ if (l === 0) return new types.Ulong0();
++ else return l > 255 ? new types.Ulong(l) : new types.SmallUlong(l);
++ }
+ };
+ types.wrap_uint = function(l) {
+ if (l === 0) return new types.Uint0();
+@@ -304,7 +315,15 @@ types.wrap_ubyte = function(l) {
+ return new types.Ubyte(l);
+ };
+ types.wrap_long = function(l) {
+- return l > 127 || l < -128 ? new types.Long(l) : new types.SmallLong(l);
++ if (Buffer.isBuffer(l)) {
++ var negFlag = (l[0] & 0x80) !== 0;
++ if (buffer_zero(l, 7, negFlag) && (l[7] & 0x80) === (negFlag ? 0x80 : 0)) {
++ return new types.SmallLong(negFlag ? -((l[7] ^ 0xff) + 1) : l[7]);
++ }
++ return new types.Long(l);
++ } else {
++ return l > 127 || l < -128 ? new types.Long(l) : new types.SmallLong(l);
++ }
+ };
+ types.wrap_int = function(l) {
+ return l > 127 || l < -128 ? new types.Int(l) : new types.SmallInt(l);
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/src/python/qpid_interop_test/amqp_types_test.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/amqp_types_test.py b/src/python/qpid_interop_test/amqp_types_test.py
index b876619..fbd2c0c 100755
--- a/src/python/qpid_interop_test/amqp_types_test.py
+++ b/src/python/qpid_interop_test/amqp_types_test.py
@@ -70,6 +70,7 @@ class AmqpPrimitiveTypes(TestTypeMap):
'0x1',
'0xff',
'0x100',
+ '0x102030405',
'0x7fffffffffffffff',
'0x8000000000000000',
'0xffffffffffffffff'],
@@ -86,12 +87,14 @@ class AmqpPrimitiveTypes(TestTypeMap):
'0x0',
'0x7fffffff'],
'long': ['-0x8000000000000000',
+ '-0x102030405',
'-0x81',
'-0x80',
'-0x1',
'0x0',
'0x7f',
'0x80',
+ '0x102030405',
'0x7fffffffffffffff'],
# float and double: Because of difficulty with rounding of floating point numbers, we use the binary
# representation instead which should be exact when comparing sent and received values.
@@ -110,7 +113,8 @@ class AmqpPrimitiveTypes(TestTypeMap):
#'0x7f800000', # +Infinity # PROTON-1149 - fails on RHEL7
#'0xff800000', # -Infinity # PROTON-1149 - fails on RHEL7
'0x7fc00000', # +NaN
- '0xffc00000'], # -NaN
+ #'0xffc00000', # -NaN # Not supported in Javascript
+ ],
'double': ['0x0000000000000000', # 0.0
'0x8000000000000000', # -0.0
'0x400921fb54442eea', # pi (3.14159265359) positive decimal
@@ -126,7 +130,8 @@ class AmqpPrimitiveTypes(TestTypeMap):
'0x7ff0000000000000', # +Infinity
'0xfff0000000000000', # -Infinity
'0x7ff8000000000000', # +NaN
- '0xfff8000000000000'], # -NaN
+ #'0xfff8000000000000', # -NaN # Not supported in Javascript
+ ],
# decimal32, decimal64, decimal128:
# Until more formal support for decimal32, decimal64 and decimal128 are included in Python, we use
# a hex format for basic tests, and treat the data as a binary blob.
@@ -140,12 +145,18 @@ class AmqpPrimitiveTypes(TestTypeMap):
'0xffefffffffffffff'],
'decimal128': ['0x00000000000000000000000000000000',
'0xff0102030405060708090a0b0c0d0e0f'],
- 'char': [u'a',
- u'Z',
- u'0x1',
+ 'char': [u' ', # single ASCII chars
+ u'0',
+ u'A',
+ u'z',
+ u'~',
+ u'0x1', # Hex representation
u'0x7f',
u'0x16b5', # Rune 'G'
- u'0x10ffff'],
+ u'0x10203',
+ u'0x10ffff',
+ #u'0x12345678' # 32-bit number, not real char # Disabled until Python can handle it
+ ],
# timestamp: Must be in milliseconds since the Unix epoch
'timestamp': ['0x0',
'0x%x' % int(mktime((2000, 1, 1, 0, 0, 0, 5, 1, 0))*1000),
@@ -169,7 +180,8 @@ class AmqpPrimitiveTypes(TestTypeMap):
],
'symbol': ['',
'myDomain.123',
- 'domain.0123456789.' * 100],
+ 'domain.0123456789.' * 100,
+ ],
'list': [[],
['ubyte:1', 'int:-2', 'float:3.14'],
['string:a', 'string:b', 'string:c'],
@@ -200,35 +212,47 @@ class AmqpPrimitiveTypes(TestTypeMap):
'short:8',
'short:9'] * 10
],
- 'map': [
- # Enpty map
- {},
- # Map with string keys
- {'string:one': 'ubyte:1',
- 'string:two': 'ushort:2'},
- # Map with other AMQP simple types as keys
- {'none:': 'string:None',
- 'string:None': 'none:',
- 'string:One': 'long:-1234567890',
- 'short:2': 'int:2',
- 'boolean:True': 'string:True',
- 'string:False': 'boolean:False',
- #['string:AAA', 'ushort:5951']: 'string:list value',
- #{'byte:-55': 'ubyte:200',
- # 'boolean:True': 'string:Hello, world!'}: 'symbol:map.value',
- #'string:list': [],
- 'string:map': {'char:A': 'int:1',
- 'char:B': 'int:2'}},
- ],
- # TODO: Support all AMQP types in array (including keys)
- #'array': [[],
- # [1, 2, 3],
- # ['Hello', 'world'],
- # [[1, 2, 3],
- # ['a', 'b', 'c'],
- # [2.3, 3.4, 4,5],
- # [True, False, True, True]]
- # ]
+ 'map': [{}, # Enpty map
+ # Map with string keys
+ {'string:one': 'ubyte:1',
+ 'string:two': 'ushort:2'},
+ # Map with other AMQP simple types as keys
+ {'none:': 'string:None',
+ 'string:None': 'none:',
+ 'string:One': 'long:-1234567890',
+ 'short:2': 'int:2',
+ 'boolean:True': 'string:True',
+ 'string:False': 'boolean:False',
+ #['string:AAA', 'ushort:5951']: 'string:list value',
+ #{'byte:-55': 'ubyte:200',
+ # 'boolean:True': 'string:Hello, world!'}: 'symbol:map.value',
+ #'string:list': [],
+ 'string:map': {'char:A': 'int:1',
+ 'char:B': 'int:2'}},
+ ],
+ # array: Each array is constructed from the test values in this map. This list contains
+ # the keys to the array value types to be included in the test. See function create_test_arrays()
+ # for the top-level function that performs the array creation.
+ #'array': ['boolean',
+ # 'ubyte',
+ # 'ushort',
+ # 'uint',
+ # 'ulong',
+ # 'byte',
+ # 'short',
+ # 'int',
+ # 'long',
+ # 'float',
+ # 'double',
+ # 'decimal32',
+ # 'decimal64',
+ # 'decimal128',
+ # 'char',
+ # 'uuid',
+ # 'binary',
+ # 'string',
+ # 'symbol',
+ # ],
}
# This section contains tests that should be skipped because of know issues that would cause the test to fail.
@@ -250,6 +274,31 @@ class AmqpPrimitiveTypes(TestTypeMap):
'double': {'apache-activemq-artemis': '-NaN is stripped of its sign: ENTMQ-1686'},
}
+ def create_array(self, amqp_type, repeat):
+ """
+ Create a single test array for a given AMQP type from the test values for that type. It can be optionally
+ repeated for greater number of elements.
+ """
+ test_array = [amqp_type]
+ for _ in range(repeat):
+ for val in self.TYPE_MAP[amqp_type]:
+ test_array.append(val)
+ return test_array
+
+ def create_test_arrays(self):
+ """ Method to synthesize the test arrays from the values used in the previous type tests """
+ test_arrays = []
+ for amqp_type in self.TYPE_MAP['array']:
+ test_arrays.append(self.create_array(amqp_type, 1))
+ print test_arrays
+ return test_arrays
+
+ def get_test_values(self, amqp_type):
+ """ Overload the parent method so that arrays can be synthesized rather than read directly """
+ if amqp_type == 'array':
+ return self.create_test_arrays()
+ return super(AmqpPrimitiveTypes, self).get_test_values(amqp_type)
+
class AmqpTypeTestCase(unittest.TestCase):
"""
@@ -353,11 +402,17 @@ PROTON_PYTHON_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-p
'Receiver.py')
PROTON_PYTHON_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'qpid-proton-python', 'src', 'amqp_types_test',
'Sender.py')
+PROTON_RHEAJS_RECEIVER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'rhea-js', 'amqp_types_test',
+ 'Receiver.js')
+PROTON_RHEAJS_SENDER_SHIM = path.join(QPID_INTEROP_TEST_HOME, 'shims', 'rhea-js', 'amqp_types_test',
+ 'Sender.js')
SHIM_MAP = {qpid_interop_test.shims.ProtonCppShim.NAME: \
qpid_interop_test.shims.ProtonCppShim(PROTON_CPP_SENDER_SHIM, PROTON_CPP_RECEIVER_SHIM),
qpid_interop_test.shims.ProtonPythonShim.NAME: \
qpid_interop_test.shims.ProtonPythonShim(PROTON_PYTHON_SENDER_SHIM, PROTON_PYTHON_RECEIVER_SHIM),
+ qpid_interop_test.shims.RheaJsShim.NAME: \
+ qpid_interop_test.shims.RheaJsShim(PROTON_RHEAJS_SENDER_SHIM, PROTON_RHEAJS_RECEIVER_SHIM),
}
http://git-wip-us.apache.org/repos/asf/qpid-interop-test/blob/156ac5a5/src/python/qpid_interop_test/shims.py
----------------------------------------------------------------------
diff --git a/src/python/qpid_interop_test/shims.py b/src/python/qpid_interop_test/shims.py
index 5d824ad..210f9b6 100644
--- a/src/python/qpid_interop_test/shims.py
+++ b/src/python/qpid_interop_test/shims.py
@@ -186,6 +186,15 @@ class ProtonCppShim(Shim):
self.receive_params = [self.receiver_shim]
+class RheaJsShim(Shim):
+ """Shim for Rhea Javascript client"""
+ NAME = 'RheaJs'
+ def __init__(self, sender_shim, receiver_shim):
+ super(RheaJsShim, self).__init__(sender_shim, receiver_shim)
+ self.send_params = [self.sender_shim]
+ self.receive_params = [self.receiver_shim]
+
+
class QpidJmsShim(Shim):
"""Shim for qpid-jms JMS client"""
NAME = 'QpidJms'
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org