Bug 1894270 - Schedule pings alongside their parent ping r=chutten,mach-reviewers

This is a bit of a hack to make it all work.
On every `submit` of a ping we call into `schedule_pings` to also
schedule ride-along pings.

Preferably we would like to have that in glean-core, but for builtin
pings that won't work because they are not code-generated and thus will
never see their `schedules_pings` array.
So instead we generate a function in m-c that does the mapping and call
that in the ping wrapper used inside m-c.

Another side effect: `testBeforeNextSubmit` callbacks from
JavaScript/C++ will _not_ be called, because they are only on the JS/C++
object and not reachable from the Rust parts where we actually submit the
ride-along pings.

Differential Revision: https://phabricator.services.mozilla.com/D209671
This commit is contained in:
Jan-Erik Rediger 2024-05-15 09:07:47 +00:00
parent 66d8d0bb34
commit 27ef1fa8ac
25 changed files with 222 additions and 47 deletions

View file

@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: glean_parser
Version: 14.0.1
Version: 14.1.2
Summary: Parser tools for Mozilla's Glean telemetry
Home-page: https://github.com/mozilla/glean_parser
Author: The Glean Team
@ -77,6 +77,20 @@ $ glean_parser check < ping.json
# Changelog
## Unreleased
## 14.1.2
- ping schedule: Gracefully handle missing ping ([#705](https://github.com/mozilla/glean_parser/pull/705))
## 14.1.1
- Replace deprecated methods and package ([#699](https://github.com/mozilla/glean_parser/pull/699))
## 14.1.0
- Add Go log outputter support for datetime (`go_server`) ([#693](https://github.com/mozilla/glean_parser/pull/693))
## 14.0.1
- BUGFIX: Fix missing `ping_arg` in util.py ([#687](https://github.com/mozilla/glean_parser/pull/687))

View file

@ -1,15 +1,15 @@
glean_parser/__init__.py,sha256=bJljD052_0y-efcBhYpllICVCXOMHLcXRLNyrvfgt5A,533
glean_parser/__init__.py,sha256=mB3nXWXhV9zJXymgmeGCjUnPFzQgcexx0Klw0XvLkS8,515
glean_parser/__main__.py,sha256=Rw0PpuQtAvdHJMK1YLozeZkc6x1yjeNZwidu4faovdk,8633
glean_parser/coverage.py,sha256=2IwC4XMDtDamMkBFoYilmqJzW4gyypq65YVCur8SNas,4405
glean_parser/data_review.py,sha256=BweeeTkNNS6HrIDkztawhbDByrk_-Avxpg7YeST3VAs,2152
glean_parser/go_server.py,sha256=s6lxK9IAFY55pNl3Rv4MHlV-nQwSoyhO9ppTQE9VCik,5346
glean_parser/go_server.py,sha256=VaPymy5bxAM9jlD0UkkzOndRxT3Wqym193pMMrfBYz0,5421
glean_parser/javascript.py,sha256=w4ZhNBHBKWYk0h3t7G0Ud2tR__hRqzn9dlEXNKLdQrA,11230
glean_parser/javascript_server.py,sha256=PZSTl63TR3cY8Y99jXMOLu-8rzgQarymzjnHJm9aYK0,8389
glean_parser/kotlin.py,sha256=5nXnen4s2YOj503Z77HVTUgDHWdulB8BMl8vOie38o4,13365
glean_parser/lint.py,sha256=STqdgyOhR4Q3fHivSizgn9bOOyqrNHhzjaqyJxz6qzI,19948
glean_parser/markdown.py,sha256=GkCr1CrV6mnRQseT6FO1-JJ7Eup8X3lxUfRMBTxXpe4,9066
glean_parser/metrics.py,sha256=YAO8wPuRHTLkdT9M4zh9ZwoFI1_VS8O9oQqwZNYyDp0,14612
glean_parser/parser.py,sha256=3-uF-Hi5LlvdFc1NxZOKX0EoEyekZGnZV094eTIJut0,16361
glean_parser/parser.py,sha256=eIlXYUOeeqy6-Ec2V-XFf4dFc2gnRhkgd9ZXjp1RYvU,16366
glean_parser/pings.py,sha256=-CIiMBVOTFULmNybV8YTFI7vmfOYOGQ5TD9hEfYPUII,3435
glean_parser/python_server.py,sha256=ERpYcbSwF19xKFagxX0mZAvlR1y6D7Ah5DSvW8LipCY,4791
glean_parser/ruby_server.py,sha256=e5lkfcLQAUMUBQDCjqNU82LkdUzT5x-G6HOnsUInbsU,5190
@ -18,7 +18,7 @@ glean_parser/swift.py,sha256=paUzF6tItdktFwIQYCKsYpqXfn8zxR2coU_jMYrmwlc,8957
glean_parser/tags.py,sha256=bemKYvcbMO4JrghiNSe-A4BNNDtx_FlUPkgrPPJy84Y,1391
glean_parser/translate.py,sha256=luKQoraARZ2tjenHs0SVtCxflnYaMkzPYFfKEdKdSqQ,8403
glean_parser/translation_options.py,sha256=Lxzr6G7MP0tC_ZYlZXftS4j0SLiqO-5mGVTEc7ggXis,2037
glean_parser/util.py,sha256=wftmoWBUQM_o7pUwdhBp3HuDCVHIBw1PXtrfxwPLD0Q,16187
glean_parser/util.py,sha256=xECYZVlcVzmUn7PT4zp5hVa0iYW2Qh3ik71iPgjeQvY,16223
glean_parser/validate_ping.py,sha256=0TNvILH6dtzJDys3W8Kqorw6kk03me73OCUDtpoHcXU,2118
glean_parser/schemas/metrics.1-0-0.schema.yaml,sha256=cND3cvi6iBfPUVmtfIBQfGJV9AALpbvN7nu8E33_J-o,19566
glean_parser/schemas/metrics.2-0-0.schema.yaml,sha256=wx1q0L4C0-Vcwk1SPU6t8OfjDEQvgrwwEG6xfSHO1MI,26365
@ -26,7 +26,7 @@ glean_parser/schemas/pings.1-0-0.schema.yaml,sha256=hwCnsKpEysmrmVp-QHGBArEkVY3v
glean_parser/schemas/pings.2-0-0.schema.yaml,sha256=f8PClAlMoLTmX6ANq8Ai0CpiE74i3LOgU5SoTJpoh0M,6149
glean_parser/schemas/tags.1-0-0.schema.yaml,sha256=OGXIJlvvVW1vaqB_NVZnwKeZ-sLlfH57vjBSHbj6DNI,1231
glean_parser/templates/data_review.jinja2,sha256=jeYU29T1zLSyu9fKBBFu5BFPfIw8_hmOUXw8RXhRXK8,3287
glean_parser/templates/go_server.jinja2,sha256=Jy1e0uQqr_WZNoj-AWnygRmygX2jyj_GQMMV8mSah2k,6825
glean_parser/templates/go_server.jinja2,sha256=EHf4KBKNPzC1sLugN9yS6_vPNlSl3YCxcoVQGWGL6aM,7039
glean_parser/templates/javascript.buildinfo.jinja2,sha256=4mXiZCQIk9if4lxlA05kpSIL4a95IdwGwqle2OqqNAs,474
glean_parser/templates/javascript.jinja2,sha256=cT_bG-jC6m4afECXmcsqHwiiHjRuVtJnfv90OD2Mwxw,2669
glean_parser/templates/javascript_server.jinja2,sha256=k-XI3QIhHQ1vbIPqSMTmCu93b1oZhm7KLmx9LfO3IJ0,9472
@ -37,12 +37,12 @@ glean_parser/templates/markdown.jinja2,sha256=vAHHGGm28HRDPd3zO_wQMAUZIuxE9uQ7hl
glean_parser/templates/python_server.jinja2,sha256=gu2C1rkn760IqBCG2SWaK7o32T1ify94wDEsudLPUg8,7260
glean_parser/templates/qmldir.jinja2,sha256=m6IGsp-tgTiOfQ7VN8XW6GqX0gJqJkt3B6Pkaul6FVo,156
glean_parser/templates/ruby_server.jinja2,sha256=vm4BEenOqzomQNTLFfMOzlWHARnsWUjTBbnR-v2cadI,6247
glean_parser/templates/rust.jinja2,sha256=Ir_JqWRIUs1KLoYNDolgTRjWfWdzzBfouCP-YeTJa-c,5495
glean_parser/templates/rust.jinja2,sha256=sNphecHKehGOzwtIz-Q54Zz1mHcNXFsIPn7BaK78ln4,5517
glean_parser/templates/swift.jinja2,sha256=4f993l_zZk_Tz1efiz3nbvDK1H3Uq3dWQ2T6glT9XQ4,6695
glean_parser-14.0.1.dist-info/AUTHORS.md,sha256=yxgj8MioO4wUnrh0gmfb8l3DJJrf-l4HmmEDbQsbbNI,455
glean_parser-14.0.1.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
glean_parser-14.0.1.dist-info/METADATA,sha256=Ghvw-Y7woQUJ38P8TYT5TFt8sL61GJoZPBajaB0WLeQ,32276
glean_parser-14.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
glean_parser-14.0.1.dist-info/entry_points.txt,sha256=mf9d3sv8BwSjjR58x9KDnpVkONCnv3fPQC2NjJl15Xg,68
glean_parser-14.0.1.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13
glean_parser-14.0.1.dist-info/RECORD,,
glean_parser-14.1.2.dist-info/AUTHORS.md,sha256=yxgj8MioO4wUnrh0gmfb8l3DJJrf-l4HmmEDbQsbbNI,455
glean_parser-14.1.2.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
glean_parser-14.1.2.dist-info/METADATA,sha256=rS3vTnQHptZNwin6HEKOZoeBiiPFi8Dq4G2TjPDbs5Q,32651
glean_parser-14.1.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
glean_parser-14.1.2.dist-info/entry_points.txt,sha256=mf9d3sv8BwSjjR58x9KDnpVkONCnv3fPQC2NjJl15Xg,68
glean_parser-14.1.2.dist-info/top_level.txt,sha256=q7T3duD-9tYZFyDry6Wv2LcdMsK2jGnzdDFhxWcT2Z8,13
glean_parser-14.1.2.dist-info/RECORD,,

View file

@ -6,11 +6,11 @@
"""Top-level package for Glean parser."""
from pkg_resources import get_distribution, DistributionNotFound
import importlib.metadata
try:
__version__ = get_distribution(__name__).version
except DistributionNotFound:
__version__ = importlib.metadata.version(__name__)
except importlib.metadata.PackageNotFoundError:
# package is not installed
pass

View file

@ -32,7 +32,7 @@ from . import util
# Adding a metric here will require updating the `generate_metric_type` function
# and require adjustments to `metrics` variables the the template.
SUPPORTED_METRIC_TYPES = ["string", "quantity", "event"]
SUPPORTED_METRIC_TYPES = ["string", "quantity", "event", "datetime"]
def generate_event_type_name(metric: metrics.Metric) -> str:
@ -58,6 +58,8 @@ def generate_metric_type(metric_type: str) -> str:
return "string"
elif metric_type == "boolean":
return "bool"
elif metric_type == "datetime":
return "time.Time"
else:
print("❌ Unable to generate Go type from metric type: " + metric_type)
exit

View file

@ -299,8 +299,6 @@ def _instantiate_pings(
ping_schedule_reverse_map[ping_schedule] = set()
ping_schedule_reverse_map[ping_schedule].add(ping_key)
del ping_val["metadata"]["ping_schedule"]
try:
ping_obj = Ping(
defined_in=getattr(ping_val, "defined_in", None),
@ -331,7 +329,9 @@ def _instantiate_pings(
sources[ping_key] = filepath
for scheduler, scheduled in ping_schedule_reverse_map.items():
if isinstance(all_objects["pings"][scheduler], Ping):
if scheduler in all_objects["pings"] and isinstance(
all_objects["pings"][scheduler], Ping
):
scheduler_obj: Ping = cast(Ping, all_objects["pings"][scheduler])
scheduler_obj.schedules_pings = sorted(list(scheduled))

View file

@ -10,7 +10,7 @@ package glean
// required imports
import (
"encoding/json"
"fmt"
"fmt"
"strconv"
"time"
@ -185,7 +185,11 @@ func (g GleanEventsLogger) Record{{ event|event_type_name }}(
{% if metric_type != 'event' %}
"{{ metric_type }}": {
{% for metric in metrics %}
"{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
{% if metric_type =='datetime' %}
"{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
{% else %}
"{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
{% endif %}
{% endfor %}
},
{% endif %}

View file

@ -24,7 +24,7 @@ Jinja2 template is not. Please file bugs! #}
#[serde(skip_serializing_if = "Option::is_none")]
pub {{itemname|snake_case}}: Option<{{ name ~ "Item" ~ itemname|Camelize ~ "Object" }}>,
{% elif val.type == "array" %}
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(skip_serializing_if = "Vec::is_empty", default = "Vec::new")]
pub {{itemname|snake_case}}: {{ name ~ "Item" ~ itemname|Camelize }},
{% else %}
#[serde(skip_serializing_if = "Option::is_none")]

View file

@ -406,7 +406,7 @@ def is_expired(expires: str, major_version: Optional[int] = None) -> bool:
return parse_expiration_version(expires) <= major_version
else:
date = parse_expiration_date(expires)
return date <= datetime.datetime.utcnow().date()
return date <= datetime.datetime.now(datetime.timezone.utc).date()
def validate_expires(expires: str, major_version: Optional[int] = None) -> None:
@ -458,7 +458,7 @@ def build_date(date: Optional[str]) -> datetime.datetime:
else:
ts = datetime_fromisoformat(date).replace(tzinfo=datetime.timezone.utc)
else:
ts = datetime.datetime.utcnow()
ts = datetime.datetime.now(datetime.timezone.utc)
return ts

9
third_party/python/poetry.lock generated vendored
View file

@ -592,14 +592,14 @@ files = [
[[package]]
name = "glean-parser"
version = "14.0.1"
version = "14.1.2"
description = "Parser tools for Mozilla's Glean telemetry"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "glean_parser-14.0.1-py3-none-any.whl", hash = "sha256:3275ca235885c99da659fa7d9bf929b8fb020df79d26fcbec317328c369cd039"},
{file = "glean_parser-14.0.1.tar.gz", hash = "sha256:3e9e5f99ad8592300e364b70d6247b21c445774a73a2ad274677fb58a0065809"},
{file = "glean_parser-14.1.2-py3-none-any.whl", hash = "sha256:c3e87165fe0a0fcbcb28b76bbad025601a86eb447c5779472b62915c46cd44ab"},
{file = "glean_parser-14.1.2.tar.gz", hash = "sha256:38be7d4e0fab0f83340e3427914e08a8631c7fab088a8c60e9b543cab6ea830c"},
]
[package.dependencies]
@ -1161,6 +1161,7 @@ files = [
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
@ -1624,4 +1625,4 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black (
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
content-hash = "8e72dc9ba9b4f08d27d90f99666459a814d1bb293c68de222614ea57db5b70ef"
content-hash = "a683c725217ca4a2d61b56b43b137217b5f8630ee0715e44637fd29599e0b0a2"

View file

@ -22,7 +22,7 @@ fluent.migrate==0.13.0
fluent.syntax==0.19.0
# Pin `frozenlist` as it is required for `aiohttp`. Use minimum required version.
frozenlist==1.1.1
glean_parser==14.0.1
glean_parser==14.1.2
importlib-metadata==6.0.0
# required for compatibility with Flask >= 2 in tools/tryselect/selectors/chooser
jinja2==3.1.2

View file

@ -275,9 +275,9 @@ frozenlist==1.1.1 ; python_version >= "3.8" and python_version < "4.0" \
giturlparse==0.10.0 ; python_version >= "3.8" and python_version < "4.0" \
--hash=sha256:04ba1a3a099c3093fa8d24a422913c6a9b2c2cd22bcffc939cf72e3e98f672d7 \
--hash=sha256:2595ab291d30717cda8474b874c9fd509f1b9802ad7f6968c36a45e4b13eb337
glean-parser==14.0.1 ; python_version >= "3.8" and python_version < "4.0" \
--hash=sha256:3275ca235885c99da659fa7d9bf929b8fb020df79d26fcbec317328c369cd039 \
--hash=sha256:3e9e5f99ad8592300e364b70d6247b21c445774a73a2ad274677fb58a0065809
glean-parser==14.1.2 ; python_version >= "3.8" and python_version < "4.0" \
--hash=sha256:38be7d4e0fab0f83340e3427914e08a8631c7fab088a8c60e9b543cab6ea830c \
--hash=sha256:c3e87165fe0a0fcbcb28b76bbad025601a86eb447c5779472b62915c46cd44ab
idna==2.10 ; python_version >= "3.8" and python_version < "4.0" \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
@ -492,6 +492,7 @@ pyyaml==6.0.1 ; python_version >= "3.8" and python_version < "4.0" \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \

View file

@ -11,7 +11,7 @@ use crate::ipc::need_ipc;
/// See [Glean Pings](https://mozilla.github.io/glean/book/user/pings/index.html).
#[derive(Clone)]
pub enum Ping {
Parent(glean::private::PingType),
Parent(glean::private::PingType, String),
Child,
}
@ -38,16 +38,20 @@ impl Ping {
if need_ipc() {
Ping::Child
} else {
Ping::Parent(glean::private::PingType::new(
let name = name.into();
Ping::Parent(
glean::private::PingType::new(
name.clone(),
include_client_id,
send_if_empty,
precise_timestamps,
include_info_sections,
enabled,
schedules_pings,
reason_codes,
),
name,
include_client_id,
send_if_empty,
precise_timestamps,
include_info_sections,
enabled,
schedules_pings,
reason_codes,
))
)
}
}
@ -61,7 +65,7 @@ impl Ping {
/// `send_if_empty` is `false`).
pub fn test_before_next_submit(&self, cb: impl FnOnce(Option<&str>) + Send + 'static) {
match self {
Ping::Parent(p) => p.test_before_next_submit(cb),
Ping::Parent(p, _) => p.test_before_next_submit(cb),
Ping::Child => {
panic!("Cannot use ping test API from non-parent process!");
}
@ -79,8 +83,9 @@ impl glean::traits::Ping for Ping {
/// `ping_info.reason` part of the payload.
pub fn submit(&self, reason: Option<&str>) {
match self {
Ping::Parent(p) => {
Ping::Parent(p, name) => {
p.submit(reason);
crate::pings::schedule_pings(&name, reason);
}
Ping::Child => {
log::error!(

View file

@ -174,6 +174,22 @@ def extra_keys(allowed_extra_keys):
return "&[" + ", ".join(map(lambda key: '"' + key + '"', allowed_extra_keys)) + "]"
def get_schedule_reverse_map(objs):
ping_schedule_reverse_map = dict()
if "pings" in objs:
for ping_key, ping_val in objs["pings"].items():
for ping_schedule in ping_val.metadata.get("ping_schedule", []):
if ping_schedule not in ping_schedule_reverse_map:
ping_schedule_reverse_map[ping_schedule] = set()
ping_schedule_reverse_map[ping_schedule].add(ping_key)
for ping, schedules in ping_schedule_reverse_map.items():
sorted_schedule = sorted(schedules)
ping_schedule_reverse_map[ping] = sorted_schedule
return ping_schedule_reverse_map
def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
"""
Given a tree of objects, output Rust code to the file-like object `output_fd`.
@ -205,6 +221,7 @@ def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
util.get_jinja2_template = get_local_template
get_metric_id = generate_metric_ids(objs)
get_ping_id = generate_ping_ids(objs)
ping_schedule_reverse_map = get_schedule_reverse_map(objs)
# Map from a tuple (const, typ) to an array of tuples (id, path)
# where:
@ -311,6 +328,7 @@ def output_rust(objs, output_fd, ping_names_by_app_id, options={}):
labeleds_by_id_by_type=labeleds_by_id_by_type,
submetric_bit=ID_BITS - ID_SIGNAL_BITS,
ping_names_by_app_id=ping_names_by_app_id,
ping_schedule_reverse_map=ping_schedule_reverse_map,
)
)
output_fd.write("\n")

View file

@ -54,6 +54,37 @@ pub fn register_pings(application_id: Option<&str>) {
}
}
/// Schedule pings alongside a parent ping.
///
/// Should be called in `submit` of the parent ping
/// to also submit pings that should ride along.
///
/// # Arguments
///
/// `submitted_ping`: The parent ping that is submitted
/// `reason`: The original reason for the submitted ping.
/// Will be used for the ride-along ping too.
#[doc(hidden)]
pub fn schedule_pings(submitted_ping: &str, reason: Option<&str>) {
{% if ping_schedule_reverse_map|length %}
match submitted_ping {
{% for ping, schedule in ping_schedule_reverse_map.items() %}
"{{ping}}" => {
log::info!("Submitting pings {{ schedule|join(', ') }} along with {{ping}}");
{% for ping_name in schedule %}
let _ = {{ ping_name|snake_case }}.submit(reason);
{% endfor %}
},
{% endfor %}
_ => {},
}
{% else %}
// Ignore arguments.
_ = submitted_ping;
_ = reason;
{% endif %}
}
#[cfg(feature = "with_gecko")]
pub(crate) fn submit_ping_by_id(id: u32, reason: Option<&str>) {
if id & (1 << crate::factory::DYNAMIC_PING_BIT) > 0 {

View file

@ -493,3 +493,6 @@ TEST_F(FOGFixture, TestRustInGTest) { Rust_TestRustInGTest(); }
extern "C" void Rust_TestJogfile();
TEST_F(FOGFixture, TestJogfile) { Rust_TestJogfile(); }
extern "C" void Rust_TestRideAlongPing();
TEST_F(FOGFixture, TestRustRideAlongPing) { Rust_TestRideAlongPing(); }

View file

@ -1,8 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
extern crate firefox_on_glean;
use firefox_on_glean::metrics;
use firefox_on_glean::{metrics, pings};
extern crate nsstring;
use nsstring::nsString;
@ -53,3 +56,33 @@ pub extern "C" fn Rust_TestJogfile() {
// If it can't, that's perhaps a sign that the inner workings need to be updated.
expect!(jog::jog_load_jogfile(&nsString::from("jogfile_output")));
}
#[no_mangle]
pub extern "C" fn Rust_TestRideAlongPing() {
// A similar test exists in `xpcshell/test_Glean.js`.
// But here we can test that the `test_before_next_submit` callback
// is correctly called.
let test_submitted = Arc::new(AtomicBool::new(false));
let ride_along_submitted = Arc::new(AtomicBool::new(false));
{
let test_submitted = Arc::clone(&test_submitted);
pings::test_ping.test_before_next_submit(move |_reason| {
test_submitted.store(true, Ordering::Release);
});
}
{
let ride_along_submitted = Arc::clone(&ride_along_submitted);
pings::ride_along_ping.test_before_next_submit(move |_reason| {
ride_along_submitted.store(true, Ordering::Release);
});
}
// Submit only a single ping, the other will ride along.
pings::test_ping.submit(None);
expect!(test_submitted.load(Ordering::Acquire));
expect!(ride_along_submitted.load(Ordering::Acquire));
}

View file

@ -119,6 +119,23 @@ pub fn register_pings(application_id: Option<&str>) {
}
}
/// Schedule pings alongside a parent ping.
///
/// Should be called in `submit` of the parent ping
/// to also submit pings that should ride along.
///
/// # Arguments
///
/// `submitted_ping`: The parent ping that is submitted
/// `reason`: The original reason for the submitted ping.
/// Will be used for the ride-along ping too.
#[doc(hidden)]
pub fn schedule_pings(submitted_ping: &str, reason: Option<&str>) {
// Ignore arguments.
_ = submitted_ping;
_ = reason;
}
#[cfg(feature = "with_gecko")]
pub(crate) fn submit_ping_by_id(id: u32, reason: Option<&str>) {
if id & (1 << crate::factory::DYNAMIC_PING_BIT) > 0 {

View file

@ -24,6 +24,7 @@ test_only:
expires: never
send_in_pings:
- test-ping
- ride-along-ping
can_we_time_it:
type: timespan

View file

@ -59,3 +59,20 @@ test-ohttp-ping:
- glean-team@mozilla.com
no_lint:
- REDUNDANT_PING
ride-along-ping:
description: |
This ping is for tests only.
include_client_id: false
send_if_empty: true
bugs:
- https://bugzilla.mozilla.org/1894270
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1894270#c1
notification_emails:
- glean-team@mozilla.com
no_lint:
- REDUNDANT_PING
metadata:
ping_schedule:
- test-ping

View file

@ -628,3 +628,31 @@ add_task(async function test_fog_complex_object_works() {
result = Glean.testOnly.crashStack.testGetValue();
Assert.deepEqual(stack, result);
});
add_task(function test_fog_ride_along_pings() {
Assert.equal(null, Glean.testOnly.badCode.testGetValue("test-ping"));
Assert.equal(null, Glean.testOnly.badCode.testGetValue("ride-along-ping"));
Glean.testOnly.badCode.add(37);
Assert.equal(37, Glean.testOnly.badCode.testGetValue("test-ping"));
Assert.equal(37, Glean.testOnly.badCode.testGetValue("ride-along-ping"));
let testPingSubmitted = false;
GleanPings.testPing.testBeforeNextSubmit(() => {
testPingSubmitted = true;
});
// FIXME(bug 1896356):
// We can't use `testBeforeNextSubmit` for `ride-along-ping`
// because it's triggered internally, but the callback would only be available
// in the C++ bits, not in the internal Rust parts.
// Submit only a single ping, the other will ride along.
GleanPings.testPing.submit();
Assert.ok(testPingSubmitted, "Test ping was submitted, callback was called.");
// Both pings have been submitted, so the values should be cleared.
Assert.equal(null, Glean.testOnly.badCode.testGetValue("test-ping"));
Assert.equal(null, Glean.testOnly.badCode.testGetValue("ride-along-ping"));
});