зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1698184 - Test runtime registration of FOG metrics r=janerik
Adds a test-only method to JS that permits the runtime registration of metrics. Also uses that to cover JOG with tests: registering and smoke-testing metrics of each metric type. (Events being a notable (temporary) exception) Instead of writing parsers, use serde_json for the optional extra metric args. Differential Revision: https://phabricator.services.mozilla.com/D143051
This commit is contained in:
Родитель
5de7c2d4c9
Коммит
557f0cf57b
|
@ -2764,8 +2764,13 @@ name = "jog"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fog",
|
||||
"log",
|
||||
"mozbuild",
|
||||
"nsstring",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -7,5 +7,13 @@ publish = false
|
|||
|
||||
[dependencies]
|
||||
fog = { path = "../../api" }
|
||||
once_cell = "1.2.0"
|
||||
log = "0.4"
|
||||
mozbuild = "0.1"
|
||||
nsstring = { path = "../../../../../xpcom/rust/nsstring", optional = true }
|
||||
once_cell = "1.2.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }
|
||||
|
||||
[features]
|
||||
with_gecko = [ "nsstring" ]
|
||||
|
|
|
@ -14,10 +14,10 @@ line_length = 100
|
|||
tab_width = 2
|
||||
language = "C++"
|
||||
namespaces = ["mozilla::glean::jog"]
|
||||
#includes = ["nsTArray.h", "nsString.h"]
|
||||
includes = ["nsTArray.h", "nsString.h"]
|
||||
|
||||
[export.rename]
|
||||
#"ThinVec" = "nsTArray"
|
||||
"ThinVec" = "nsTArray"
|
||||
#"nsCStringRepr" = "nsCString"
|
||||
|
||||
[parse]
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use fog::factory;
|
||||
use fog::private::Lifetime;
|
||||
use fog::private::traits::HistogramType;
|
||||
use fog::private::{CommonMetricData, MemoryUnit, TimeUnit};
|
||||
#[cfg(feature = "with_gecko")]
|
||||
use nsstring::{nsACString, nsCString};
|
||||
use serde::Deserialize;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// Activate the JOG runtime registrar.
|
||||
/// This is where the Artefact Build support happens.
|
||||
|
@ -11,39 +16,86 @@ use fog::private::Lifetime;
|
|||
/// returns whether it successfully found and processed metrics files.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn jog_runtime_registrar() -> bool {
|
||||
let _ = factory::create_and_register_metric(
|
||||
"counter",
|
||||
"category".into(),
|
||||
"name".into(),
|
||||
vec!["store1".into()],
|
||||
Lifetime::Ping,
|
||||
true,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
false
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
struct ExtraMetricArgs {
|
||||
time_unit: Option<TimeUnit>,
|
||||
memory_unit: Option<MemoryUnit>,
|
||||
allowed_extra_keys: Option<Vec<String>>,
|
||||
range_min: Option<u64>,
|
||||
range_max: Option<u64>,
|
||||
bucket_count: Option<u64>,
|
||||
histogram_type: Option<HistogramType>,
|
||||
numerators: Option<Vec<CommonMetricData>>,
|
||||
labels: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Test-only method.
|
||||
///
|
||||
/// Registers a metric.
|
||||
/// Doesn't check to see if it's been registered before.
|
||||
/// Doesn't check that it would pass schema validation if it were a real metric.
|
||||
///
|
||||
/// `extra_args` is a JSON-encoded string in a form that serde can read into an ExtraMetricArgs.
|
||||
///
|
||||
/// No effort has been made to make this pleasant to use, since it's for
|
||||
/// internal testing only (ie, the testing of JOG itself).
|
||||
#[cfg(feature = "with_gecko")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn jog_test_register_metric() {
|
||||
// What information do we need for registration?
|
||||
// Pretty much everything in CommonMetricData except `disabled` which we presume is `false`, so
|
||||
// name, category, send_in_pings, lifetime
|
||||
pub extern "C" fn jog_test_register_metric(
|
||||
metric_type: &nsACString,
|
||||
category: &nsACString,
|
||||
name: &nsACString,
|
||||
send_in_pings: &ThinVec<nsCString>,
|
||||
lifetime: &nsACString,
|
||||
disabled: bool,
|
||||
extra_args: &nsACString,
|
||||
) -> u32 {
|
||||
log::warn!("Type: {:?}, Category: {:?}, Name: {:?}, SendInPings: {:?}, Lifetime: {:?}, Disabled: {}, ExtraArgs: {}",
|
||||
metric_type, category, name, send_in_pings, lifetime, disabled, extra_args);
|
||||
let ns_category = category;
|
||||
let ns_name = name;
|
||||
let metric_type = &metric_type.to_utf8();
|
||||
let category = category.to_string();
|
||||
let name = name.to_string();
|
||||
let send_in_pings = send_in_pings.iter().map(|ping| ping.to_string()).collect();
|
||||
let lifetime = serde_json::from_str(&lifetime.to_utf8())
|
||||
.expect("Lifetime didn't deserialize happily. Is it valid JSON?");
|
||||
|
||||
// Then we need everything else we might need (cf glean_parser.util.extra_metric_args:
|
||||
// time_unit, memory_unit, allowed_extra_keys, reason_codes, range_min, range_max, bucket_count, histogram_type, numerators
|
||||
let extra_args: ExtraMetricArgs = if extra_args.is_empty() {
|
||||
Default::default()
|
||||
} else {
|
||||
serde_json::from_str(&extra_args.to_utf8())
|
||||
.expect("Extras didn't deserialize happily. Are they valid JSON?")
|
||||
};
|
||||
let metric = factory::create_and_register_metric(
|
||||
metric_type,
|
||||
category,
|
||||
name,
|
||||
send_in_pings,
|
||||
lifetime,
|
||||
disabled,
|
||||
extra_args.time_unit,
|
||||
extra_args.memory_unit,
|
||||
extra_args.allowed_extra_keys,
|
||||
extra_args.range_min,
|
||||
extra_args.range_max,
|
||||
extra_args.bucket_count,
|
||||
extra_args.histogram_type,
|
||||
extra_args.numerators,
|
||||
extra_args.labels,
|
||||
);
|
||||
extern "C" {
|
||||
fn JOG_RegisterMetric(category: &nsACString, name: &nsACString, metric: u32);
|
||||
}
|
||||
let metric = metric.unwrap();
|
||||
// Safety: We're loaning to C++ the same nsCStrings they leant us.
|
||||
unsafe {
|
||||
JOG_RegisterMetric(ns_category, ns_name, metric);
|
||||
}
|
||||
metric
|
||||
}
|
||||
|
||||
/// Test-only method.
|
||||
|
|
|
@ -0,0 +1,653 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
function sleep(ms) {
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
add_task(
|
||||
/* on Android FOG is set up through head.js */
|
||||
{ skip_if: () => AppConstants.platform == "android" },
|
||||
function test_setup() {
|
||||
// FOG needs a profile directory to put its data in.
|
||||
do_get_profile();
|
||||
|
||||
// We need to initialize it once, otherwise operations will be stuck in the pre-init queue.
|
||||
Services.fog.initializeFOG();
|
||||
}
|
||||
);
|
||||
|
||||
add_task(function test_jog_counter_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"counter",
|
||||
"jog_cat",
|
||||
"jog_counter",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCat.jogCounter.add(53);
|
||||
Assert.equal(53, Glean.jogCat.jogCounter.testGetValue());
|
||||
});
|
||||
|
||||
add_task(async function test_jog_string_works() {
|
||||
const value = "an active string!";
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"string",
|
||||
"jog_cat",
|
||||
"jog_string",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCat.jogString.set(value);
|
||||
|
||||
Assert.equal(value, Glean.jogCat.jogString.testGetValue());
|
||||
});
|
||||
|
||||
add_task(async function test_jog_string_list_works() {
|
||||
const value = "an active string!";
|
||||
const value2 = "a more active string!";
|
||||
const value3 = "the most active of strings.";
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"string_list",
|
||||
"jog_cat",
|
||||
"jog_string_list",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
|
||||
const jogList = [value, value2];
|
||||
Glean.jogCat.jogStringList.set(jogList);
|
||||
|
||||
let val = Glean.jogCat.jogStringList.testGetValue();
|
||||
// Note: This is incredibly fragile and will break if we ever rearrange items
|
||||
// in the string list.
|
||||
Assert.deepEqual(jogList, val);
|
||||
|
||||
Glean.jogCat.jogStringList.add(value3);
|
||||
Assert.ok(Glean.jogCat.jogStringList.testGetValue().includes(value3));
|
||||
});
|
||||
|
||||
add_task(async function test_jog_timespan_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"timespan",
|
||||
"jog_cat",
|
||||
"jog_timespan",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ time_unit: "millisecond" })
|
||||
);
|
||||
Glean.jogCat.jogTimespan.start();
|
||||
Glean.jogCat.jogTimespan.cancel();
|
||||
Assert.equal(undefined, Glean.jogCat.jogTimespan.testGetValue());
|
||||
|
||||
// We start, briefly sleep and then stop.
|
||||
// That guarantees some time to measure.
|
||||
Glean.jogCat.jogTimespan.start();
|
||||
await sleep(10);
|
||||
Glean.jogCat.jogTimespan.stop();
|
||||
|
||||
Assert.ok(Glean.jogCat.jogTimespan.testGetValue() > 0);
|
||||
});
|
||||
|
||||
add_task(async function test_jog_uuid_works() {
|
||||
const kTestUuid = "decafdec-afde-cafd-ecaf-decafdecafde";
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"uuid",
|
||||
"jog_cat",
|
||||
"jog_uuid",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCat.jogUuid.set(kTestUuid);
|
||||
Assert.equal(kTestUuid, Glean.jogCat.jogUuid.testGetValue());
|
||||
|
||||
Glean.jogCat.jogUuid.generateAndSet();
|
||||
// Since we generate v4 UUIDs, and the first character of the third group
|
||||
// isn't 4, this won't ever collide with kTestUuid.
|
||||
Assert.notEqual(kTestUuid, Glean.jogCat.jogUuid.testGetValue());
|
||||
});
|
||||
|
||||
add_task(function test_jog_datetime_works() {
|
||||
const value = new Date("2020-06-11T12:00:00");
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"datetime",
|
||||
"jog_cat",
|
||||
"jog_datetime",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ time_unit: "nanosecond" })
|
||||
);
|
||||
|
||||
Glean.jogCat.jogDatetime.set(value.getTime() * 1000);
|
||||
|
||||
const received = Glean.jogCat.jogDatetime.testGetValue();
|
||||
Assert.equal(received.getTime(), value.getTime());
|
||||
});
|
||||
|
||||
add_task(function test_jog_boolean_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"boolean",
|
||||
"jog_cat",
|
||||
"jog_bool",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCat.jogBool.set(false);
|
||||
Assert.equal(false, Glean.jogCat.jogBool.testGetValue());
|
||||
});
|
||||
|
||||
add_task(
|
||||
{ skip_if: () => true /* bug XXX */ },
|
||||
async function test_jog_event_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"event",
|
||||
"jog_cat",
|
||||
"jog_event_no_extra",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCat.jogEventNoExtra.record();
|
||||
var events = Glean.testOnlyIpc.noExtraEvent.testGetValue();
|
||||
Assert.equal(1, events.length);
|
||||
Assert.equal("jog_cat", events[0].category);
|
||||
Assert.equal("jog_event_no_extra", events[0].name);
|
||||
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"event",
|
||||
"jog_cat",
|
||||
"jog_event",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ extras: { extra1: "string", extra2: "string" } })
|
||||
);
|
||||
let extra = { extra1: "can set extras", extra2: "passing more data" };
|
||||
Glean.jogCat.jogEvent.record(extra);
|
||||
events = Glean.jogCat.jogEvent.testGetValue();
|
||||
Assert.equal(1, events.length);
|
||||
Assert.equal("jog_cat", events[0].category);
|
||||
Assert.equal("jog_event", events[0].name);
|
||||
Assert.deepEqual(extra, events[0].extra);
|
||||
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"event",
|
||||
"jog_cat",
|
||||
"jog_event_with_extra",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({
|
||||
extras: {
|
||||
extra1: "string",
|
||||
extra2: "quantity",
|
||||
extra3_longer_name: "boolean",
|
||||
},
|
||||
})
|
||||
);
|
||||
let extra2 = {
|
||||
extra1: "can set extras",
|
||||
extra2: 37,
|
||||
extra3_longer_name: false,
|
||||
};
|
||||
Glean.jogCat.jogEventWithExtra.record(extra2);
|
||||
events = Glean.jogCat.jogEventWithExtra.testGetValue();
|
||||
Assert.equal(1, events.length);
|
||||
Assert.equal("jog_cat", events[0].category);
|
||||
Assert.equal("jog_event_with_extra", events[0].name);
|
||||
let expectedExtra = {
|
||||
extra1: "can set extras",
|
||||
extra2: "37",
|
||||
extra3_longer_name: "false",
|
||||
};
|
||||
Assert.deepEqual(expectedExtra, events[0].extra);
|
||||
|
||||
// Invalid extra keys don't crash, the event is not recorded.
|
||||
let extra3 = {
|
||||
extra1_nonexistent_extra: "this does not crash",
|
||||
};
|
||||
Glean.jogCat.jogEventWithExtra.record(extra3);
|
||||
events = Glean.jogCat.jogEventWithExtra.testGetValue();
|
||||
Assert.equal(1, events.length, "Recorded one event too many.");
|
||||
|
||||
// Quantities need to be non-negative.
|
||||
let extra4 = {
|
||||
extra2: -1,
|
||||
};
|
||||
Glean.jogCat.jogEventWithExtra.record(extra4);
|
||||
events = Glean.jogCat.jogEventWithExtra.testGetValue();
|
||||
Assert.equal(1, events.length, "Recorded one event too many.");
|
||||
}
|
||||
);
|
||||
|
||||
add_task(async function test_jog_memory_distribution_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"memory_distribution",
|
||||
"jog_cat",
|
||||
"jog_memory_dist",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ memory_unit: "megabyte" })
|
||||
);
|
||||
Glean.jogCat.jogMemoryDist.accumulate(7);
|
||||
Glean.jogCat.jogMemoryDist.accumulate(17);
|
||||
|
||||
let data = Glean.jogCat.jogMemoryDist.testGetValue();
|
||||
// `data.sum` is in bytes, but the metric is in MB.
|
||||
Assert.equal(24 * 1024 * 1024, data.sum, "Sum's correct");
|
||||
for (let [bucket, count] of Object.entries(data.values)) {
|
||||
Assert.ok(
|
||||
count == 0 || (count == 1 && (bucket == 17520006 || bucket == 7053950)),
|
||||
"Only two buckets have a sample"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_jog_custom_distribution_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"custom_distribution",
|
||||
"jog_cat",
|
||||
"jog_custom_dist",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({
|
||||
range_min: 1,
|
||||
range_max: 2147483646,
|
||||
bucket_count: 10,
|
||||
histogram_type: "linear",
|
||||
})
|
||||
);
|
||||
Glean.jogCat.jogCustomDist.accumulateSamples([7, 268435458]);
|
||||
|
||||
let data = Glean.jogCat.jogCustomDist.testGetValue();
|
||||
Assert.equal(7 + 268435458, data.sum, "Sum's correct");
|
||||
for (let [bucket, count] of Object.entries(data.values)) {
|
||||
Assert.ok(
|
||||
count == 0 || (count == 1 && (bucket == 1 || bucket == 268435456)),
|
||||
`Only two buckets have a sample ${bucket} ${count}`
|
||||
);
|
||||
}
|
||||
|
||||
// Negative values will not be recorded, instead an error is recorded.
|
||||
Glean.jogCat.jogCustomDist.accumulateSamples([-7]);
|
||||
Assert.throws(
|
||||
() => Glean.jogCat.jogCustomDist.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/
|
||||
);
|
||||
});
|
||||
|
||||
add_task(
|
||||
/* TODO(bug 1737520 and XXX): Enable custom ping support in JOG and on Android */
|
||||
{ skip_if: () => true /*|| AppConstants.platform == "android"*/ },
|
||||
function test_jog_custom_pings() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"boolean",
|
||||
"jog_cat",
|
||||
"jog_ping_bool",
|
||||
["jog-ping"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
//Services.fog.testRegisterRuntimePing("jog-ping");
|
||||
Assert.ok("jogPing" in GleanPings);
|
||||
let submitted = false;
|
||||
Glean.jogCat.jogPingBool.set(false);
|
||||
GleanPings.onePingOnly.testBeforeNextSubmit(reason => {
|
||||
submitted = true;
|
||||
Assert.equal(false, Glean.jogCat.jogPingBool.testGetValue());
|
||||
});
|
||||
GleanPings.onePingOnly.submit();
|
||||
Assert.ok(submitted, "Ping was submitted, callback was called.");
|
||||
// ping-lifetime value was cleared.
|
||||
Assert.equal(undefined, Glean.jogCat.jogPingBool.testGetValue());
|
||||
}
|
||||
);
|
||||
|
||||
add_task(async function test_jog_timing_distribution_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"timing_distribution",
|
||||
"jog_cat",
|
||||
"jog_timing_dist",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ time_unit: "microsecond" })
|
||||
);
|
||||
let t1 = Glean.jogCat.jogTimingDist.start();
|
||||
let t2 = Glean.jogCat.jogTimingDist.start();
|
||||
|
||||
await sleep(5);
|
||||
|
||||
let t3 = Glean.jogCat.jogTimingDist.start();
|
||||
Glean.jogCat.jogTimingDist.cancel(t1);
|
||||
|
||||
await sleep(5);
|
||||
|
||||
Glean.jogCat.jogTimingDist.stopAndAccumulate(t2); // 10ms
|
||||
Glean.jogCat.jogTimingDist.stopAndAccumulate(t3); // 5ms
|
||||
|
||||
let data = Glean.jogCat.jogTimingDist.testGetValue();
|
||||
const NANOS_IN_MILLIS = 1e6;
|
||||
// bug 1701949 - Sleep gets close, but sometimes doesn't wait long enough.
|
||||
const EPSILON = 40000;
|
||||
|
||||
// Variance in timing makes getting the sum impossible to know.
|
||||
Assert.greater(data.sum, 15 * NANOS_IN_MILLIS - EPSILON);
|
||||
|
||||
// No guarantees from timers means no guarantees on buckets.
|
||||
// But we can guarantee it's only two samples.
|
||||
Assert.equal(
|
||||
2,
|
||||
Object.entries(data.values).reduce(
|
||||
(acc, [bucket, count]) => acc + count,
|
||||
0
|
||||
),
|
||||
"Only two buckets with samples"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_jog_labeled_boolean_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"labeled_boolean",
|
||||
"jog_cat",
|
||||
"jog_labeled_bool",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledBool.label_1.testGetValue(),
|
||||
"New labels with no values should return undefined"
|
||||
);
|
||||
Glean.jogCat.jogLabeledBool.label_1.set(true);
|
||||
Glean.jogCat.jogLabeledBool.label_2.set(false);
|
||||
Assert.equal(true, Glean.jogCat.jogLabeledBool.label_1.testGetValue());
|
||||
Assert.equal(false, Glean.jogCat.jogLabeledBool.label_2.testGetValue());
|
||||
// What about invalid/__other__?
|
||||
Assert.equal(undefined, Glean.jogCat.jogLabeledBool.__other__.testGetValue());
|
||||
Glean.jogCat.jogLabeledBool.InvalidLabel.set(true);
|
||||
Assert.equal(true, Glean.jogCat.jogLabeledBool.__other__.testGetValue());
|
||||
// TODO: Test that we have the right number and type of errors (bug 1683171)
|
||||
});
|
||||
|
||||
add_task(async function test_jog_labeled_boolean_with_static_labels_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"labeled_boolean",
|
||||
"jog_cat",
|
||||
"jog_labeled_bool_with_labels",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ labels: ["label_1", "label_2"] })
|
||||
);
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.label_1.testGetValue(),
|
||||
"New labels with no values should return undefined"
|
||||
);
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.label_1.set(true);
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.label_2.set(false);
|
||||
Assert.equal(
|
||||
true,
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.label_1.testGetValue()
|
||||
);
|
||||
Assert.equal(
|
||||
false,
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.label_2.testGetValue()
|
||||
);
|
||||
// What about invalid/__other__?
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.__other__.testGetValue()
|
||||
);
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.label_3.set(true);
|
||||
Assert.equal(
|
||||
true,
|
||||
Glean.jogCat.jogLabeledBoolWithLabels.__other__.testGetValue()
|
||||
);
|
||||
// TODO: Test that we have the right number and type of errors (bug 1683171)
|
||||
});
|
||||
|
||||
add_task(async function test_jog_labeled_counter_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"labeled_counter",
|
||||
"jog_cat",
|
||||
"jog_labeled_counter",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledCounter.label_1.testGetValue(),
|
||||
"New labels with no values should return undefined"
|
||||
);
|
||||
Glean.jogCat.jogLabeledCounter.label_1.add(1);
|
||||
Glean.jogCat.jogLabeledCounter.label_2.add(2);
|
||||
Assert.equal(1, Glean.jogCat.jogLabeledCounter.label_1.testGetValue());
|
||||
Assert.equal(2, Glean.jogCat.jogLabeledCounter.label_2.testGetValue());
|
||||
// What about invalid/__other__?
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledCounter.__other__.testGetValue()
|
||||
);
|
||||
Glean.jogCat.jogLabeledCounter.InvalidLabel.add(1);
|
||||
Assert.throws(
|
||||
() => Glean.jogCat.jogLabeledCounter.__other__.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/,
|
||||
"Should throw because of a recording error."
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_jog_labeled_counter_with_static_labels_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"labeled_counter",
|
||||
"jog_cat",
|
||||
"jog_labeled_counter_with_labels",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ labels: ["label_1", "label_2"] })
|
||||
);
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.label_1.testGetValue(),
|
||||
"New labels with no values should return undefined"
|
||||
);
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.label_1.add(1);
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.label_2.add(2);
|
||||
Assert.equal(
|
||||
1,
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.label_1.testGetValue()
|
||||
);
|
||||
Assert.equal(
|
||||
2,
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.label_2.testGetValue()
|
||||
);
|
||||
// What about invalid/__other__?
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.__other__.testGetValue()
|
||||
);
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.InvalidLabel.add(1);
|
||||
// TODO:(bug 1766515) - This should throw.
|
||||
/*Assert.throws(
|
||||
() => Glean.jogCat.jogLabeledCounterWithLabels.__other__.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/,
|
||||
"Should throw because of a recording error."
|
||||
);*/
|
||||
Assert.equal(
|
||||
1,
|
||||
Glean.jogCat.jogLabeledCounterWithLabels.__other__.testGetValue()
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_jog_labeled_string_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"labeled_string",
|
||||
"jog_cat",
|
||||
"jog_labeled_string",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledString.label_1.testGetValue(),
|
||||
"New labels with no values should return undefined"
|
||||
);
|
||||
Glean.jogCat.jogLabeledString.label_1.set("crimson");
|
||||
Glean.jogCat.jogLabeledString.label_2.set("various");
|
||||
Assert.equal("crimson", Glean.jogCat.jogLabeledString.label_1.testGetValue());
|
||||
Assert.equal("various", Glean.jogCat.jogLabeledString.label_2.testGetValue());
|
||||
// What about invalid/__other__?
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledString.__other__.testGetValue()
|
||||
);
|
||||
Glean.jogCat.jogLabeledString.InvalidLabel.set("valid");
|
||||
Assert.throws(
|
||||
() => Glean.jogCat.jogLabeledString.__other__.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_jog_labeled_string_with_labels_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"labeled_string",
|
||||
"jog_cat",
|
||||
"jog_labeled_string_with_labels",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ labels: ["label_1", "label_2"] })
|
||||
);
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledStringWithLabels.label_1.testGetValue(),
|
||||
"New labels with no values should return undefined"
|
||||
);
|
||||
Glean.jogCat.jogLabeledStringWithLabels.label_1.set("crimson");
|
||||
Glean.jogCat.jogLabeledStringWithLabels.label_2.set("various");
|
||||
Assert.equal(
|
||||
"crimson",
|
||||
Glean.jogCat.jogLabeledStringWithLabels.label_1.testGetValue()
|
||||
);
|
||||
Assert.equal(
|
||||
"various",
|
||||
Glean.jogCat.jogLabeledStringWithLabels.label_2.testGetValue()
|
||||
);
|
||||
// What about invalid/__other__?
|
||||
Assert.equal(
|
||||
undefined,
|
||||
Glean.jogCat.jogLabeledStringWithLabels.__other__.testGetValue()
|
||||
);
|
||||
Glean.jogCat.jogLabeledStringWithLabels.InvalidLabel.set("valid");
|
||||
// TODO:(bug 1766515) - This should throw.
|
||||
/*Assert.throws(
|
||||
() => Glean.jogCat.jogLabeledStringWithLabels.__other__.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/
|
||||
);*/
|
||||
Assert.equal(
|
||||
"valid",
|
||||
Glean.jogCat.jogLabeledStringWithLabels.__other__.testGetValue()
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function test_jog_quantity_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"quantity",
|
||||
"jog_cat",
|
||||
"jog_quantity",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCat.jogQuantity.set(42);
|
||||
Assert.equal(42, Glean.jogCat.jogQuantity.testGetValue());
|
||||
});
|
||||
|
||||
add_task(function test_jog_rate_works() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"rate",
|
||||
"jog_cat",
|
||||
"jog_rate",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
// 1) Standard rate with internal denominator
|
||||
Glean.jogCat.jogRate.addToNumerator(22);
|
||||
Glean.jogCat.jogRate.addToDenominator(7);
|
||||
Assert.deepEqual(
|
||||
{ numerator: 22, denominator: 7 },
|
||||
Glean.jogCat.jogRate.testGetValue()
|
||||
);
|
||||
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"denominator",
|
||||
"jog_cat",
|
||||
"jog_denominator",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({
|
||||
numerators: [
|
||||
{
|
||||
name: "jog_rate_ext",
|
||||
category: "jog_cat",
|
||||
send_in_pings: ["test-only"],
|
||||
lifetime: "ping",
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"rate",
|
||||
"jog_cat",
|
||||
"jog_rate_ext",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
// 2) Rate with external denominator
|
||||
Glean.jogCat.jogDenominator.add(11);
|
||||
Glean.jogCat.jogRateExt.addToNumerator(121);
|
||||
Assert.equal(11, Glean.jogCat.jogDenominator.testGetValue());
|
||||
Assert.deepEqual(
|
||||
{ numerator: 121, denominator: 11 },
|
||||
Glean.jogCat.jogRateExt.testGetValue()
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function test_jog_dotted_categories_work() {
|
||||
Services.fog.testRegisterRuntimeMetric(
|
||||
"counter",
|
||||
"jog_cat.dotted",
|
||||
"jog_counter",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false
|
||||
);
|
||||
Glean.jogCatDotted.jogCounter.add(314);
|
||||
Assert.equal(314, Glean.jogCatDotted.jogCounter.testGetValue());
|
||||
});
|
|
@ -0,0 +1,258 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
function sleep(ms) {
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
add_task(
|
||||
/* on Android FOG is set up through head.js */
|
||||
{ skip_if: () => !runningInParent || AppConstants.platform == "android" },
|
||||
function test_setup() {
|
||||
// Give FOG a temp profile to init within.
|
||||
do_get_profile();
|
||||
|
||||
// We need to initialize it once, otherwise operations will be stuck in the pre-init queue.
|
||||
Services.fog.initializeFOG();
|
||||
}
|
||||
);
|
||||
|
||||
const COUNT = 42;
|
||||
const STRING = "a string!";
|
||||
const ANOTHER_STRING = "another string!";
|
||||
/* TODO:(bugXXX) Support events in JOG
|
||||
const EVENT_EXTRA = { extra1: "so very extra" };
|
||||
*/
|
||||
const MEMORIES = [13, 31];
|
||||
const MEMORY_BUCKETS = ["13509772", "32131834"]; // buckets are strings : |
|
||||
const COUNTERS_1 = 3;
|
||||
const COUNTERS_2 = 5;
|
||||
const INVALID_COUNTERS = 7;
|
||||
|
||||
// It is CRUCIAL that we register metrics in the same order in the parent and
|
||||
// in the child or their metric ids will not line up and ALL WILL EXPLODE.
|
||||
const METRICS = [
|
||||
["counter", "jog_ipc", "jog_counter", ["test-only"], `"ping"`, false],
|
||||
["string_list", "jog_ipc", "jog_string_list", ["test-only"], `"ping"`, false],
|
||||
/* TODO:(bugXXX) Support events in JOG
|
||||
["event", "jog_ipc", "jog_event_no_extra", ["test-only"], `"ping"`, false],
|
||||
["event", "jog_ipc", "jog_event", ["test-only"], `"ping"`, false, JSON.stringify({extras: {extra1: "string"})}],
|
||||
*/
|
||||
[
|
||||
"memory_distribution",
|
||||
"jog_ipc",
|
||||
"jog_memory_dist",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ memory_unit: "megabyte" }),
|
||||
],
|
||||
[
|
||||
"timing_distribution",
|
||||
"jog_ipc",
|
||||
"jog_timing_dist",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ time_unit: "nanosecond" }),
|
||||
],
|
||||
[
|
||||
"custom_distribution",
|
||||
"jog_ipc",
|
||||
"jog_custom_dist",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({
|
||||
range_min: 1,
|
||||
range_max: 2147483646,
|
||||
bucket_count: 10,
|
||||
histogram_type: "linear",
|
||||
}),
|
||||
],
|
||||
[
|
||||
"labeled_counter",
|
||||
"jog_ipc",
|
||||
"jog_labeled_counter",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
],
|
||||
[
|
||||
"labeled_counter",
|
||||
"jog_ipc",
|
||||
"jog_labeled_counter_err",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
],
|
||||
[
|
||||
"labeled_counter",
|
||||
"jog_ipc",
|
||||
"jog_labeled_counter_with_labels",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ labels: ["label_1", "label_2"] }),
|
||||
],
|
||||
[
|
||||
"labeled_counter",
|
||||
"jog_ipc",
|
||||
"jog_labeled_counter_with_labels_err",
|
||||
["test-only"],
|
||||
`"ping"`,
|
||||
false,
|
||||
JSON.stringify({ labels: ["label_1", "label_2"] }),
|
||||
],
|
||||
["rate", "jog_ipc", "jog_rate", ["test-only"], `"ping"`, false],
|
||||
];
|
||||
|
||||
add_task({ skip_if: () => runningInParent }, async function run_child_stuff() {
|
||||
for (let metric of METRICS) {
|
||||
Services.fog.testRegisterRuntimeMetric(...metric);
|
||||
}
|
||||
Glean.jogIpc.jogCounter.add(COUNT);
|
||||
Glean.jogIpc.jogStringList.add(STRING);
|
||||
Glean.jogIpc.jogStringList.add(ANOTHER_STRING);
|
||||
|
||||
/* TODO:(bugXXX) Support events in JOG
|
||||
Glean.jogIpc.jogEventNoExtra.record();
|
||||
Glean.jogIpc.jogEvent.record(EVENT_EXTRA);
|
||||
*/
|
||||
|
||||
for (let memory of MEMORIES) {
|
||||
Glean.jogIpc.jogMemoryDist.accumulate(memory);
|
||||
}
|
||||
|
||||
let t1 = Glean.jogIpc.jogTimingDist.start();
|
||||
let t2 = Glean.jogIpc.jogTimingDist.start();
|
||||
|
||||
await sleep(5);
|
||||
|
||||
let t3 = Glean.jogIpc.jogTimingDist.start();
|
||||
Glean.jogIpc.jogTimingDist.cancel(t1);
|
||||
|
||||
await sleep(5);
|
||||
|
||||
Glean.jogIpc.jogTimingDist.stopAndAccumulate(t2); // 10ms
|
||||
Glean.jogIpc.jogTimingDist.stopAndAccumulate(t3); // 5ms
|
||||
|
||||
Glean.jogIpc.jogCustomDist.accumulateSamples([3, 4]);
|
||||
|
||||
Glean.jogIpc.jogLabeledCounter.label_1.add(COUNTERS_1);
|
||||
Glean.jogIpc.jogLabeledCounter.label_2.add(COUNTERS_2);
|
||||
|
||||
Glean.jogIpc.jogLabeledCounterErr.InvalidLabel.add(INVALID_COUNTERS);
|
||||
|
||||
Glean.jogIpc.jogLabeledCounterWithLabels.label_1.add(COUNTERS_1);
|
||||
Glean.jogIpc.jogLabeledCounterWithLabels.label_2.add(COUNTERS_2);
|
||||
|
||||
Glean.jogIpc.jogLabeledCounterWithLabelsErr.InvalidLabel.add(
|
||||
INVALID_COUNTERS
|
||||
);
|
||||
|
||||
Glean.jogIpc.jogRate.addToNumerator(44);
|
||||
Glean.jogIpc.jogRate.addToDenominator(14);
|
||||
});
|
||||
|
||||
add_task(
|
||||
{ skip_if: () => !runningInParent },
|
||||
async function test_child_metrics() {
|
||||
for (let metric of METRICS) {
|
||||
Services.fog.testRegisterRuntimeMetric(...metric);
|
||||
}
|
||||
await run_test_in_child("test_JOGIPC.js");
|
||||
await Services.fog.testFlushAllChildren();
|
||||
|
||||
Assert.equal(Glean.jogIpc.jogCounter.testGetValue(), COUNT);
|
||||
|
||||
// Note: this will break if string list ever rearranges its items.
|
||||
const strings = Glean.jogIpc.jogStringList.testGetValue();
|
||||
Assert.deepEqual(strings, [STRING, ANOTHER_STRING]);
|
||||
|
||||
const data = Glean.jogIpc.jogMemoryDist.testGetValue();
|
||||
Assert.equal(MEMORIES.reduce((a, b) => a + b, 0) * 1024 * 1024, data.sum);
|
||||
for (let [bucket, count] of Object.entries(data.values)) {
|
||||
// We could assert instead, but let's skip to save the logspam.
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
Assert.ok(count == 1 && MEMORY_BUCKETS.includes(bucket));
|
||||
}
|
||||
|
||||
const customData = Glean.jogIpc.jogCustomDist.testGetValue();
|
||||
Assert.equal(3 + 4, customData.sum, "Sum's correct");
|
||||
for (let [bucket, count] of Object.entries(customData.values)) {
|
||||
Assert.ok(
|
||||
count == 0 || (count == 2 && bucket == 1), // both values in the low bucket
|
||||
`Only two buckets have a sample ${bucket} ${count}`
|
||||
);
|
||||
}
|
||||
|
||||
/* TODO(bug XXX): Support events in JOG
|
||||
var events = Glean.jogIpc.jogEventNoExtra.testGetValue();
|
||||
Assert.equal(1, events.length);
|
||||
Assert.equal("jog_ipc", events[0].category);
|
||||
Assert.equal("jog_event_no_extra", events[0].name);
|
||||
|
||||
events = Glean.jogIpc.jogEvent.testGetValue();
|
||||
Assert.equal(1, events.length);
|
||||
Assert.equal("jog_ipc", events[0].category);
|
||||
Assert.equal("jog_event", events[0].name);
|
||||
Assert.deepEqual(EVENT_EXTRA, events[0].extra);
|
||||
*/
|
||||
|
||||
const NANOS_IN_MILLIS = 1e6;
|
||||
const EPSILON = 40000; // bug 1701949
|
||||
const times = Glean.jogIpc.jogTimingDist.testGetValue();
|
||||
Assert.greater(times.sum, 15 * NANOS_IN_MILLIS - EPSILON);
|
||||
// We can't guarantee any specific time values (thank you clocks),
|
||||
// but we can assert there are only two samples.
|
||||
Assert.equal(
|
||||
2,
|
||||
Object.entries(times.values).reduce(
|
||||
(acc, [bucket, count]) => acc + count,
|
||||
0
|
||||
)
|
||||
);
|
||||
|
||||
const labeledCounter = Glean.jogIpc.jogLabeledCounter;
|
||||
Assert.equal(labeledCounter.label_1.testGetValue(), COUNTERS_1);
|
||||
Assert.equal(labeledCounter.label_2.testGetValue(), COUNTERS_2);
|
||||
|
||||
Assert.throws(
|
||||
() => Glean.jogIpc.jogLabeledCounterErr.__other__.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/,
|
||||
"Invalid labels record errors, which throw"
|
||||
);
|
||||
|
||||
const labeledCounterWLabels = Glean.jogIpc.jogLabeledCounterWithLabels;
|
||||
Assert.equal(labeledCounterWLabels.label_1.testGetValue(), COUNTERS_1);
|
||||
Assert.equal(labeledCounterWLabels.label_2.testGetValue(), COUNTERS_2);
|
||||
|
||||
// TODO:(bug 1766515) - This should throw.
|
||||
/*Assert.throws(
|
||||
() =>
|
||||
Glean.jogIpc.jogLabeledCounterWithLabelsErr.__other__.testGetValue(),
|
||||
/NS_ERROR_LOSS_OF_SIGNIFICANT_DATA/,
|
||||
"Invalid labels record errors, which throw"
|
||||
);*/
|
||||
Assert.equal(
|
||||
Glean.jogIpc.jogLabeledCounterWithLabelsErr.__other__.testGetValue(),
|
||||
INVALID_COUNTERS
|
||||
);
|
||||
|
||||
Assert.deepEqual(
|
||||
{ numerator: 44, denominator: 14 },
|
||||
Glean.jogIpc.jogRate.testGetValue()
|
||||
);
|
||||
}
|
||||
);
|
|
@ -18,3 +18,7 @@ skip-if = os == "android" # FOG isn't responsible for monitoring prefs and contr
|
|||
|
||||
[test_GleanExperiments.js]
|
||||
skip-if = os == "android" # FOG isn't responsible for experiment annotations on Android
|
||||
|
||||
[test_JOG.js]
|
||||
|
||||
[test_JOGIPC.js]
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/FOGIPC.h"
|
||||
#include "mozilla/glean/bindings/Common.h"
|
||||
#include "mozilla/glean/bindings/jog/jog_ffi_generated.h"
|
||||
#include "mozilla/glean/fog_ffi_generated.h"
|
||||
#include "mozilla/glean/GleanMetrics.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
@ -336,6 +337,18 @@ FOG::TestTriggerMetrics(uint32_t aProcessType, JSContext* aCx,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FOG::TestRegisterRuntimeMetric(
|
||||
const nsACString& aType, const nsACString& aCategory,
|
||||
const nsACString& aName, const nsTArray<nsCString>& aPings,
|
||||
const nsACString& aLifetime, const bool aDisabled,
|
||||
const nsACString& aExtraArgs, uint32_t* aMetricIdOut) {
|
||||
*aMetricIdOut = 0;
|
||||
*aMetricIdOut = glean::jog::jog_test_register_metric(
|
||||
&aType, &aCategory, &aName, &aPings, &aLifetime, aDisabled, &aExtraArgs);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(FOG, nsIFOG, nsIObserver)
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -133,4 +133,28 @@ interface nsIFOG : nsISupports
|
|||
*/
|
||||
[implicit_jscontext]
|
||||
Promise testTriggerMetrics(in unsigned long aProcessType);
|
||||
|
||||
/**
|
||||
* ** Test-only Method **
|
||||
*
|
||||
* Register a metric.
|
||||
*
|
||||
* This function is deliberately not too friendly to use. You probably aren't
|
||||
* supposed to use it unless you're testing metric registration itself.
|
||||
*
|
||||
* @param aType - The metric's type.
|
||||
* @param aCategory - The metric's category.
|
||||
* @param aName - The metric's name.
|
||||
* @param aPings - The pings to send it in.
|
||||
* @param aLifetime - The metric's lifetime.
|
||||
* @param aDisabled - Whether the metric, though existing, isn't enabled.
|
||||
* @param aExtraArgs - Optional JSON string of extra args.
|
||||
*/
|
||||
uint32_t testRegisterRuntimeMetric(in ACString aType,
|
||||
in ACString aCategory,
|
||||
in ACString aName,
|
||||
in Array<ACString> aPings,
|
||||
in ACString aLifetime,
|
||||
in boolean aDisabled,
|
||||
[optional] in ACString aExtraArgs);
|
||||
};
|
||||
|
|
|
@ -124,7 +124,7 @@ new_xulstore = ["xulstore"]
|
|||
libfuzzer = ["neqo_glue/fuzzing"]
|
||||
webrtc = ["mdns_service"]
|
||||
glean_disable_upload = ["fog_control/disable_upload"]
|
||||
glean_with_gecko = ["fog_control/with_gecko"]
|
||||
glean_with_gecko = ["fog_control/with_gecko", "jog/with_gecko"]
|
||||
oxidized_breakpad = ["rust_minidump_writer_linux"]
|
||||
with_dbus = ["audio_thread_priority/with_dbus"]
|
||||
thread_sanitizer = ["xpcom/thread_sanitizer"]
|
||||
|
|
Загрузка…
Ссылка в новой задаче