1#!/usr/bin/env python 2# ***** BEGIN LICENSE BLOCK ***** 3# This Source Code Form is subject to the terms of the Mozilla Public 4# License, v. 2.0. If a copy of the MPL was not distributed with this file, 5# You can obtain one at http://mozilla.org/MPL/2.0/. 6# ***** END LICENSE BLOCK ***** 7"""configtest.py 8 9Verify the .json and .py files in the configs/ directory are well-formed. 10Further tests to verify validity would be desirable. 11 12This is also a good example script to look at to understand mozharness. 13""" 14 15import os 16import pprint 17import sys 18try: 19 import simplejson as json 20except ImportError: 21 import json 22 23sys.path.insert(1, os.path.dirname(sys.path[0])) 24 25from mozharness.base.script import BaseScript 26 27 28# ConfigTest {{{1 29class ConfigTest(BaseScript): 30 config_options = [[ 31 ["--test-file", ], 32 {"action": "extend", 33 "dest": "test_files", 34 "help": "Specify which config files to test" 35 } 36 ]] 37 38 def __init__(self, require_config_file=False): 39 self.config_files = [] 40 BaseScript.__init__(self, config_options=self.config_options, 41 all_actions=['list-config-files', 42 'test-json-configs', 43 'test-python-configs', 44 'summary', 45 ], 46 default_actions=['test-json-configs', 47 'test-python-configs', 48 'summary', 49 ], 50 require_config_file=require_config_file) 51 52 def query_config_files(self): 53 """This query method, much like others, caches its runtime 54 settings in self.VAR so we don't have to figure out config_files 55 multiple times. 56 """ 57 if self.config_files: 58 return self.config_files 59 c = self.config 60 if 'test_files' in c: 61 self.config_files = c['test_files'] 62 return self.config_files 63 self.debug("No --test-file(s) specified; defaulting to crawling the configs/ directory.") 64 config_files = [] 65 for root, dirs, files in os.walk(os.path.join(sys.path[0], "..", 66 "configs")): 67 for name in files: 68 # Hardcode =P 69 if name.endswith(".json") or name.endswith(".py"): 70 if not name.startswith("test_malformed"): 71 config_files.append(os.path.join(root, name)) 72 self.config_files = config_files 73 return self.config_files 74 75 def list_config_files(self): 76 """ Non-default action that is mainly here to demonstrate how 77 non-default actions work in a mozharness script. 78 """ 79 config_files = self.query_config_files() 80 for config_file in config_files: 81 self.info(config_file) 82 83 def test_json_configs(self): 84 """ Currently only "is this well-formed json?" 85 86 """ 87 config_files = self.query_config_files() 88 filecount = [0, 0] 89 for config_file in config_files: 90 if config_file.endswith(".json"): 91 filecount[0] += 1 92 self.info("Testing %s." % config_file) 93 contents = self.read_from_file(config_file, verbose=False) 94 try: 95 json.loads(contents) 96 except ValueError: 97 self.add_summary("%s is invalid json." % config_file, 98 level="error") 99 self.error(pprint.pformat(sys.exc_info()[1])) 100 else: 101 self.info("Good.") 102 filecount[1] += 1 103 if filecount[0]: 104 self.add_summary("%d of %d json config files were good." % 105 (filecount[1], filecount[0])) 106 else: 107 self.add_summary("No json config files to test.") 108 109 def test_python_configs(self): 110 """Currently only "will this give me a config dictionary?" 111 112 """ 113 config_files = self.query_config_files() 114 filecount = [0, 0] 115 for config_file in config_files: 116 if config_file.endswith(".py"): 117 filecount[0] += 1 118 self.info("Testing %s." % config_file) 119 global_dict = {} 120 local_dict = {} 121 try: 122 execfile(config_file, global_dict, local_dict) 123 except Exception: 124 self.add_summary("%s is invalid python." % config_file, 125 level="error") 126 self.error(pprint.pformat(sys.exc_info()[1])) 127 else: 128 if 'config' in local_dict and isinstance(local_dict['config'], dict): 129 self.info("Good.") 130 filecount[1] += 1 131 else: 132 self.add_summary("%s is valid python, " 133 "but doesn't create a config dictionary." % 134 config_file, level="error") 135 if filecount[0]: 136 self.add_summary("%d of %d python config files were good." % 137 (filecount[1], filecount[0])) 138 else: 139 self.add_summary("No python config files to test.") 140 141 142# __main__ {{{1 143if __name__ == '__main__': 144 config_test = ConfigTest() 145 config_test.run_and_exit() 146