xml_validations_test.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. # Copyright 2019 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. import unittest
  5. import xml_validations
  6. from xml.dom import minidom
  7. class UkmXmlValidationTest(unittest.TestCase):
  8. def toUkmConfig(self, xml_string):
  9. dom = minidom.parseString(xml_string)
  10. [ukm_config] = dom.getElementsByTagName('ukm-configuration')
  11. return ukm_config
  12. def testEventsHaveOwners(self):
  13. ukm_config = self.toUkmConfig("""
  14. <ukm-configuration>
  15. <event name="Event1">
  16. <owner>dev@chromium.org</owner>
  17. </event>
  18. </ukm-configuration>
  19. """.strip())
  20. validator = xml_validations.UkmXmlValidation(ukm_config)
  21. success, errors = validator.checkEventsHaveOwners()
  22. self.assertTrue(success)
  23. self.assertListEqual([], errors)
  24. def testEventsMissingOwners(self):
  25. ukm_config = self.toUkmConfig("""
  26. <ukm-configuration>
  27. <event name="Event1"/>
  28. <event name="Event2">
  29. <owner></owner>
  30. </event>
  31. <event name="Event3">
  32. <owner>johndoe</owner>
  33. </event>
  34. </ukm-configuration>
  35. """.strip())
  36. expected_errors = [
  37. "<owner> tag is required for event 'Event1'.",
  38. "<owner> tag for event 'Event2' should not be empty.",
  39. "<owner> tag for event 'Event3' expects a Chromium or Google email "
  40. "address.",
  41. ]
  42. validator = xml_validations.UkmXmlValidation(ukm_config)
  43. success, errors = validator.checkEventsHaveOwners()
  44. self.assertFalse(success)
  45. self.assertListEqual(expected_errors, errors)
  46. def testMetricHasUndefinedEnum(self):
  47. ukm_config = self.toUkmConfig("""
  48. <ukm-configuration>
  49. <event name="Event1">
  50. <metric name="Metric2" enum="FeatureObserver"/>
  51. </event>
  52. <event name="Event2">
  53. <metric name="Metric1" enum="BadEnum"/>
  54. <metric name="Metric2" enum="FeatureObserver"/>
  55. <metric name="Metric3" unit="ms"/>
  56. <metric name="Metric4"/>
  57. </event>
  58. </ukm-configuration>
  59. """.strip())
  60. expected_errors = [
  61. "Unknown enum BadEnum in ukm metric Event2:Metric1.",
  62. ]
  63. expected_warnings = [
  64. "Warning: Neither 'enum' or 'unit' is specified for ukm metric "
  65. "Event2:Metric4.",
  66. ]
  67. validator = xml_validations.UkmXmlValidation(ukm_config)
  68. success, errors, warnings = validator.checkMetricTypeIsSpecified()
  69. self.assertFalse(success)
  70. self.assertListEqual(expected_errors, errors)
  71. self.assertListEqual(expected_warnings, warnings)
  72. def testCheckLocalMetricIsAggregated(self):
  73. bad_ukm_config = self.toUkmConfig("""
  74. <ukm-configuration>
  75. <event name="Event">
  76. <metric name="M1" enum="Enum1"/>
  77. <metric name="M2" enum="Enum2">
  78. <aggregation>
  79. <history>
  80. <index fields="metrics.M1,metrics.M4,profile.country"/>
  81. <statistics>
  82. <enumeration/>
  83. </statistics>
  84. </history>
  85. </aggregation>
  86. </metric>
  87. <metric name="M3" unit="ms">
  88. <aggregation>
  89. <history>
  90. <index fields="metrics.M1,metrics.M2,metrics.M4"/>
  91. <statistics>
  92. <enumeration/>
  93. </statistics>
  94. </history>
  95. </aggregation>
  96. </metric>
  97. <metric name="M4"/>
  98. </event>
  99. </ukm-configuration>
  100. """.strip())
  101. expected_errors = [
  102. xml_validations.INVALID_LOCAL_METRIC_FIELD_ERROR %(
  103. {'event':'Event', 'metric':'M2', 'invalid_metrics':'M1, M4'}),
  104. xml_validations.INVALID_LOCAL_METRIC_FIELD_ERROR %(
  105. # M3 is not included in invalid_metrics because it's configured to
  106. # aggregate as an enumeration.
  107. {'event':'Event', 'metric':'M3', 'invalid_metrics':'M1, M4'}),
  108. ]
  109. validator = xml_validations.UkmXmlValidation(bad_ukm_config)
  110. success, errors = validator.checkLocalMetricIsAggregated()
  111. self.assertFalse(success)
  112. self.assertListEqual(expected_errors, errors)
  113. # Add aggregation definitions to M1 and M4 to make it valid. Note the
  114. # export="False" that prevents M1 and M4 from being aggregated, and only
  115. # useful as an index field.
  116. good_ukm_config = self.toUkmConfig("""
  117. <ukm-configuration>
  118. <event name="Event">
  119. <metric name="M1" enum="Enum1">
  120. <aggregation>
  121. <history>
  122. <statistics export="False">
  123. <enumeration/>
  124. </statistics>
  125. </history>
  126. </aggregation>
  127. </metric>
  128. <metric name="M2" enum="Enum2">
  129. <aggregation>
  130. <history>
  131. <index fields="metrics.M1,metrics.M4,profile.country"/>
  132. <statistics>
  133. <enumeration/>
  134. </statistics>
  135. </history>
  136. </aggregation>
  137. </metric>
  138. <metric name="M3" unit="ms">
  139. <aggregation>
  140. <history>
  141. <index fields="metrics.M1,metrics.M2,metrics.M4"/>
  142. <statistics>
  143. <enumeration/>
  144. </statistics>
  145. </history>
  146. </aggregation>
  147. </metric>
  148. <metric name="M4">
  149. <aggregation>
  150. <history>
  151. <statistics export="False">
  152. <enumeration/>
  153. </statistics>
  154. </history>
  155. </aggregation>
  156. </metric>
  157. </event>
  158. </ukm-configuration>
  159. """.strip())
  160. validator = xml_validations.UkmXmlValidation(good_ukm_config)
  161. success, errors = validator.checkLocalMetricIsAggregated()
  162. self.assertTrue(success)
  163. self.assertListEqual([], errors)
  164. if __name__ == '__main__':
  165. unittest.main()