import unittest
import xml_validations
from xml.dom import minidom
class UkmXmlValidationTest(unittest.TestCase):
def toUkmConfig(self, xml_string):
dom = minidom.parseString(xml_string)
[ukm_config] = dom.getElementsByTagName('ukm-configuration')
return ukm_config
def testEventsHaveOwners(self):
ukm_config = self.toUkmConfig("""
<ukm-configuration>
<event name="Event1">
<owner>dev@chromium.org</owner>
</event>
</ukm-configuration>
""".strip())
validator = xml_validations.UkmXmlValidation(ukm_config)
success, errors = validator.checkEventsHaveOwners()
self.assertTrue(success)
self.assertListEqual([], errors)
def testEventsMissingOwners(self):
ukm_config = self.toUkmConfig("""
<ukm-configuration>
<event name="Event1"/>
<event name="Event2">
<owner></owner>
</event>
<event name="Event3">
<owner>johndoe</owner>
</event>
</ukm-configuration>
""".strip())
expected_errors = [
"<owner> tag is required for event 'Event1'.",
"<owner> tag for event 'Event2' should not be empty.",
"<owner> tag for event 'Event3' expects a Chromium or Google email "
"address.",
]
validator = xml_validations.UkmXmlValidation(ukm_config)
success, errors = validator.checkEventsHaveOwners()
self.assertFalse(success)
self.assertListEqual(expected_errors, errors)
def testMetricHasUndefinedEnum(self):
ukm_config = self.toUkmConfig("""
<ukm-configuration>
<event name="Event1">
<metric name="Metric2" enum="FeatureObserver"/>
</event>
<event name="Event2">
<metric name="Metric1" enum="BadEnum"/>
<metric name="Metric2" enum="FeatureObserver"/>
<metric name="Metric3" unit="ms"/>
<metric name="Metric4"/>
</event>
</ukm-configuration>
""".strip())
expected_errors = [
"Unknown enum BadEnum in ukm metric Event2:Metric1.",
]
expected_warnings = [
"Warning: Neither 'enum' or 'unit' is specified for ukm metric "
"Event2:Metric4.",
]
validator = xml_validations.UkmXmlValidation(ukm_config)
success, errors, warnings = validator.checkMetricTypeIsSpecified()
self.assertFalse(success)
self.assertListEqual(expected_errors, errors)
self.assertListEqual(expected_warnings, warnings)
def testCheckLocalMetricIsAggregated(self):
bad_ukm_config = self.toUkmConfig("""
<ukm-configuration>
<event name="Event">
<metric name="M1" enum="Enum1"/>
<metric name="M2" enum="Enum2">
<aggregation>
<history>
<index fields="metrics.M1,metrics.M4,profile.country"/>
<statistics>
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
<metric name="M3" unit="ms">
<aggregation>
<history>
<index fields="metrics.M1,metrics.M2,metrics.M4"/>
<statistics>
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
<metric name="M4"/>
</event>
</ukm-configuration>
""".strip())
expected_errors = [
xml_validations.INVALID_LOCAL_METRIC_FIELD_ERROR %(
{'event':'Event', 'metric':'M2', 'invalid_metrics':'M1, M4'}),
xml_validations.INVALID_LOCAL_METRIC_FIELD_ERROR %(
{'event':'Event', 'metric':'M3', 'invalid_metrics':'M1, M4'}),
]
validator = xml_validations.UkmXmlValidation(bad_ukm_config)
success, errors = validator.checkLocalMetricIsAggregated()
self.assertFalse(success)
self.assertListEqual(expected_errors, errors)
good_ukm_config = self.toUkmConfig("""
<ukm-configuration>
<event name="Event">
<metric name="M1" enum="Enum1">
<aggregation>
<history>
<statistics export="False">
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
<metric name="M2" enum="Enum2">
<aggregation>
<history>
<index fields="metrics.M1,metrics.M4,profile.country"/>
<statistics>
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
<metric name="M3" unit="ms">
<aggregation>
<history>
<index fields="metrics.M1,metrics.M2,metrics.M4"/>
<statistics>
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
<metric name="M4">
<aggregation>
<history>
<statistics export="False">
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
</event>
</ukm-configuration>
""".strip())
validator = xml_validations.UkmXmlValidation(good_ukm_config)
success, errors = validator.checkLocalMetricIsAggregated()
self.assertTrue(success)
self.assertListEqual([], errors)
parameters_test_statistics = [
(
"""
<ukm-configuration>
<event name="Test.Event">
<metric name="Test.Metric">
<aggregation>
<history>
<statistics>
<enumeration/>
</statistics>
</history>
</aggregation>
</metric>
</event>
</ukm-configuration>""".strip(),
True,
[]),
(
"""
<ukm-configuration>
<event name="Test.Event">
<metric name="Test.Metric">
<aggregation>
<history>
<statistics/>
</history>
</aggregation>
</metric>
</event>
</ukm-configuration>""".strip(),
False,
[
'Invalid statistics field specification in ukm.xml, in metric '
'Test.Event:Test.Metric. To have a metric aggregated, '
'aggregation, history and statistics tags need to be added along'
' with the type of statistic. See https://chromium.googlesource.'
'com/chromium/src.git/+/main/services/metrics/ukm_api.md#'
'controlling-the-aggregation-of-metrics.'
]),
(
"""
<ukm-configuration>
<event name="Test.Event">
<metric name="Test.Metric">
<aggregation>
<history>
<statistics>
<wrong_tag/>
</statistics>
</history>
</aggregation>
</metric>
</event>
</ukm-configuration>""".strip(),
False,
[
'Invalid statistics field specification in ukm.xml, in metric '
'Test.Event:Test.Metric. To have a metric aggregated, '
'aggregation, history and statistics tags need to be added along'
' with the type of statistic. See https://chromium.googlesource.'
'com/chromium/src.git/+/main/services/metrics/ukm_api.md#'
'controlling-the-aggregation-of-metrics.'
]),
(
"""
<ukm-configuration>
<event name="Test.Event">
<metric name="Test.Metric">
<aggregation>
<history>
<statistics>
<quantiles type="wrong-type"/>
</statistics>
</history>
</aggregation>
</metric>
</event>
</ukm-configuration>""".strip(),
False,
[
'Invalid statistics field specification in ukm.xml, in metric '
'Test.Event:Test.Metric. To have a metric aggregated, '
'aggregation, history and statistics tags need to be added along'
' with the type of statistic. See https://chromium.googlesource.'
'com/chromium/src.git/+/main/services/metrics/ukm_api.md#'
'controlling-the-aggregation-of-metrics.'
])
]
def testStatisticsNonEmptyValid(self):
'''Validate passed parameters against checkStatisticsNonEmptyValid.'''
for config, ex_success, ex_error in self.parameters_test_statistics:
ukm_config = self.toUkmConfig(config)
validator = xml_validations.UkmXmlValidation(ukm_config)
result_success, result_error = validator.checkStatisticsNonEmptyValid()
self.assertTrue(result_success) if ex_success else self.assertFalse(
result_success)
self.assertListEqual(ex_error, result_error)
if __name__ == '__main__':
unittest.main()