Bug 1673664 - Implement C++ and JS FOG APIs for UUID r=janerik,brizental

Differential Revision: https://phabricator.services.mozilla.com/D95590
This commit is contained in:
Chris H-C 2020-11-06 14:38:50 +00:00
Родитель 02ff8b6e97
Коммит a79272a14e
12 изменённых файлов: 303 добавлений и 2 удалений

2
Cargo.lock сгенерированный
Просмотреть файл

@ -1543,8 +1543,10 @@ dependencies = [
"bincode",
"chrono",
"crossbeam-channel",
"ffi-support",
"glean-core",
"log",
"nsstring",
"once_cell",
"serde",
"tempfile",

Просмотреть файл

@ -8,8 +8,10 @@ publish = false
[dependencies]
bincode = "1.0"
chrono = "0.4.10"
ffi-support = "0.4"
glean-core = "31.4.0"
log = "0.4"
nsstring = { path = "../../../../xpcom/rust/nsstring", optional = true }
once_cell = "1.2.0"
serde = { version = "1.0", features = ["derive"] }
uuid = { version = "0.8.1", features = ["v4"] }
@ -21,4 +23,4 @@ crossbeam-channel = "0.4.3"
tempfile = "3.1.0"
[features]
with_gecko = ["xpcom"]
with_gecko = ["xpcom", "nsstring"]

Просмотреть файл

@ -5,6 +5,10 @@
#[macro_use]
mod macros;
use ffi_support::FfiStr;
#[cfg(feature = "with_gecko")]
use {nsstring::nsACString, uuid::Uuid};
define_metric_ffi!(COUNTER_MAP {
test_has -> fog_counter_test_has_value,
test_get -> fog_counter_test_get_value: i32,
@ -17,3 +21,50 @@ define_metric_ffi!(TIMESPAN_MAP {
start -> fog_timespan_start(),
stop -> fog_timespan_stop(),
});
// The Uuid functions are custom because test_get needs to use an outparam.
// If we can make test_get optional, we can go back to using the macro to
// generate the rest of the functions, or something.
#[no_mangle]
pub extern "C" fn fog_uuid_test_has_value(id: u32, storage_name: FfiStr) -> u8 {
match crate::metrics::__glean_metric_maps::UUID_MAP.get(&id.into()) {
Some(metric) => metric.test_get_value(storage_name.as_str()).is_some() as u8,
None => panic!("No metric for id {}", id),
}
}
#[cfg(feature = "with_gecko")]
#[no_mangle]
pub extern "C" fn fog_uuid_test_get_value(id: u32, storage_name: FfiStr, value: &mut nsACString) {
match crate::metrics::__glean_metric_maps::UUID_MAP.get(&id.into()) {
Some(uuid) => {
value.assign(
&uuid
.test_get_value(storage_name.as_str())
.unwrap()
.to_string(),
);
}
None => panic!("No metric for id {}", id),
}
}
#[cfg(feature = "with_gecko")]
#[no_mangle]
pub extern "C" fn fog_uuid_set(id: u32, value: &nsACString) {
if let Ok(uuid) = Uuid::parse_str(&value.to_utf8()) {
match crate::metrics::__glean_metric_maps::UUID_MAP.get(&id.into()) {
Some(metric) => metric.set(uuid),
None => panic!("No metric for id {}", id),
}
}
}
#[no_mangle]
pub extern "C" fn fog_uuid_generate_and_set(id: u32) {
match crate::metrics::__glean_metric_maps::UUID_MAP.get(&id.into()) {
Some(metric) => metric.generate_and_set(),
None => panic!("No metric for id {}", id),
}
}

Просмотреть файл

@ -7,5 +7,6 @@
#include "mozilla/glean/Counter.h"
#include "mozilla/glean/Timespan.h"
#include "mozilla/glean/Uuid.h"
#endif // mozilla_Glean_MetricTypes_h

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/glean/Uuid.h"
#include "nsString.h"
#include "mozilla/Components.h"
#include "nsIClassInfoImpl.h"
namespace mozilla {
namespace glean {
NS_IMPL_CLASSINFO(GleanUuid, nullptr, 0, {0})
NS_IMPL_ISUPPORTS_CI(GleanUuid, nsIGleanUuid)
NS_IMETHODIMP
GleanUuid::Set(const nsACString& value, JSContext* cx) {
this->mUuid.Set(value);
return NS_OK;
}
NS_IMETHODIMP
GleanUuid::GenerateAndSet(JSContext* cx) {
this->mUuid.GenerateAndSet();
return NS_OK;
}
NS_IMETHODIMP
GleanUuid::TestHasValue(const nsACString& aStorageName, JSContext* cx,
bool* result) {
*result = this->mUuid.TestHasValue(PromiseFlatCString(aStorageName).get());
return NS_OK;
}
NS_IMETHODIMP
GleanUuid::TestGetValue(const nsACString& aStorageName, JSContext* cx,
nsACString& result) {
result.Assign(
this->mUuid.TestGetValue(PromiseFlatCString(aStorageName).get()));
return NS_OK;
}
} // namespace glean
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_glean_GleanUuid_h
#define mozilla_glean_GleanUuid_h
#include "nsIGleanMetrics.h"
#include "nsString.h"
namespace mozilla {
namespace glean {
namespace impl {
extern "C" {
void fog_uuid_set(uint32_t id, const nsACString& uuid);
void fog_uuid_generate_and_set(uint32_t id);
uint32_t fog_uuid_test_has_value(uint32_t id, const char* storageName);
void fog_uuid_test_get_value(uint32_t id, const char* storageName,
nsACString& value);
}
class UuidMetric {
public:
constexpr explicit UuidMetric(uint32_t id) : mId(id) {}
/*
* Sets to the specified value.
*
* @param value The UUID to set the metric to.
*/
void Set(const nsACString& value) const { fog_uuid_set(mId, value); }
/*
* Generate a new random UUID and set the metric to it.
*/
void GenerateAndSet() const { fog_uuid_generate_and_set(mId); }
/**
* **Test-only API**
*
* Tests whether a value is stored for the metric.
*
* This function will attempt to await the last parent-process task (if any)
* writing to the the metric's storage engine before returning a value.
* This function will not wait for data from child processes.
*
* Parent process only. Panics in child processes.
*
* @param aStorageName the name of the ping to retrieve the metric for.
* @return true if metric value exists, otherwise false
*/
bool TestHasValue(const char* aStorageName) const {
return fog_uuid_test_has_value(mId, aStorageName) != 0;
}
/**
* **Test-only API**
*
* Gets the currently stored value as a hyphenated string.
*
* This function will attempt to await the last parent-process task (if any)
* writing to the the metric's storage engine before returning a value.
* This function will not wait for data from child processes.
*
* This doesn't clear the stored value.
* Parent process only. Panics in child processes.
* Panics if there is no value to get.
*
* @return value of the stored metric.
*/
nsCString TestGetValue(const char* aStorageName) const {
nsCString ret;
fog_uuid_test_get_value(mId, aStorageName, ret);
return ret;
}
private:
const uint32_t mId;
};
} // namespace impl
class GleanUuid final : public nsIGleanUuid {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIGLEANUUID
explicit GleanUuid(uint32_t id) : mUuid(id){};
private:
virtual ~GleanUuid() = default;
const impl::UuidMetric mUuid;
};
} // namespace glean
} // namespace mozilla
#endif /* mozilla_glean_GleanUuid.h */

Просмотреть файл

@ -29,7 +29,7 @@ def generate_metric_ids(objs):
return lambda metric: metric_id_mapping[(metric.category, metric.name)]
IMPLEMENTED_CPP_TYPES = ["counter", "timespan"]
IMPLEMENTED_CPP_TYPES = ["counter", "timespan", "uuid"]
def is_implemented_metric_type(typ):

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsString.h"
using mozilla::Preferences;
using namespace mozilla::glean;
#define DATA_PREF "datareporting.healthreport.uploadEnabled"
@ -69,3 +70,18 @@ TEST(FOG, TestCppTimespanWorks)
ASSERT_TRUE(
mozilla::glean::test_only::can_we_time_it.TestGetValue("test-ping") > 0);
}
TEST(FOG, TestCppUuidWorks)
{
nsCString kTestUuid("decafdec-afde-cafd-ecaf-decafdecafde");
test_only::what_id_it.Set(kTestUuid);
ASSERT_TRUE(test_only::what_id_it.TestHasValue("test-ping"));
ASSERT_STREQ(kTestUuid.get(),
test_only::what_id_it.TestGetValue("test-ping").get());
test_only::what_id_it.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_STRNE(kTestUuid.get(),
test_only::what_id_it.TestGetValue("test-ping").get());
}

Просмотреть файл

@ -24,6 +24,7 @@ if CONFIG["MOZ_GLEAN"]:
"bindings/MetricTypes.h",
"bindings/private/Counter.h",
"bindings/private/Timespan.h",
"bindings/private/Uuid.h",
]
UNIFIED_SOURCES += [
@ -31,6 +32,7 @@ if CONFIG["MOZ_GLEAN"]:
"bindings/Glean.cpp",
"bindings/private/Counter.cpp",
"bindings/private/Timespan.cpp",
"bindings/private/Uuid.cpp",
"ipc/FOGIPC.cpp",
]

Просмотреть файл

@ -47,6 +47,18 @@ test_only:
send_in_pings:
- test-ping
what_id_it: # Using a different metrics yaml style for fun.
type: uuid
description: |
Just a UUID.
This is a test-only metric.
bugs: ["https://bugzilla.mozilla.org/show_bug.cgi?id=1673664"]
data_reviews: ["https://bugzilla.mozilla.org/show_bug.cgi?id=1673664#c1"]
data_sensitivity: ["technical"]
notification_emails: ["glean-team@mozilla.com"]
expires: never
send_in_pings: ["test-ping"]
test_only.ipc:
a_counter:
type: counter

Просмотреть файл

@ -109,3 +109,55 @@ interface nsIGleanTimespan : nsISupports
[implicit_jscontext]
long long testGetValue(in ACString aStorageName);
};
[scriptable, uuid(395700e7-06f6-46be-adcc-ea58977fda6d)]
interface nsIGleanUuid : nsISupports
{
/**
* Set to the specified value.
*
* @param aValue The UUID to set the metric to.
*/
[implicit_jscontext]
void set(in ACString aValue);
/**
* Generate a new random UUID and set the metric to it.
*/
[implicit_jscontext]
void generateAndSet();
/**
* **Test-only API**
*
* Tests whether a value is stored for the metric.
*
* This function will attempt to await the last parent-process task (if any)
* writing to the the metric's storage engine before returning a value.
* This function will not wait for data from child processes.
*
* Parent process only. Panics in child processes.
*
* @param aStorageName the name of the ping to retrieve the metric for.
* @return true if metric value exists, otherwise false
*/
[implicit_jscontext]
bool testHasValue(in ACString aStorageName);
/**
* **Test-only API**
*
* Gets the currently stored value as an integer.
*
* This function will attempt to await the last parent-process task (if any)
* writing to the the metric's storage engine before returning a value.
* This function will not wait for data from child processes.
*
* This doesn't clear the stored value.
* Parent process only. Panics in child processes.
*
* @return value of the stored metric.
*/
[implicit_jscontext]
ACString testGetValue(in ACString aStorageName);
};

Просмотреть файл

@ -42,3 +42,18 @@ add_task(async function test_fog_timespan_works() {
Assert.ok(Glean.test_only.can_we_time_it.testHasValue("test-ping"));
Assert.ok(Glean.test_only.can_we_time_it.testGetValue("test-ping") > 0);
});
add_task(async function test_fog_uuid_works() {
const kTestUuid = "decafdec-afde-cafd-ecaf-decafdecafde";
Glean.test_only.what_id_it.set(kTestUuid);
Assert.ok(Glean.test_only.what_id_it.testHasValue("test-ping"));
Assert.equal(kTestUuid, Glean.test_only.what_id_it.testGetValue("test-ping"));
Glean.test_only.what_id_it.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.test_only.what_id_it.testGetValue("test-ping")
);
});