1#!/usr/bin/env python3 2# 3# Copyright (C) 2024 The Android Open Source Project 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""" 18Tool to bulk-enable tests that are now passing on Ravenwood. 19 20Currently only offers to include classes which are fully passing; ignores 21classes that have partial success. 22 23Typical usage: 24$ RAVENWOOD_RUN_DISABLED_TESTS=1 atest MyTestsRavenwood 25$ cd /path/to/tests/root 26$ python bulk_enable.py /path/to/atest/output/host_log.txt 27""" 28 29import collections 30import os 31import re 32import subprocess 33import sys 34 35re_result = re.compile("I/ModuleListener.+?null-device-0 (.+?)#(.+?) ([A-Z_]+)(.*)$") 36 37DRY_RUN = "-n" in sys.argv 38 39ANNOTATION = "@android.platform.test.annotations.EnabledOnRavenwood" 40SED_ARG = "s/^((public )?class )/%s\\n\\1/g" % (ANNOTATION) 41 42STATE_PASSED = "PASSED" 43STATE_FAILURE = "FAILURE" 44STATE_ASSUMPTION_FAILURE = "ASSUMPTION_FAILURE" 45STATE_CANDIDATE = "CANDIDATE" 46 47stats_total = collections.defaultdict(int) 48stats_class = collections.defaultdict(lambda: collections.defaultdict(int)) 49stats_method = collections.defaultdict() 50 51with open(sys.argv[-1]) as f: 52 for line in f.readlines(): 53 result = re_result.search(line) 54 if result: 55 clazz, method, state, msg = result.groups() 56 if state == STATE_FAILURE and "actually passed under Ravenwood" in msg: 57 state = STATE_CANDIDATE 58 stats_total[state] += 1 59 stats_class[clazz][state] += 1 60 stats_method[(clazz, method)] = state 61 62# Find classes who are fully "candidates" (would be entirely green if enabled) 63num_enabled = 0 64for clazz in stats_class.keys(): 65 stats = stats_class[clazz] 66 if STATE_CANDIDATE in stats and len(stats) == 1: 67 num_enabled += stats[STATE_CANDIDATE] 68 print("Enabling fully-passing class", clazz) 69 clazz_match = re.compile("%s\.(kt|java)" % (clazz.split(".")[-1])) 70 for root, dirs, files in os.walk("."): 71 for f in files: 72 if clazz_match.match(f) and not DRY_RUN: 73 path = os.path.join(root, f) 74 subprocess.run(["sed", "-i", "-E", SED_ARG, path]) 75 76print("Overall stats", stats_total) 77print("Candidates actually enabled", num_enabled) 78