diff options
author | Young Gyu Park <younggyu@google.com> | 2018-08-21 16:25:41 +0900 |
---|---|---|
committer | Young Gyu Park <younggyu@google.com> | 2018-08-24 08:52:05 +0900 |
commit | 85586068d384d4e51d22cee1fe0f3ab75167a34a (patch) | |
tree | facd45ddac28910a417a2b3ea1bfa36e22ab3e73 /src/main | |
parent | 7148352cb05e0d011d568f1465cfb1ef1882dcce (diff) | |
download | dashboard-85586068d384d4e51d22cee1fe0f3ab75167a34a.tar.gz |
Implementing rest API for API coverage.
Test: go/vts-web-staging
Bug: 111481322
Change-Id: I68604b91f38adb8bfec94d9f2a1d1a7585193a6f
Diffstat (limited to 'src/main')
6 files changed, 205 insertions, 76 deletions
diff --git a/src/main/java/com/android/vts/api/CoverageRestServlet.java b/src/main/java/com/android/vts/api/CoverageRestServlet.java index 460949e..b2bbe63 100644 --- a/src/main/java/com/android/vts/api/CoverageRestServlet.java +++ b/src/main/java/com/android/vts/api/CoverageRestServlet.java @@ -16,77 +16,161 @@ package com.android.vts.api; +import com.android.vts.entity.ApiCoverageEntity; import com.android.vts.entity.CoverageEntity; import com.android.vts.entity.TestCoverageStatusEntity; -import com.android.vts.entity.TestSuiteFileEntity; -import com.android.vts.entity.TestSuiteResultEntity; -import com.android.vts.proto.TestSuiteResultMessageProto.TestSuiteResultMessage; -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.jackson.JacksonFactory; -import com.google.api.services.oauth2.Oauth2; -import com.google.api.services.oauth2.model.Tokeninfo; +import com.android.vts.entity.TestPlanRunEntity; import com.google.gson.Gson; import com.googlecode.objectify.Key; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Properties; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.codec.binary.Base64; -/** - * REST endpoint for posting test suite data to the Dashboard. - */ +import static com.googlecode.objectify.ObjectifyService.ofy; + +/** REST endpoint for posting test suite data to the Dashboard. */ public class CoverageRestServlet extends BaseApiServlet { - private static final Logger logger = - Logger.getLogger(CoverageRestServlet.class.getName()); + private static final Logger logger = Logger.getLogger(CoverageRestServlet.class.getName()); + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + String pathInfo = request.getPathInfo(); + String json = ""; + if (Objects.nonNull(pathInfo)) { + if (pathInfo.equalsIgnoreCase("/api/data")) { + String key = request.getParameter("key"); + json = apiCoverageData(key); + } 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); + } + + private String apiCoverageData(String key) { + ApiCoverageEntity apiCoverageEntity = ApiCoverageEntity.getByUrlSafeKey(key); + String apiCoverageEntityJson = new Gson().toJson(apiCoverageEntity); + return apiCoverageEntityJson; + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws IOException { + + String pathInfo = request.getPathInfo(); + String json = ""; + if (Objects.nonNull(pathInfo)) { + if (pathInfo.equalsIgnoreCase("/api/data")) { + String cmd = request.getParameter("cmd"); + String coverageId = request.getParameter("coverageId"); + String testName = request.getParameter("testName"); + String testRunId = request.getParameter("testRunId"); + json = postCoverageData(cmd, coverageId, testName, testRunId); + } else if (pathInfo.equalsIgnoreCase("/api/sum")) { + String urlSafeKey = request.getParameter("urlSafeKey"); + json = postCoverageDataSum(urlSafeKey); + } else { + json = "{error: 'true', message: 'unexpected path!!!'}"; + } + } 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); + } + + private String postCoverageDataSum(String urlSafeKey) { + List<List<String>> allHalApiList = new ArrayList(); + List<List<String>> allCoveredHalApiList = new ArrayList(); + + Key<TestPlanRunEntity> key = Key.create(urlSafeKey); + TestPlanRunEntity testPlanRunEntity = ofy().load().key(key).now(); + + for (Key testRunKey : testPlanRunEntity.getTestRuns()) { + List<ApiCoverageEntity> apiCoverageEntityList = + ofy().load().type(ApiCoverageEntity.class).ancestor(testRunKey).list(); + for (ApiCoverageEntity apiCoverageEntity : apiCoverageEntityList) { + allHalApiList.add(apiCoverageEntity.getHalApi()); + allCoveredHalApiList.add(apiCoverageEntity.getCoveredHalApi()); + } + } + long totalHalApiNum = allHalApiList.stream().flatMap(Collection::stream).distinct().count(); + long totalCoveredHalApiNum = + allCoveredHalApiList.stream().flatMap(Collection::stream).distinct().count(); + testPlanRunEntity.setTotalApiCount(totalHalApiNum); + testPlanRunEntity.setCoveredApiCount(totalCoveredHalApiNum); + testPlanRunEntity.save(); + + Map<String, Long> halApiNumMap = + new HashMap<String, Long>() { + { + put("totalHalApiNum", totalHalApiNum); + put("totalCoveredHalApiNum", totalCoveredHalApiNum); + } + }; + String json = new Gson().toJson(halApiNumMap); + return json; + } + + /** + * The API to ignore the irrelevant code for calculating ratio + * + * @param cmd disable or enable command to ignore the code. + * @param coverageId the datastore ID for code coverage. + * @param testName the test name. + * @param testRunId the test run ID from datastore. + * @return success json. + */ + private String postCoverageData( + String cmd, String coverageId, String testName, String testRunId) { - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException { + Boolean isIgnored = false; + if (cmd.equals("disable")) { + isIgnored = true; + } + CoverageEntity coverageEntity = CoverageEntity.findById(testName, testRunId, coverageId); + coverageEntity.setIsIgnored(isIgnored); + coverageEntity.save(); - String cmd = request.getParameter("cmd"); - String coverageId = request.getParameter("coverageId"); - String testName = request.getParameter("testName"); - String testRunId = request.getParameter("testRunId"); + TestCoverageStatusEntity testCoverageStatusEntity = + TestCoverageStatusEntity.findById(testName); + Long newCoveredLineCount = + cmd.equals("disable") + ? testCoverageStatusEntity.getUpdatedCoveredLineCount() + - coverageEntity.getCoveredCount() + : testCoverageStatusEntity.getUpdatedCoveredLineCount() + + coverageEntity.getCoveredCount(); + Long newTotalLineCount = + cmd.equals("disable") + ? testCoverageStatusEntity.getUpdatedTotalLineCount() + - coverageEntity.getTotalCount() + : testCoverageStatusEntity.getUpdatedTotalLineCount() + + coverageEntity.getTotalCount(); + testCoverageStatusEntity.setUpdatedCoveredLineCount(newCoveredLineCount); + testCoverageStatusEntity.setUpdatedTotalLineCount(newTotalLineCount); + testCoverageStatusEntity.save(); - Boolean isIgnored = false; - if (cmd.equals("disable")) { - isIgnored = true; + String json = new Gson().toJson("Success!"); + return json; } - CoverageEntity coverageEntity = CoverageEntity.findById(testName, testRunId, coverageId); - coverageEntity.setIsIgnored(isIgnored); - coverageEntity.save(); - - TestCoverageStatusEntity testCoverageStatusEntity = TestCoverageStatusEntity.findById(testName); - Long newCoveredLineCount = - cmd.equals("disable") ? testCoverageStatusEntity.getUpdatedCoveredLineCount() - - coverageEntity.getCoveredCount() - : testCoverageStatusEntity.getUpdatedCoveredLineCount() + coverageEntity - .getCoveredCount(); - Long newTotalLineCount = - cmd.equals("disable") ? testCoverageStatusEntity.getUpdatedTotalLineCount() - coverageEntity - .getTotalCount() - : testCoverageStatusEntity.getUpdatedTotalLineCount() + coverageEntity.getTotalCount(); - testCoverageStatusEntity.setUpdatedCoveredLineCount(newCoveredLineCount); - testCoverageStatusEntity.setUpdatedTotalLineCount(newTotalLineCount); - testCoverageStatusEntity.save(); - - String json = new Gson().toJson("Success!"); - 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/api/TestDataForDevServlet.java b/src/main/java/com/android/vts/api/TestDataForDevServlet.java index 70aa74a..a265b81 100644 --- a/src/main/java/com/android/vts/api/TestDataForDevServlet.java +++ b/src/main/java/com/android/vts/api/TestDataForDevServlet.java @@ -278,7 +278,6 @@ public class TestDataForDevServlet extends HttpServlet { new TestSuiteFileEntity( pathInfo .toString()); - newTestSuiteFileEntity.save(); com.googlecode.objectify.Key< TestSuiteFileEntity> @@ -289,6 +288,8 @@ public class TestDataForDevServlet extends HttpServlet { .class, newTestSuiteFileEntity .getFilePath()); + + TestSuiteResultEntity testSuiteResultEntity = new TestSuiteResultEntity( @@ -342,7 +343,7 @@ public class TestDataForDevServlet extends HttpServlet { rand.nextInt(), rand.nextInt()); - testSuiteResultEntity.save(); + testSuiteResultEntity.save(newTestSuiteFileEntity); }))); resultMap.put("result", "successfully generated!"); return resultMap; @@ -626,6 +627,8 @@ public class TestDataForDevServlet extends HttpServlet { testBuildId, passCount, failCount, + 0L, + 0L, testRunKeys); // Create the device infos. diff --git a/src/main/java/com/android/vts/api/TestSuiteResultRestServlet.java b/src/main/java/com/android/vts/api/TestSuiteResultRestServlet.java index 8f52c85..4f2d52e 100644 --- a/src/main/java/com/android/vts/api/TestSuiteResultRestServlet.java +++ b/src/main/java/com/android/vts/api/TestSuiteResultRestServlet.java @@ -88,8 +88,10 @@ public class TestSuiteResultRestServlet extends BaseApiServlet { Tokeninfo tokenInfo = oauth2.tokeninfo().setAccessToken(accessToken).execute(); if (tokenInfo.getIssuedTo().equals(SERVICE_CLIENT_ID)) { + String filePath = "suite_result/2019/04/06/132343.bin"; Key<TestSuiteFileEntity> testSuiteFileParent = - Key.create(TestSuiteFileEntity.class, "suite_result/2019/04/06/132343.bin"); + Key.create(TestSuiteFileEntity.class, filePath); + TestSuiteFileEntity newTestSuiteFileEntity = new TestSuiteFileEntity(filePath); TestSuiteResultEntity testSuiteResultEntity = new TestSuiteResultEntity( testSuiteFileParent, @@ -114,7 +116,7 @@ public class TestSuiteResultRestServlet extends BaseApiServlet { testSuiteResultMessage.getPassedTestCaseCount(), testSuiteResultMessage.getFailedTestCaseCount()); - testSuiteResultEntity.save(); + testSuiteResultEntity.save(newTestSuiteFileEntity); resultMap.put("result", "successfully saved!"); } else { logger.log(Level.WARNING, "service_client_id didn't match!"); diff --git a/src/main/java/com/android/vts/config/ObjectifyListener.java b/src/main/java/com/android/vts/config/ObjectifyListener.java index a78fd66..2c73e1f 100644 --- a/src/main/java/com/android/vts/config/ObjectifyListener.java +++ b/src/main/java/com/android/vts/config/ObjectifyListener.java @@ -16,13 +16,20 @@ package com.android.vts.config; +import com.android.vts.entity.ApiCoverageEntity; import com.android.vts.entity.CoverageEntity; +import com.android.vts.entity.DeviceInfoEntity; +import com.android.vts.entity.ProfilingPointEntity; +import com.android.vts.entity.ProfilingPointRunEntity; +import com.android.vts.entity.ProfilingPointSummaryEntity; import com.android.vts.entity.RoleEntity; +import com.android.vts.entity.TestCaseRunEntity; import com.android.vts.entity.TestCoverageStatusEntity; import com.android.vts.entity.TestEntity; import com.android.vts.entity.TestPlanEntity; import com.android.vts.entity.TestPlanRunEntity; import com.android.vts.entity.TestRunEntity; +import com.android.vts.entity.TestStatusEntity; import com.android.vts.entity.TestSuiteFileEntity; import com.android.vts.entity.TestSuiteResultEntity; import com.android.vts.entity.UserEntity; @@ -66,12 +73,21 @@ public class ObjectifyListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { ObjectifyService.init(); + ObjectifyService.register(ApiCoverageEntity.class); ObjectifyService.register(CoverageEntity.class); + ObjectifyService.register(DeviceInfoEntity.class); ObjectifyService.register(TestCoverageStatusEntity.class); + + ObjectifyService.register(ProfilingPointEntity.class); + ObjectifyService.register(ProfilingPointRunEntity.class); + ObjectifyService.register(ProfilingPointSummaryEntity.class); + ObjectifyService.register(TestEntity.class); ObjectifyService.register(TestPlanEntity.class); ObjectifyService.register(TestPlanRunEntity.class); ObjectifyService.register(TestRunEntity.class); + ObjectifyService.register(TestCaseRunEntity.class); + ObjectifyService.register(TestStatusEntity.class); ObjectifyService.register(TestSuiteFileEntity.class); ObjectifyService.register(TestSuiteResultEntity.class); ObjectifyService.register(RoleEntity.class); diff --git a/src/main/java/com/android/vts/entity/TestStatusEntity.java b/src/main/java/com/android/vts/entity/TestStatusEntity.java index 9464352..ec5ee36 100644 --- a/src/main/java/com/android/vts/entity/TestStatusEntity.java +++ b/src/main/java/com/android/vts/entity/TestStatusEntity.java @@ -18,13 +18,24 @@ package com.android.vts.entity; import com.android.vts.entity.TestCaseRunEntity.TestCase; import com.google.appengine.api.datastore.Entity; +import com.googlecode.objectify.annotation.Cache; +import com.googlecode.objectify.annotation.Id; +import com.googlecode.objectify.annotation.Ignore; +import com.googlecode.objectify.annotation.Index; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import lombok.Data; +import lombok.NoArgsConstructor; +@com.googlecode.objectify.annotation.Entity(name = "TestStatus") +@Cache +@Data +@NoArgsConstructor /** Entity describing test status. */ -public class TestStatusEntity implements DashboardEntity { +public class TestStatusEntity implements Serializable { protected static final Logger logger = Logger.getLogger(TestStatusEntity.class.getName()); public static final String KIND = "TestStatus"; @@ -37,11 +48,25 @@ public class TestStatusEntity implements DashboardEntity { protected static final String FAILING_IDS = "failingTestcaseIds"; protected static final String FAILING_OFFSETS = "failingTestcaseOffsets"; - public final String testName; - public final int passCount; - public final int failCount; - public final long timestamp; - public final List<TestCaseReference> failingTestCases; + /** ID field */ + @Id private String testName; + + /** Failing Testcase ID List field */ + private List<Long> failingTestcaseIds; + + /** Failing Testcase Offsets List field */ + private List<Integer> failingTestcaseOffsets; + + /** pass count field */ + @Index private int passCount; + + /** fail count field */ + @Index private int failCount; + + /** updated timestamp field */ + @Index private long updatedTimestamp; + + @Ignore private List<TestCaseReference> failingTestCases; /** Object representing a reference to a test case. */ public static class TestCaseReference { @@ -79,13 +104,13 @@ public class TestStatusEntity implements DashboardEntity { * @param failingTestCases The TestCaseReferences of the last observed failing test cases. */ public TestStatusEntity( - String testName, - long timestamp, - int passCount, - int failCount, - List<TestCaseReference> failingTestCases) { + String testName, + long timestamp, + int passCount, + int failCount, + List<TestCaseReference> failingTestCases) { this.testName = testName; - this.timestamp = timestamp; + this.updatedTimestamp = timestamp; this.passCount = passCount; this.failCount = failCount; this.failingTestCases = failingTestCases; @@ -100,11 +125,10 @@ public class TestStatusEntity implements DashboardEntity { this(testName, 0, -1, -1, new ArrayList<TestCaseReference>()); } - @Override public Entity toEntity() { Entity testEntity = new Entity(KIND, this.testName); - if (this.timestamp >= 0 && this.passCount >= 0 && this.failCount >= 0) { - testEntity.setProperty(UPDATED_TIMESTAMP, this.timestamp); + if (this.updatedTimestamp >= 0 && this.passCount >= 0 && this.failCount >= 0) { + testEntity.setProperty(UPDATED_TIMESTAMP, this.updatedTimestamp); testEntity.setProperty(PASS_COUNT, this.passCount); testEntity.setProperty(FAIL_COUNT, this.failCount); if (this.failingTestCases.size() > 0) { @@ -154,7 +178,7 @@ public class TestStatusEntity implements DashboardEntity { if (ids.size() == offsets.size()) { for (int i = 0; i < ids.size(); i++) { failingTestCases.add( - new TestCaseReference(ids.get(i), offsets.get(i).intValue())); + new TestCaseReference(ids.get(i), offsets.get(i).intValue())); } } } diff --git a/src/main/webapp/js/test_results.js b/src/main/webapp/js/test_results.js index e00d6ac..45c1de4 100644 --- a/src/main/webapp/js/test_results.js +++ b/src/main/webapp/js/test_results.js @@ -264,7 +264,7 @@ var total = metadata.testRun.totalApiCount; var apiCoverage = ('API Coverage: ' + covered + '/' + total); createClickableIndicator( - div, apiCoverage, 'yellow grey-text', + div, apiCoverage, 'orange', function (evt) { $('#apiCoverageModal').data("urlSafeKeyList", metadata.testRun.apiCoverageKeyList); $('#apiCoverageModal').modal('open'); |