Add sub-command for listing expired field trials

Bug: webrtc:14154
Change-Id: I9c5c8c4a177fb863af7e2c0ed7fa99454019cfbe
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/321183
Commit-Queue: Emil Lundmark <lndmrk@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40817}
This commit is contained in:
Emil Lundmark 2023-09-22 15:58:09 +02:00 committed by WebRTC LUCI CQ
parent b7fca15fd4
commit 9686a4b580

View File

@ -8,28 +8,33 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import datetime
from datetime import date
import sys
from typing import FrozenSet
from typing import FrozenSet, Set
import argparse
import dataclasses
# TODO(bugs.webrtc.org/14154): End date and bug should also be stored.
@dataclasses.dataclass(frozen=True)
class FieldTrial:
"""Representation of all attributes associated with a field trial.
Attributes:
key: Field trial key.
bug: Associated open bug containing more context.
end_date: Date when the field trial expires and must be deleted.
"""
key: str
bug: str
end_date: date
# As per the policy in `g3doc/field-trials.md`, all field trials should be
# registered in the container below. Please keep the keys sorted.
REGISTERED_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
FieldTrial(''), # TODO(bugs.webrtc.org/14154): Populate
FieldTrial('', '', date(1, 1, 1)), # TODO(bugs.webrtc.org/14154): Populate
])
@ -44,7 +49,11 @@ def registry_header(
String representation of a C++ header file containing all field trial
keys.
>>> trials = {FieldTrial('B'), FieldTrial('A'), FieldTrial('B')}
>>> trials = {
... FieldTrial('B', '', date(1, 1, 1)),
... FieldTrial('A', '', date(1, 1, 1)),
... FieldTrial('B', '', date(2, 2, 2)),
... }
>>> print(registry_header(trials))
// This file was automatically generated. Do not edit.
<BLANKLINE>
@ -65,7 +74,7 @@ def registry_header(
#endif // GEN_REGISTERED_FIELD_TRIALS_H_
<BLANKLINE>
"""
registered_keys = [f.key for f in field_trials]
registered_keys = {f.key for f in field_trials}
keys = '\n'.join(f' "{k}",' for k in sorted(registered_keys))
return ('// This file was automatically generated. Do not edit.\n'
'\n'
@ -85,13 +94,54 @@ def registry_header(
'#endif // GEN_REGISTERED_FIELD_TRIALS_H_\n')
def expired_field_trials(
threshold: date,
field_trials: FrozenSet[FieldTrial] = REGISTERED_FIELD_TRIALS
) -> Set[FieldTrial]:
"""Obtains expired field trials.
Args:
threshold: Date from which to check end date.
field_trials: Field trials to validate.
Returns:
All expired field trials.
>>> trials = {
... FieldTrial('Expired', '', date(1, 1, 1)),
... FieldTrial('Not-Expired', '', date(1, 1, 2)),
... }
>>> expired_field_trials(date(1, 1, 1), trials)
{FieldTrial(key='Expired', bug='', end_date=datetime.date(1, 1, 1))}
"""
return {f for f in field_trials if f.end_date <= threshold}
def cmd_header(args: argparse.Namespace) -> None:
args.output.write(registry_header())
def cmd_expired(args: argparse.Namespace) -> None:
now = datetime.datetime.now(datetime.timezone.utc)
today = date(now.year, now.month, now.day)
diff = datetime.timedelta(days=args.in_days)
expired = expired_field_trials(today + diff)
if len(expired) <= 0:
return
expired_by_date = sorted([(f.end_date, f.key) for f in expired])
print('\n'.join(
f'{key} {"expired" if date <= today else "expires"} on {date}'
for date, key in expired_by_date))
if any(date <= today for date, _ in expired_by_date):
sys.exit(1)
def main() -> None:
parser = argparse.ArgumentParser()
subcommand = parser.add_subparsers(dest='cmd')
parser_header = subcommand.add_parser(
'header',
help='generate C++ header file containing registered field trial keys')
@ -101,6 +151,22 @@ def main() -> None:
required=False,
help='output file')
parser_header.set_defaults(cmd=cmd_header)
parser_expired = subcommand.add_parser(
'expired',
help='lists all expired field trials',
description='''
Lists all expired field trials. Exits with a non-zero exit status if
any field trials has expired, ignoring the --in-days argument.
''')
parser_expired.add_argument(
'--in-days',
default=0,
type=int,
required=False,
help='number of days relative to today to check')
parser_expired.set_defaults(cmd=cmd_expired)
args = parser.parse_args()
if not args.cmd: