1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tradefed.util; 18 19 import com.android.ddmlib.IShellOutputReceiver; 20 import com.android.ddmlib.MultiLineReceiver; 21 import com.android.tradefed.log.LogUtil.CLog; 22 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Collections; 26 import java.util.HashSet; 27 import java.util.List; 28 import java.util.Objects; 29 import java.util.Set; 30 import java.util.regex.Matcher; 31 import java.util.regex.Pattern; 32 33 /** 34 * A {@link IShellOutputReceiver} that parses the output of a 'pm list instrumentation' query 35 */ 36 public class ListInstrumentationParser extends MultiLineReceiver { 37 38 // Each line of output from `pm list instrumentation` has the following format: 39 // instrumentation:com.example.test/android.test.InstrumentationTestRunner (target=com.example) 40 private static final Pattern LIST_INSTR_PATTERN = 41 Pattern.compile("instrumentation:(.+)/(.+) \\(target=(.+)\\)"); 42 43 // A set of shardable instrumentation runner names. A limitation of the `pm list 44 // instrumentation` output is that Tradefed will be unable to tell whether or not an 45 // Instrumentation is shardable. A workaround is to have a list of shardable instrumentation 46 // runners, and check if a target uses that particular runner, although this means that any 47 // subclasses or other custom runner classes won't be acknowledged as shardable. 48 public static final Set<String> SHARDABLE_RUNNERS = 49 new HashSet<>( 50 Arrays.asList( 51 "android.support.test.runner.AndroidJUnitRunner", 52 "androidx.test.runner.AndroidJUnitRunner")); 53 54 private List<InstrumentationTarget> mInstrumentationTargets = new ArrayList<>(); 55 56 public static class InstrumentationTarget implements Comparable<InstrumentationTarget> { 57 public final String packageName; 58 public final String runnerName; 59 public final String targetName; 60 InstrumentationTarget(String packageName, String runnerName, String targetName)61 public InstrumentationTarget(String packageName, String runnerName, String targetName) { 62 this.packageName = packageName; 63 this.runnerName = runnerName; 64 this.targetName = targetName; 65 } 66 67 /** 68 * {@inheritDoc} 69 */ 70 @Override equals(Object object)71 public boolean equals(Object object) { 72 if (object instanceof InstrumentationTarget) { 73 InstrumentationTarget that = (InstrumentationTarget)object; 74 return Objects.equals(this.packageName, that.packageName) 75 && Objects.equals(this.runnerName, that.runnerName) 76 && Objects.equals(this.targetName, that.targetName); 77 } 78 return false; 79 } 80 81 /** 82 * {@inheritDoc} 83 */ 84 @Override hashCode()85 public int hashCode() { 86 return Objects.hash(packageName, runnerName, targetName); 87 } 88 89 /** 90 * {@inheritDoc} 91 */ 92 @Override compareTo(InstrumentationTarget o)93 public int compareTo(InstrumentationTarget o) { 94 if (!this.packageName.equals(o.packageName)) { 95 return this.packageName.compareTo(o.packageName); 96 } else if (!this.runnerName.equals(o.runnerName)) { 97 return this.runnerName.compareTo(o.runnerName); 98 } 99 return this.targetName.compareTo(o.targetName); 100 } 101 102 /** 103 * {@inheritDoc} 104 */ 105 @Override toString()106 public String toString() { 107 return String.format("instrumentation:%s/%s (target=%s)", 108 packageName, runnerName, targetName); 109 } 110 111 /** 112 * Returns <tt>true</tt> if this instrumentation target is shardable. 113 */ isShardable()114 public boolean isShardable() { 115 return SHARDABLE_RUNNERS.contains(runnerName); 116 } 117 } 118 getInstrumentationTargets()119 public List<InstrumentationTarget> getInstrumentationTargets() { 120 Collections.sort(mInstrumentationTargets); 121 return mInstrumentationTargets; 122 } 123 124 /** 125 * {@inheritDoc} 126 */ 127 @Override isCancelled()128 public boolean isCancelled() { 129 return false; 130 } 131 132 /** 133 * {@inheritDoc} 134 */ 135 @Override processNewLines(String[] lines)136 public void processNewLines(String[] lines) { 137 for (String line : lines) { 138 CLog.d(line); 139 Matcher m = LIST_INSTR_PATTERN.matcher(line); 140 if (m.find()) { 141 mInstrumentationTargets.add( 142 new InstrumentationTarget(m.group(1), m.group(2), m.group(3))); 143 } 144 } 145 } 146 } 147