michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {utils: Cu} = Components; michael@0: michael@0: Cu.import("resource://gre/modules/Promise.jsm"); michael@0: Cu.import("resource://gre/modules/Metrics.jsm"); michael@0: Cu.import("resource://services-common/utils.js"); michael@0: michael@0: michael@0: const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000; michael@0: michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_test(function test_days_date_conversion() { michael@0: let toDays = Metrics.dateToDays; michael@0: let toDate = Metrics.daysToDate; michael@0: michael@0: let d = new Date(0); michael@0: do_check_eq(toDays(d), 0); michael@0: michael@0: d = new Date(MILLISECONDS_PER_DAY); michael@0: do_check_eq(toDays(d), 1); michael@0: michael@0: d = new Date(MILLISECONDS_PER_DAY - 1); michael@0: do_check_eq(toDays(d), 0); michael@0: michael@0: d = new Date("1970-12-31T23:59:59.999Z"); michael@0: do_check_eq(toDays(d), 364); michael@0: michael@0: d = new Date("1971-01-01T00:00:00Z"); michael@0: do_check_eq(toDays(d), 365); michael@0: michael@0: d = toDate(0); michael@0: do_check_eq(d.getTime(), 0); michael@0: michael@0: d = toDate(1); michael@0: do_check_eq(d.getTime(), MILLISECONDS_PER_DAY); michael@0: michael@0: d = toDate(365); michael@0: do_check_eq(d.getUTCFullYear(), 1971); michael@0: do_check_eq(d.getUTCMonth(), 0); michael@0: do_check_eq(d.getUTCDate(), 1); michael@0: do_check_eq(d.getUTCHours(), 0); michael@0: do_check_eq(d.getUTCMinutes(), 0); michael@0: do_check_eq(d.getUTCSeconds(), 0); michael@0: do_check_eq(d.getUTCMilliseconds(), 0); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_task(function test_get_sqlite_backend() { michael@0: let backend = yield Metrics.Storage("get_sqlite_backend.sqlite"); michael@0: michael@0: do_check_neq(backend._connection, null); michael@0: michael@0: // Ensure WAL and auto checkpoint are enabled. michael@0: do_check_neq(backend._enabledWALCheckpointPages, null); michael@0: let rows = yield backend._connection.execute("PRAGMA journal_mode"); michael@0: do_check_eq(rows[0].getResultByIndex(0), "wal"); michael@0: rows = yield backend._connection.execute("PRAGMA wal_autocheckpoint"); michael@0: do_check_eq(rows[0].getResultByIndex(0), backend._enabledWALCheckpointPages); michael@0: michael@0: yield backend.close(); michael@0: do_check_null(backend._connection); michael@0: }); michael@0: michael@0: add_task(function test_reconnect() { michael@0: let backend = yield Metrics.Storage("reconnect"); michael@0: yield backend.close(); michael@0: michael@0: let backend2 = yield Metrics.Storage("reconnect"); michael@0: yield backend2.close(); michael@0: }); michael@0: michael@0: add_task(function test_future_schema_errors() { michael@0: let backend = yield Metrics.Storage("future_schema_errors"); michael@0: yield backend._connection.setSchemaVersion(2); michael@0: yield backend.close(); michael@0: michael@0: let backend2; michael@0: let failed = false; michael@0: try { michael@0: backend2 = yield Metrics.Storage("future_schema_errors"); michael@0: } catch (ex) { michael@0: failed = true; michael@0: do_check_true(ex.message.startsWith("Unknown database schema")); michael@0: } michael@0: michael@0: do_check_null(backend2); michael@0: do_check_true(failed); michael@0: }); michael@0: michael@0: add_task(function test_checkpoint_apis() { michael@0: let backend = yield Metrics.Storage("checkpoint_apis"); michael@0: let c = backend._connection; michael@0: let count = c._statementCounter; michael@0: michael@0: yield backend.setAutoCheckpoint(0); michael@0: do_check_eq(c._statementCounter, count + 1); michael@0: michael@0: let rows = yield c.execute("PRAGMA wal_autocheckpoint"); michael@0: do_check_eq(rows[0].getResultByIndex(0), 0); michael@0: count = c._statementCounter; michael@0: michael@0: yield backend.setAutoCheckpoint(1); michael@0: do_check_eq(c._statementCounter, count + 1); michael@0: michael@0: rows = yield c.execute("PRAGMA wal_autocheckpoint"); michael@0: do_check_eq(rows[0].getResultByIndex(0), backend._enabledWALCheckpointPages); michael@0: count = c._statementCounter; michael@0: michael@0: yield backend.checkpoint(); michael@0: do_check_eq(c._statementCounter, count + 1); michael@0: michael@0: yield backend.checkpoint(); michael@0: do_check_eq(c._statementCounter, count + 2); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_measurement_registration() { michael@0: let backend = yield Metrics.Storage("measurement_registration"); michael@0: michael@0: do_check_false(backend.hasProvider("foo")); michael@0: do_check_false(backend.hasMeasurement("foo", "bar", 1)); michael@0: michael@0: let id = yield backend.registerMeasurement("foo", "bar", 1); michael@0: do_check_eq(id, 1); michael@0: michael@0: do_check_true(backend.hasProvider("foo")); michael@0: do_check_true(backend.hasMeasurement("foo", "bar", 1)); michael@0: do_check_eq(backend.measurementID("foo", "bar", 1), id); michael@0: do_check_false(backend.hasMeasurement("foo", "bar", 2)); michael@0: michael@0: let id2 = yield backend.registerMeasurement("foo", "bar", 2); michael@0: do_check_eq(id2, 2); michael@0: do_check_true(backend.hasMeasurement("foo", "bar", 2)); michael@0: do_check_eq(backend.measurementID("foo", "bar", 2), id2); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_field_registration_basic() { michael@0: let backend = yield Metrics.Storage("field_registration_basic"); michael@0: michael@0: do_check_false(backend.hasField("foo", "bar", 1, "baz")); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: do_check_false(backend.hasField("foo", "bar", 1, "baz")); michael@0: do_check_false(backend.hasFieldFromMeasurement(mID, "baz")); michael@0: michael@0: let bazID = yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_COUNTER); michael@0: do_check_true(backend.hasField("foo", "bar", 1, "baz")); michael@0: do_check_true(backend.hasFieldFromMeasurement(mID, "baz")); michael@0: michael@0: let bar2ID = yield backend.registerMeasurement("foo", "bar2", 1); michael@0: michael@0: yield backend.registerField(bar2ID, "baz", michael@0: backend.FIELD_DAILY_DISCRETE_NUMERIC); michael@0: michael@0: do_check_true(backend.hasField("foo", "bar2", 1, "baz")); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: // Ensure changes types of fields results in fatal error. michael@0: add_task(function test_field_registration_changed_type() { michael@0: let backend = yield Metrics.Storage("field_registration_changed_type"); michael@0: michael@0: let mID = yield backend.registerMeasurement("bar", "bar", 1); michael@0: michael@0: let id = yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_COUNTER); michael@0: michael@0: let caught = false; michael@0: try { michael@0: yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_DISCRETE_NUMERIC); michael@0: } catch (ex) { michael@0: caught = true; michael@0: do_check_true(ex.message.startsWith("Field already defined with different type")); michael@0: } michael@0: michael@0: do_check_true(caught); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_field_registration_repopulation() { michael@0: let backend = yield Metrics.Storage("field_registration_repopulation"); michael@0: michael@0: let mID1 = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let mID2 = yield backend.registerMeasurement("foo", "bar", 2); michael@0: let mID3 = yield backend.registerMeasurement("foo", "biz", 1); michael@0: let mID4 = yield backend.registerMeasurement("baz", "foo", 1); michael@0: michael@0: let fID1 = yield backend.registerField(mID1, "foo", backend.FIELD_DAILY_COUNTER); michael@0: let fID2 = yield backend.registerField(mID1, "bar", backend.FIELD_DAILY_DISCRETE_NUMERIC); michael@0: let fID3 = yield backend.registerField(mID4, "foo", backend.FIELD_LAST_TEXT); michael@0: michael@0: yield backend.close(); michael@0: michael@0: backend = yield Metrics.Storage("field_registration_repopulation"); michael@0: michael@0: do_check_true(backend.hasProvider("foo")); michael@0: do_check_true(backend.hasProvider("baz")); michael@0: do_check_true(backend.hasMeasurement("foo", "bar", 1)); michael@0: do_check_eq(backend.measurementID("foo", "bar", 1), mID1); michael@0: do_check_true(backend.hasMeasurement("foo", "bar", 2)); michael@0: do_check_eq(backend.measurementID("foo", "bar", 2), mID2); michael@0: do_check_true(backend.hasMeasurement("foo", "biz", 1)); michael@0: do_check_eq(backend.measurementID("foo", "biz", 1), mID3); michael@0: do_check_true(backend.hasMeasurement("baz", "foo", 1)); michael@0: do_check_eq(backend.measurementID("baz", "foo", 1), mID4); michael@0: michael@0: do_check_true(backend.hasField("foo", "bar", 1, "foo")); michael@0: do_check_eq(backend.fieldID("foo", "bar", 1, "foo"), fID1); michael@0: do_check_true(backend.hasField("foo", "bar", 1, "bar")); michael@0: do_check_eq(backend.fieldID("foo", "bar", 1, "bar"), fID2); michael@0: do_check_true(backend.hasField("baz", "foo", 1, "foo")); michael@0: do_check_eq(backend.fieldID("baz", "foo", 1, "foo"), fID3); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_enqueue_operation_execution_order() { michael@0: let backend = yield Metrics.Storage("enqueue_operation_execution_order"); michael@0: michael@0: let executionCount = 0; michael@0: michael@0: let fns = { michael@0: op1: function () { michael@0: do_check_eq(executionCount, 1); michael@0: }, michael@0: michael@0: op2: function () { michael@0: do_check_eq(executionCount, 2); michael@0: }, michael@0: michael@0: op3: function () { michael@0: do_check_eq(executionCount, 3); michael@0: }, michael@0: }; michael@0: michael@0: function enqueuedOperation(fn) { michael@0: let deferred = Promise.defer(); michael@0: michael@0: CommonUtils.nextTick(function onNextTick() { michael@0: executionCount++; michael@0: fn(); michael@0: deferred.resolve(); michael@0: }); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: let promises = []; michael@0: for (let i = 1; i <= 3; i++) { michael@0: let fn = fns["op" + i]; michael@0: promises.push(backend.enqueueOperation(enqueuedOperation.bind(this, fn))); michael@0: } michael@0: michael@0: for (let promise of promises) { michael@0: yield promise; michael@0: } michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_enqueue_operation_many() { michael@0: let backend = yield Metrics.Storage("enqueue_operation_many"); michael@0: michael@0: let promises = []; michael@0: for (let i = 0; i < 100; i++) { michael@0: promises.push(backend.registerMeasurement("foo", "bar" + i, 1)); michael@0: } michael@0: michael@0: for (let promise of promises) { michael@0: yield promise; michael@0: } michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: // If the operation did not return a promise, everything should still execute. michael@0: add_task(function test_enqueue_operation_no_return_promise() { michael@0: let backend = yield Metrics.Storage("enqueue_operation_no_return_promise"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let fID = yield backend.registerField(mID, "baz", backend.FIELD_DAILY_COUNTER); michael@0: let now = new Date(); michael@0: michael@0: let promises = []; michael@0: for (let i = 0; i < 10; i++) { michael@0: promises.push(backend.enqueueOperation(function op() { michael@0: backend.incrementDailyCounterFromFieldID(fID, now); michael@0: })); michael@0: } michael@0: michael@0: let deferred = Promise.defer(); michael@0: michael@0: let finished = 0; michael@0: for (let promise of promises) { michael@0: promise.then( michael@0: do_throw.bind(this, "Unexpected resolve."), michael@0: function onError() { michael@0: finished++; michael@0: michael@0: if (finished == promises.length) { michael@0: backend.getDailyCounterCountFromFieldID(fID, now).then(function onCount(count) { michael@0: // There should not be a race condition here because storage michael@0: // serializes all statements. So, for the getDailyCounterCount michael@0: // query to finish means that all counter update statements must michael@0: // have completed. michael@0: do_check_eq(count, promises.length); michael@0: deferred.resolve(); michael@0: }); michael@0: } michael@0: } michael@0: ); michael@0: } michael@0: michael@0: yield deferred.promise; michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: // If an operation throws, subsequent operations should still execute. michael@0: add_task(function test_enqueue_operation_throw_exception() { michael@0: let backend = yield Metrics.Storage("enqueue_operation_rejected_promise"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let fID = yield backend.registerField(mID, "baz", backend.FIELD_DAILY_COUNTER); michael@0: let now = new Date(); michael@0: michael@0: let deferred = Promise.defer(); michael@0: backend.enqueueOperation(function bad() { michael@0: throw new Error("I failed."); michael@0: }).then(do_throw, function onError(error) { michael@0: do_check_true(error.message.contains("I failed.")); michael@0: deferred.resolve(); michael@0: }); michael@0: michael@0: let promise = backend.enqueueOperation(function () { michael@0: return backend.incrementDailyCounterFromFieldID(fID, now); michael@0: }); michael@0: michael@0: yield deferred.promise; michael@0: yield promise; michael@0: michael@0: let count = yield backend.getDailyCounterCountFromFieldID(fID, now); michael@0: do_check_eq(count, 1); michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: // If an operation rejects, subsequent operations should still execute. michael@0: add_task(function test_enqueue_operation_reject_promise() { michael@0: let backend = yield Metrics.Storage("enqueue_operation_reject_promise"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let fID = yield backend.registerField(mID, "baz", backend.FIELD_DAILY_COUNTER); michael@0: let now = new Date(); michael@0: michael@0: let deferred = Promise.defer(); michael@0: backend.enqueueOperation(function reject() { michael@0: let d = Promise.defer(); michael@0: michael@0: CommonUtils.nextTick(function nextTick() { michael@0: d.reject("I failed."); michael@0: }); michael@0: michael@0: return d.promise; michael@0: }).then(do_throw, function onError(error) { michael@0: deferred.resolve(); michael@0: }); michael@0: michael@0: let promise = backend.enqueueOperation(function () { michael@0: return backend.incrementDailyCounterFromFieldID(fID, now); michael@0: }); michael@0: michael@0: yield deferred.promise; michael@0: yield promise; michael@0: michael@0: let count = yield backend.getDailyCounterCountFromFieldID(fID, now); michael@0: do_check_eq(count, 1); michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_enqueue_transaction() { michael@0: let backend = yield Metrics.Storage("enqueue_transaction"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let fID = yield backend.registerField(mID, "baz", backend.FIELD_DAILY_COUNTER); michael@0: let now = new Date(); michael@0: michael@0: yield backend.incrementDailyCounterFromFieldID(fID, now); michael@0: michael@0: yield backend.enqueueTransaction(function transaction() { michael@0: yield backend.incrementDailyCounterFromFieldID(fID, now); michael@0: }); michael@0: michael@0: let count = yield backend.getDailyCounterCountFromFieldID(fID, now); michael@0: do_check_eq(count, 2); michael@0: michael@0: let errored = false; michael@0: try { michael@0: yield backend.enqueueTransaction(function aborted() { michael@0: yield backend.incrementDailyCounterFromFieldID(fID, now); michael@0: michael@0: throw new Error("Some error."); michael@0: }); michael@0: } catch (ex) { michael@0: errored = true; michael@0: } finally { michael@0: do_check_true(errored); michael@0: } michael@0: michael@0: count = yield backend.getDailyCounterCountFromFieldID(fID, now); michael@0: do_check_eq(count, 2); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_increment_daily_counter_basic() { michael@0: let backend = yield Metrics.Storage("increment_daily_counter_basic"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: michael@0: let fieldID = yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_COUNTER); michael@0: michael@0: let now = new Date(); michael@0: yield backend.incrementDailyCounterFromFieldID(fieldID, now); michael@0: michael@0: let count = yield backend.getDailyCounterCountFromFieldID(fieldID, now); michael@0: do_check_eq(count, 1); michael@0: michael@0: yield backend.incrementDailyCounterFromFieldID(fieldID, now); michael@0: count = yield backend.getDailyCounterCountFromFieldID(fieldID, now); michael@0: do_check_eq(count, 2); michael@0: michael@0: yield backend.incrementDailyCounterFromFieldID(fieldID, now, 10); michael@0: count = yield backend.getDailyCounterCountFromFieldID(fieldID, now); michael@0: do_check_eq(count, 12); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_increment_daily_counter_multiple_days() { michael@0: let backend = yield Metrics.Storage("increment_daily_counter_multiple_days"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let fieldID = yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_COUNTER); michael@0: michael@0: let days = []; michael@0: let now = Date.now(); michael@0: for (let i = 0; i < 100; i++) { michael@0: days.push(new Date(now - i * MILLISECONDS_PER_DAY)); michael@0: } michael@0: michael@0: for (let day of days) { michael@0: yield backend.incrementDailyCounterFromFieldID(fieldID, day); michael@0: } michael@0: michael@0: let result = yield backend.getDailyCounterCountsFromFieldID(fieldID); michael@0: do_check_eq(result.size, 100); michael@0: for (let day of days) { michael@0: do_check_true(result.hasDay(day)); michael@0: do_check_eq(result.getDay(day), 1); michael@0: } michael@0: michael@0: let fields = yield backend.getMeasurementDailyCountersFromMeasurementID(mID); michael@0: do_check_eq(fields.size, 1); michael@0: do_check_true(fields.has("baz")); michael@0: do_check_eq(fields.get("baz").size, 100); michael@0: michael@0: for (let day of days) { michael@0: do_check_true(fields.get("baz").hasDay(day)); michael@0: do_check_eq(fields.get("baz").getDay(day), 1); michael@0: } michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_last_values() { michael@0: let backend = yield Metrics.Storage("set_last"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let numberID = yield backend.registerField(mID, "number", michael@0: backend.FIELD_LAST_NUMERIC); michael@0: let textID = yield backend.registerField(mID, "text", michael@0: backend.FIELD_LAST_TEXT); michael@0: let now = new Date(); michael@0: let nowDay = new Date(Math.floor(now.getTime() / MILLISECONDS_PER_DAY) * MILLISECONDS_PER_DAY); michael@0: michael@0: yield backend.setLastNumericFromFieldID(numberID, 42, now); michael@0: yield backend.setLastTextFromFieldID(textID, "hello world", now); michael@0: michael@0: let result = yield backend.getLastNumericFromFieldID(numberID); michael@0: do_check_true(Array.isArray(result)); michael@0: do_check_eq(result[0].getTime(), nowDay.getTime()); michael@0: do_check_eq(typeof(result[1]), "number"); michael@0: do_check_eq(result[1], 42); michael@0: michael@0: result = yield backend.getLastTextFromFieldID(textID); michael@0: do_check_true(Array.isArray(result)); michael@0: do_check_eq(result[0].getTime(), nowDay.getTime()); michael@0: do_check_eq(typeof(result[1]), "string"); michael@0: do_check_eq(result[1], "hello world"); michael@0: michael@0: let missingID = yield backend.registerField(mID, "missing", michael@0: backend.FIELD_LAST_NUMERIC); michael@0: do_check_null(yield backend.getLastNumericFromFieldID(missingID)); michael@0: michael@0: let fields = yield backend.getMeasurementLastValuesFromMeasurementID(mID); michael@0: do_check_eq(fields.size, 2); michael@0: do_check_true(fields.has("number")); michael@0: do_check_true(fields.has("text")); michael@0: do_check_eq(fields.get("number")[1], 42); michael@0: do_check_eq(fields.get("text")[1], "hello world"); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_discrete_values_basic() { michael@0: let backend = yield Metrics.Storage("discrete_values_basic"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let numericID = yield backend.registerField(mID, "numeric", michael@0: backend.FIELD_DAILY_DISCRETE_NUMERIC); michael@0: let textID = yield backend.registerField(mID, "text", michael@0: backend.FIELD_DAILY_DISCRETE_TEXT); michael@0: michael@0: let now = new Date(); michael@0: let expectedNumeric = []; michael@0: let expectedText = []; michael@0: for (let i = 0; i < 100; i++) { michael@0: expectedNumeric.push(i); michael@0: expectedText.push("value" + i); michael@0: yield backend.addDailyDiscreteNumericFromFieldID(numericID, i, now); michael@0: yield backend.addDailyDiscreteTextFromFieldID(textID, "value" + i, now); michael@0: } michael@0: michael@0: let values = yield backend.getDailyDiscreteNumericFromFieldID(numericID); michael@0: do_check_eq(values.size, 1); michael@0: do_check_true(values.hasDay(now)); michael@0: do_check_true(Array.isArray(values.getDay(now))); michael@0: do_check_eq(values.getDay(now).length, expectedNumeric.length); michael@0: michael@0: for (let i = 0; i < expectedNumeric.length; i++) { michael@0: do_check_eq(values.getDay(now)[i], expectedNumeric[i]); michael@0: } michael@0: michael@0: values = yield backend.getDailyDiscreteTextFromFieldID(textID); michael@0: do_check_eq(values.size, 1); michael@0: do_check_true(values.hasDay(now)); michael@0: do_check_true(Array.isArray(values.getDay(now))); michael@0: do_check_eq(values.getDay(now).length, expectedText.length); michael@0: michael@0: for (let i = 0; i < expectedText.length; i++) { michael@0: do_check_eq(values.getDay(now)[i], expectedText[i]); michael@0: } michael@0: michael@0: let fields = yield backend.getMeasurementDailyDiscreteValuesFromMeasurementID(mID); michael@0: do_check_eq(fields.size, 2); michael@0: do_check_true(fields.has("numeric")); michael@0: do_check_true(fields.has("text")); michael@0: michael@0: let numeric = fields.get("numeric"); michael@0: let text = fields.get("text"); michael@0: do_check_true(numeric.hasDay(now)); michael@0: do_check_true(text.hasDay(now)); michael@0: do_check_eq(numeric.getDay(now).length, expectedNumeric.length); michael@0: do_check_eq(text.getDay(now).length, expectedText.length); michael@0: michael@0: for (let i = 0; i < expectedNumeric.length; i++) { michael@0: do_check_eq(numeric.getDay(now)[i], expectedNumeric[i]); michael@0: } michael@0: michael@0: for (let i = 0; i < expectedText.length; i++) { michael@0: do_check_eq(text.getDay(now)[i], expectedText[i]); michael@0: } michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_discrete_values_multiple_days() { michael@0: let backend = yield Metrics.Storage("discrete_values_multiple_days"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let id = yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_DISCRETE_NUMERIC); michael@0: michael@0: let now = new Date(); michael@0: let dates = []; michael@0: for (let i = 0; i < 50; i++) { michael@0: let date = new Date(now.getTime() + i * MILLISECONDS_PER_DAY); michael@0: dates.push(date); michael@0: michael@0: yield backend.addDailyDiscreteNumericFromFieldID(id, i, date); michael@0: } michael@0: michael@0: let values = yield backend.getDailyDiscreteNumericFromFieldID(id); michael@0: do_check_eq(values.size, 50); michael@0: michael@0: let i = 0; michael@0: for (let date of dates) { michael@0: do_check_true(values.hasDay(date)); michael@0: do_check_eq(values.getDay(date)[0], i); michael@0: i++; michael@0: } michael@0: michael@0: let fields = yield backend.getMeasurementDailyDiscreteValuesFromMeasurementID(mID); michael@0: do_check_eq(fields.size, 1); michael@0: do_check_true(fields.has("baz")); michael@0: let baz = fields.get("baz"); michael@0: do_check_eq(baz.size, 50); michael@0: i = 0; michael@0: for (let date of dates) { michael@0: do_check_true(baz.hasDay(date)); michael@0: do_check_eq(baz.getDay(date).length, 1); michael@0: do_check_eq(baz.getDay(date)[0], i); michael@0: i++; michael@0: } michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_daily_last_values() { michael@0: let backend = yield Metrics.Storage("daily_last_values"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let numericID = yield backend.registerField(mID, "numeric", michael@0: backend.FIELD_DAILY_LAST_NUMERIC); michael@0: let textID = yield backend.registerField(mID, "text", michael@0: backend.FIELD_DAILY_LAST_TEXT); michael@0: michael@0: let now = new Date(); michael@0: let yesterday = new Date(now.getTime() - MILLISECONDS_PER_DAY); michael@0: let dayBefore = new Date(yesterday.getTime() - MILLISECONDS_PER_DAY); michael@0: michael@0: yield backend.setDailyLastNumericFromFieldID(numericID, 1, yesterday); michael@0: yield backend.setDailyLastNumericFromFieldID(numericID, 2, now); michael@0: yield backend.setDailyLastNumericFromFieldID(numericID, 3, dayBefore); michael@0: yield backend.setDailyLastTextFromFieldID(textID, "foo", now); michael@0: yield backend.setDailyLastTextFromFieldID(textID, "bar", yesterday); michael@0: yield backend.setDailyLastTextFromFieldID(textID, "baz", dayBefore); michael@0: michael@0: let days = yield backend.getDailyLastNumericFromFieldID(numericID); michael@0: do_check_eq(days.size, 3); michael@0: do_check_eq(days.getDay(yesterday), 1); michael@0: do_check_eq(days.getDay(now), 2); michael@0: do_check_eq(days.getDay(dayBefore), 3); michael@0: michael@0: days = yield backend.getDailyLastTextFromFieldID(textID); michael@0: do_check_eq(days.size, 3); michael@0: do_check_eq(days.getDay(now), "foo"); michael@0: do_check_eq(days.getDay(yesterday), "bar"); michael@0: do_check_eq(days.getDay(dayBefore), "baz"); michael@0: michael@0: yield backend.setDailyLastNumericFromFieldID(numericID, 4, yesterday); michael@0: days = yield backend.getDailyLastNumericFromFieldID(numericID); michael@0: do_check_eq(days.getDay(yesterday), 4); michael@0: michael@0: yield backend.setDailyLastTextFromFieldID(textID, "biz", yesterday); michael@0: days = yield backend.getDailyLastTextFromFieldID(textID); michael@0: do_check_eq(days.getDay(yesterday), "biz"); michael@0: michael@0: days = yield backend.getDailyLastNumericFromFieldID(numericID, yesterday); michael@0: do_check_eq(days.size, 1); michael@0: do_check_eq(days.getDay(yesterday), 4); michael@0: michael@0: days = yield backend.getDailyLastTextFromFieldID(textID, yesterday); michael@0: do_check_eq(days.size, 1); michael@0: do_check_eq(days.getDay(yesterday), "biz"); michael@0: michael@0: let fields = yield backend.getMeasurementDailyLastValuesFromMeasurementID(mID); michael@0: do_check_eq(fields.size, 2); michael@0: do_check_true(fields.has("numeric")); michael@0: do_check_true(fields.has("text")); michael@0: let numeric = fields.get("numeric"); michael@0: let text = fields.get("text"); michael@0: do_check_true(numeric.hasDay(yesterday)); michael@0: do_check_true(numeric.hasDay(dayBefore)); michael@0: do_check_true(numeric.hasDay(now)); michael@0: do_check_true(text.hasDay(yesterday)); michael@0: do_check_true(text.hasDay(dayBefore)); michael@0: do_check_true(text.hasDay(now)); michael@0: do_check_eq(numeric.getDay(yesterday), 4); michael@0: do_check_eq(text.getDay(yesterday), "biz"); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_prune_data_before() { michael@0: let backend = yield Metrics.Storage("prune_data_before"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: michael@0: let counterID = yield backend.registerField(mID, "baz", michael@0: backend.FIELD_DAILY_COUNTER); michael@0: let text1ID = yield backend.registerField(mID, "one_text_1", michael@0: backend.FIELD_LAST_TEXT); michael@0: let text2ID = yield backend.registerField(mID, "one_text_2", michael@0: backend.FIELD_LAST_TEXT); michael@0: let numeric1ID = yield backend.registerField(mID, "one_numeric_1", michael@0: backend.FIELD_LAST_NUMERIC); michael@0: let numeric2ID = yield backend.registerField(mID, "one_numeric_2", michael@0: backend.FIELD_LAST_NUMERIC); michael@0: let text3ID = yield backend.registerField(mID, "daily_last_text_1", michael@0: backend.FIELD_DAILY_LAST_TEXT); michael@0: let text4ID = yield backend.registerField(mID, "daily_last_text_2", michael@0: backend.FIELD_DAILY_LAST_TEXT); michael@0: let numeric3ID = yield backend.registerField(mID, "daily_last_numeric_1", michael@0: backend.FIELD_DAILY_LAST_NUMERIC); michael@0: let numeric4ID = yield backend.registerField(mID, "daily_last_numeric_2", michael@0: backend.FIELD_DAILY_LAST_NUMERIC); michael@0: michael@0: let now = new Date(); michael@0: let yesterday = new Date(now.getTime() - MILLISECONDS_PER_DAY); michael@0: let dayBefore = new Date(yesterday.getTime() - MILLISECONDS_PER_DAY); michael@0: michael@0: yield backend.incrementDailyCounterFromFieldID(counterID, now); michael@0: yield backend.incrementDailyCounterFromFieldID(counterID, yesterday); michael@0: yield backend.incrementDailyCounterFromFieldID(counterID, dayBefore); michael@0: yield backend.setLastTextFromFieldID(text1ID, "hello", dayBefore); michael@0: yield backend.setLastTextFromFieldID(text2ID, "world", yesterday); michael@0: yield backend.setLastNumericFromFieldID(numeric1ID, 42, dayBefore); michael@0: yield backend.setLastNumericFromFieldID(numeric2ID, 43, yesterday); michael@0: yield backend.setDailyLastTextFromFieldID(text3ID, "foo", dayBefore); michael@0: yield backend.setDailyLastTextFromFieldID(text3ID, "bar", yesterday); michael@0: yield backend.setDailyLastTextFromFieldID(text4ID, "hello", dayBefore); michael@0: yield backend.setDailyLastTextFromFieldID(text4ID, "world", yesterday); michael@0: yield backend.setDailyLastNumericFromFieldID(numeric3ID, 40, dayBefore); michael@0: yield backend.setDailyLastNumericFromFieldID(numeric3ID, 41, yesterday); michael@0: yield backend.setDailyLastNumericFromFieldID(numeric4ID, 42, dayBefore); michael@0: yield backend.setDailyLastNumericFromFieldID(numeric4ID, 43, yesterday); michael@0: michael@0: let days = yield backend.getDailyCounterCountsFromFieldID(counterID); michael@0: do_check_eq(days.size, 3); michael@0: michael@0: yield backend.pruneDataBefore(yesterday); michael@0: days = yield backend.getDailyCounterCountsFromFieldID(counterID); michael@0: do_check_eq(days.size, 2); michael@0: do_check_false(days.hasDay(dayBefore)); michael@0: michael@0: do_check_null(yield backend.getLastTextFromFieldID(text1ID)); michael@0: do_check_null(yield backend.getLastNumericFromFieldID(numeric1ID)); michael@0: michael@0: let result = yield backend.getLastTextFromFieldID(text2ID); michael@0: do_check_true(Array.isArray(result)); michael@0: do_check_eq(result[1], "world"); michael@0: michael@0: result = yield backend.getLastNumericFromFieldID(numeric2ID); michael@0: do_check_true(Array.isArray(result)); michael@0: do_check_eq(result[1], 43); michael@0: michael@0: result = yield backend.getDailyLastNumericFromFieldID(numeric3ID); michael@0: do_check_eq(result.size, 1); michael@0: do_check_true(result.hasDay(yesterday)); michael@0: michael@0: result = yield backend.getDailyLastTextFromFieldID(text3ID); michael@0: do_check_eq(result.size, 1); michael@0: do_check_true(result.hasDay(yesterday)); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_provider_state() { michael@0: let backend = yield Metrics.Storage("provider_state"); michael@0: michael@0: yield backend.registerMeasurement("foo", "bar", 1); michael@0: yield backend.setProviderState("foo", "apple", "orange"); michael@0: let value = yield backend.getProviderState("foo", "apple"); michael@0: do_check_eq(value, "orange"); michael@0: michael@0: yield backend.setProviderState("foo", "apple", "pear"); michael@0: value = yield backend.getProviderState("foo", "apple"); michael@0: do_check_eq(value, "pear"); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: michael@0: add_task(function test_get_measurement_values() { michael@0: let backend = yield Metrics.Storage("get_measurement_values"); michael@0: michael@0: let mID = yield backend.registerMeasurement("foo", "bar", 1); michael@0: let id1 = yield backend.registerField(mID, "id1", backend.FIELD_DAILY_COUNTER); michael@0: let id2 = yield backend.registerField(mID, "id2", backend.FIELD_DAILY_DISCRETE_NUMERIC); michael@0: let id3 = yield backend.registerField(mID, "id3", backend.FIELD_DAILY_DISCRETE_TEXT); michael@0: let id4 = yield backend.registerField(mID, "id4", backend.FIELD_DAILY_LAST_NUMERIC); michael@0: let id5 = yield backend.registerField(mID, "id5", backend.FIELD_DAILY_LAST_TEXT); michael@0: let id6 = yield backend.registerField(mID, "id6", backend.FIELD_LAST_NUMERIC); michael@0: let id7 = yield backend.registerField(mID, "id7", backend.FIELD_LAST_TEXT); michael@0: michael@0: let now = new Date(); michael@0: let yesterday = new Date(now.getTime() - MILLISECONDS_PER_DAY); michael@0: michael@0: yield backend.incrementDailyCounterFromFieldID(id1, now); michael@0: yield backend.addDailyDiscreteNumericFromFieldID(id2, 3, now); michael@0: yield backend.addDailyDiscreteNumericFromFieldID(id2, 4, now); michael@0: yield backend.addDailyDiscreteNumericFromFieldID(id2, 5, yesterday); michael@0: yield backend.addDailyDiscreteNumericFromFieldID(id2, 6, yesterday); michael@0: yield backend.addDailyDiscreteTextFromFieldID(id3, "1", now); michael@0: yield backend.addDailyDiscreteTextFromFieldID(id3, "2", now); michael@0: yield backend.addDailyDiscreteTextFromFieldID(id3, "3", yesterday); michael@0: yield backend.addDailyDiscreteTextFromFieldID(id3, "4", yesterday); michael@0: yield backend.setDailyLastNumericFromFieldID(id4, 1, now); michael@0: yield backend.setDailyLastNumericFromFieldID(id4, 2, yesterday); michael@0: yield backend.setDailyLastTextFromFieldID(id5, "foo", now); michael@0: yield backend.setDailyLastTextFromFieldID(id5, "bar", yesterday); michael@0: yield backend.setLastNumericFromFieldID(id6, 42, now); michael@0: yield backend.setLastTextFromFieldID(id7, "foo", now); michael@0: michael@0: let fields = yield backend.getMeasurementValues(mID); michael@0: do_check_eq(Object.keys(fields).length, 2); michael@0: do_check_true("days" in fields); michael@0: do_check_true("singular" in fields); michael@0: do_check_eq(fields.days.size, 2); michael@0: do_check_true(fields.days.hasDay(now)); michael@0: do_check_true(fields.days.hasDay(yesterday)); michael@0: do_check_eq(fields.days.getDay(now).size, 5); michael@0: do_check_eq(fields.days.getDay(yesterday).size, 4); michael@0: do_check_eq(fields.days.getDay(now).get("id3")[0], 1); michael@0: do_check_eq(fields.days.getDay(yesterday).get("id4"), 2); michael@0: do_check_eq(fields.singular.size, 2); michael@0: do_check_eq(fields.singular.get("id6")[1], 42); michael@0: do_check_eq(fields.singular.get("id7")[1], "foo"); michael@0: michael@0: yield backend.close(); michael@0: }); michael@0: