Home | History | Annotate | Download | only in servlet
      1 /*
      2  * Copyright (c) 2017 Google Inc. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you
      5  * may not use this file except in compliance with the License. You may
      6  * 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
     13  * implied. See the License for the specific language governing
     14  * permissions and limitations under the License.
     15  */
     16 
     17 package com.android.vts.servlet;
     18 
     19 import com.android.vts.entity.DeviceInfoEntity;
     20 import com.android.vts.entity.ProfilingPointRunEntity;
     21 import com.android.vts.entity.TestCaseRunEntity;
     22 import com.android.vts.entity.TestEntity;
     23 import com.android.vts.entity.TestRunEntity;
     24 import com.android.vts.proto.VtsReportMessage.TestCaseResult;
     25 import com.android.vts.util.DatastoreHelper;
     26 import com.android.vts.util.FilterUtil;
     27 import com.android.vts.util.TestRunDetails;
     28 import com.android.vts.util.TestRunMetadata;
     29 import com.google.appengine.api.datastore.DatastoreService;
     30 import com.google.appengine.api.datastore.DatastoreServiceFactory;
     31 import com.google.appengine.api.datastore.Entity;
     32 import com.google.appengine.api.datastore.Key;
     33 import com.google.appengine.api.datastore.KeyFactory;
     34 import com.google.appengine.api.datastore.Query;
     35 import com.google.appengine.api.datastore.Query.Filter;
     36 import com.google.appengine.api.datastore.Query.SortDirection;
     37 import com.google.gson.Gson;
     38 import com.google.gson.JsonObject;
     39 import java.io.IOException;
     40 import java.util.ArrayList;
     41 import java.util.Comparator;
     42 import java.util.HashMap;
     43 import java.util.HashSet;
     44 import java.util.List;
     45 import java.util.Map;
     46 import java.util.Set;
     47 import java.util.logging.Level;
     48 import javax.servlet.RequestDispatcher;
     49 import javax.servlet.ServletException;
     50 import javax.servlet.http.HttpServletRequest;
     51 import javax.servlet.http.HttpServletResponse;
     52 
     53 /** Servlet for handling requests to load individual tables. */
     54 public class ShowTreeServlet extends BaseServlet {
     55     private static final String TABLE_JSP = "WEB-INF/jsp/show_tree.jsp";
     56     // Error message displayed on the webpage is tableName passed is null.
     57     private static final String TABLE_NAME_ERROR = "Error : Table name must be passed!";
     58     private static final String PROFILING_DATA_ALERT = "No profiling data was found.";
     59     private static final int MAX_RESULT_COUNT = 60;
     60     private static final int MAX_PREFETCH_COUNT = 10;
     61 
     62     @Override
     63     public PageType getNavParentType() {
     64         return PageType.TOT;
     65     }
     66 
     67     @Override
     68     public List<Page> getBreadcrumbLinks(HttpServletRequest request) {
     69         List<Page> links = new ArrayList<>();
     70         String testName = request.getParameter("testName");
     71         links.add(new Page(PageType.TREE, testName, "?testName=" + testName));
     72         return links;
     73     }
     74 
     75     /**
     76      * Get the test run details for a test run.
     77      *
     78      * @param metadata The metadata for the test run whose details will be fetched.
     79      * @return The TestRunDetails object for the provided test run.
     80      */
     81     public static TestRunDetails processTestDetails(TestRunMetadata metadata) {
     82         DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
     83         TestRunDetails details = new TestRunDetails();
     84         List<Key> gets = new ArrayList<>();
     85         for (long testCaseId : metadata.testRun.testCaseIds) {
     86             gets.add(KeyFactory.createKey(TestCaseRunEntity.KIND, testCaseId));
     87         }
     88         Map<Key, Entity> entityMap = datastore.get(gets);
     89         for (int i = 0; i < 1; i++) {
     90             for (Key key : entityMap.keySet()) {
     91                 TestCaseRunEntity testCaseRun = TestCaseRunEntity.fromEntity(entityMap.get(key));
     92                 if (testCaseRun == null) {
     93                     continue;
     94                 }
     95                 details.addTestCase(testCaseRun);
     96             }
     97         }
     98         return details;
     99     }
    100 
    101     @Override
    102     public void doGetHandler(HttpServletRequest request, HttpServletResponse response)
    103             throws IOException {
    104         boolean unfiltered = request.getParameter("unfiltered") != null;
    105         boolean showPresubmit = request.getParameter("showPresubmit") != null;
    106         boolean showPostsubmit = request.getParameter("showPostsubmit") != null;
    107         Long startTime = null; // time in microseconds
    108         Long endTime = null; // time in microseconds
    109         DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    110         RequestDispatcher dispatcher = null;
    111 
    112         // message to display if profiling point data is not available
    113         String profilingDataAlert = "";
    114 
    115         if (request.getParameter("testName") == null) {
    116             request.setAttribute("testName", TABLE_NAME_ERROR);
    117             return;
    118         }
    119         String testName = request.getParameter("testName");
    120 
    121         if (request.getParameter("startTime") != null) {
    122             String time = request.getParameter("startTime");
    123             try {
    124                 startTime = Long.parseLong(time);
    125                 startTime = startTime > 0 ? startTime : null;
    126             } catch (NumberFormatException e) {
    127                 startTime = null;
    128             }
    129         }
    130         if (request.getParameter("endTime") != null) {
    131             String time = request.getParameter("endTime");
    132             try {
    133                 endTime = Long.parseLong(time);
    134                 endTime = endTime > 0 ? endTime : null;
    135             } catch (NumberFormatException e) {
    136                 endTime = null;
    137             }
    138         }
    139 
    140         // If no params are specified, set to default of postsubmit-only.
    141         if (!(showPresubmit || showPostsubmit)) {
    142             showPostsubmit = true;
    143         }
    144 
    145         // If unfiltered, set showPre- and Post-submit to true for accurate UI.
    146         if (unfiltered) {
    147             showPostsubmit = true;
    148             showPresubmit = true;
    149         }
    150 
    151         // Add result names to list
    152         List<String> resultNames = new ArrayList<>();
    153         for (TestCaseResult r : TestCaseResult.values()) {
    154             resultNames.add(r.name());
    155         }
    156 
    157         SortDirection dir = SortDirection.DESCENDING;
    158         if (startTime != null && endTime == null) {
    159             dir = SortDirection.ASCENDING;
    160         }
    161         Key testKey = KeyFactory.createKey(TestEntity.KIND, testName);
    162 
    163         Filter typeFilter = FilterUtil.getTestTypeFilter(showPresubmit, showPostsubmit, unfiltered);
    164         Filter testFilter =
    165                 FilterUtil.getTimeFilter(
    166                         testKey, TestRunEntity.KIND, startTime, endTime, typeFilter);
    167 
    168         Map<String, Object> parameterMap = request.getParameterMap();
    169         List<Filter> userTestFilters = FilterUtil.getUserTestFilters(parameterMap);
    170         userTestFilters.add(0, testFilter);
    171         Filter userDeviceFilter = FilterUtil.getUserDeviceFilter(parameterMap);
    172 
    173         List<TestRunMetadata> testRunMetadata = new ArrayList<>();
    174         Map<Key, TestRunMetadata> metadataMap = new HashMap<>();
    175         Key minKey = null;
    176         Key maxKey = null;
    177         List<Key> gets =
    178                 FilterUtil.getMatchingKeys(
    179                         testKey,
    180                         TestRunEntity.KIND,
    181                         userTestFilters,
    182                         userDeviceFilter,
    183                         dir,
    184                         MAX_RESULT_COUNT);
    185         Map<Key, Entity> entityMap = datastore.get(gets);
    186         for (Key key : gets) {
    187             if (!entityMap.containsKey(key)) {
    188                 continue;
    189             }
    190             TestRunEntity testRunEntity = TestRunEntity.fromEntity(entityMap.get(key));
    191             if (testRunEntity == null) {
    192                 continue;
    193             }
    194             if (minKey == null || key.compareTo(minKey) < 0) {
    195                 minKey = key;
    196             }
    197             if (maxKey == null || key.compareTo(maxKey) > 0) {
    198                 maxKey = key;
    199             }
    200             TestRunMetadata metadata = new TestRunMetadata(testName, testRunEntity);
    201             testRunMetadata.add(metadata);
    202             metadataMap.put(key, metadata);
    203         }
    204 
    205         List<String> profilingPointNames = new ArrayList<>();
    206         if (minKey != null && maxKey != null) {
    207             Filter deviceFilter =
    208                     FilterUtil.getDeviceTimeFilter(
    209                             testKey, TestRunEntity.KIND, minKey.getId(), maxKey.getId());
    210             Query deviceQuery =
    211                     new Query(DeviceInfoEntity.KIND)
    212                             .setAncestor(testKey)
    213                             .setFilter(deviceFilter)
    214                             .setKeysOnly();
    215             List<Key> deviceGets = new ArrayList<>();
    216             for (Entity device :
    217                     datastore
    218                             .prepare(deviceQuery)
    219                             .asIterable(DatastoreHelper.getLargeBatchOptions())) {
    220                 if (metadataMap.containsKey(device.getParent())) {
    221                     deviceGets.add(device.getKey());
    222                 }
    223             }
    224             Map<Key, Entity> devices = datastore.get(deviceGets);
    225             for (Key key : devices.keySet()) {
    226                 if (!metadataMap.containsKey(key.getParent())) continue;
    227                 DeviceInfoEntity device = DeviceInfoEntity.fromEntity(devices.get(key));
    228                 if (device == null) continue;
    229                 TestRunMetadata metadata = metadataMap.get(key.getParent());
    230                 metadata.addDevice(device);
    231             }
    232 
    233             Filter profilingFilter =
    234                     FilterUtil.getProfilingTimeFilter(
    235                             testKey, TestRunEntity.KIND, minKey.getId(), maxKey.getId());
    236 
    237             Set<String> profilingPoints = new HashSet<>();
    238             Query profilingPointQuery =
    239                     new Query(ProfilingPointRunEntity.KIND)
    240                             .setAncestor(testKey)
    241                             .setFilter(profilingFilter)
    242                             .setKeysOnly();
    243             for (Entity e : datastore.prepare(profilingPointQuery).asIterable()) {
    244                 profilingPoints.add(e.getKey().getName());
    245             }
    246 
    247             if (profilingPoints.size() == 0) {
    248                 profilingDataAlert = PROFILING_DATA_ALERT;
    249             }
    250             profilingPointNames.addAll(profilingPoints);
    251             profilingPointNames.sort(Comparator.naturalOrder());
    252         }
    253 
    254         testRunMetadata.sort(
    255                 (t1, t2) ->
    256                         new Long(t2.testRun.startTimestamp).compareTo(t1.testRun.startTimestamp));
    257         List<JsonObject> testRunObjects = new ArrayList<>();
    258 
    259         int prefetchCount = 0;
    260         for (TestRunMetadata metadata : testRunMetadata) {
    261             if (metadata.testRun.failCount > 0 && prefetchCount < MAX_PREFETCH_COUNT) {
    262                 // process
    263                 metadata.addDetails(processTestDetails(metadata));
    264                 ++prefetchCount;
    265             }
    266             testRunObjects.add(metadata.toJson());
    267         }
    268 
    269         int[] topBuildResultCounts = null;
    270         String topBuild = "";
    271         if (testRunMetadata.size() > 0) {
    272             TestRunMetadata firstRun = testRunMetadata.get(0);
    273             topBuild = firstRun.getDeviceInfo();
    274             endTime = firstRun.testRun.startTimestamp;
    275             TestRunDetails topDetails = firstRun.getDetails();
    276             if (topDetails == null) {
    277                 topDetails = processTestDetails(firstRun);
    278             }
    279             topBuildResultCounts = topDetails.resultCounts;
    280 
    281             TestRunMetadata lastRun = testRunMetadata.get(testRunMetadata.size() - 1);
    282             startTime = lastRun.testRun.startTimestamp;
    283         }
    284 
    285         FilterUtil.setAttributes(request, parameterMap);
    286 
    287         request.setAttribute("testName", request.getParameter("testName"));
    288 
    289         request.setAttribute("error", profilingDataAlert);
    290 
    291         request.setAttribute("profilingPointNames", profilingPointNames);
    292         request.setAttribute("resultNames", resultNames);
    293         request.setAttribute("resultNamesJson", new Gson().toJson(resultNames));
    294         request.setAttribute("testRuns", new Gson().toJson(testRunObjects));
    295 
    296         // data for pie chart
    297         request.setAttribute("topBuildResultCounts", new Gson().toJson(topBuildResultCounts));
    298         request.setAttribute("topBuildId", topBuild);
    299         request.setAttribute("startTime", new Gson().toJson(startTime));
    300         request.setAttribute("endTime", new Gson().toJson(endTime));
    301         request.setAttribute(
    302                 "hasNewer",
    303                 new Gson().toJson(DatastoreHelper.hasNewer(testKey, TestRunEntity.KIND, endTime)));
    304         request.setAttribute(
    305                 "hasOlder",
    306                 new Gson()
    307                         .toJson(DatastoreHelper.hasOlder(testKey, TestRunEntity.KIND, startTime)));
    308         request.setAttribute("unfiltered", unfiltered);
    309         request.setAttribute("showPresubmit", showPresubmit);
    310         request.setAttribute("showPostsubmit", showPostsubmit);
    311 
    312         request.setAttribute("branches", new Gson().toJson(DatastoreHelper.getAllBranches()));
    313         request.setAttribute("devices", new Gson().toJson(DatastoreHelper.getAllBuildFlavors()));
    314 
    315         dispatcher = request.getRequestDispatcher(TABLE_JSP);
    316         try {
    317             dispatcher.forward(request, response);
    318         } catch (ServletException e) {
    319             logger.log(Level.SEVERE, "Servlet Exception caught : " + e.toString());
    320         }
    321     }
    322 }
    323