diff options
Diffstat (limited to 'src/main/java/com/android/vts')
8 files changed, 609 insertions, 205 deletions
diff --git a/src/main/java/com/android/vts/api/DataRestServlet.java b/src/main/java/com/android/vts/api/DataRestServlet.java new file mode 100644 index 0000000..409818e --- /dev/null +++ b/src/main/java/com/android/vts/api/DataRestServlet.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Google Inc. All Rights Reserved. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.api; + +import com.android.vts.entity.BranchEntity; +import com.android.vts.entity.TestCoverageStatusEntity; +import com.google.gson.Gson; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.android.vts.entity.BuildTargetEntity; + +/** REST endpoint for getting all branch and buildFlavors information. */ +public class DataRestServlet extends BaseApiServlet { + + private static final Logger logger = Logger.getLogger(DataRestServlet.class.getName()); + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String pathInfo = request.getPathInfo(); + String json = ""; + if (Objects.nonNull(pathInfo)) { + String schKey = + Objects.isNull(request.getParameter("schKey")) + ? "" + : request.getParameter("schKey"); + if (pathInfo.equalsIgnoreCase("/branch")) { + json = new Gson().toJson(BranchEntity.getByBranch(schKey)); + } else if (pathInfo.equalsIgnoreCase("/device")) { + json = new Gson().toJson(BuildTargetEntity.getByBuildTarget(schKey)); + } else if (pathInfo.startsWith("/code/coverage/status/")) { + List<TestCoverageStatusEntity> testCoverageStatusEntityList = + TestCoverageStatusEntity.getAllTestCoverage(); + if (pathInfo.endsWith("branch")) { + json = + new Gson() + .toJson( + TestCoverageStatusEntity.getBranchSet( + testCoverageStatusEntityList)); + } else { + json = + new Gson() + .toJson( + TestCoverageStatusEntity.getDeviceSet( + testCoverageStatusEntityList)); + } + } else { + json = "{error: 'true', message: 'unexpected path!!!'}"; + logger.log(Level.INFO, "Path Info => " + pathInfo); + logger.log(Level.WARNING, "Unknown path access!"); + } + } else { + json = "{error: 'true', message: 'the path info is not existed!!!'}"; + } + + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().write(json); + } +} diff --git a/src/main/java/com/android/vts/config/ObjectifyListener.java b/src/main/java/com/android/vts/config/ObjectifyListener.java index 2610ab8..66f1480 100644 --- a/src/main/java/com/android/vts/config/ObjectifyListener.java +++ b/src/main/java/com/android/vts/config/ObjectifyListener.java @@ -17,6 +17,8 @@ package com.android.vts.config; import com.android.vts.entity.ApiCoverageEntity; +import com.android.vts.entity.BranchEntity; +import com.android.vts.entity.BuildTargetEntity; import com.android.vts.entity.CodeCoverageEntity; import com.android.vts.entity.CoverageEntity; import com.android.vts.entity.DeviceInfoEntity; @@ -47,12 +49,10 @@ import javax.servlet.annotation.WebListener; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; -import static com.googlecode.objectify.ObjectifyService.ofy; /** * The @WebListener annotation for registering a class as a listener of a web application. @@ -73,6 +73,9 @@ public class ObjectifyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { ObjectifyService.init(); + ObjectifyService.register(BranchEntity.class); + ObjectifyService.register(BuildTargetEntity.class); + ObjectifyService.register(ApiCoverageEntity.class); ObjectifyService.register(CodeCoverageEntity.class); ObjectifyService.register(CoverageEntity.class); diff --git a/src/main/java/com/android/vts/entity/BranchEntity.java b/src/main/java/com/android/vts/entity/BranchEntity.java index f1b5a4c..fa3f7a5 100644 --- a/src/main/java/com/android/vts/entity/BranchEntity.java +++ b/src/main/java/com/android/vts/entity/BranchEntity.java @@ -19,9 +19,22 @@ package com.android.vts.entity; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.KeyFactory; +import com.googlecode.objectify.annotation.Cache; +import com.googlecode.objectify.annotation.Id; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; + +import static com.googlecode.objectify.ObjectifyService.ofy; +@com.googlecode.objectify.annotation.Entity(name = "Branch") +@Cache +@Data +@NoArgsConstructor /** Entity describing a branch. */ public class BranchEntity implements DashboardEntity { protected static final Logger logger = Logger.getLogger(BranchEntity.class.getName()); @@ -30,6 +43,8 @@ public class BranchEntity implements DashboardEntity { public Key key; // The key for the entity in the database. + @Id private String name; + /** * Create a BranchEntity object. * @@ -39,6 +54,38 @@ public class BranchEntity implements DashboardEntity { this.key = KeyFactory.createKey(KIND, branchName); } + /** find by branch name */ + public static List<String> getByBranch(String branchName) { + if (branchName.equals("*")) { + return ofy().load() + .type(BranchEntity.class) + .limit(100) + .list() + .stream() + .map(b -> b.name) + .collect(Collectors.toList()); + } else { + com.googlecode.objectify.Key startKey = + com.googlecode.objectify.Key.create(BranchEntity.class, branchName); + + int lastPosition = branchName.length() - 1; + int lastCharValue = branchName.charAt(lastPosition); + String nextChar = String.valueOf((char) (lastCharValue + 1)); + + String nextBranchName = branchName.substring(0, lastPosition) + nextChar; + com.googlecode.objectify.Key endKey = + com.googlecode.objectify.Key.create(BranchEntity.class, nextBranchName); + return ofy().load() + .type(BranchEntity.class) + .filterKey(">=", startKey) + .filterKey("<", endKey) + .list() + .stream() + .map(b -> b.name) + .collect(Collectors.toList()); + } + } + @Override public Entity toEntity() { return new Entity(this.key); diff --git a/src/main/java/com/android/vts/entity/BuildTargetEntity.java b/src/main/java/com/android/vts/entity/BuildTargetEntity.java index ddcd4f8..b204d0c 100644 --- a/src/main/java/com/android/vts/entity/BuildTargetEntity.java +++ b/src/main/java/com/android/vts/entity/BuildTargetEntity.java @@ -19,9 +19,22 @@ package com.android.vts.entity; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.KeyFactory; +import com.googlecode.objectify.annotation.Cache; +import com.googlecode.objectify.annotation.Id; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; + +import static com.googlecode.objectify.ObjectifyService.ofy; +@com.googlecode.objectify.annotation.Entity(name = "BuildTarget") +@Cache +@Data +@NoArgsConstructor /** Entity describing a build target. */ public class BuildTargetEntity implements DashboardEntity { protected static final Logger logger = Logger.getLogger(BuildTargetEntity.class.getName()); @@ -30,6 +43,8 @@ public class BuildTargetEntity implements DashboardEntity { public Key key; // The key for the entity in the database. + @Id private String name; + /** * Create a BuildTargetEntity object. * @@ -44,6 +59,39 @@ public class BuildTargetEntity implements DashboardEntity { return new Entity(this.key); } + /** find by Build Target Name */ + public static List<String> getByBuildTarget(String buildTargetName) { + if (buildTargetName.equals("*")) { + return ofy().load() + .type(BuildTargetEntity.class) + .limit(100) + .list() + .stream() + .map(b -> b.name) + .collect(Collectors.toList()); + } else { + com.googlecode.objectify.Key startKey = + com.googlecode.objectify.Key.create(BuildTargetEntity.class, buildTargetName); + + int lastPosition = buildTargetName.length() - 1; + int lastCharValue = buildTargetName.charAt(lastPosition); + String nextChar = String.valueOf((char) (lastCharValue + 1)); + + String nextBuildTargetName = buildTargetName.substring(0, lastPosition) + nextChar; + com.googlecode.objectify.Key endKey = + com.googlecode.objectify.Key.create( + BuildTargetEntity.class, nextBuildTargetName); + return ofy().load() + .type(BuildTargetEntity.class) + .filterKey(">=", startKey) + .filterKey("<", endKey) + .list() + .stream() + .map(b -> b.name) + .collect(Collectors.toList()); + } + } + /** * Convert an Entity object to a BuildTargetEntity. * diff --git a/src/main/java/com/android/vts/entity/DeviceInfoEntity.java b/src/main/java/com/android/vts/entity/DeviceInfoEntity.java index 6992983..d0c3d00 100644 --- a/src/main/java/com/android/vts/entity/DeviceInfoEntity.java +++ b/src/main/java/com/android/vts/entity/DeviceInfoEntity.java @@ -21,6 +21,7 @@ import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.memcache.MemcacheService; import com.google.appengine.api.memcache.MemcacheServiceFactory; +import com.google.apphosting.api.ApiProxy; import com.googlecode.objectify.annotation.Cache; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Ignore; @@ -106,8 +107,14 @@ public class DeviceInfoEntity implements Serializable { * @param abiBitness The abi bitness of the device. * @param abiName The name of the abi. */ - public DeviceInfoEntity(Key parentKey, String branch, String product, String buildFlavor, - String buildID, String abiBitness, String abiName) { + public DeviceInfoEntity( + Key parentKey, + String branch, + String product, + String buildFlavor, + String buildID, + String abiBitness, + String abiName) { this.parentKey = parentKey; this.branch = branch; this.product = product; @@ -118,12 +125,54 @@ public class DeviceInfoEntity implements Serializable { } /** + * Create a DeviceInfoEntity object with objectify Key + * + * @param parent The objectify key for the parent entity in the database. + * @param branch The build branch. + * @param product The device product. + * @param buildFlavor The device build flavor. + * @param buildID The device build ID. + * @param abiBitness The abi bitness of the device. + * @param abiName The name of the abi. + */ + public DeviceInfoEntity( + com.googlecode.objectify.Key parent, + String branch, + String product, + String buildFlavor, + String buildID, + String abiBitness, + String abiName) { + this.parent = parent; + this.branch = branch; + this.product = product; + this.buildFlavor = buildFlavor; + this.buildId = buildID; + this.abiBitness = abiBitness; + this.abiName = abiName; + } + + /** * Get All Branch List from DeviceInfoEntity */ public static List<String> getAllBranches() { - List<String> branchList = (List<String>) syncCache.get("branchList"); - if (Objects.isNull(branchList)) { - branchList = ofy().load() + try { + List<String> branchList = (List<String>) syncCache.get("branchList"); + if (Objects.isNull(branchList)) { + branchList = + ofy().load() + .type(DeviceInfoEntity.class) + .project("branch") + .distinct(true) + .list() + .stream() + .map(device -> device.branch) + .collect(Collectors.toList()); + syncCache.put("branchList", branchList); + } + return branchList; + } catch (ApiProxy.CallNotFoundException e) { + return ofy().load() .type(DeviceInfoEntity.class) .project("branch") .distinct(true) @@ -131,18 +180,30 @@ public class DeviceInfoEntity implements Serializable { .stream() .map(device -> device.branch) .collect(Collectors.toList()); - syncCache.put("branchList", branchList); } - return branchList; } /** * Get All BuildFlavors List from DeviceInfoEntity */ public static List<String> getAllBuildFlavors() { - List<String> buildFlavorList = (List<String>) syncCache.get("buildFlavorList"); - if (Objects.isNull(buildFlavorList)) { - buildFlavorList = ofy().load() + try { + List<String> buildFlavorList = (List<String>) syncCache.get("buildFlavorList"); + if (Objects.isNull(buildFlavorList)) { + buildFlavorList = + ofy().load() + .type(DeviceInfoEntity.class) + .project("buildFlavor") + .distinct(true) + .list() + .stream() + .map(device -> device.buildFlavor) + .collect(Collectors.toList()); + syncCache.put("buildFlavorList", buildFlavorList); + } + return buildFlavorList; + } catch (ApiProxy.CallNotFoundException e) { + return ofy().load() .type(DeviceInfoEntity.class) .project("buildFlavor") .distinct(true) @@ -150,9 +211,12 @@ public class DeviceInfoEntity implements Serializable { .stream() .map(device -> device.buildFlavor) .collect(Collectors.toList()); - syncCache.put("buildFlavorList", buildFlavorList); } - return buildFlavorList; + } + + /** Saving function for the instance of this class */ + public void save() { + ofy().save().entity(this).now(); } public Entity toEntity() { diff --git a/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java b/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java index 12572ce..cc630c3 100644 --- a/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java +++ b/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java @@ -19,13 +19,16 @@ package com.android.vts.entity; import static com.googlecode.objectify.ObjectifyService.ofy; import com.google.appengine.api.datastore.Entity; +import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Cache; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Index; import java.io.Serializable; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -50,6 +53,7 @@ public class TestCoverageStatusEntity implements Serializable { public static final String TOTAL_LINE_COUNT = "totalLineCount"; public static final String COVERED_LINE_COUNT = "coveredLineCount"; public static final String UPDATED_TIMESTAMP = "updatedTimestamp"; + public static final String DEVICE_INFO_ID = "deviceInfoId"; /** TestCoverageStatusEntity name field */ @Id @Getter @Setter String testName; @@ -63,6 +67,9 @@ public class TestCoverageStatusEntity implements Serializable { /** TestCoverageStatusEntity updatedTimestamp field */ @Index @Getter @Setter long updatedTimestamp; + /** TestCoverageStatusEntity DeviceInfo Entity ID reference field */ + @Index @Getter @Setter long deviceInfoId; + /** TestCoverageStatusEntity updatedCoveredLineCount field */ @Index @Getter @Setter long updatedCoveredLineCount; @@ -81,11 +88,16 @@ public class TestCoverageStatusEntity implements Serializable { * @param totalLineCount The total number of lines. */ public TestCoverageStatusEntity( - String testName, long timestamp, long coveredLineCount, long totalLineCount) { + String testName, + long timestamp, + long coveredLineCount, + long totalLineCount, + long deviceInfoId) { this.testName = testName; this.updatedTimestamp = timestamp; this.coveredLineCount = coveredLineCount; this.totalLineCount = totalLineCount; + this.deviceInfoId = deviceInfoId; } /** find TestCoverageStatus entity by ID */ @@ -103,11 +115,69 @@ public class TestCoverageStatusEntity implements Serializable { return testCoverageStatusMap; } + /** Get all DeviceInfoEntity List by TestCoverageStatusEntities' key list */ + public static List<Key<DeviceInfoEntity>> getDeviceInfoEntityKeyList( + List<TestCoverageStatusEntity> testCoverageStatusEntityList) { + return testCoverageStatusEntityList + .stream() + .map( + testCoverageStatusEntity -> { + com.googlecode.objectify.Key testKey = + com.googlecode.objectify.Key.create( + TestEntity.class, + testCoverageStatusEntity.getTestName()); + com.googlecode.objectify.Key testRunKey = + com.googlecode.objectify.Key.create( + testKey, + TestRunEntity.class, + testCoverageStatusEntity.getUpdatedTimestamp()); + return com.googlecode.objectify.Key.create( + testRunKey, + DeviceInfoEntity.class, + testCoverageStatusEntity.getDeviceInfoId()); + }) + .collect(Collectors.toList()); + } + /** Get all TestCoverageStatusEntity List */ public static List<TestCoverageStatusEntity> getAllTestCoverage() { return ofy().load().type(TestCoverageStatusEntity.class).list(); } + /** Get all TestCoverageStatusEntities' Branch List */ + public static Set<String> getBranchSet( + List<TestCoverageStatusEntity> testCoverageStatusEntityList) { + List<com.googlecode.objectify.Key<DeviceInfoEntity>> deviceInfoEntityKeyList = + getDeviceInfoEntityKeyList(testCoverageStatusEntityList); + + Collection<DeviceInfoEntity> deviceInfoEntityList = + ofy().load().keys(() -> deviceInfoEntityKeyList.iterator()).values(); + + Set<String> branchSet = + deviceInfoEntityList + .stream() + .map(deviceInfoEntity -> deviceInfoEntity.getBranch()) + .collect(Collectors.toSet()); + return branchSet; + } + + /** Get all TestCoverageStatusEntities' Device List */ + public static Set<String> getDeviceSet( + List<TestCoverageStatusEntity> testCoverageStatusEntityList) { + List<com.googlecode.objectify.Key<DeviceInfoEntity>> deviceInfoEntityKeyList = + getDeviceInfoEntityKeyList(testCoverageStatusEntityList); + + Collection<DeviceInfoEntity> deviceInfoEntityList = + ofy().load().keys(() -> deviceInfoEntityKeyList.iterator()).values(); + + Set<String> deviceSet = + deviceInfoEntityList + .stream() + .map(deviceInfoEntity -> deviceInfoEntity.getBuildFlavor()) + .collect(Collectors.toSet()); + return deviceSet; + } + /** TestRunEntity function to get the related TestRunEntity from id value */ public TestRunEntity getTestRunEntity() { com.googlecode.objectify.Key testKey = @@ -146,7 +216,8 @@ public class TestCoverageStatusEntity implements Serializable { || e.getKey().getName() == null || !e.hasProperty(UPDATED_TIMESTAMP) || !e.hasProperty(COVERED_LINE_COUNT) - || !e.hasProperty(TOTAL_LINE_COUNT)) { + || !e.hasProperty(TOTAL_LINE_COUNT) + || !e.hasProperty(DEVICE_INFO_ID)) { logger.log(Level.WARNING, "Missing test attributes in entity: " + e.toString()); return null; } @@ -154,15 +225,18 @@ public class TestCoverageStatusEntity implements Serializable { long timestamp = 0; long coveredLineCount = -1; long totalLineCount = -1; + long deviceInfoId = 0; try { timestamp = (long) e.getProperty(UPDATED_TIMESTAMP); coveredLineCount = (Long) e.getProperty(COVERED_LINE_COUNT); totalLineCount = (Long) e.getProperty(TOTAL_LINE_COUNT); + deviceInfoId = (Long) e.getProperty(DEVICE_INFO_ID); } catch (ClassCastException exception) { // Invalid contents or null values logger.log(Level.WARNING, "Error parsing test entity.", exception); return null; } - return new TestCoverageStatusEntity(testName, timestamp, coveredLineCount, totalLineCount); + return new TestCoverageStatusEntity( + testName, timestamp, coveredLineCount, totalLineCount, deviceInfoId); } } diff --git a/src/main/java/com/android/vts/job/VtsCoverageAlertJobServlet.java b/src/main/java/com/android/vts/job/VtsCoverageAlertJobServlet.java index 106ffb5..b5453b7 100644 --- a/src/main/java/com/android/vts/job/VtsCoverageAlertJobServlet.java +++ b/src/main/java/com/android/vts/job/VtsCoverageAlertJobServlet.java @@ -261,11 +261,12 @@ public class VtsCoverageAlertJobServlet extends BaseJobServlet { logger.log(Level.WARNING, "Error composing email : ", e); } } - return new TestCoverageStatusEntity( - testName, - testRunEntity.getStartTimestamp(), - codeCoverageEntity.getCoveredLineCount(), - codeCoverageEntity.getTotalLineCount()); + return new TestCoverageStatusEntity( + testName, + testRunEntity.getStartTimestamp(), + codeCoverageEntity.getCoveredLineCount(), + codeCoverageEntity.getTotalLineCount(), + devices.size() > 0 ? devices.get(0).getId() : 0); } /** @@ -299,7 +300,7 @@ public class VtsCoverageAlertJobServlet extends BaseJobServlet { TestCoverageStatusEntity status = ofy().load().type(TestCoverageStatusEntity.class).id(testName) .now(); if (status == null) { - status = new TestCoverageStatusEntity(testName, 0, -1, -1); + status = new TestCoverageStatusEntity(testName, 0, -1, -1, 0); } StringBuffer fullUrl = request.getRequestURL(); diff --git a/src/main/java/com/android/vts/servlet/ShowCoverageOverviewServlet.java b/src/main/java/com/android/vts/servlet/ShowCoverageOverviewServlet.java index 719ade9..210c980 100644 --- a/src/main/java/com/android/vts/servlet/ShowCoverageOverviewServlet.java +++ b/src/main/java/com/android/vts/servlet/ShowCoverageOverviewServlet.java @@ -17,6 +17,7 @@ package com.android.vts.servlet; import com.android.vts.entity.CodeCoverageEntity; +import com.android.vts.entity.DeviceInfoEntity; import com.android.vts.entity.TestCoverageStatusEntity; import com.android.vts.entity.TestEntity; import com.android.vts.entity.TestRunEntity; @@ -30,7 +31,6 @@ import com.google.cloud.datastore.StructuredQuery.CompositeFilter; import com.google.cloud.datastore.StructuredQuery.Filter; import com.google.cloud.datastore.StructuredQuery.PropertyFilter; import com.google.gson.Gson; -import com.google.gson.JsonObject; import com.google.visualization.datasource.DataSourceHelper; import com.google.visualization.datasource.DataSourceRequest; import com.google.visualization.datasource.base.DataSourceException; @@ -50,15 +50,19 @@ import com.ibm.icu.util.TimeZone; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; -import java.time.Duration; -import java.time.Instant; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; +import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; import java.util.logging.Level; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -69,79 +73,82 @@ import org.joda.time.format.DateTimeFormatter; import static com.googlecode.objectify.ObjectifyService.ofy; -/** - * Represents the servlet that is invoked on loading the coverage overview page. - */ +/** Represents the servlet that is invoked on loading the coverage overview page. */ public class ShowCoverageOverviewServlet extends BaseServlet { - @Override - public PageType getNavParentType() { - return PageType.COVERAGE_OVERVIEW; - } - - @Override - public List<Page> getBreadcrumbLinks(HttpServletRequest request) { - return null; - } - - @Override - public void doGetHandler(HttpServletRequest request, HttpServletResponse response) - throws IOException { + @Override + public PageType getNavParentType() { + return PageType.COVERAGE_OVERVIEW; + } - String pageType = - request.getParameter("pageType") == null ? "html" : request.getParameter("pageType"); + @Override + public List<Page> getBreadcrumbLinks(HttpServletRequest request) { + return null; + } - RequestDispatcher dispatcher; - if (pageType.equalsIgnoreCase("html")) { - dispatcher = this.getCoverageDispatcher(request, response); - try { - request.setAttribute("pageType", pageType); - response.setStatus(HttpServletResponse.SC_OK); - dispatcher.forward(request, response); - } catch (ServletException e) { - logger.log(Level.SEVERE, "Servlet Exception caught : ", e); - } - } else { - - String testName = request.getParameter("testName"); - - DataTable data = getCoverageDataTable(testName); - DataSourceRequest dsRequest = null; - - try { - // Extract the datasource request parameters. - dsRequest = new DataSourceRequest(request); - - // NOTE: If you want to work in restricted mode, which means that only - // requests from the same domain can access the data source, uncomment the following call. - // - // DataSourceHelper.verifyAccessApproved(dsRequest); - - // Apply the query to the data table. - DataTable newData = DataSourceHelper.applyQuery(dsRequest.getQuery(), data, - dsRequest.getUserLocale()); - - // Set the response. - DataSourceHelper.setServletResponse(newData, dsRequest, response); - } catch (RuntimeException rte) { - logger.log(Level.SEVERE, "A runtime exception has occured", rte); - ResponseStatus status = new ResponseStatus(StatusType.ERROR, ReasonType.INTERNAL_ERROR, - rte.getMessage()); - if (dsRequest == null) { - dsRequest = DataSourceRequest.getDefaultDataSourceRequest(request); - } - DataSourceHelper.setServletErrorResponse(status, dsRequest, response); - } catch (DataSourceException e) { - if (dsRequest != null) { - DataSourceHelper.setServletErrorResponse(e, dsRequest, response); + @Override + public void doGetHandler(HttpServletRequest request, HttpServletResponse response) + throws IOException { + + String pageType = + request.getParameter("pageType") == null + ? "html" + : request.getParameter("pageType"); + + RequestDispatcher dispatcher; + if (pageType.equalsIgnoreCase("html")) { + dispatcher = this.getCoverageDispatcher(request, response); + try { + request.setAttribute("pageType", pageType); + response.setStatus(HttpServletResponse.SC_OK); + dispatcher.forward(request, response); + } catch (ServletException e) { + logger.log(Level.SEVERE, "Servlet Exception caught : ", e); + } } else { - DataSourceHelper.setServletErrorResponse(e, request, response); + + String testName = request.getParameter("testName"); + + DataTable data = getCoverageDataTable(testName); + DataSourceRequest dsRequest = null; + + try { + // Extract the datasource request parameters. + dsRequest = new DataSourceRequest(request); + + // NOTE: If you want to work in restricted mode, which means that only + // requests from the same domain can access the data source, uncomment the following + // call. + // + // DataSourceHelper.verifyAccessApproved(dsRequest); + + // Apply the query to the data table. + DataTable newData = + DataSourceHelper.applyQuery( + dsRequest.getQuery(), data, dsRequest.getUserLocale()); + + // Set the response. + DataSourceHelper.setServletResponse(newData, dsRequest, response); + } catch (RuntimeException rte) { + logger.log(Level.SEVERE, "A runtime exception has occured", rte); + ResponseStatus status = + new ResponseStatus( + StatusType.ERROR, ReasonType.INTERNAL_ERROR, rte.getMessage()); + if (dsRequest == null) { + dsRequest = DataSourceRequest.getDefaultDataSourceRequest(request); + } + DataSourceHelper.setServletErrorResponse(status, dsRequest, response); + } catch (DataSourceException e) { + if (dsRequest != null) { + DataSourceHelper.setServletErrorResponse(e, dsRequest, response); + } else { + DataSourceHelper.setServletErrorResponse(e, request, response); + } + } } - } } - } - private List<Key<TestRunEntity>> getTestCoverageStatusEntityKeyList( + private List<Key<TestRunEntity>> getTestRunEntityKeyList( List<TestCoverageStatusEntity> testCoverageStatusEntityList) { return testCoverageStatusEntityList.stream() .map( @@ -158,43 +165,102 @@ public class ShowCoverageOverviewServlet extends BaseServlet { .collect(Collectors.toList()); } - private RequestDispatcher getCoverageDispatcher( - HttpServletRequest request, HttpServletResponse response) { - - String COVERAGE_OVERVIEW_JSP = "WEB-INF/jsp/show_coverage_overview.jsp"; - - RequestDispatcher dispatcher = null; - boolean unfiltered = request.getParameter("unfiltered") != null; - boolean showPresubmit = request.getParameter("showPresubmit") != null; - boolean showPostsubmit = request.getParameter("showPostsubmit") != null; - - // If no params are specified, set to default of postsubmit-only. - if (!(showPresubmit || showPostsubmit)) { - showPostsubmit = true; + private Predicate<DeviceInfoEntity> isBranchAndDevice(String branch, String device) { + return d -> d.getBranch().equals(branch) && d.getBuildFlavor().equals(device); } - // If unfiltered, set showPre- and Post-submit to true for accurate UI. - if (unfiltered) { - showPostsubmit = true; - showPresubmit = true; + private Predicate<DeviceInfoEntity> isBranch(String branch) { + return d -> d.getBranch().equals(branch); } - // Add test names to list - List<String> resultNames = new ArrayList<>(); - for (VtsReportMessage.TestCaseResult r : VtsReportMessage.TestCaseResult.values()) { - resultNames.add(r.name()); + private Predicate<DeviceInfoEntity> isDevice(String device) { + return d -> d.getBuildFlavor().equals(device); } - Map<String, String[]> parameterMap = request.getParameterMap(); + private RequestDispatcher getCoverageDispatcher( + HttpServletRequest request, HttpServletResponse response) { - List<TestCoverageStatusEntity> testCoverageStatusEntityList = - TestCoverageStatusEntity.getAllTestCoverage(); + String COVERAGE_OVERVIEW_JSP = "WEB-INF/jsp/show_coverage_overview.jsp"; - List<com.googlecode.objectify.Key<TestRunEntity>> testCoverageStatusEntityKeyList = - this.getTestCoverageStatusEntityKeyList(testCoverageStatusEntityList); + RequestDispatcher dispatcher = null; + boolean unfiltered = request.getParameter("unfiltered") != null; + boolean showPresubmit = request.getParameter("showPresubmit") != null; + boolean showPostsubmit = request.getParameter("showPostsubmit") != null; + + // If no params are specified, set to default of postsubmit-only. + if (!(showPresubmit || showPostsubmit)) { + showPostsubmit = true; + } + + // If unfiltered, set showPre- and Post-submit to true for accurate UI. + if (unfiltered) { + showPostsubmit = true; + showPresubmit = true; + } + + // Add test names to list + List<String> resultNames = + Arrays.stream(VtsReportMessage.TestCaseResult.values()) + .map(testCaseResult -> testCaseResult.name()) + .collect(Collectors.toList()); + + Map<String, String[]> parameterMap = request.getParameterMap(); + + List<TestCoverageStatusEntity> testCoverageStatusEntityList = + TestCoverageStatusEntity.getAllTestCoverage(); + + List<com.googlecode.objectify.Key<TestRunEntity>> testRunEntityKeyList = new ArrayList<>(); + + if (Objects.nonNull(parameterMap.get("branch")) + || Objects.nonNull(parameterMap.get("device"))) { + List<com.googlecode.objectify.Key<DeviceInfoEntity>> deviceInfoEntityKeyList = + TestCoverageStatusEntity.getDeviceInfoEntityKeyList( + testCoverageStatusEntityList); + + Collection<DeviceInfoEntity> deviceInfoEntityMap = + ofy().load().keys(() -> deviceInfoEntityKeyList.iterator()).values(); + + Stream<DeviceInfoEntity> deviceInfoEntityStream = Stream.empty(); + if (Objects.nonNull(parameterMap.get("branch")) + && Objects.nonNull(parameterMap.get("device"))) { + String branch = parameterMap.get("branch")[0]; + String device = parameterMap.get("device")[0]; + deviceInfoEntityStream = + deviceInfoEntityMap.stream().filter(isBranchAndDevice(branch, device)); + } else if (Objects.nonNull(parameterMap.get("branch"))) { + String branch = parameterMap.get("branch")[0]; + deviceInfoEntityStream = deviceInfoEntityMap.stream().filter(isBranch(branch)); + } else if (Objects.nonNull(parameterMap.get("device"))) { + String device = parameterMap.get("device")[0]; + deviceInfoEntityStream = deviceInfoEntityMap.stream().filter(isDevice(device)); + } else { + logger.log(Level.WARNING, "unmet search condition!"); + } + testRunEntityKeyList = + deviceInfoEntityStream + .map( + deviceInfoEntity -> { + com.googlecode.objectify.Key testKey = + com.googlecode.objectify.Key.create( + TestEntity.class, + deviceInfoEntity + .getParent() + .getParent() + .getName()); + return com.googlecode.objectify.Key.create( + testKey, + TestRunEntity.class, + deviceInfoEntity.getParent().getId()); + }) + .collect(Collectors.toList()); + logger.log(Level.INFO, "testRunEntityKeyList size => " + testRunEntityKeyList.size()); + } else { + testRunEntityKeyList = this.getTestRunEntityKeyList(testCoverageStatusEntityList); + } + Iterator<Key<TestRunEntity>> testRunEntityKeyIterator = testRunEntityKeyList.iterator(); Map<Key<TestRunEntity>, TestRunEntity> keyTestRunEntityMap = - ofy().load().keys(() -> testCoverageStatusEntityKeyList.iterator()); + ofy().load().keys(() -> testRunEntityKeyIterator); List<com.googlecode.objectify.Key<CodeCoverageEntity>> codeCoverageEntityKeyList = new ArrayList<>(); @@ -212,100 +278,120 @@ public class ShowCoverageOverviewServlet extends BaseServlet { keyCodeCoverageEntityMap = ofy().load().keys(() -> codeCoverageEntityKeyList.iterator()); - Map<Long, CodeCoverageEntity> codeCoverageEntityMap = new HashMap<>(); + Map<Long, CodeCoverageEntity> codeCoverageEntityMap = new HashMap<>(); for (Map.Entry<com.googlecode.objectify.Key<CodeCoverageEntity>, CodeCoverageEntity> entry : keyCodeCoverageEntityMap.entrySet()) { codeCoverageEntityMap.put(entry.getValue().getId(), entry.getValue()); } - int coveredLines = 0; - int uncoveredLines = 0; - int passCount = 0; - int failCount = 0; - for (Map.Entry<Long, CodeCoverageEntity> entry : codeCoverageEntityMap.entrySet()) { - TestRunEntity testRunEntity = testRunEntityMap.get(entry.getKey()); + int coveredLines = 0; + int uncoveredLines = 0; + int passCount = 0; + int failCount = 0; + for (Map.Entry<Long, CodeCoverageEntity> entry : codeCoverageEntityMap.entrySet()) { + TestRunEntity testRunEntity = testRunEntityMap.get(entry.getKey()); + + CodeCoverageEntity codeCoverageEntity = entry.getValue(); + + coveredLines += codeCoverageEntity.getCoveredLineCount(); + uncoveredLines += + codeCoverageEntity.getTotalLineCount() + - codeCoverageEntity.getCoveredLineCount(); + passCount += testRunEntity.getPassCount(); + failCount += testRunEntity.getFailCount(); + } + + FilterUtil.setAttributes(request, parameterMap); - CodeCoverageEntity codeCoverageEntity = entry.getValue(); + int[] testStats = new int[VtsReportMessage.TestCaseResult.values().length]; + testStats[VtsReportMessage.TestCaseResult.TEST_CASE_RESULT_PASS.getNumber()] = passCount; + testStats[VtsReportMessage.TestCaseResult.TEST_CASE_RESULT_FAIL.getNumber()] = failCount; - coveredLines += codeCoverageEntity.getCoveredLineCount(); - uncoveredLines += codeCoverageEntity.getTotalLineCount() - codeCoverageEntity.getCoveredLineCount(); - passCount += testRunEntity.getPassCount(); - failCount += testRunEntity.getFailCount(); + response.setStatus(HttpServletResponse.SC_OK); + request.setAttribute("resultNames", resultNames); + request.setAttribute("resultNamesJson", new Gson().toJson(resultNames)); + request.setAttribute("testRunEntityList", testRunEntityMap.values()); + request.setAttribute("codeCoverageEntityMap", codeCoverageEntityMap); + request.setAttribute("coveredLines", new Gson().toJson(coveredLines)); + request.setAttribute("uncoveredLines", new Gson().toJson(uncoveredLines)); + request.setAttribute("testStats", new Gson().toJson(testStats)); + + request.setAttribute("unfiltered", unfiltered); + request.setAttribute("showPresubmit", showPresubmit); + request.setAttribute("showPostsubmit", showPostsubmit); + + request.setAttribute( + "deviceOptions", + TestCoverageStatusEntity.getDeviceSet(testCoverageStatusEntityList)); + request.setAttribute( + "branchOptions", + TestCoverageStatusEntity.getBranchSet(testCoverageStatusEntityList)); + dispatcher = request.getRequestDispatcher(COVERAGE_OVERVIEW_JSP); + return dispatcher; } - FilterUtil.setAttributes(request, parameterMap); - - int[] testStats = new int[VtsReportMessage.TestCaseResult.values().length]; - testStats[VtsReportMessage.TestCaseResult.TEST_CASE_RESULT_PASS.getNumber()] = passCount; - testStats[VtsReportMessage.TestCaseResult.TEST_CASE_RESULT_FAIL.getNumber()] = failCount; - - response.setStatus(HttpServletResponse.SC_OK); - request.setAttribute("resultNames", resultNames); - request.setAttribute("resultNamesJson", new Gson().toJson(resultNames)); - request.setAttribute("testRunEntityList", testRunEntityMap.values()); - request.setAttribute("codeCoverageEntityMap", codeCoverageEntityMap); - request.setAttribute("coveredLines", new Gson().toJson(coveredLines)); - request.setAttribute("uncoveredLines", new Gson().toJson(uncoveredLines)); - request.setAttribute("testStats", new Gson().toJson(testStats)); - - request.setAttribute("unfiltered", unfiltered); - request.setAttribute("showPresubmit", showPresubmit); - request.setAttribute("showPostsubmit", showPostsubmit); - request.setAttribute("branches", new Gson().toJson(new ArrayList<>())); // DeviceInfoEntity.getAllBranches() - request.setAttribute("devices", new Gson().toJson(new ArrayList<>())); // DeviceInfoEntity.getAllBuildFlavors() - dispatcher = request.getRequestDispatcher(COVERAGE_OVERVIEW_JSP); - return dispatcher; - } - - private DataTable getCoverageDataTable(String testName) { - - Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); - - DataTable dataTable = new DataTable(); - ArrayList<ColumnDescription> cd = new ArrayList<>(); - ColumnDescription startDate = new ColumnDescription("startDate", ValueType.DATETIME, "Date"); - startDate.setPattern("yyyy-MM-dd"); - cd.add(startDate); - cd.add(new ColumnDescription("coveredLineCount", ValueType.NUMBER, - "Covered Source Code Line Count")); - cd.add( - new ColumnDescription("totalLineCount", ValueType.NUMBER, "Total Source Code Line Count")); - cd.add(new ColumnDescription("percentage", ValueType.NUMBER, "Coverage Ratio (%)")); - - dataTable.addColumns(cd); - - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.MONTH, -6); - Long startTime = cal.getTime().getTime() * 1000; - Long endTime = Calendar.getInstance().getTime().getTime() * 1000; - - com.google.cloud.datastore.Key startKey = datastore.newKeyFactory() - .setKind(TestRunEntity.KIND) - .addAncestors(PathElement.of(TestEntity.KIND, testName), - PathElement.of(TestRunEntity.KIND, startTime)) - .newKey(startTime); - - com.google.cloud.datastore.Key endKey = datastore.newKeyFactory() - .setKind(TestRunEntity.KIND) - .addAncestors(PathElement.of(TestEntity.KIND, testName), - PathElement.of(TestRunEntity.KIND, endTime)) - .newKey(endTime); - - Filter codeCoverageFilter = CompositeFilter.and( - PropertyFilter.lt("__key__", endKey), - PropertyFilter.gt("__key__", startKey) - ); - - List<CodeCoverageEntity> codeCoverageEntityList = ofy().load() - .type(CodeCoverageEntity.class) - .filter(codeCoverageFilter) - .limit(10) - .list(); - - DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd"); - Map<String, List<CodeCoverageEntity>> codeCoverageEntityListMap = codeCoverageEntityList.stream().collect( - Collectors.groupingBy(v -> dateTimeFormatter.print(v.getId() / 1000)) - ); + private DataTable getCoverageDataTable(String testName) { + + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + DataTable dataTable = new DataTable(); + ArrayList<ColumnDescription> cd = new ArrayList<>(); + ColumnDescription startDate = + new ColumnDescription("startDate", ValueType.DATETIME, "Date"); + startDate.setPattern("yyyy-MM-dd"); + cd.add(startDate); + cd.add( + new ColumnDescription( + "coveredLineCount", ValueType.NUMBER, "Covered Source Code Line Count")); + cd.add( + new ColumnDescription( + "totalLineCount", ValueType.NUMBER, "Total Source Code Line Count")); + cd.add(new ColumnDescription("percentage", ValueType.NUMBER, "Coverage Ratio (%)")); + + dataTable.addColumns(cd); + + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.MONTH, -6); + Long startTime = cal.getTime().getTime() * 1000; + Long endTime = Calendar.getInstance().getTime().getTime() * 1000; + + com.google.cloud.datastore.Key startKey = + datastore + .newKeyFactory() + .setKind(TestRunEntity.KIND) + .addAncestors( + PathElement.of(TestEntity.KIND, testName), + PathElement.of(TestRunEntity.KIND, startTime)) + .newKey(startTime); + + com.google.cloud.datastore.Key endKey = + datastore + .newKeyFactory() + .setKind(TestRunEntity.KIND) + .addAncestors( + PathElement.of(TestEntity.KIND, testName), + PathElement.of(TestRunEntity.KIND, endTime)) + .newKey(endTime); + + Filter codeCoverageFilter = + CompositeFilter.and( + PropertyFilter.lt("__key__", endKey), + PropertyFilter.gt("__key__", startKey)); + + List<CodeCoverageEntity> codeCoverageEntityList = + ofy().load() + .type(CodeCoverageEntity.class) + .filter(codeCoverageFilter) + .limit(10) + .list(); + + DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyy-MM-dd"); + Map<String, List<CodeCoverageEntity>> codeCoverageEntityListMap = + codeCoverageEntityList + .stream() + .collect( + Collectors.groupingBy( + v -> dateTimeFormatter.print(v.getId() / 1000))); codeCoverageEntityListMap.forEach( (key, entityList) -> { @@ -341,6 +427,6 @@ public class ShowCoverageOverviewServlet extends BaseServlet { } }); - return dataTable; - } + return dataTable; + } } |