From c067ff8ae17c9db52536afc2ffbf8d32712c8494 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Thu, 19 Aug 2010 00:59:44 +0100 Subject: First test --- jarmon.test.js | 34 ++++++++++++++++++++++++++++++++++ test.html | 10 ++++++++++ 2 files changed, 44 insertions(+) create mode 100644 jarmon.test.js create mode 100644 test.html diff --git a/jarmon.test.js b/jarmon.test.js new file mode 100644 index 0000000..c4c1410 --- /dev/null +++ b/jarmon.test.js @@ -0,0 +1,34 @@ +/* Copyright (c) 2010 Richard Wall + * See LICENSE for details. + * + * Unit tests for Jarmon + **/ + +YUI().use('test', function(Y) { + Y.Test.Runner.add(new Y.Test.Case({ + name: "jarmon.downloadBinary", + + setUp : function () { + }, + + tearDown : function () { + }, + + test_urlNotFound: function () { + var d = new jarmon.downloadBinary('non-existent-file.html'); + d.addBoth( + function(self, ret) { + console.log(ret); + self.resume(function() { + Y.Assert.isInstanceOf(Error, ret); + Y.Assert.areEqual(404, ret.message); + }); + }, this); + + this.wait(); + }, + })); + + //run all tests + Y.Test.Runner.run(); +}); diff --git a/test.html b/test.html new file mode 100644 index 0000000..9300d16 --- /dev/null +++ b/test.html @@ -0,0 +1,10 @@ + + + + Jarmon Unit Test Runner + + + + + + -- cgit v1.1-4-g5e80 From d2f5c22d5bfb0148ea8a039ddf5cba921fdcaf85 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Mon, 23 Aug 2010 23:25:20 +0100 Subject: remove the console.log --- jarmon.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/jarmon.test.js b/jarmon.test.js index c4c1410..90cb62c 100644 --- a/jarmon.test.js +++ b/jarmon.test.js @@ -18,7 +18,6 @@ YUI().use('test', function(Y) { var d = new jarmon.downloadBinary('non-existent-file.html'); d.addBoth( function(self, ret) { - console.log(ret); self.resume(function() { Y.Assert.isInstanceOf(Error, ret); Y.Assert.areEqual(404, ret.message); -- cgit v1.1-4-g5e80 From 4afe231bc8371560cc87f6865d74f052691ea582 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Tue, 24 Aug 2010 00:02:30 +0100 Subject: use new paths and smarten up the test results --- jarmon.test.js | 33 --------------------------------- jarmon/jarmon.test.js | 40 ++++++++++++++++++++++++++++++++++++++++ test.html | 21 +++++++++++++++------ 3 files changed, 55 insertions(+), 39 deletions(-) delete mode 100644 jarmon.test.js create mode 100644 jarmon/jarmon.test.js diff --git a/jarmon.test.js b/jarmon.test.js deleted file mode 100644 index 90cb62c..0000000 --- a/jarmon.test.js +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (c) 2010 Richard Wall - * See LICENSE for details. - * - * Unit tests for Jarmon - **/ - -YUI().use('test', function(Y) { - Y.Test.Runner.add(new Y.Test.Case({ - name: "jarmon.downloadBinary", - - setUp : function () { - }, - - tearDown : function () { - }, - - test_urlNotFound: function () { - var d = new jarmon.downloadBinary('non-existent-file.html'); - d.addBoth( - function(self, ret) { - self.resume(function() { - Y.Assert.isInstanceOf(Error, ret); - Y.Assert.areEqual(404, ret.message); - }); - }, this); - - this.wait(); - }, - })); - - //run all tests - Y.Test.Runner.run(); -}); diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js new file mode 100644 index 0000000..b6ee035 --- /dev/null +++ b/jarmon/jarmon.test.js @@ -0,0 +1,40 @@ +/* Copyright (c) 2010 Richard Wall + * See LICENSE for details. + * + * Unit tests for Jarmon + **/ + +YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { + Y.Test.Runner.add(new Y.Test.Case({ + name: "jarmon.downloadBinary", + + setUp : function () { + }, + + tearDown : function () { + }, + + test_urlNotFound: function () { + var d = new jarmon.downloadBinary('non-existent-file.html'); + d.addBoth( + function(self, ret) { + self.resume(function() { + Y.Assert.isInstanceOf(Error, ret); + Y.Assert.areEqual(404, ret.message); + }); + }, this); + + this.wait(); + }, + })); + + //initialize the console + var yconsole = new Y.Console({ + newestOnTop: false, + width:'600px' + }); + yconsole.render('#log'); + + //run all tests + Y.Test.Runner.run(); +}); diff --git a/test.html b/test.html index 9300d16..6db4f55 100644 --- a/test.html +++ b/test.html @@ -1,10 +1,19 @@ - - Jarmon Unit Test Runner + + + Jarmon Unit Test Runner + + - - - - + + + + + + +
+ -- cgit v1.1-4-g5e80 From a741b9e561512e258fe4a589ac074c548eb37e3a Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Wed, 25 Aug 2010 21:06:07 +0100 Subject: Add a test for successful binary download --- jarmon/jarmon.test.js | 22 ++++++++++++++++++++++ testfile.bin | Bin 0 -> 1 bytes 2 files changed, 22 insertions(+) create mode 100644 testfile.bin diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index b6ee035..4a5c273 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -15,6 +15,10 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { }, test_urlNotFound: function () { + /** + * When url cannot be found, the deferred should errback with status + * 404. + **/ var d = new jarmon.downloadBinary('non-existent-file.html'); d.addBoth( function(self, ret) { @@ -26,6 +30,24 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.wait(); }, + + test_urlFound: function () { + /** + * When url is found, the deferred should callback with an instance + * of javascriptrrd.BinaryFile + **/ + var d = new jarmon.downloadBinary('testfile.bin'); + d.addBoth( + function(self, ret) { + self.resume(function() { + Y.Assert.isInstanceOf(BinaryFile, ret); + Y.Assert.areEqual(String.fromCharCode(0), ret.getRawData()); + }); + }, this); + + this.wait(); + }, + })); //initialize the console diff --git a/testfile.bin b/testfile.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/testfile.bin differ -- cgit v1.1-4-g5e80 From 64f965d74374f3a15342bf6e807ac50513a69f68 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Wed, 25 Aug 2010 22:20:41 +0100 Subject: Add a test for query timerange --- jarmon/jarmon.js | 23 +++++++++++++++++++++++ jarmon/jarmon.test.js | 30 +++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 44c4dad..6296fc5 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -27,6 +27,7 @@ if(typeof jarmon == 'undefined') { var jarmon = {}; } + jarmon.downloadBinary = function(url) { /** * Download a binary file asynchronously using the jQuery.ajax function @@ -126,6 +127,20 @@ jarmon.localTimeFormatter = function (v, axis) { }; +jarmon.TimeRangeError = function(message) { + /** + * Raised when an invalid timerange is encountered. + * + * @class jarmon.TimeRangeError + * @constructor + * @param message {String} A description of the error reason + **/ + this.name = "TimeRangeError"; + this.message = (message || ""); +} +jarmon.TimeRangeError.prototype = Error.prototype; + + /** * A wrapper around an instance of javascriptrrd.RRDFile which provides a * convenient way to query the RRDFile based on time range, RRD data source (DS) @@ -156,6 +171,14 @@ jarmon.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) { * @return {Object} A Flot compatible data series * eg label: '', data: [], unit: '' **/ + + if (startTime >= endTime) { + throw new jarmon.TimeRangeError( + ['starttime must be less than endtime. ', + 'starttime: ', starttime, + 'endtime: ', endtime].join('')); + } + var startTimestamp = startTime/1000; var lastUpdated = this.rrd.getLastUpdate(); diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 4a5c273..86243b4 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -8,12 +8,6 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { Y.Test.Runner.add(new Y.Test.Case({ name: "jarmon.downloadBinary", - setUp : function () { - }, - - tearDown : function () { - }, - test_urlNotFound: function () { /** * When url cannot be found, the deferred should errback with status @@ -46,10 +40,32 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { }, this); this.wait(); - }, + } })); + + Y.Test.Runner.add(new Y.Test.Case({ + name: "jarmon.RrdQuery", + + test_getDataTimeRangeOverlapError: function () { + /** + * The starttime must be less than the endtime + **/ + var rq = new jarmon.RrdQuery({}, ''); + var error = null; + try { + rq.getData(1, 0); + } catch(e) { + error = e; + } + Y.Assert.isInstanceOf(jarmon.TimeRangeError, error); + } + + })); + + + //initialize the console var yconsole = new Y.Console({ newestOnTop: false, -- cgit v1.1-4-g5e80 From 333dfba10d99e5a2eec391c2481156329e2949dc Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sat, 28 Aug 2010 22:34:26 +0100 Subject: the start of a builder of simple, testable rrd files --- jarmon/jarmon.js | 2 +- jarmon/jarmon.test.js | 53 ++++++++++++++++++++++++++++++++++++++++--------- jarmonbuild/commands.py | 21 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 6296fc5..24f967d 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -263,7 +263,7 @@ jarmon.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) { jarmon.RrdQueryRemote = function(url, unit, downloader) { this.url = url; this.unit = unit; - this.downloader = downloader; + this.downloader = downloader || jarmon.downloadBinary; this.lastUpdate = 0; this._download = null; }; diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 86243b4..229b9a8 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -48,19 +48,54 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { Y.Test.Runner.add(new Y.Test.Case({ name: "jarmon.RrdQuery", + setUp: function() { + this.d = new jarmon.downloadBinary('simple.rrd') + .addCallback( + function(self, binary) { + try { + return new RRDFile(binary); + } catch(e) { + console.log(e); + } + }, this) + .addErrback( + function(ret) { + console.log(ret); + }); + }, + test_getDataTimeRangeOverlapError: function () { /** * The starttime must be less than the endtime **/ - var rq = new jarmon.RrdQuery({}, ''); - var error = null; - try { - rq.getData(1, 0); - } catch(e) { - error = e; - } - Y.Assert.isInstanceOf(jarmon.TimeRangeError, error); - } + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + var rq = new jarmon.RrdQuery(self.rrd, ''); + var error = null; + try { + rq.getData(1, 0); + } catch(e) { + error = e; + } + Y.Assert.isInstanceOf(jarmon.TimeRangeError, error); + }); + }, this); + this.wait(); + }, + + test_getDataSimple: function () { + /** + * The starttime must be less than the endtime + **/ + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + Y.Assert.areEqual(1, rrd.getLastUpdate()); + }); + }, this); + this.wait(); + }, })); diff --git a/jarmonbuild/commands.py b/jarmonbuild/commands.py index 5071a46..91b266a 100644 --- a/jarmonbuild/commands.py +++ b/jarmonbuild/commands.py @@ -185,10 +185,31 @@ class BuildReleaseCommand(BuildCommand): z.close() +class BuildTestDataCommand(object): + def __init__(self, buildversion): + self.log = logging.getLogger( + '%s.%s' % (__name__, self.__class__.__name__)) + + def main(self, argv): + from pyrrd.rrd import DataSource, RRA, RRD + + dss = [] + rras = [] + filename = '/tmp/test.rrd' + dss.append(DataSource(dsName='speed', dsType='COUNTER', heartbeat=600)) + rras.append(RRA(cf='AVERAGE', xff=0.5, steps=1, rows=24)) + rras.append(RRA(cf='AVERAGE', xff=0.5, steps=6, rows=10)) + my_rrd = RRD(filename, ds=dss, rra=rras, start=0) + my_rrd.create() + my_rrd.bufferValue(1, '12363') + my_rrd.bufferValue(2, '12363') + my_rrd.update() + # The available sub commands build_commands = { 'apidocs': BuildApidocsCommand, 'release': BuildReleaseCommand, + 'testdata': BuildTestDataCommand, } -- cgit v1.1-4-g5e80 From bce8a067e4b37b36bade0ed1f1c5348553c6e822 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sat, 28 Aug 2010 23:14:25 +0100 Subject: Implement subcommand argument parsing --- jarmonbuild/commands.py | 81 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/jarmonbuild/commands.py b/jarmonbuild/commands.py index 91b266a..c63848b 100644 --- a/jarmonbuild/commands.py +++ b/jarmonbuild/commands.py @@ -34,13 +34,9 @@ class BuildError(Exception): class BuildCommand(object): - def __init__(self, buildversion, log=None): - self.buildversion = buildversion - if log is not None: - self.log = log - else: - self.log = logging.getLogger( - '%s.%s' % (__name__, self.__class__.__name__)) + def __init__(self): + self.log = logging.getLogger( + '%s.%s' % (__name__, self.__class__.__name__)) self.workingbranch_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), '..')) @@ -60,12 +56,26 @@ class BuildApidocsCommand(BuildCommand): Download YUI Doc and use it to generate apidocs for jarmon """ + command_name = 'apidocs' + def main(self, argv): """ The main entry point for the build-apidocs command @param argv: The list of arguments passed to the build-apidocs command """ + + parser = OptionParser( + usage='build [options] %s VERSION' % (self.command_name,)) + parser.disable_interspersed_args() + options, args = parser.parse_args(argv) + + if len(args) != 1: + parser.error('Wrong number of arguments. This command expects a ' + 'version number only.') + + buildversion = args[0] + tmpdir = gettempdir() workingbranch_dir = self.workingbranch_dir build_dir = self.build_dir @@ -131,7 +141,7 @@ class BuildApidocsCommand(BuildCommand): '--template=%s' % ( os.path.join( workingbranch_dir, 'jarmonbuild', 'yuidoc_template'),), - '--version=%s' % (self.buildversion,), + '--version=%s' % (buildversion,), '--project=%s' % (JARMON_PROJECT_TITLE,), '--projecturl=%s' % (JARMON_PROJECT_URL,) ), stdout=PIPE, stderr=PIPE,) @@ -145,7 +155,21 @@ class BuildReleaseCommand(BuildCommand): upload to Launchpad. """ + command_name = 'release' + def main(self, argv): + + parser = OptionParser( + usage='build [options] %s VERSION' % (self.command_name,)) + parser.disable_interspersed_args() + options, args = parser.parse_args(argv) + + if len(args) != 1: + parser.error('Wrong number of arguments. This command expects a ' + 'version number only.') + + buildversion = args[0] + workingbranch_dir = self.workingbranch_dir build_dir = self.build_dir @@ -167,11 +191,11 @@ class BuildReleaseCommand(BuildCommand): self.log.debug('Generate apidocs') - BuildApidocsCommand(buildversion=self.buildversion).main(argv) + BuildApidocsCommand().main([buildversion]) self.log.debug('Generate archive') - archive_root = 'jarmon-%s' % (self.buildversion,) + archive_root = 'jarmon-%s' % (buildversion,) prefix_len = len(build_dir) + 1 z = ZipFile('%s.zip' % (archive_root,), 'w', ZIP_DEFLATED) try: @@ -185,10 +209,12 @@ class BuildReleaseCommand(BuildCommand): z.close() -class BuildTestDataCommand(object): - def __init__(self, buildversion): - self.log = logging.getLogger( - '%s.%s' % (__name__, self.__class__.__name__)) +class BuildTestDataCommand(BuildCommand): + """ + Create data for use in unittests + """ + + command_name = 'testdata' def main(self, argv): from pyrrd.rrd import DataSource, RRA, RRD @@ -205,12 +231,14 @@ class BuildTestDataCommand(object): my_rrd.bufferValue(2, '12363') my_rrd.update() -# The available sub commands -build_commands = { - 'apidocs': BuildApidocsCommand, - 'release': BuildReleaseCommand, - 'testdata': BuildTestDataCommand, -} + + +# The available subcommands +SUBCOMMAND_HANDLERS = [ + BuildApidocsCommand, + BuildReleaseCommand, + BuildTestDataCommand, +] def main(argv=sys.argv[1:]): @@ -218,10 +246,13 @@ def main(argv=sys.argv[1:]): The root build command which dispatches to various subcommands for eg building apidocs and release zip files. """ - parser = OptionParser(usage='%prog [options] SUBCOMMAND [options]') - parser.add_option( - '-V', '--build-version', dest='buildversion', default='0', - metavar='BUILDVERSION', help='Specify the build version') + + build_commands = dict( + (handler.command_name, handler) for handler in SUBCOMMAND_HANDLERS) + + parser = OptionParser( + usage='build [options] SUBCOMMAND [options]', + description='Available subcommands are: %r' % (build_commands.keys(),)) parser.add_option( '-d', '--debug', action='store_true', default=False, dest='debug', help='Print verbose debug log to stderr') @@ -257,4 +288,4 @@ def main(argv=sys.argv[1:]): log.setLevel(logging.DEBUG) ch.setLevel(logging.DEBUG) - command_factory(buildversion=options.buildversion).main(argv=args) + command_factory().main(argv=args) -- cgit v1.1-4-g5e80 From 24751968187f59cdbb45a17b37f188fc9e169c1c Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 29 Aug 2010 19:02:34 +0100 Subject: build an rrd file with simple / testable content --- jarmonbuild/commands.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/jarmonbuild/commands.py b/jarmonbuild/commands.py index c63848b..48e679b 100644 --- a/jarmonbuild/commands.py +++ b/jarmonbuild/commands.py @@ -8,6 +8,7 @@ import logging import os import shutil import sys +import time from optparse import OptionParser from subprocess import check_call, PIPE @@ -217,18 +218,27 @@ class BuildTestDataCommand(BuildCommand): command_name = 'testdata' def main(self, argv): + """ + Create an RRD file with values 0-9 entered at 1 second intervals from + 1980-01-01 00:00:00 (the first date that rrdtool allows) + """ + from datetime import datetime from pyrrd.rrd import DataSource, RRA, RRD - + start = int(datetime(1980, 1, 1, 0, 0).strftime('%s')) dss = [] rras = [] - filename = '/tmp/test.rrd' - dss.append(DataSource(dsName='speed', dsType='COUNTER', heartbeat=600)) - rras.append(RRA(cf='AVERAGE', xff=0.5, steps=1, rows=24)) - rras.append(RRA(cf='AVERAGE', xff=0.5, steps=6, rows=10)) - my_rrd = RRD(filename, ds=dss, rra=rras, start=0) + filename = os.path.join(self.build_dir, 'test.rrd') + + rows = 10 + + dss.append(DataSource(dsName='speed', dsType='GAUGE', heartbeat=1)) + rras.append(RRA(cf='AVERAGE', xff=0.5, steps=1, rows=rows)) + my_rrd = RRD(filename, ds=dss, rra=rras, start=start, step=1) my_rrd.create() - my_rrd.bufferValue(1, '12363') - my_rrd.bufferValue(2, '12363') + + for i, t in enumerate(range(start, start+rows, 1)): + my_rrd.bufferValue(t+1, i) + my_rrd.update() -- cgit v1.1-4-g5e80 From 3c28be95136220398ff8b5b808742c8028876950 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 29 Aug 2010 19:24:25 +0100 Subject: A first rrdquery test --- jarmon/jarmon.test.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 229b9a8..7a2d6ec 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -49,7 +49,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { name: "jarmon.RrdQuery", setUp: function() { - this.d = new jarmon.downloadBinary('simple.rrd') + this.d = new jarmon.downloadBinary('build/test.rrd') .addCallback( function(self, binary) { try { @@ -86,12 +86,20 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { test_getDataSimple: function () { /** - * The starttime must be less than the endtime + * The generated rrd file should have values 0-9 at 1s intervals + * starting at 1980-01-01 00:00:00 **/ this.d.addCallback( function(self, rrd) { self.resume(function() { - Y.Assert.areEqual(1, rrd.getLastUpdate()); + var firstUpdate = new Date('1 jan 1980 00:00:00').getTime(); + var lastUpdate = firstUpdate + 10*1000; + Y.Assert.areEqual( + lastUpdate/1000, rrd.getLastUpdate()); + var q = new jarmon.RrdQuery(rrd, ''); + var data = q.getData(firstUpdate, lastUpdate); + Y.Assert.areEqual( + 0, data.data[0][1]); }); }, this); this.wait(); -- cgit v1.1-4-g5e80 From ca0884b96c26fb08353e982263e096fa9777fb10 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 29 Aug 2010 21:39:07 +0100 Subject: Add tests for the parts of RRDFile that we use. --- jarmon/jarmon.test.js | 117 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 2 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 7a2d6ec..3d96d5a 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -46,6 +46,110 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { Y.Test.Runner.add(new Y.Test.Case({ + name: "javascriptrrd.RRDFile", + + setUp: function() { + this.d = new jarmon.downloadBinary('build/test.rrd') + .addCallback( + function(self, binary) { + try { + return new RRDFile(binary); + } catch(e) { + console.log(e); + } + }, this) + .addErrback( + function(ret) { + console.log(ret); + }); + }, + + test_getLastUpdate: function () { + /** + * The generated rrd file should have a lastupdate date of + * 1980-01-01 00:00:10 + **/ + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + var lastUpdate = new Date('1 jan 1980 00:00:10').getTime(); + Y.Assert.areEqual( + lastUpdate/1000, rrd.getLastUpdate()); + }); + }, this); + this.wait(); + }, + + test_getDSIndex: function () { + /** + * The generated rrd file should have a single DS whose name is + * 'speed'. A RangeError is thrown if the requested index or dsName + * doesnt exist. + **/ + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + Y.Assert.areEqual('speed', rrd.getDS(0).getName()); + Y.Assert.areEqual(0, rrd.getDS('speed').getIdx()); + var error = null; + try { + rrd.getDS(1); + } catch(e) { + error = e; + } + Y.assert(error instanceof RangeError); + }); + }, this); + this.wait(); + }, + + test_getNrRRAs: function () { + /** + * The generated rrd file should have a single RRA + **/ + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + Y.Assert.areEqual(1, rrd.getNrRRAs()); + }); + }, this); + this.wait(); + }, + + test_getRRA: function () { + /** + * The generated rrd file should have a single RRA using AVERAGE + * consolidation, step=1, rows=10 and values 0-9 + * rra.getEl throws a RangeError if asked for row which doesn't + * exist. + **/ + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + var rra = rrd.getRRA(0); + Y.Assert.areEqual('AVERAGE', rra.getCFName()); + Y.Assert.areEqual(1, rra.getStep()); + Y.Assert.areEqual(10, rra.getNrRows()); + for(var i=0; i<10; i++) { + Y.Assert.areEqual(i, rra.getEl(i, 0)); + } + var error = null + try { + rra.getEl(10, 0); + } catch(e) { + error = e; + } + Y.assert(error instanceof RangeError); + }); + }, this); + this.wait(); + }, + + + + })); + + Y.Test.Runner.add(new Y.Test.Case({ name: "jarmon.RrdQuery", setUp: function() { @@ -92,14 +196,22 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.d.addCallback( function(self, rrd) { self.resume(function() { + var rra = rrd.getRRA(0) + console.log(rra.getEl(0, 0)); + + var firstUpdate = new Date('1 jan 1980 00:00:00').getTime(); var lastUpdate = firstUpdate + 10*1000; Y.Assert.areEqual( lastUpdate/1000, rrd.getLastUpdate()); + + + /* var q = new jarmon.RrdQuery(rrd, ''); var data = q.getData(firstUpdate, lastUpdate); Y.Assert.areEqual( - 0, data.data[0][1]); + firstUpdate+1000, data.data[0][0]); + */ }); }, this); this.wait(); @@ -112,7 +224,8 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { //initialize the console var yconsole = new Y.Console({ newestOnTop: false, - width:'600px' + width:'600px', + height: '400px' }); yconsole.render('#log'); -- cgit v1.1-4-g5e80 From 877f4724204f0d68f44116ef21b8425813c8285d Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 29 Aug 2010 23:16:18 +0100 Subject: a filing test for RrdQuery getData --- jarmon/jarmon.test.js | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 3d96d5a..6360685 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -52,11 +52,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.d = new jarmon.downloadBinary('build/test.rrd') .addCallback( function(self, binary) { - try { - return new RRDFile(binary); - } catch(e) { - console.log(e); - } + return new RRDFile(binary); }, this) .addErrback( function(ret) { @@ -143,10 +139,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { }); }, this); this.wait(); - }, - - - + } })); Y.Test.Runner.add(new Y.Test.Case({ @@ -156,11 +149,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.d = new jarmon.downloadBinary('build/test.rrd') .addCallback( function(self, binary) { - try { - return new RRDFile(binary); - } catch(e) { - console.log(e); - } + return new RRDFile(binary); }, this) .addErrback( function(ret) { @@ -188,34 +177,31 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.wait(); }, - test_getDataSimple: function () { + test_getData: function () { /** * The generated rrd file should have values 0-9 at 1s intervals - * starting at 1980-01-01 00:00:00 + * starting at 1980-01-01 00:00:01 + * Result should include a data points with times > starttime and + * <= endTime **/ this.d.addCallback( function(self, rrd) { self.resume(function() { - var rra = rrd.getRRA(0) - console.log(rra.getEl(0, 0)); - - - var firstUpdate = new Date('1 jan 1980 00:00:00').getTime(); - var lastUpdate = firstUpdate + 10*1000; - Y.Assert.areEqual( - lastUpdate/1000, rrd.getLastUpdate()); + var startTime = new Date('1 jan 1980 00:00:00').getTime(); + var endTime = new Date('1 jan 1980 00:00:10').getTime(); - - /* var q = new jarmon.RrdQuery(rrd, ''); - var data = q.getData(firstUpdate, lastUpdate); + var data = q.getData(startTime, endTime); + Y.Assert.areEqual( + 10, data.data.length); Y.Assert.areEqual( - firstUpdate+1000, data.data[0][0]); - */ + startTime+1000, data.data[0][0]); + Y.Assert.areEqual( + endTime, data.data[9][0]); }); }, this); this.wait(); - }, + } })); -- cgit v1.1-4-g5e80 From 4b7ed618664c5404c390f8e6ef8c106189eaf44c Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Mon, 30 Aug 2010 13:16:19 +0100 Subject: more realistic rrd step sizes and data --- jarmon/jarmon.test.js | 53 ++++++++++++++++++++++++++----------------------- jarmonbuild/commands.py | 21 ++++++++++++++------ 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 6360685..09fec1a 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -44,6 +44,12 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { })); + var RRD_STEP = 10; + var RRD_DSNAME = 'speed'; + var RRD_DSINDEX = 0; + var RRD_RRAROWS = 6; + var RRD_STARTTIME = new Date('1 jan 1980 00:00:00').getTime(); + var RRD_ENDTIME = new Date('1 jan 1980 00:01:01').getTime(); Y.Test.Runner.add(new Y.Test.Case({ name: "javascriptrrd.RRDFile", @@ -63,14 +69,13 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { test_getLastUpdate: function () { /** * The generated rrd file should have a lastupdate date of - * 1980-01-01 00:00:10 + * 1980-01-01 00:50:01 **/ this.d.addCallback( function(self, rrd) { self.resume(function() { - var lastUpdate = new Date('1 jan 1980 00:00:10').getTime(); Y.Assert.areEqual( - lastUpdate/1000, rrd.getLastUpdate()); + RRD_ENDTIME/1000, rrd.getLastUpdate()); }); }, this); this.wait(); @@ -85,11 +90,12 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.d.addCallback( function(self, rrd) { self.resume(function() { - Y.Assert.areEqual('speed', rrd.getDS(0).getName()); - Y.Assert.areEqual(0, rrd.getDS('speed').getIdx()); + Y.Assert.areEqual(RRD_DSNAME, rrd.getDS(0).getName()); + Y.Assert.areEqual( + RRD_DSINDEX, rrd.getDS('speed').getIdx()); var error = null; try { - rrd.getDS(1); + rrd.getDS(RRD_DSINDEX+1); } catch(e) { error = e; } @@ -115,7 +121,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { test_getRRA: function () { /** * The generated rrd file should have a single RRA using AVERAGE - * consolidation, step=1, rows=10 and values 0-9 + * consolidation, step=10, rows=6 and values 0-5 * rra.getEl throws a RangeError if asked for row which doesn't * exist. **/ @@ -124,10 +130,10 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { self.resume(function() { var rra = rrd.getRRA(0); Y.Assert.areEqual('AVERAGE', rra.getCFName()); - Y.Assert.areEqual(1, rra.getStep()); - Y.Assert.areEqual(10, rra.getNrRows()); - for(var i=0; i<10; i++) { - Y.Assert.areEqual(i, rra.getEl(i, 0)); + Y.Assert.areEqual(RRD_STEP, rra.getStep()); + Y.Assert.areEqual(RRD_RRAROWS, rra.getNrRows()); + for(var i=0; i starttime and * <= endTime **/ this.d.addCallback( function(self, rrd) { self.resume(function() { - var startTime = new Date('1 jan 1980 00:00:00').getTime(); - var endTime = new Date('1 jan 1980 00:00:10').getTime(); - - var q = new jarmon.RrdQuery(rrd, ''); - var data = q.getData(startTime, endTime); - Y.Assert.areEqual( - 10, data.data.length); - Y.Assert.areEqual( - startTime+1000, data.data[0][0]); - Y.Assert.areEqual( - endTime, data.data[9][0]); + var rq = new jarmon.RrdQuery(rrd, ''); + var data = rq.getData(RRD_STARTTIME, RRD_ENDTIME); + console.log(data.data); + Y.Assert.areEqual(RRD_RRAROWS, data.data.length); + Y.Assert.areEqual(2, data.data[2][1]); + Y.Assert.areEqual(RRD_STARTTIME+RRD_STEP*1000, data.data[0][0]); + //Y.Assert.areEqual( + // RRD_ENDTIME, data.data[RRD_RRAROWS-1][0]); }); }, this); this.wait(); - } + }, })); diff --git a/jarmonbuild/commands.py b/jarmonbuild/commands.py index 48e679b..5823042 100644 --- a/jarmonbuild/commands.py +++ b/jarmonbuild/commands.py @@ -10,6 +10,7 @@ import shutil import sys import time +from datetime import datetime from optparse import OptionParser from subprocess import check_call, PIPE from tempfile import gettempdir @@ -229,18 +230,26 @@ class BuildTestDataCommand(BuildCommand): rras = [] filename = os.path.join(self.build_dir, 'test.rrd') - rows = 10 + rows = 6 + step = 10 - dss.append(DataSource(dsName='speed', dsType='GAUGE', heartbeat=1)) + dss.append(DataSource(dsName='speed', dsType='GAUGE', heartbeat=2*step)) rras.append(RRA(cf='AVERAGE', xff=0.5, steps=1, rows=rows)) - my_rrd = RRD(filename, ds=dss, rra=rras, start=start, step=1) + my_rrd = RRD(filename, ds=dss, rra=rras, start=start, step=step) my_rrd.create() - for i, t in enumerate(range(start, start+rows, 1)): - my_rrd.bufferValue(t+1, i) + for i, t in enumerate(range(start+step, start+step+(rows*step), step)): + self.log.debug('DATA: %s %s (%s)' % (t, i, datetime.fromtimestamp(t))) + my_rrd.bufferValue(t, i) - my_rrd.update() + # Add further data 1 second later to demonstrate that the rrd + # lastupdatetime does not necessarily fall on a step boundary + t += 1 + i += 1 + self.log.debug('DATA: %s %s (%s)' % (t, i, datetime.fromtimestamp(t))) + my_rrd.bufferValue(t, i) + my_rrd.update() # The available subcommands -- cgit v1.1-4-g5e80 From 337882182bd0ab3e7a147159245a8d1331fbfbf0 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Mon, 30 Aug 2010 15:22:25 +0100 Subject: Add another RRA to demonstrate that jarmon is currently selecting the wrong RRA --- jarmon/jarmon.test.js | 13 +++++++------ jarmonbuild/commands.py | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 09fec1a..0aca865 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -47,9 +47,10 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { var RRD_STEP = 10; var RRD_DSNAME = 'speed'; var RRD_DSINDEX = 0; - var RRD_RRAROWS = 6; + var RRD_RRACOUNT = 2; + var RRD_RRAROWS = 12; var RRD_STARTTIME = new Date('1 jan 1980 00:00:00').getTime(); - var RRD_ENDTIME = new Date('1 jan 1980 00:01:01').getTime(); + var RRD_ENDTIME = new Date('1 jan 1980 00:02:01').getTime(); Y.Test.Runner.add(new Y.Test.Case({ name: "javascriptrrd.RRDFile", @@ -112,7 +113,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.d.addCallback( function(self, rrd) { self.resume(function() { - Y.Assert.areEqual(1, rrd.getNrRRAs()); + Y.Assert.areEqual(RRD_RRACOUNT, rrd.getNrRRAs()); }); }, this); this.wait(); @@ -137,7 +138,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { } var error = null try { - rra.getEl(10, 0); + rra.getEl(RRD_RRAROWS+1, 0); } catch(e) { error = e; } @@ -195,10 +196,10 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { self.resume(function() { var rq = new jarmon.RrdQuery(rrd, ''); var data = rq.getData(RRD_STARTTIME, RRD_ENDTIME); - console.log(data.data); Y.Assert.areEqual(RRD_RRAROWS, data.data.length); Y.Assert.areEqual(2, data.data[2][1]); - Y.Assert.areEqual(RRD_STARTTIME+RRD_STEP*1000, data.data[0][0]); + Y.Assert.areEqual( + RRD_STARTTIME+RRD_STEP*1000, data.data[0][0]); //Y.Assert.areEqual( // RRD_ENDTIME, data.data[RRD_RRAROWS-1][0]); }); diff --git a/jarmonbuild/commands.py b/jarmonbuild/commands.py index 5823042..9ababd9 100644 --- a/jarmonbuild/commands.py +++ b/jarmonbuild/commands.py @@ -230,11 +230,12 @@ class BuildTestDataCommand(BuildCommand): rras = [] filename = os.path.join(self.build_dir, 'test.rrd') - rows = 6 + rows = 12 step = 10 dss.append(DataSource(dsName='speed', dsType='GAUGE', heartbeat=2*step)) rras.append(RRA(cf='AVERAGE', xff=0.5, steps=1, rows=rows)) + rras.append(RRA(cf='AVERAGE', xff=0.5, steps=12, rows=rows)) my_rrd = RRD(filename, ds=dss, rra=rras, start=start, step=step) my_rrd.create() -- cgit v1.1-4-g5e80 From 047d284b792ce7ac2b8e47e8067b142c5f081ee7 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Mon, 30 Aug 2010 22:02:51 +0100 Subject: hopefully more consistent behaviour - more like rrdtool fetch --- jarmon/jarmon.js | 71 ++++++++++++++++++++++++++++++++++++--------------- jarmon/jarmon.test.js | 11 ++++---- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 24f967d..ed26702 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -156,15 +156,15 @@ jarmon.RrdQuery = function(rrd, unit) { this.unit = unit; }; -jarmon.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) { +jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfName) { /** * Generate a Flot compatible data object containing rows between start and * end time. The rows are taken from the first RRA whose data spans the * requested time range. * * @method getData - * @param startTime {Number} start timestamp - * @param endTime {Number} end timestamp + * @param startTimeJs {Number} start timestamp in microseconds + * @param endTimeJs {Number} end timestamp in microseconds * @param dsId {Variant} identifier of the RRD datasource (string or number) * @param cfName {String} The name of an RRD consolidation function (CF) * eg AVERAGE, MIN, MAX @@ -172,22 +172,31 @@ jarmon.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) { * eg label: '', data: [], unit: '' **/ - if (startTime >= endTime) { + if (startTimeJs >= endTimeJs) { throw new jarmon.TimeRangeError( ['starttime must be less than endtime. ', - 'starttime: ', starttime, - 'endtime: ', endtime].join('')); + 'starttime: ', startTimeJs, + 'endtime: ', endTimeJs].join('')); } - var startTimestamp = startTime/1000; - + // The startTime, endTime and lastupdate time are not necessarily on a step + // boundaries. Here we divide, round and then multiply by the step size to + // find the nearest "Primary Data Point" (PDP) time. + var minStep = this.rrd.getMinStep(); + var startTime = Math.round(startTimeJs/1000/minStep) * minStep; var lastUpdated = this.rrd.getLastUpdate(); - var endTimestamp = lastUpdated; - if(endTime) { - endTimestamp = endTime/1000; + var lastPdpTime = Math.round(lastUpdated / minStep) * minStep; + + var endTime = lastPdpTime; + if(endTimeJs) { + endTime = endTimeJs/1000; // If end time stamp is beyond the range of this rrd then reset it - if(lastUpdated < endTimestamp) { - endTimestamp = lastUpdated; + // XXX: Is this the correct behaviour. Perhaps better to throw exception + // or simply return nan for each missing PDP - like rrdtool fetch. + if(lastPdpTime < endTime) { + endTime = lastPdpTime; + } else { + endTime = Math.round(endTime / minStep) * minStep; } } @@ -200,7 +209,7 @@ jarmon.RrdQuery.prototype.getData = function(startTime, endTime, dsId, cfName) { cfName = 'AVERAGE'; } - var rra, step, rraRowCount, firstUpdated; + var rra, step, rraRowCount, firstPdpTime; for(var i=0; i Date: Mon, 30 Aug 2010 23:50:34 +0100 Subject: Properly calculate the index of first result row --- jarmon/jarmon.js | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index ed26702..32e0283 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -190,14 +190,6 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam var endTime = lastPdpTime; if(endTimeJs) { endTime = endTimeJs/1000; - // If end time stamp is beyond the range of this rrd then reset it - // XXX: Is this the correct behaviour. Perhaps better to throw exception - // or simply return nan for each missing PDP - like rrdtool fetch. - if(lastPdpTime < endTime) { - endTime = lastPdpTime; - } else { - endTime = Math.round(endTime / minStep) * minStep; - } } if(dsId == null) { @@ -209,7 +201,7 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam cfName = 'AVERAGE'; } - var rra, step, rraRowCount, firstPdpTime; + var rra, step, rraRowCount, lastRowTime, firstRowTime; for(var i=0; i Date: Thu, 2 Sep 2010 23:52:25 +0100 Subject: Add test for unknown consolidation function error --- jarmon/jarmon.js | 19 +++---------------- jarmon/jarmon.test.js | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 32e0283..3f63b3e 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -127,20 +127,6 @@ jarmon.localTimeFormatter = function (v, axis) { }; -jarmon.TimeRangeError = function(message) { - /** - * Raised when an invalid timerange is encountered. - * - * @class jarmon.TimeRangeError - * @constructor - * @param message {String} A description of the error reason - **/ - this.name = "TimeRangeError"; - this.message = (message || ""); -} -jarmon.TimeRangeError.prototype = Error.prototype; - - /** * A wrapper around an instance of javascriptrrd.RRDFile which provides a * convenient way to query the RRDFile based on time range, RRD data source (DS) @@ -173,7 +159,7 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam **/ if (startTimeJs >= endTimeJs) { - throw new jarmon.TimeRangeError( + throw RangeError( ['starttime must be less than endtime. ', 'starttime: ', startTimeJs, 'endtime: ', endTimeJs].join('')); @@ -182,6 +168,7 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam // The startTime, endTime and lastupdate time are not necessarily on a step // boundaries. Here we divide, round and then multiply by the step size to // find the nearest "Primary Data Point" (PDP) time. + console.log('RRD: ', this.rrd); var minStep = this.rrd.getMinStep(); var startTime = Math.round(startTimeJs/1000/minStep) * minStep; var lastUpdated = this.rrd.getLastUpdate(); @@ -229,7 +216,7 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam // If we got to the end of the loop without ever defining step, it means // that the CF check never succeded. if(!step) { - throw new Error('Unrecognised consolidation function: ' + cfName); + throw TypeError('Unrecognised consolidation function: ' + cfName); } var startRowTime = Math.floor(startTime/step)*step + step; diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 7bffb1b..9e8eaca 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -171,19 +171,42 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { this.d.addCallback( function(self, rrd) { self.resume(function() { - var rq = new jarmon.RrdQuery(self.rrd, ''); + var rq = new jarmon.RrdQuery(rrd, ''); var error = null; try { rq.getData(1, 0); } catch(e) { error = e; } - Y.Assert.isInstanceOf(jarmon.TimeRangeError, error); + Y.Assert.isInstanceOf(RangeError, error); }); }, this); this.wait(); }, + + test_getDataUnknownCfError: function () { + /** + * Error is raised if the rrd file doesn't contain an RRA with the + * requested consolidation function (CF) + **/ + this.d.addCallback( + function(self, rrd) { + self.resume(function() { + var rq = new jarmon.RrdQuery(rrd, ''); + var error = null; + try { + rq.getData(RRD_STARTTIME, RRD_ENDTIME, 0, 'FOO'); + } catch(e) { + error = e; + } + Y.Assert.isInstanceOf(TypeError, error); + }); + }, this); + this.wait(); + }, + + test_getData: function () { /** * The generated rrd file should have values 0-9 at 300s intervals -- cgit v1.1-4-g5e80 From e9b1a0b4728d9e74ae3c6dccbf037e07f36f5fd4 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 3 Oct 2010 20:57:16 +0100 Subject: More complete tests for getData and associated simplification of the getData code. --- jarmon/jarmon.js | 56 ++++++++++++++++++++------------------------------- jarmon/jarmon.test.js | 52 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 3f63b3e..6ac410c 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -165,16 +165,11 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam 'endtime: ', endTimeJs].join('')); } - // The startTime, endTime and lastupdate time are not necessarily on a step - // boundaries. Here we divide, round and then multiply by the step size to - // find the nearest "Primary Data Point" (PDP) time. - console.log('RRD: ', this.rrd); - var minStep = this.rrd.getMinStep(); - var startTime = Math.round(startTimeJs/1000/minStep) * minStep; + var startTime = startTimeJs/1000; var lastUpdated = this.rrd.getLastUpdate(); - var lastPdpTime = Math.round(lastUpdated / minStep) * minStep; - var endTime = lastPdpTime; + // default endTime to the last updated time (quantized to rrd step boundry) + var endTime = lastUpdated - lastUpdated%this.rrd.getMinStep(); if(endTimeJs) { endTime = endTimeJs/1000; } @@ -202,8 +197,7 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam step = rra.getStep(); rraRowCount = rra.getNrRows(); - - lastRowTime = Math.round(lastUpdated/step)*step; + lastRowTime = lastUpdated-lastUpdated%step; firstRowTime = lastRowTime - rraRowCount * step; // We assume that the RRAs are listed in ascending order of time range, @@ -219,36 +213,30 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam throw TypeError('Unrecognised consolidation function: ' + cfName); } - var startRowTime = Math.floor(startTime/step)*step + step; - var endRowTime = Math.floor(endTime/step)*step + step; - var flotData = []; - var timestamp = startRowTime; + var dsIndex = ds.getIdx(); - // Fill in any blank values at the start of the query, before we reach the - // first data in the chosen RRA - while(timestamp<=endRowTime && timestamp Date: Mon, 4 Oct 2010 00:27:06 +0100 Subject: A test case for the Chart class --- jarmon/jarmon.test.js | 35 +++++++++++++++++++++++++++++++++++ test.html | 7 ++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 0ff1840..9ae7531 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -276,6 +276,41 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { })); + Y.Test.Runner.add(new Y.Test.Case({ + name: "jarmon.Chart", + + XsetUp: function() { + this.d = new jarmon.downloadBinary('build/test.rrd') + .addCallback( + function(self, binary) { + return new RRDFile(binary); + }, this) + .addErrback( + function(ret) { + console.log(ret); + }); + }, + + test_draw: function () { + /** + * + **/ + var $tpl = $('
').appendTo($('body')); + var c = new jarmon.Chart($tpl, {xaxis: {mode: "time"}}); + //jarmon.Chart.BASE_OPTIONS + //c.options.xaxis.tzoffset = 0; + c.addData('speed', new jarmon.RrdQueryRemote('build/test.rrd', 'm/s'), true); + var d = c.setTimeRange(RRD_STARTTIME, RRD_ENDTIME); + d.addCallback( + function(self) { + self.resume(function() { + Y.Assert.areEqual(1, 1); + }); + }, this); + this.wait(); + }, + })); + //initialize the console var yconsole = new Y.Console({ diff --git a/test.html b/test.html index 6db4f55..e8508f6 100644 --- a/test.html +++ b/test.html @@ -7,7 +7,12 @@ href="http://developer.yahoo.com/yui/3/assets/yui.css"/> - + -- cgit v1.1-4-g5e80 From 319abdbf06a052180b61bc8f5be5eb272690b4f2 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Mon, 4 Oct 2010 00:54:48 +0100 Subject: Add an error placeholder instead of replacing entire template content with error message - preventing subsequent chart rendering. --- docs/examples/index.html | 1 + jarmon/jarmon.js | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/examples/index.html b/docs/examples/index.html index 9d12389..3debd18 100644 --- a/docs/examples/index.html +++ b/docs/examples/index.html @@ -208,6 +208,7 @@

+
diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 6ac410c..06ec4c8 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -521,6 +521,9 @@ jarmon.Chart.prototype.draw = function() { return MochiKit.Async.gatherResults(results) .addCallback( function(self, data) { + // Clear any previous error messages. + self.template.find('.error').empty().hide(); + var i, label, disabled = []; unit = ''; for(i=0; i').text(self.siPrefix + unit) .css({width: '100px', @@ -556,7 +559,7 @@ jarmon.Chart.prototype.draw = function() { // table is useful as it generates an optimum label element // width which we can copy to the new divs + a little extra // to accomodate the color box - var legend = self.template.find('.graph-legend'); + var legend = self.template.find('.graph-legend').show(); legend.empty(); self.template.find('.legendLabel') .each(function(i, el) { @@ -585,7 +588,10 @@ jarmon.Chart.prototype.draw = function() { }, this) .addErrback( function(self, failure) { - self.template.text('error: ' + failure.message); + self.template.find('.chart').empty().hide(); + self.template.find('.graph-legend').empty().hide(); + self.template.find('.error').text('error: ' + failure.message); + }, this) .addBoth( function(self, res) { -- cgit v1.1-4-g5e80 From b0d9466ca1f987775c75cdf68607a0ae19a772ca Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Mon, 4 Oct 2010 23:59:04 +0100 Subject: add caps on the start and end times in rrd query --- jarmon/jarmon.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/jarmon/jarmon.js b/jarmon/jarmon.js index 06ec4c8..406c4d1 100644 --- a/jarmon/jarmon.js +++ b/jarmon/jarmon.js @@ -216,14 +216,21 @@ jarmon.RrdQuery.prototype.getData = function(startTimeJs, endTimeJs, dsId, cfNam var flotData = []; var dsIndex = ds.getIdx(); - var startRowTime = startTime - startTime%step; - var endRowTime = endTime - endTime%step; - - //console.log('FRT: ', new Date(startRowTime*1000)); - //console.log('ERT: ', new Date(endRowTime*1000)); - //console.log('LRT: ', new Date(lastRowTime*1000)); - //console.log('DIFF: ', (lastRowTime - startRowTime) / step); - //console.log('ROWS: ', rraRowCount); + var startRowTime = Math.max(firstRowTime, startTime - startTime%step); + var endRowTime = Math.min(lastRowTime, endTime - endTime%step); + // If RRD exists, but hasn't been updated then the start time might end up + // being higher than the end time (which is capped at the last row time of + // the chosen RRA, so cap startTime at endTime...if you see what I mean) + startRowTime = Math.min(startRowTime, endRowTime); + + /* + console.log('FRT: ', new Date(firstRowTime*1000)); + console.log('LRT: ', new Date(lastRowTime*1000)); + console.log('SRT: ', new Date(startRowTime*1000)); + console.log('ERT: ', new Date(endRowTime*1000)); + console.log('DIFF: ', (lastRowTime - startRowTime) / step); + console.log('ROWS: ', rraRowCount); + */ var startRowIndex = rraRowCount - (lastRowTime - startRowTime) / step; var endRowIndex = rraRowCount - (lastRowTime - endRowTime) / step; -- cgit v1.1-4-g5e80 From 834649eb48062724a1f66c0c7473fb93f743bf74 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Tue, 5 Oct 2010 00:06:12 +0100 Subject: use jarmon BASE OPTIONS for increased coverage --- jarmon/jarmon.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index 9ae7531..bab708d 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -53,7 +53,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { var RRD_ENDTIME = new Date('1 jan 1980 00:02:00').getTime(); Y.Test.Runner.add(new Y.Test.Case({ - name: "javascriptrrd.RRDFile", + name: "jarmon.RRDFile", setUp: function() { this.d = new jarmon.downloadBinary('build/test.rrd') @@ -296,9 +296,9 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { * **/ var $tpl = $('
').appendTo($('body')); - var c = new jarmon.Chart($tpl, {xaxis: {mode: "time"}}); - //jarmon.Chart.BASE_OPTIONS - //c.options.xaxis.tzoffset = 0; + var c = new jarmon.Chart($tpl, jarmon.Chart.BASE_OPTIONS); + // + c.options.xaxis.tzoffset = 0; c.addData('speed', new jarmon.RrdQueryRemote('build/test.rrd', 'm/s'), true); var d = c.setTimeRange(RRD_STARTTIME, RRD_ENDTIME); d.addCallback( -- cgit v1.1-4-g5e80 From 7bcfbd72d1ded68fdd55a49a0b90e226eb8ceed1 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 28 Nov 2010 14:50:38 +0000 Subject: The beginnings of a test for jarmon.Chart --- jarmon/jarmon.test.js | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/jarmon/jarmon.test.js b/jarmon/jarmon.test.js index bab708d..c838023 100644 --- a/jarmon/jarmon.test.js +++ b/jarmon/jarmon.test.js @@ -279,21 +279,10 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { Y.Test.Runner.add(new Y.Test.Case({ name: "jarmon.Chart", - XsetUp: function() { - this.d = new jarmon.downloadBinary('build/test.rrd') - .addCallback( - function(self, binary) { - return new RRDFile(binary); - }, this) - .addErrback( - function(ret) { - console.log(ret); - }); - }, - test_draw: function () { /** - * + * Test that a rendered chart has the correct dimensions, legend, + * axis, labels etc **/ var $tpl = $('
').appendTo($('body')); var c = new jarmon.Chart($tpl, jarmon.Chart.BASE_OPTIONS); @@ -304,7 +293,7 @@ YUI({ logInclude: { TestRunner: true } }).use('console', 'test', function(Y) { d.addCallback( function(self) { self.resume(function() { - Y.Assert.areEqual(1, 1); + // TODO: write useful tests }); }, this); this.wait(); -- cgit v1.1-4-g5e80 From 02f4700f65df11c5ed286c716e9351daf547e853 Mon Sep 17 00:00:00 2001 From: Richard Wall Date: Sun, 28 Nov 2010 15:30:29 +0000 Subject: document how to run the unit tests --- docs/index.html | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 1d57d49..b5ea14a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,6 +10,7 @@
  • Browser Compatibility
  • API documentation
  • Release process and tools
  • +
  • Running automated tests
  • Browser Compatibility

    Jarmon depends upon the Flot @@ -46,7 +47,7 @@

    This is the default IE compatibility workaround. Jarmon bundles the excanvas library which translates canvas api calls into VML, but this is much slower - than the native canvas support in other browsers. In the absense of + than the native canvas support in other browsers. In the absence of other workarounds, Jarmon will transparently use the excanvas library.
    Chrome Frame @@ -92,3 +93,39 @@ out the source code, then issue the ./bin/build -V 10.8 release command from within the source tree.

    + +

    Running automated tests

    +

    Jarmon includes unit tests which are used to exercise the library + code, to check for compatibility with various platforms and web client + software and to check for regressions as the library evolves.

    +

    The unit tests are designed to be run inside a web browser using the + YUI test harness.

    +
      +
    1. Generate test data by running the following command + ./bin/build testdata from within the source tree. +
    2. Start a web server to serve the test page. Eg + $ nginx -p . -c docs/examples/nginx.conf.example
    3. +
    4. Use a web browser to load + the test page + ( + http://localhost:8080/test.html)
    5. +
    +

    Measure code coverage

    +

    There are number of tools available to measure the + code coverage of + Javascript unit tests.

    +

    One such tool is + JSCoverage. It is very easy to install JSCoverage on a Debian / Ubuntu + system and use it to measure the coverage of the Jarmon unit tests.

    +
      +
    1. sudo aptitude install jscoverage - install + jscoverage.
    2. +
    3. jscoverage-server - run the JSCoverage web server from + the root of the Jarmon source tree.
    4. +
    5. Visit + http://localhost:8080/jscoverage.html?test.html to run the unit + tests through the JSCoverage server. The server will automatically + + instrument the Jarmon code and present a web interface which reports + how much of the code has been exercised.
    6. +
    -- cgit v1.1-4-g5e80