#!/usr/bin/env python # ***** BEGIN LICENSE BLOCK ***** # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. # ***** END LICENSE BLOCK ***** """configtest.py Verify the .json and .py files in the configs/ directory are well-formed. Further tests to verify validity would be desirable. This is also a good example script to look at to understand mozharness. """ import os import pprint import sys try: import simplejson as json except ImportError: import json sys.path.insert(1, os.path.dirname(sys.path[0])) from mozharness.base.script import BaseScript # ConfigTest {{{1 class ConfigTest(BaseScript): config_options = [ [ [ "--test-file", ], { "action": "extend", "dest": "test_files", "help": "Specify which config files to test", }, ] ] def __init__(self, require_config_file=False): self.config_files = [] BaseScript.__init__( self, config_options=self.config_options, all_actions=[ "list-config-files", "test-json-configs", "test-python-configs", "summary", ], default_actions=[ "test-json-configs", "test-python-configs", "summary", ], require_config_file=require_config_file, ) def query_config_files(self): """This query method, much like others, caches its runtime settings in self.VAR so we don't have to figure out config_files multiple times. """ if self.config_files: return self.config_files c = self.config if "test_files" in c: self.config_files = c["test_files"] return self.config_files self.debug( "No --test-file(s) specified; defaulting to crawling the configs/ directory." ) config_files = [] for root, dirs, files in os.walk(os.path.join(sys.path[0], "..", "configs")): for name in files: # Hardcode =P if name.endswith(".json") or name.endswith(".py"): if not name.startswith("test_malformed"): config_files.append(os.path.join(root, name)) self.config_files = config_files return self.config_files def list_config_files(self): """Non-default action that is mainly here to demonstrate how non-default actions work in a mozharness script. """ config_files = self.query_config_files() for config_file in config_files: self.info(config_file) def test_json_configs(self): """Currently only "is this well-formed json?" """ config_files = self.query_config_files() filecount = [0, 0] for config_file in config_files: if config_file.endswith(".json"): filecount[0] += 1 self.info("Testing %s." % config_file) contents = self.read_from_file(config_file, verbose=False) try: json.loads(contents) except ValueError: self.add_summary("%s is invalid json." % config_file, level="error") self.error(pprint.pformat(sys.exc_info()[1])) else: self.info("Good.") filecount[1] += 1 if filecount[0]: self.add_summary( "%d of %d json config files were good." % (filecount[1], filecount[0]) ) else: self.add_summary("No json config files to test.") def test_python_configs(self): """Currently only "will this give me a config dictionary?" """ config_files = self.query_config_files() filecount = [0, 0] for config_file in config_files: if config_file.endswith(".py"): filecount[0] += 1 self.info("Testing %s." % config_file) global_dict = {} local_dict = {} try: with open(config_file, "r") as f: exec(f.read(), global_dict, local_dict) except Exception: self.add_summary( "%s is invalid python." % config_file, level="error" ) self.error(pprint.pformat(sys.exc_info()[1])) else: if "config" in local_dict and isinstance( local_dict["config"], dict ): self.info("Good.") filecount[1] += 1 else: self.add_summary( "%s is valid python, " "but doesn't create a config dictionary." % config_file, level="error", ) if filecount[0]: self.add_summary( "%d of %d python config files were good." % (filecount[1], filecount[0]) ) else: self.add_summary("No python config files to test.") # __main__ {{{1 if __name__ == "__main__": config_test = ConfigTest() config_test.run_and_exit()