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.api; 18 19 import com.android.vts.entity.TestCaseRunEntity; 20 import com.android.vts.entity.TestEntity; 21 import com.android.vts.entity.TestRunEntity; 22 import com.android.vts.util.FilterUtil; 23 import com.android.vts.util.TestRunDetails; 24 import com.google.appengine.api.datastore.DatastoreService; 25 import com.google.appengine.api.datastore.DatastoreServiceFactory; 26 import com.google.appengine.api.datastore.Entity; 27 import com.google.appengine.api.datastore.EntityNotFoundException; 28 import com.google.appengine.api.datastore.FetchOptions; 29 import com.google.appengine.api.datastore.Key; 30 import com.google.appengine.api.datastore.KeyFactory; 31 import com.google.appengine.api.datastore.Query; 32 import com.google.gson.Gson; 33 import java.io.IOException; 34 import java.io.PrintWriter; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.logging.Logger; 39 import javax.servlet.http.HttpServlet; 40 import javax.servlet.http.HttpServletRequest; 41 import javax.servlet.http.HttpServletResponse; 42 43 /** Servlet for handling requests to fetch test case results. */ 44 public class TestRunRestServlet extends HttpServlet { 45 private static final String LATEST = "latest"; 46 protected static final Logger logger = Logger.getLogger(TestRunRestServlet.class.getName()); 47 48 /** 49 * Get the test case results for the specified run of the specified test. 50 * 51 * @param test The test whose test cases to get. 52 * @param timeString The string representation of the test run timestamp (in microseconds). 53 * @return A TestRunDetails object with the test case details for the specified run. 54 */ 55 private static TestRunDetails getTestRunDetails(String test, String timeString) { 56 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 57 long timestamp; 58 try { 59 timestamp = Long.parseLong(timeString); 60 if (timestamp <= 0) throw new NumberFormatException(); 61 timestamp = timestamp > 0 ? timestamp : null; 62 } catch (NumberFormatException e) { 63 return null; 64 } 65 66 Key testKey = KeyFactory.createKey(TestEntity.KIND, test); 67 Key testRunKey = KeyFactory.createKey(testKey, TestRunEntity.KIND, timestamp); 68 TestRunEntity testRunEntity; 69 try { 70 Entity testRun = datastore.get(testRunKey); 71 testRunEntity = TestRunEntity.fromEntity(testRun); 72 if (testRunEntity == null) { 73 throw new EntityNotFoundException(testRunKey); 74 } 75 } catch (EntityNotFoundException e) { 76 return null; 77 } 78 TestRunDetails details = new TestRunDetails(); 79 List<Key> gets = new ArrayList<>(); 80 for (long testCaseId : testRunEntity.testCaseIds) { 81 gets.add(KeyFactory.createKey(TestCaseRunEntity.KIND, testCaseId)); 82 } 83 Map<Key, Entity> entityMap = datastore.get(gets); 84 for (Key key : entityMap.keySet()) { 85 TestCaseRunEntity testCaseRun = TestCaseRunEntity.fromEntity(entityMap.get(key)); 86 if (testCaseRun == null) { 87 continue; 88 } 89 details.addTestCase(testCaseRun); 90 } 91 return details; 92 } 93 94 /** 95 * Get the test case results for the latest run of the specified test. 96 * 97 * @param test The test whose test cases to get. 98 * @return A TestRunDetails object with the test case details for the latest run. 99 */ 100 private static TestRunDetails getLatestTestRunDetails(String test) { 101 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 102 Key testKey = KeyFactory.createKey(TestEntity.KIND, test); 103 Query.Filter typeFilter = FilterUtil.getTestTypeFilter(false, true, false); 104 Query testRunQuery = 105 new Query(TestRunEntity.KIND) 106 .setAncestor(testKey) 107 .setFilter(typeFilter) 108 .addSort(Entity.KEY_RESERVED_PROPERTY, Query.SortDirection.DESCENDING); 109 TestRunEntity testRun = null; 110 for (Entity testRunEntity : 111 datastore.prepare(testRunQuery).asIterable(FetchOptions.Builder.withLimit(1))) { 112 testRun = TestRunEntity.fromEntity(testRunEntity); 113 } 114 if (testRun == null) return null; 115 TestRunDetails details = new TestRunDetails(); 116 117 List<Key> gets = new ArrayList<>(); 118 for (long testCaseId : testRun.testCaseIds) { 119 gets.add(KeyFactory.createKey(TestCaseRunEntity.KIND, testCaseId)); 120 } 121 Map<Key, Entity> entityMap = datastore.get(gets); 122 for (Key key : entityMap.keySet()) { 123 TestCaseRunEntity testCaseRun = TestCaseRunEntity.fromEntity(entityMap.get(key)); 124 if (testCaseRun == null) { 125 continue; 126 } 127 details.addTestCase(testCaseRun); 128 } 129 return details; 130 } 131 132 /** 133 * Get the test case details for a test run. 134 * 135 * Expected format: (1) /api/test_run?test=[test name]×tamp=[timestamp] to the details 136 * for a specific run, or (2) /api/test_run?test=[test name]×tamp=latest -- the details for 137 * the latest test run. 138 */ 139 @Override 140 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { 141 String test = request.getParameter("test"); 142 String timeString = request.getParameter("timestamp"); 143 TestRunDetails details = null; 144 145 if (timeString != null && timeString.equals(LATEST)) { 146 details = getLatestTestRunDetails(test); 147 } else if (timeString != null) { 148 details = getTestRunDetails(test, timeString); 149 } 150 151 if (details == null) { 152 response.setStatus(HttpServletResponse.SC_BAD_REQUEST); 153 } else { 154 response.setStatus(HttpServletResponse.SC_OK); 155 response.setContentType("application/json"); 156 PrintWriter writer = response.getWriter(); 157 writer.print(new Gson().toJson(details.toJson())); 158 writer.flush(); 159 } 160 } 161 } 162