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 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.Collections; 25 import java.util.HashSet; 26 import java.util.List; 27 import java.util.Objects; 28 import java.util.regex.Matcher; 29 import java.util.regex.Pattern; 30 import java.util.Set; 31 32 /** 33 * A {@link IShellOutputReceiver} that parses the output of a 'pm list instrumentation' query 34 */ 35 public class ListInstrumentationParser extends MultiLineReceiver { 36 37 // Each line of output from `pm list instrumentation` has the following format: 38 // instrumentation:com.example.test/android.test.InstrumentationTestRunner (target=com.example) 39 private static final Pattern LIST_INSTR_PATTERN = 40 Pattern.compile("instrumentation:(.+)/(.+) \\(target=(.+)\\)"); 41 42 // A set of shardable instrumentation runner names. A limitation of the `pm list 43 // instrumentation` output is that Tradefed will be unable to tell whether or not an 44 // Instrumentation is shardable. A workaround is to have a list of shardable instrumentation 45 // runners, and check if a target uses that particular runner, although this means that any 46 // subclasses or other custom runner classes won't be acknowledged as shardable. 47 public static final Set<String> SHARDABLE_RUNNERS = new HashSet<>(Arrays.asList( 48 "android.support.test.runner.AndroidJUnitRunner")); 49 50 private List<InstrumentationTarget> mInstrumentationTargets = new ArrayList<>(); 51 52 public static class InstrumentationTarget implements Comparable<InstrumentationTarget> { 53 public final String packageName; 54 public final String runnerName; 55 public final String targetName; 56 InstrumentationTarget(String packageName, String runnerName, String targetName)57 public InstrumentationTarget(String packageName, String runnerName, String targetName) { 58 this.packageName = packageName; 59 this.runnerName = runnerName; 60 this.targetName = targetName; 61 } 62 63 /** 64 * {@inheritDoc} 65 */ 66 @Override equals(Object object)67 public boolean equals(Object object) { 68 if (object instanceof InstrumentationTarget) { 69 InstrumentationTarget that = (InstrumentationTarget)object; 70 return Objects.equals(this.packageName, that.packageName) 71 && Objects.equals(this.runnerName, that.runnerName) 72 && Objects.equals(this.targetName, that.targetName); 73 } 74 return false; 75 } 76 77 /** 78 * {@inheritDoc} 79 */ 80 @Override hashCode()81 public int hashCode() { 82 return Objects.hash(packageName, runnerName, targetName); 83 } 84 85 /** 86 * {@inheritDoc} 87 */ 88 @Override compareTo(InstrumentationTarget o)89 public int compareTo(InstrumentationTarget o) { 90 if (!this.packageName.equals(o.packageName)) { 91 return this.packageName.compareTo(o.packageName); 92 } else if (!this.runnerName.equals(o.runnerName)) { 93 return this.runnerName.compareTo(o.runnerName); 94 } 95 return this.targetName.compareTo(o.targetName); 96 } 97 98 /** 99 * {@inheritDoc} 100 */ 101 @Override toString()102 public String toString() { 103 return String.format("instrumentation:%s/%s (target=%s)", 104 packageName, runnerName, targetName); 105 } 106 107 /** 108 * Returns <tt>true</tt> if this instrumentation target is shardable. 109 */ isShardable()110 public boolean isShardable() { 111 return SHARDABLE_RUNNERS.contains(runnerName); 112 } 113 } 114 getInstrumentationTargets()115 public List<InstrumentationTarget> getInstrumentationTargets() { 116 Collections.sort(mInstrumentationTargets); 117 return mInstrumentationTargets; 118 } 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override isCancelled()124 public boolean isCancelled() { 125 return false; 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override processNewLines(String[] lines)132 public void processNewLines(String[] lines) { 133 for (String line : lines) { 134 Matcher m = LIST_INSTR_PATTERN.matcher(line); 135 if (m.find()) { 136 mInstrumentationTargets.add( 137 new InstrumentationTarget(m.group(1), m.group(2), m.group(3))); 138 } 139 } 140 } 141 } 142