k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/metrics/bigquery_test.py (about)

     1  #!/usr/bin/env python3
     2  
     3  # Copyright 2017 The Kubernetes Authors.
     4  #
     5  # Licensed under the Apache License, Version 2.0 (the "License");
     6  # you may not use this file except in compliance with the License.
     7  # You may obtain a copy of the License at
     8  #
     9  #     http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  
    17  """Tests for bigquery.py"""
    18  
    19  import argparse
    20  import os
    21  import re
    22  import shutil
    23  import sys
    24  import tempfile
    25  import unittest
    26  
    27  import ruamel.yaml as yaml
    28  
    29  import bigquery
    30  
    31  class TestBigquery(unittest.TestCase):
    32      """Tests the bigquery scenario."""
    33  
    34      def test_configs(self):
    35          """All yaml files in metrics are valid."""
    36          config_metrics = set()
    37          for path in bigquery.all_configs(search='**'):
    38              name = os.path.basename(path)
    39              if name in ['BUILD', 'BUILD.bazel', 'README.md']:
    40                  continue
    41              if not path.endswith('.yaml'):
    42                  self.fail('Only .yaml files allowed: %s' % path)
    43  
    44              with open(path) as config_file:
    45                  try:
    46                      config = yaml.safe_load(config_file)
    47                  except yaml.YAMLError:
    48                      self.fail(path)
    49                  self.assertIn('metric', config)
    50                  self.assertIn('query', config)
    51                  self.assertIn('jqfilter', config)
    52                  self.assertIn('description', config)
    53                  metric = config['metric'].strip()
    54                  bigquery.validate_metric_name(metric)
    55                  config_metrics.add(metric)
    56          configs = bigquery.all_configs()
    57          self.assertTrue(all(p.endswith('.yaml') for p in configs), configs)
    58  
    59          # Check that the '**' search finds the same number of yaml
    60          # files as the default search.
    61          self.assertEqual(len(configs), len(config_metrics), "verify the `metric` feild is unique")
    62  
    63          # Check that config files correlate with metrics listed in
    64          # test-infra/metrics/README.md.
    65          with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme_file:
    66              readme = readme_file.read()
    67  
    68          readme_metrics = set(re.findall(
    69              r'\(http://storage\.googleapis\.com/k8s-metrics/([\w-]+)-latest\.json\)',
    70              readme,
    71          ))
    72          missing = config_metrics - readme_metrics
    73          if missing:
    74              self.fail(
    75                  'test-infra/metrics/README.md is missing entries for metrics: %s.'
    76                  % ', '.join(sorted(missing)),
    77              )
    78          extra = readme_metrics - config_metrics
    79          if extra:
    80              self.fail(
    81                  'test-infra/metrics/README.md includes metrics that are missing config files: %s.'
    82                  % ', '.join(sorted(extra)),
    83              )
    84  
    85          # Check that all configs are linked in readme.
    86          self.assertTrue(all(os.path.basename(p) in readme for p in configs))
    87  
    88      def test_jq(self):
    89          """do_jq executes a jq filter properly."""
    90          def check(expr, data, expected):
    91              """Check a test scenario."""
    92              with open(self.data_filename, 'w') as data_file:
    93                  data_file.write(data)
    94              bigquery.do_jq(
    95                  expr,
    96                  self.data_filename,
    97                  self.out_filename,
    98                  jq_bin=ARGS.jq,
    99              )
   100              with open(self.out_filename) as out_file:
   101                  actual = out_file.read().replace(' ', '').replace('\n', '')
   102                  self.assertEqual(actual, expected)
   103  
   104          check(
   105              expr='.',
   106              data='{ "field": "value" }',
   107              expected='{"field":"value"}',
   108          )
   109          check(
   110              expr='.field',
   111              data='{ "field": "value" }',
   112              expected='"value"',
   113          )
   114  
   115      def test_validate_metric_name(self):
   116          """validate_metric_name rejects invalid metric names."""
   117          bigquery.validate_metric_name('normal')
   118  
   119          def check(test):
   120              """Check invalid names."""
   121              self.assertRaises(ValueError, bigquery.validate_metric_name, test)
   122  
   123          check('invalid#metric')
   124          check('invalid/metric')
   125          check('in\\valid')
   126          check('invalid?yes')
   127          check('*invalid')
   128          check('[metric]')
   129          check('metric\n')
   130          check('met\ric')
   131          check('metric& invalid')
   132  
   133      def setUp(self):
   134          self.assertTrue(ARGS.jq)
   135          self.tmpdir = tempfile.mkdtemp(prefix='bigquery_test_')
   136          self.out_filename = os.path.join(self.tmpdir, 'out.json')
   137          self.data_filename = os.path.join(self.tmpdir, 'data.json')
   138  
   139      def tearDown(self):
   140          shutil.rmtree(self.tmpdir)
   141  
   142  if __name__ == '__main__':
   143      PARSER = argparse.ArgumentParser()
   144      PARSER.add_argument('--jq', default='jq', help='path to jq binary')
   145      ARGS, _ = PARSER.parse_known_args()
   146  
   147      # Remove the --jq flag and its value so that unittest.main can parse the remaining args without
   148      # complaining about an unknown flag.
   149      for i in range(len(sys.argv)):
   150          if sys.argv[i].startswith('--jq'):
   151              arg = sys.argv.pop(i)
   152              if '=' not in arg:
   153                  del sys.argv[i]
   154              break
   155  
   156      unittest.main()