blob: e7149224eac559062f1a36cf76a9311e26d854fa [file] [log] [blame]
#!/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.
*
*/
/**
* This is a fairly literal JavaScript port of message.py used to unit test the
* proton.Message wrapper class.
*/
// Check if the environment is Node.js and if not log an error and exit.
if (typeof process === 'object' && typeof require === 'function') {
var unittest = require("./unittest.js");
var assert = require("assert");
var proton = require("qpid-proton-messenger");
/**
* JavaScript Implementation of Python's range() function taken from:
* http://stackoverflow.com/questions/8273047/javascript-function-similar-to-python-range
*/
var range = function(start, stop, step) {
if (typeof stop == 'undefined') {
// one param defined
stop = start;
start = 0;
};
if (typeof step == 'undefined') {
step = 1;
};
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
return [];
};
var result = [];
for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
result.push(i);
};
return result;
};
// Extend TestCase by creating a new Test class as we're using it in a few places.
var Test = function() { // Test constructor.
/**
* The following call is the equivalent of "super" in Java. It's not necessary
* here as the unittest.TestCase constructor doesn't set any state, but it
* is the correct thing to do when implementing classical inheritance in
* JavaScript so I've kept it here as a useful reminder of the "pattern".
*/
//unittest.TestCase.prototype.constructor.call(this);
};
Test.prototype = new unittest.TestCase(); // Here's where the inheritance occurs.
Test.prototype.constructor = Test; // Otherwise instances of Test would have a constructor of unittest.TestCase.
Test.prototype.setUp = function() {
this.msg = new proton.Message();
};
Test.prototype.tearDown = function() {
this.msg.free();
this.msg = null;
};
// Extend Test more simply by creating a prototype instance and adding test methods as properties.
var AccessorsTest = new Test();
AccessorsTest._test = function(name, defaultValue, values) {
/**
* For the case of Binary values under test we retrieve their toString().
* This is because the methods under test "consume" the data, in other
* words ownership of the underlying raw data transfers to the Message
* object so the sent Binary object becomes "empty" after calling the setter.
* In addition Binary values merely contain a "pointer" to the raw data
* so even a "deepEqual" comparison won't accurately compare two Binaries.
* For these tests we "cheat" and store an array of characters in the
* Binary so that we can use their String forms for comparison tests.
*
* We also get the String value of Uuid for the case of setUserID because
* that method transparently creates Binary values from the String form
* of non-Binary data passed to it. It's a convenience method, but makes
* testing somewhat more fiddly.
*/
// First get the values passed to the method.
var values = Array.prototype.slice.apply(arguments, [2]);
// If the first element of values is actually an Array then use the Array.
// This scenario is what happens in the tests that use the range() function.
values = (Object.prototype.toString.call(values[0]) === '[object Array]') ? values[0] : values;
// Work out the accessor/mutator names noting that boolean accessors use "is" not "get".
var setter = 'set' + name;
var getter = (typeof defaultValue === 'boolean') ? 'is' + name : 'get' + name;
// Get the message's default value first.
var d = this.msg[getter]();
d = (d instanceof proton.Data.Binary) ? d.toString() : d;
// Compare the message's default with the expected default value passed in the test case.
assert.deepEqual(d, defaultValue);
for (var i = 0; i < values.length; i++) {
var v = values[i];
var value = (v instanceof proton.Data.Binary ||
(name === 'UserID' && v instanceof proton.Data.Uuid)) ? v.toString() : v;
value = (v instanceof Date) ? v.valueOf() : v;
this.msg[setter](v); // This call will "consume" Binary data.
var gotten = this.msg[getter]();
gotten = (gotten instanceof proton.Data.Binary) ? gotten.toString() : gotten;
gotten = (gotten instanceof Date) ? gotten.valueOf() : v;
assert.deepEqual(value, gotten);
}
};
AccessorsTest._testString = function(name) {
this._test(name, "", "asdf", "fdsa", "");
};
AccessorsTest._testTime = function(name) {
// The ExpiryTime and CreationTime methods can take either a number or a Date Object.
this._test(name, new Date(0), new Date(0), 123456789, new Date(987654321));
};
AccessorsTest.testID = function() {
console.log("testID");
this._test("ID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
console.log("OK\n");
};
AccessorsTest.testCorrelationID = function() {
console.log("testCorrelationID");
this._test("CorrelationID", null, "bytes", null, 123, "string", new proton.Data.Uuid(), new proton.Data.Binary("ВИНАРЫ"));
console.log("OK\n");
};
AccessorsTest.testDurable = function() {
console.log("testDurable");
this._test("Durable", false, true, false);
console.log("OK\n");
};
AccessorsTest.testPriority = function() {
console.log("testPriority");
this._test("Priority", proton.Message.DEFAULT_PRIORITY, range(0, 256));
console.log("OK\n");
};
AccessorsTest.testTTL = function() {
console.log("testTTL");
this._test("TTL", 0, range(12345, 54321));
console.log("OK\n");
};
AccessorsTest.testFirstAcquirer = function() {
console.log("testFirstAcquirer");
this._test("FirstAcquirer", false, true, false);
console.log("OK\n");
};
AccessorsTest.testDeliveryCount = function() {
console.log("testDeliveryCount");
this._test("DeliveryCount", 0, range(0, 1024));
console.log("OK\n");
};
AccessorsTest.testUserID = function() {
console.log("testUserID");
this._test("UserID", "", "asdf", "fdsa", 123, new proton.Data.Binary("ВИНАРЫ"), new proton.Data.Uuid(), "");
console.log("OK\n");
};
AccessorsTest.testAddress = function() {
console.log("testAddress");
this._testString("Address");
console.log("OK\n");
};
AccessorsTest.testSubject = function() {
console.log("testSubject");
this._testString("Subject");
console.log("OK\n");
};
AccessorsTest.testReplyTo = function() {
console.log("testReplyTo");
this._testString("ReplyTo");
console.log("OK\n");
};
AccessorsTest.testContentType = function() {
console.log("testContentType");
this._testString("ContentType");
console.log("OK\n");
};
AccessorsTest.testContentEncoding = function() {
console.log("testContentEncoding");
this._testString("ContentEncoding");
console.log("OK\n");
};
AccessorsTest.testExpiryTime = function() {
console.log("testExpiryTime");
this._testTime("ExpiryTime");
console.log("OK\n");
};
AccessorsTest.testCreationTime = function() {
console.log("testCreationTime");
this._testTime("CreationTime");
console.log("OK\n");
};
AccessorsTest.testGroupID = function() {
console.log("testGroupID");
this._testString("GroupID");
console.log("OK\n");
};
AccessorsTest.testGroupSequence = function() {
console.log("testGroupSequence");
this._test("GroupSequence", 0, 0, -10, 10, 20, -20);
console.log("OK\n");
};
AccessorsTest.testReplyToGroupID = function() {
console.log("testReplyToGroupID");
this._testString("ReplyToGroupID");
console.log("OK\n");
};
var CodecTest = new Test();
CodecTest.testRoundTrip = function() {
console.log("testRoundTrip");
this.msg.setID("asdf");
this.msg.setCorrelationID(new proton.Data.Uuid());
this.msg.setTTL(3);
this.msg.setPriority(100);
this.msg.setAddress("address");
this.msg.setSubject("subject");
this.msg.body = "Hello World!";
var data = this.msg.encode();
var msg2 = new proton.Message();
msg2.decode(data);
assert(this.msg.getID() === msg2.getID());
assert(this.msg.getCorrelationID().toString() === msg2.getCorrelationID().toString());
assert(this.msg.getTTL() === msg2.getTTL());
assert(this.msg.getPriority() === msg2.getPriority());
assert(this.msg.getAddress() === msg2.getAddress());
assert(this.msg.getSubject() === msg2.getSubject());
assert(this.msg.body === msg2.body);
msg2.free();
console.log("OK\n");
};
/**
* This test tests the transparent serialisation and deserialisation of JavaScript
* Objects using the AMQP type system (this is the default behaviour).
*/
CodecTest.testRoundTripBodyObject = function() {
console.log("testRoundTripBodyObject");
this.msg.setAddress("address");
this.msg.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
var data = this.msg.encode();
var msg2 = new proton.Message();
msg2.decode(data);
assert(this.msg.getAddress() === msg2.getAddress());
assert(this.msg.getContentType() === msg2.getContentType());
assert.deepEqual(this.msg.body, msg2.body);
msg2.free();
console.log("OK\n");
};
/**
* This test tests the transparent serialisation and deserialisation of JavaScript
* Objects as JSON. In this case the "on-the-wire" representation is an AMQP binary
* stored in the AMQP data section.
*/
CodecTest.testRoundTripBodyObjectAsJSON = function() {
console.log("testRoundTripBodyObjectAsJSON");
this.msg.setAddress("address");
this.msg.setContentType("application/json");
this.msg.body = {array: [1, 2, 3, 4], object: {name: "John Smith", age: 65}};
var data = this.msg.encode();
var msg2 = new proton.Message();
msg2.decode(data);
assert(this.msg.getAddress() === msg2.getAddress());
assert(this.msg.getContentType() === msg2.getContentType());
assert.deepEqual(this.msg.body, msg2.body);
msg2.free();
console.log("OK\n");
};
/**
* By default the API will encode using the AMQP type system, but is the content-type
* is set it will encode as an opaque Binary in an AMQP data section. For certain
* types however this isn't the most useful thing. For application/json (see
* previous test) we convert to and from JavaScript Objects and for text/* MIME
* types the API will automatically convert the received Binary into a String.
*/
CodecTest.testRoundTripMIMETextObject = function() {
console.log("testRoundTripMIMETextObject");
this.msg.setAddress("address");
this.msg.setContentType("text/plain");
this.msg.body = "some text";
var data = this.msg.encode();
var msg2 = new proton.Message();
msg2.decode(data);
assert(this.msg.getAddress() === msg2.getAddress());
assert(this.msg.getContentType() === msg2.getContentType());
assert.deepEqual(this.msg.body, msg2.body);
msg2.free();
console.log("OK\n");
};
// load and save are deprecated so not implemented in the JavaScript binding.
AccessorsTest.run();
CodecTest.run();
} else {
console.error("message.js should be run in Node.js");
}