|
32 | 32 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
33 | 33 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | 34 |
|
35 | | -import socket |
| 35 | +import socket, re, os |
36 | 36 |
|
37 | 37 | from django.conf import settings |
38 | 38 | from django.template import TemplateDoesNotExist |
|
44 | 44 | import ietf.utils.mail |
45 | 45 |
|
46 | 46 | loaded_templates = set() |
| 47 | +visited_urls = set() |
47 | 48 | test_database_name = None |
48 | 49 | old_destroy = None |
49 | 50 | old_create = None |
@@ -74,25 +75,111 @@ def template_coverage_loader(template_name, dirs): |
74 | 75 |
|
75 | 76 | template_coverage_loader.is_usable = True |
76 | 77 |
|
| 78 | +class RecordUrlsMiddleware(object): |
| 79 | + def process_request(self, request): |
| 80 | + visited_urls.add(request.path) |
| 81 | + |
| 82 | +def get_patterns(module): |
| 83 | + all = [] |
| 84 | + try: |
| 85 | + patterns = module.urlpatterns |
| 86 | + except AttributeError: |
| 87 | + patterns = [] |
| 88 | + for item in patterns: |
| 89 | + try: |
| 90 | + subpatterns = get_patterns(item.urlconf_module) |
| 91 | + except: |
| 92 | + subpatterns = [""] |
| 93 | + for sub in subpatterns: |
| 94 | + if not sub: |
| 95 | + all.append(item.regex.pattern) |
| 96 | + elif sub.startswith("^"): |
| 97 | + all.append(item.regex.pattern + sub[1:]) |
| 98 | + else: |
| 99 | + all.append(item.regex.pattern + ".*" + sub) |
| 100 | + return all |
| 101 | + |
| 102 | +def check_url_coverage(): |
| 103 | + patterns = get_patterns(ietf.urls) |
| 104 | + |
| 105 | + IGNORED_PATTERNS = ("admin",) |
| 106 | + |
| 107 | + patterns = [(p, re.compile(p)) for p in patterns if p[1:].split("/")[0] not in IGNORED_PATTERNS] |
| 108 | + |
| 109 | + covered = set() |
| 110 | + for url in visited_urls: |
| 111 | + for pattern, compiled in patterns: |
| 112 | + if pattern not in covered and compiled.match(url[1:]): # strip leading / |
| 113 | + covered.add(pattern) |
| 114 | + break |
| 115 | + |
| 116 | + missing = list(set(p for p, compiled in patterns) - covered) |
| 117 | + |
| 118 | + if missing: |
| 119 | + print "The following URL patterns were not tested" |
| 120 | + for pattern in sorted(missing): |
| 121 | + print " Not tested", pattern |
| 122 | + |
| 123 | +def get_templates(): |
| 124 | + templates = set() |
| 125 | + # Should we teach this to use TEMPLATE_DIRS? |
| 126 | + templatepath = os.path.join(settings.BASE_DIR, "templates") |
| 127 | + for root, dirs, files in os.walk(templatepath): |
| 128 | + if ".svn" in dirs: |
| 129 | + dirs.remove(".svn") |
| 130 | + relative_path = root[len(templatepath)+1:] |
| 131 | + for file in files: |
| 132 | + if file.endswith("~") or file.startswith("#"): |
| 133 | + continue |
| 134 | + if relative_path == "": |
| 135 | + templates.add(file) |
| 136 | + else: |
| 137 | + templates.add(os.path.join(relative_path, file)) |
| 138 | + return templates |
| 139 | + |
| 140 | +def check_template_coverage(): |
| 141 | + all_templates = get_templates() |
| 142 | + |
| 143 | + not_loaded = list(all_templates - loaded_templates) |
| 144 | + if not_loaded: |
| 145 | + print "The following templates were never loaded during test" |
| 146 | + for t in sorted(not_loaded): |
| 147 | + print " Not loaded", t |
| 148 | + |
77 | 149 | def run_tests_1(test_labels, *args, **kwargs): |
78 | 150 | global old_destroy, old_create, test_database_name |
79 | 151 | from django.db import connection |
80 | 152 | old_create = connection.creation.__class__.create_test_db |
81 | 153 | connection.creation.__class__.create_test_db = safe_create_1 |
82 | 154 | old_destroy = connection.creation.__class__.destroy_test_db |
83 | 155 | connection.creation.__class__.destroy_test_db = safe_destroy_0_1 |
84 | | - if not test_labels: |
| 156 | + |
| 157 | + check_coverage = not test_labels |
| 158 | + |
| 159 | + if check_coverage: |
85 | 160 | settings.TEMPLATE_LOADERS = ('ietf.utils.test_runner.template_coverage_loader',) + settings.TEMPLATE_LOADERS |
86 | | - test_labels = [x.split(".")[-1] for x in settings.INSTALLED_APPS if x.startswith("ietf")] + ['redirects.TemplateCoverageTestCase',] |
| 161 | + settings.MIDDLEWARE_CLASSES = ('ietf.utils.test_runner.RecordUrlsMiddleware',) + settings.MIDDLEWARE_CLASSES |
| 162 | + |
| 163 | + if not test_labels: |
| 164 | + test_labels = [x.split(".")[-1] for x in settings.INSTALLED_APPS if x.startswith("ietf")] |
| 165 | + |
87 | 166 | if settings.SITE_ID != 1: |
88 | 167 | print " Changing SITE_ID to '1' during testing." |
89 | 168 | settings.SITE_ID = 1 |
| 169 | + |
90 | 170 | if settings.TEMPLATE_STRING_IF_INVALID != '': |
91 | 171 | print " Changing TEMPLATE_STRING_IF_INVALID to '' during testing." |
92 | 172 | settings.TEMPLATE_STRING_IF_INVALID = '' |
| 173 | + |
93 | 174 | assert(not settings.IDTRACKER_BASE_URL.endswith('/')) |
94 | | - kwargs["verbosity"] = kwargs["verbosity"] |
95 | | - return django_run_tests(test_labels, *args, **kwargs) |
| 175 | + |
| 176 | + results = django_run_tests(test_labels, *args, **kwargs) |
| 177 | + |
| 178 | + if check_coverage: |
| 179 | + check_url_coverage() |
| 180 | + check_template_coverage() |
| 181 | + |
| 182 | + return results |
96 | 183 |
|
97 | 184 | def run_tests(*args, **kwargs): |
98 | 185 | # Tests that involve switching back and forth between the real |
|
0 commit comments