diff options
Diffstat (limited to 'src/main/java/com/android/vts/util/FilterUtil.java')
-rw-r--r-- | src/main/java/com/android/vts/util/FilterUtil.java | 537 |
1 files changed, 0 insertions, 537 deletions
diff --git a/src/main/java/com/android/vts/util/FilterUtil.java b/src/main/java/com/android/vts/util/FilterUtil.java deleted file mode 100644 index 5a567e5..0000000 --- a/src/main/java/com/android/vts/util/FilterUtil.java +++ /dev/null @@ -1,537 +0,0 @@ -/** - * Copyright 2016 Google Inc. All Rights Reserved. - * - * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * <p>http://www.apache.org/licenses/LICENSE-2.0 - * - * <p>Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.vts.util; - -import com.android.vts.entity.DeviceInfoEntity; -import com.android.vts.entity.ProfilingPointRunEntity; -import com.android.vts.entity.TestRunEntity; -import com.google.appengine.api.datastore.DatastoreService; -import com.google.appengine.api.datastore.DatastoreServiceFactory; -import com.google.appengine.api.datastore.Entity; -import com.google.appengine.api.datastore.FetchOptions; -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; -import com.google.appengine.api.datastore.Query; -import com.google.appengine.api.datastore.Query.CompositeFilterOperator; -import com.google.appengine.api.datastore.Query.Filter; -import com.google.appengine.api.datastore.Query.FilterOperator; -import com.google.appengine.api.datastore.Query.FilterPredicate; -import com.google.common.collect.Sets; -import com.google.gson.Gson; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.servlet.http.HttpServletRequest; - -/** FilterUtil, a helper class for parsing and matching search queries to data. */ -public class FilterUtil { - protected static final Logger logger = Logger.getLogger(FilterUtil.class.getName()); - private static final String INEQUALITY_REGEX = "(<=|>=|<|>|=)"; - - /** Key class to represent a filter token. */ - public enum FilterKey { - DEVICE_BUILD_ID("deviceBuildId", DeviceInfoEntity.BUILD_ID, true), - BRANCH("branch", DeviceInfoEntity.BRANCH, true), - TARGET("device", DeviceInfoEntity.BUILD_FLAVOR, true), - VTS_BUILD_ID("testBuildId", TestRunEntity.TEST_BUILD_ID, false), - HOSTNAME("hostname", TestRunEntity.HOST_NAME, false), - PASSING("passing", TestRunEntity.PASS_COUNT, false), - NONPASSING("nonpassing", TestRunEntity.FAIL_COUNT, false); - - private static final Map<String, FilterKey> keyMap; - - static { - keyMap = new HashMap<>(); - for (FilterKey k : EnumSet.allOf(FilterKey.class)) { - keyMap.put(k.keyString, k); - } - } - - /** - * Test if a string is a valid device key. - * - * @param keyString The key string. - * @return True if they key string matches a key and the key is a device filter. - */ - public static boolean isDeviceKey(String keyString) { - return keyMap.containsKey(keyString) && keyMap.get(keyString).isDevice; - } - - /** - * Test if a string is a valid test key. - * - * @param keyString The key string. - * @return True if they key string matches a key and the key is a test filter. - */ - public static boolean isTestKey(String keyString) { - return keyMap.containsKey(keyString) && !keyMap.get(keyString).isDevice; - } - - /** - * Parses a key string into a key. - * - * @param keyString The key string. - * @return The key matching the key string. - */ - public static FilterKey parse(String keyString) { - return keyMap.get(keyString); - } - - private final String keyString; - private final String property; - private final boolean isDevice; - - /** - * Constructs a key with the specified key string. - * - * @param keyString The identifying key string. - * @param propertyName The name of the property to match. - */ - private FilterKey(String keyString, String propertyName, boolean isDevice) { - this.keyString = keyString; - this.property = propertyName; - this.isDevice = isDevice; - } - - /** - * Return a filter predicate for string equality. - * - * @param matchString The string to match. - * @return A filter predicate enforcing equality on the property. - */ - public FilterPredicate getFilterForString(String matchString) { - return new FilterPredicate(this.property, FilterOperator.EQUAL, matchString); - } - - /** - * Return a filter predicate for number inequality or equality. - * - * @param matchNumber A string, either a number or an inequality symbol followed by a - * number. - * @return A filter predicate enforcing equality on the property, or null if invalid. - */ - public FilterPredicate getFilterForNumber(String matchNumber) { - String numberString = matchNumber.trim(); - Pattern p = Pattern.compile(INEQUALITY_REGEX); - Matcher m = p.matcher(numberString); - - // Default operator is equality. - FilterOperator op = FilterOperator.EQUAL; - - // Determine if there is an inequality operator. - if (m.find() && m.start() == 0 && m.end() != numberString.length()) { - String opString = m.group(); - - // Inequality operator can be <=, <, >, >=, or =. - if (opString.equals("<=")) { - op = FilterOperator.LESS_THAN_OR_EQUAL; - } else if (opString.equals("<")) { - op = FilterOperator.LESS_THAN; - } else if (opString.equals(">")) { - op = FilterOperator.GREATER_THAN; - } else if (opString.equals(">=")) { - op = FilterOperator.GREATER_THAN_OR_EQUAL; - } else if (!opString.equals("=")) { // unrecognized inequality. - return null; - } - numberString = matchNumber.substring(m.end()).trim(); - } - try { - long number = Long.parseLong(numberString); - return new FilterPredicate(this.property, op, number); - } catch (NumberFormatException e) { - // invalid number - return null; - } - } - - /** - * Get the enum value - * - * @return The string value associated with the key. - */ - public String getValue() { - return this.keyString; - } - } - - /** - * Get the common elements among multiple collections. - * - * @param collections The collections containing all sub collections to find common element. - * @return The common elements set found from the collections param. - */ - public static <T> Set<T> getCommonElements(Collection<? extends Collection<T>> collections) { - - Set<T> common = new LinkedHashSet<T>(); - if (!collections.isEmpty()) { - Iterator<? extends Collection<T>> iterator = collections.iterator(); - common.addAll(iterator.next()); - while (iterator.hasNext()) { - common.retainAll(iterator.next()); - } - } - return common; - } - - /** - * Get the first value associated with the key in the parameter map. - * - * @param parameterMap The parameter map with string keys and (Object) String[] values. - * @param key The key whose value to get. - * @return The first value associated with the provided key. - */ - public static String getFirstParameter(Map<String, String[]> parameterMap, String key) { - String[] values = (String[]) parameterMap.get(key); - if (values.length == 0) return null; - return values[0]; - } - - /** - * Get a filter on devices from a user search query. - * - * @param parameterMap The key-value map of url parameters. - * @return A filter with the values from the user search parameters. - */ - public static Filter getUserDeviceFilter(Map<String, String[]> parameterMap) { - Filter deviceFilter = null; - for (String key : parameterMap.keySet()) { - if (!FilterKey.isDeviceKey(key)) continue; - String value = getFirstParameter(parameterMap, key); - if (value == null) continue; - FilterKey filterKey = FilterKey.parse(key); - Filter f = filterKey.getFilterForString(value); - if (deviceFilter == null) { - deviceFilter = f; - } else { - deviceFilter = CompositeFilterOperator.and(deviceFilter, f); - } - } - return deviceFilter; - } - - /** - * Get a list of test filters given the user parameters. - * - * @param parameterMap The key-value map of url parameters. - * @return A list of filters, each having at most one inequality filter. - */ - public static List<Filter> getUserTestFilters(Map<String, String[]> parameterMap) { - List<Filter> userFilters = new ArrayList<>(); - for (String key : parameterMap.keySet()) { - if (!FilterKey.isTestKey(key)) continue; - String stringValue = getFirstParameter(parameterMap, key); - if (stringValue == null) continue; - FilterKey filterKey = FilterKey.parse(key); - switch (filterKey) { - case NONPASSING: - case PASSING: - userFilters.add(filterKey.getFilterForNumber(stringValue)); - break; - case HOSTNAME: - case VTS_BUILD_ID: - userFilters.add(filterKey.getFilterForString(stringValue.toLowerCase())); - break; - default: - continue; - } - } - return userFilters; - } - - /** - * Get a filter on the test run type. - * - * @param showPresubmit True to display presubmit tests. - * @param showPostsubmit True to display postsubmit tests. - * @param unfiltered True if no filtering should be applied. - * @return A filter on the test type. - */ - public static Filter getTestTypeFilter( - boolean showPresubmit, boolean showPostsubmit, boolean unfiltered) { - if (unfiltered) { - return null; - } else if (showPresubmit && !showPostsubmit) { - return new FilterPredicate( - TestRunEntity.TYPE, - FilterOperator.EQUAL, - TestRunEntity.TestRunType.PRESUBMIT.getNumber()); - } else if (showPostsubmit && !showPresubmit) { - return new FilterPredicate( - TestRunEntity.TYPE, - FilterOperator.EQUAL, - TestRunEntity.TestRunType.POSTSUBMIT.getNumber()); - } else { - List<Integer> types = new ArrayList<>(); - types.add(TestRunEntity.TestRunType.PRESUBMIT.getNumber()); - types.add(TestRunEntity.TestRunType.POSTSUBMIT.getNumber()); - return new FilterPredicate(TestRunEntity.TYPE, FilterOperator.IN, types); - } - } - - /** - * Get a filter for profiling points between a specified time window. - * - * @param grandparentKey The key of the profiling point grandparent entity. - * @param parentKind The kind of the profiling point parent. - * @param startTime The start time of the window, or null if unbounded. - * @param endTime The end time of the window, or null if unbounded. - * @return A filter to query for profiling points in the time window. - */ - public static Filter getProfilingTimeFilter( - Key grandparentKey, String parentKind, Long startTime, Long endTime) { - if (startTime == null && endTime == null) { - endTime = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); - } - Filter startFilter = null; - Filter endFilter = null; - Filter filter = null; - if (startTime != null) { - Key minRunKey = KeyFactory.createKey(grandparentKey, parentKind, startTime); - Key startKey = - KeyFactory.createKey( - minRunKey, ProfilingPointRunEntity.KIND, String.valueOf((char) 0x0)); - startFilter = - new FilterPredicate( - Entity.KEY_RESERVED_PROPERTY, - FilterOperator.GREATER_THAN_OR_EQUAL, - startKey); - filter = startFilter; - } - if (endTime != null) { - Key maxRunKey = KeyFactory.createKey(grandparentKey, parentKind, endTime); - Key endKey = - KeyFactory.createKey( - maxRunKey, ProfilingPointRunEntity.KIND, String.valueOf((char) 0xff)); - endFilter = - new FilterPredicate( - Entity.KEY_RESERVED_PROPERTY, - FilterOperator.LESS_THAN_OR_EQUAL, - endKey); - filter = endFilter; - } - if (startFilter != null && endFilter != null) { - filter = CompositeFilterOperator.and(startFilter, endFilter); - } - return filter; - } - - /** - * Get a filter for device information between a specified time window. - * - * @param grandparentKey The key of the device's grandparent entity. - * @param parentKind The kind of the device's parent. - * @param startTime The start time of the window, or null if unbounded. - * @param endTime The end time of the window, or null if unbounded. - * @return A filter to query for devices in the time window. - */ - public static Filter getDeviceTimeFilter( - Key grandparentKey, String parentKind, Long startTime, Long endTime) { - if (startTime == null && endTime == null) { - endTime = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); - } - Filter startFilter = null; - Filter endFilter = null; - Filter filter = null; - if (startTime != null) { - Key minRunKey = KeyFactory.createKey(grandparentKey, parentKind, startTime); - Key startKey = KeyFactory.createKey(minRunKey, DeviceInfoEntity.KIND, 1); - startFilter = - new FilterPredicate( - Entity.KEY_RESERVED_PROPERTY, - FilterOperator.GREATER_THAN_OR_EQUAL, - startKey); - filter = startFilter; - } - if (endTime != null) { - Key maxRunKey = KeyFactory.createKey(grandparentKey, parentKind, endTime); - Key endKey = KeyFactory.createKey(maxRunKey, DeviceInfoEntity.KIND, Long.MAX_VALUE); - endFilter = - new FilterPredicate( - Entity.KEY_RESERVED_PROPERTY, - FilterOperator.LESS_THAN_OR_EQUAL, - endKey); - filter = endFilter; - } - if (startFilter != null && endFilter != null) { - filter = CompositeFilterOperator.and(startFilter, endFilter); - } - return filter; - } - - /** - * Get the time range filter to apply to a query. - * - * @param testKey The key of the parent TestEntity object. - * @param kind The kind to use for the filters. - * @param startTime The start time in microseconds, or null if unbounded. - * @param endTime The end time in microseconds, or null if unbounded. - * @param testRunFilter The existing filter on test runs to apply, or null. - * @return A filter to apply on test runs. - */ - public static Filter getTimeFilter( - Key testKey, String kind, Long startTime, Long endTime, Filter testRunFilter) { - if (startTime == null && endTime == null) { - endTime = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); - } - - Filter startFilter = null; - Filter endFilter = null; - Filter filter = null; - if (startTime != null) { - Key startKey = KeyFactory.createKey(testKey, kind, startTime); - startFilter = - new FilterPredicate( - Entity.KEY_RESERVED_PROPERTY, - FilterOperator.GREATER_THAN_OR_EQUAL, - startKey); - filter = startFilter; - } - if (endTime != null) { - Key endKey = KeyFactory.createKey(testKey, kind, endTime); - endFilter = - new FilterPredicate( - Entity.KEY_RESERVED_PROPERTY, - FilterOperator.LESS_THAN_OR_EQUAL, - endKey); - filter = endFilter; - } - if (startFilter != null && endFilter != null) { - filter = CompositeFilterOperator.and(startFilter, endFilter); - } - if (testRunFilter != null) { - filter = CompositeFilterOperator.and(filter, testRunFilter); - } - return filter; - } - - public static Filter getTimeFilter(Key testKey, String kind, Long startTime, Long endTime) { - return getTimeFilter(testKey, kind, startTime, endTime, null); - } - - /** - * Get the list of keys matching the provided test filter and device filter. - * - * @param ancestorKey The ancestor key to use in the query. - * @param kind The entity kind to use in the test query. - * @param testFilters The filter list to apply to test runs (each having <=1 inequality filter). - * @param deviceFilter The filter to apply to associated devices. - * @param dir The sort direction of the returned list. - * @param maxSize The maximum number of entities to return. - * @return a list of keys matching the provided test and device filters. - */ - public static List<Key> getMatchingKeys( - Key ancestorKey, - String kind, - List<Filter> testFilters, - Filter deviceFilter, - Query.SortDirection dir, - int maxSize) { - DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); - Set<Key> matchingTestKeys = null; - Key minKey = null; - Key maxKey = null; - for (Filter testFilter : testFilters) { - Query testQuery = - new Query(kind).setAncestor(ancestorKey).setFilter(testFilter).setKeysOnly(); - Set<Key> filterMatches = new HashSet<>(); - FetchOptions ops = DatastoreHelper.getLargeBatchOptions(); - if (deviceFilter == null && testFilters.size() == 1) { - ops.limit(maxSize); - testQuery.addSort(Entity.KEY_RESERVED_PROPERTY, dir); - } - logger.log(Level.INFO, "testQuery => " + testQuery); - for (Entity testRunKey : datastore.prepare(testQuery).asIterable(ops)) { - filterMatches.add(testRunKey.getKey()); - if (maxKey == null || testRunKey.getKey().compareTo(maxKey) > 0) - maxKey = testRunKey.getKey(); - if (minKey == null || testRunKey.getKey().compareTo(minKey) < 0) - minKey = testRunKey.getKey(); - } - if (matchingTestKeys == null) { - matchingTestKeys = filterMatches; - } else { - matchingTestKeys = Sets.intersection(matchingTestKeys, filterMatches); - } - } - logger.log(Level.INFO, "matchingTestKeys => " + matchingTestKeys); - - Set<Key> allMatchingKeys; - if (deviceFilter == null || matchingTestKeys.size() == 0) { - allMatchingKeys = matchingTestKeys; - } else { - deviceFilter = - CompositeFilterOperator.and( - deviceFilter, - getDeviceTimeFilter( - minKey.getParent(), - minKey.getKind(), - minKey.getId(), - maxKey.getId())); - allMatchingKeys = new HashSet<>(); - Query deviceQuery = - new Query(DeviceInfoEntity.KIND) - .setAncestor(ancestorKey) - .setFilter(deviceFilter) - .setKeysOnly(); - for (Entity device : - datastore - .prepare(deviceQuery) - .asIterable(DatastoreHelper.getLargeBatchOptions())) { - if (matchingTestKeys.contains(device.getKey().getParent())) { - allMatchingKeys.add(device.getKey().getParent()); - } - } - } - logger.log(Level.INFO, "allMatchingKeys => " + allMatchingKeys); - List<Key> gets = new ArrayList<>(allMatchingKeys); - if (dir == Query.SortDirection.DESCENDING) { - gets.sort(Comparator.reverseOrder()); - } else { - gets.sort(Comparator.naturalOrder()); - } - gets = gets.subList(0, Math.min(gets.size(), maxSize)); - return gets; - } - - /** - * Set the request with the provided key/value attribute map. - * - * @param request The request whose attributes to set. - * @param parameterMap The map from key to (Object) String[] value whose entries to parse. - */ - public static void setAttributes(HttpServletRequest request, Map<String, String[]> parameterMap) { - for (String key : parameterMap.keySet()) { - if (!FilterKey.isDeviceKey(key) && !FilterKey.isTestKey(key)) continue; - FilterKey filterKey = FilterKey.parse(key); - String[] values = parameterMap.get(key); - if (values.length == 0) continue; - String stringValue = values[0]; - request.setAttribute(filterKey.keyString, new Gson().toJson(stringValue)); - } - } -} |