diff options
6 files changed, 374 insertions, 263 deletions
diff --git a/src/main/java/com/android/vts/entity/CoverageEntity.java b/src/main/java/com/android/vts/entity/CoverageEntity.java index 04c863c..82b6690 100644 --- a/src/main/java/com/android/vts/entity/CoverageEntity.java +++ b/src/main/java/com/android/vts/entity/CoverageEntity.java @@ -73,7 +73,7 @@ public class CoverageEntity implements Serializable { @Id @Getter @Setter - private Long ID; + private Long id; @Parent @Getter diff --git a/src/main/java/com/android/vts/entity/DeviceInfoEntity.java b/src/main/java/com/android/vts/entity/DeviceInfoEntity.java index cedb7b7..6992983 100644 --- a/src/main/java/com/android/vts/entity/DeviceInfoEntity.java +++ b/src/main/java/com/android/vts/entity/DeviceInfoEntity.java @@ -19,17 +19,25 @@ package com.android.vts.entity; import com.android.vts.proto.VtsReportMessage.AndroidDeviceInfoMessage; 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.googlecode.objectify.annotation.Cache; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Ignore; import com.googlecode.objectify.annotation.Index; import com.googlecode.objectify.annotation.Parent; import java.io.Serializable; +import java.util.List; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; + import lombok.Data; import lombok.NoArgsConstructor; +import static com.googlecode.objectify.ObjectifyService.ofy; + @com.googlecode.objectify.annotation.Entity(name = "DeviceInfo") @Cache @Data @@ -38,6 +46,9 @@ import lombok.NoArgsConstructor; public class DeviceInfoEntity implements Serializable { protected static final Logger logger = Logger.getLogger(DeviceInfoEntity.class.getName()); + /** This is the instance of App Engine memcache service java library */ + private static MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService(); + public static final String KIND = "DeviceInfo"; // Property keys @@ -106,6 +117,44 @@ public class DeviceInfoEntity implements Serializable { 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() + .type(DeviceInfoEntity.class) + .project("branch") + .distinct(true) + .list() + .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() + .type(DeviceInfoEntity.class) + .project("buildFlavor") + .distinct(true) + .list() + .stream() + .map(device -> device.buildFlavor) + .collect(Collectors.toList()); + syncCache.put("buildFlavorList", buildFlavorList); + } + return buildFlavorList; + } + public Entity toEntity() { Entity deviceEntity = new Entity(KIND, this.parentKey); deviceEntity.setProperty(BRANCH, this.branch.toLowerCase()); diff --git a/src/main/java/com/android/vts/entity/TestCaseRunEntity.java b/src/main/java/com/android/vts/entity/TestCaseRunEntity.java index b0f16ea..6d3ba83 100644 --- a/src/main/java/com/android/vts/entity/TestCaseRunEntity.java +++ b/src/main/java/com/android/vts/entity/TestCaseRunEntity.java @@ -21,6 +21,7 @@ import com.google.appengine.api.datastore.KeyFactory; import com.googlecode.objectify.annotation.Cache; import com.googlecode.objectify.annotation.Id; import com.googlecode.objectify.annotation.Ignore; +import com.googlecode.objectify.annotation.OnLoad; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; @@ -128,6 +129,18 @@ public class TestCaseRunEntity implements DashboardEntity { } /** + * Called after the POJO is populated with data through objecitfy library + */ + @OnLoad + private void onLoad() { + if (testCaseNames.size() == results.size()) { + for (int index = 0; index < testCaseNames.size(); index++) { + this.addTestCase(testCaseNames.get(index), results.get(index).intValue()); + } + } + } + + /** * Add a test case to the test case run entity. * @param name The name of the test case. * @param result The result of the test case. diff --git a/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java b/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java index bad5268..12572ce 100644 --- a/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java +++ b/src/main/java/com/android/vts/entity/TestCoverageStatusEntity.java @@ -41,162 +41,128 @@ import lombok.Setter; /** Entity describing test coverage status. */ public class TestCoverageStatusEntity implements Serializable { - protected static final Logger logger = - Logger.getLogger(TestCoverageStatusEntity.class.getName()); - - public static final String KIND = "TestCoverageStatus"; - - // Property keys - public static final String TOTAL_LINE_COUNT = "totalLineCount"; - public static final String COVERED_LINE_COUNT = "coveredLineCount"; - public static final String UPDATED_TIMESTAMP = "updatedTimestamp"; - - /** - * TestCoverageStatusEntity name field - */ - @Id - @Getter - @Setter - String testName; - - /** - * TestCoverageStatusEntity coveredLineCount field - */ - @Index - @Getter - @Setter - long coveredLineCount; - - /** - * TestCoverageStatusEntity totalLineCount field - */ - @Index - @Getter - @Setter - long totalLineCount; - - /** - * TestCoverageStatusEntity updatedTimestamp field - */ - @Index - @Getter - @Setter - long updatedTimestamp; - - /** - * TestCoverageStatusEntity updatedCoveredLineCount field - */ - @Index - @Getter - @Setter - long updatedCoveredLineCount; - - /** - * TestCoverageStatusEntity updatedTotalLineCount field - */ - @Index - @Getter - @Setter - long updatedTotalLineCount; - - /** - * TestCoverageStatusEntity updatedDate field - */ - @Index - @Getter - @Setter - Date updatedDate; - - /** - * Create a TestCoverageStatusEntity object with status metadata. - * - * @param testName The name of the test. - * @param timestamp The timestamp indicating the most recent test run event in the test state. - * @param coveredLineCount The number of lines covered. - * @param totalLineCount The total number of lines. - */ - public TestCoverageStatusEntity( - String testName, long timestamp, long coveredLineCount, long totalLineCount) { - this.testName = testName; - this.updatedTimestamp = timestamp; - this.coveredLineCount = coveredLineCount; - this.totalLineCount = totalLineCount; - } - - /** - * find TestCoverageStatus entity by ID - */ - public static TestCoverageStatusEntity findById(String testName) { - return ofy().load().type(TestCoverageStatusEntity.class).id(testName).now(); - } - - /** - * Get all TestCoverageStatusEntity List - */ - public static Map<String, TestCoverageStatusEntity> getTestCoverageStatusMap() { - List<TestCoverageStatusEntity> testCoverageStatusEntityList = getAllTestCoverage(); - - Map<String, TestCoverageStatusEntity> testCoverageStatusMap = testCoverageStatusEntityList - .stream() - .collect( - Collectors.toMap(t -> t.getTestName(), t -> t) - ); - return testCoverageStatusMap; - } - - /** - * Get all TestCoverageStatusEntity List - */ - public static List<TestCoverageStatusEntity> getAllTestCoverage() { - return ofy().load().type(TestCoverageStatusEntity.class).list(); - } - - /** - * Saving function for the instance of this class - */ - public void save() { - this.updatedDate = new Date(); - ofy().save().entity(this).now(); - } - - public Entity toEntity() { - Entity testEntity = new Entity(KIND, this.testName); - testEntity.setProperty(UPDATED_TIMESTAMP, this.updatedTimestamp); - testEntity.setProperty(COVERED_LINE_COUNT, this.coveredLineCount); - testEntity.setProperty(TOTAL_LINE_COUNT, this.totalLineCount); - return testEntity; - } - - /** - * Convert an Entity object to a TestCoverageStatusEntity. - * - * @param e The entity to process. - * @return TestCoverageStatusEntity object with the properties from e processed, or null if - * incompatible. - */ - @SuppressWarnings("unchecked") - public static TestCoverageStatusEntity fromEntity(Entity e) { - if (!e.getKind().equals(KIND) - || e.getKey().getName() == null - || !e.hasProperty(UPDATED_TIMESTAMP) - || !e.hasProperty(COVERED_LINE_COUNT) - || !e.hasProperty(TOTAL_LINE_COUNT)) { - logger.log(Level.WARNING, "Missing test attributes in entity: " + e.toString()); - return null; + protected static final Logger logger = + Logger.getLogger(TestCoverageStatusEntity.class.getName()); + + public static final String KIND = "TestCoverageStatus"; + + // Property keys + public static final String TOTAL_LINE_COUNT = "totalLineCount"; + public static final String COVERED_LINE_COUNT = "coveredLineCount"; + public static final String UPDATED_TIMESTAMP = "updatedTimestamp"; + + /** TestCoverageStatusEntity name field */ + @Id @Getter @Setter String testName; + + /** TestCoverageStatusEntity coveredLineCount field */ + @Index @Getter @Setter long coveredLineCount; + + /** TestCoverageStatusEntity totalLineCount field */ + @Index @Getter @Setter long totalLineCount; + + /** TestCoverageStatusEntity updatedTimestamp field */ + @Index @Getter @Setter long updatedTimestamp; + + /** TestCoverageStatusEntity updatedCoveredLineCount field */ + @Index @Getter @Setter long updatedCoveredLineCount; + + /** TestCoverageStatusEntity updatedTotalLineCount field */ + @Index @Getter @Setter long updatedTotalLineCount; + + /** TestCoverageStatusEntity updatedDate field */ + @Index @Getter @Setter Date updatedDate; + + /** + * Create a TestCoverageStatusEntity object with status metadata. + * + * @param testName The name of the test. + * @param timestamp The timestamp indicating the most recent test run event in the test state. + * @param coveredLineCount The number of lines covered. + * @param totalLineCount The total number of lines. + */ + public TestCoverageStatusEntity( + String testName, long timestamp, long coveredLineCount, long totalLineCount) { + this.testName = testName; + this.updatedTimestamp = timestamp; + this.coveredLineCount = coveredLineCount; + this.totalLineCount = totalLineCount; } - String testName = e.getKey().getName(); - long timestamp = 0; - long coveredLineCount = -1; - long totalLineCount = -1; - try { - timestamp = (long) e.getProperty(UPDATED_TIMESTAMP); - coveredLineCount = (Long) e.getProperty(COVERED_LINE_COUNT); - totalLineCount = (Long) e.getProperty(TOTAL_LINE_COUNT); - } catch (ClassCastException exception) { - // Invalid contents or null values - logger.log(Level.WARNING, "Error parsing test entity.", exception); - return null; + + /** find TestCoverageStatus entity by ID */ + public static TestCoverageStatusEntity findById(String testName) { + return ofy().load().type(TestCoverageStatusEntity.class).id(testName).now(); + } + + /** Get all TestCoverageStatusEntity List */ + public static Map<String, TestCoverageStatusEntity> getTestCoverageStatusMap() { + List<TestCoverageStatusEntity> testCoverageStatusEntityList = getAllTestCoverage(); + + Map<String, TestCoverageStatusEntity> testCoverageStatusMap = + testCoverageStatusEntityList.stream() + .collect(Collectors.toMap(t -> t.getTestName(), t -> t)); + return testCoverageStatusMap; + } + + /** Get all TestCoverageStatusEntity List */ + public static List<TestCoverageStatusEntity> getAllTestCoverage() { + return ofy().load().type(TestCoverageStatusEntity.class).list(); + } + + /** TestRunEntity function to get the related TestRunEntity from id value */ + public TestRunEntity getTestRunEntity() { + com.googlecode.objectify.Key testKey = + com.googlecode.objectify.Key.create(TestEntity.class, this.testName); + return ofy().load() + .type(TestRunEntity.class) + .parent(testKey) + .id(this.updatedTimestamp) + .now(); + } + + /** Saving function for the instance of this class */ + public void save() { + this.updatedDate = new Date(); + ofy().save().entity(this).now(); + } + + public Entity toEntity() { + Entity testEntity = new Entity(KIND, this.testName); + testEntity.setProperty(UPDATED_TIMESTAMP, this.updatedTimestamp); + testEntity.setProperty(COVERED_LINE_COUNT, this.coveredLineCount); + testEntity.setProperty(TOTAL_LINE_COUNT, this.totalLineCount); + return testEntity; + } + + /** + * Convert an Entity object to a TestCoverageStatusEntity. + * + * @param e The entity to process. + * @return TestCoverageStatusEntity object with the properties from e processed, or null if + * incompatible. + */ + @SuppressWarnings("unchecked") + public static TestCoverageStatusEntity fromEntity(Entity e) { + if (!e.getKind().equals(KIND) + || e.getKey().getName() == null + || !e.hasProperty(UPDATED_TIMESTAMP) + || !e.hasProperty(COVERED_LINE_COUNT) + || !e.hasProperty(TOTAL_LINE_COUNT)) { + logger.log(Level.WARNING, "Missing test attributes in entity: " + e.toString()); + return null; + } + String testName = e.getKey().getName(); + long timestamp = 0; + long coveredLineCount = -1; + long totalLineCount = -1; + try { + timestamp = (long) e.getProperty(UPDATED_TIMESTAMP); + coveredLineCount = (Long) e.getProperty(COVERED_LINE_COUNT); + totalLineCount = (Long) e.getProperty(TOTAL_LINE_COUNT); + } 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); - } } diff --git a/src/main/java/com/android/vts/entity/TestPlanRunEntity.java b/src/main/java/com/android/vts/entity/TestPlanRunEntity.java index 95f7758..7dbb0dc 100644 --- a/src/main/java/com/android/vts/entity/TestPlanRunEntity.java +++ b/src/main/java/com/android/vts/entity/TestPlanRunEntity.java @@ -35,6 +35,7 @@ import com.googlecode.objectify.annotation.Parent; import java.io.Serializable; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -79,8 +80,6 @@ public class TestPlanRunEntity implements Serializable { @Index private String testPlanName; - @Ignore private TestRunType testRunType; - @Index private long type; @Index private long startTimestamp; @@ -119,7 +118,7 @@ public class TestPlanRunEntity implements Serializable { public TestPlanRunEntity( Key parentKey, String testPlanName, - TestRunType type, + long type, long startTimestamp, long endTimestamp, String testBuildId, @@ -130,7 +129,7 @@ public class TestPlanRunEntity implements Serializable { List<Key> testRuns) { this.key = KeyFactory.createKey(parentKey, KIND, startTimestamp); this.testPlanName = testPlanName; - this.testRunType = type; + this.type = type; this.startTimestamp = startTimestamp; this.endTimestamp = endTimestamp; this.testBuildId = testBuildId; @@ -156,7 +155,7 @@ public class TestPlanRunEntity implements Serializable { public Entity toEntity() { Entity planRun = new Entity(this.key); planRun.setProperty(TEST_PLAN_NAME, this.testPlanName); - planRun.setProperty(TYPE, this.testRunType.getNumber()); + planRun.setProperty(TYPE, this.type); planRun.setProperty(START_TIMESTAMP, this.startTimestamp); planRun.setProperty(END_TIMESTAMP, this.endTimestamp); planRun.setProperty(TEST_BUILD_ID, this.testBuildId.toLowerCase()); @@ -186,11 +185,15 @@ public class TestPlanRunEntity implements Serializable { /** Add a task to calculate the total number of coverage API */ public void addCoverageApiTask() { - Queue queue = QueueFactory.getQueue(QUEUE_NAME); - queue.add( - TaskOptions.Builder.withUrl(COVERAGE_API_URL) - .param("urlSafeKey", String.valueOf(this.getUrlSafeKey())) - .method(TaskOptions.Method.POST)); + if (Objects.isNull(this.testRuns)) { + logger.log(Level.WARNING, "testRuns is null so adding task to the queue is skipped!"); + } else { + Queue queue = QueueFactory.getQueue(QUEUE_NAME); + queue.add( + TaskOptions.Builder.withUrl(COVERAGE_API_URL) + .param("urlSafeKey", String.valueOf(this.getUrlSafeKey())) + .method(TaskOptions.Method.POST)); + } } /** @@ -225,7 +228,7 @@ public class TestPlanRunEntity implements Serializable { } try { String testPlanName = (String) e.getProperty(TEST_PLAN_NAME); - TestRunType type = TestRunType.fromNumber((int) (long) e.getProperty(TYPE)); + long type = (long) e.getProperty(TYPE); long startTimestamp = (long) e.getProperty(START_TIMESTAMP); long endTimestamp = (long) e.getProperty(END_TIMESTAMP); String testBuildId = (String) e.getProperty(TEST_BUILD_ID); diff --git a/src/main/java/com/android/vts/entity/TestRunEntity.java b/src/main/java/com/android/vts/entity/TestRunEntity.java index 625fc2c..bdd0ac8 100644 --- a/src/main/java/com/android/vts/entity/TestRunEntity.java +++ b/src/main/java/com/android/vts/entity/TestRunEntity.java @@ -18,6 +18,7 @@ package com.android.vts.entity; import static com.googlecode.objectify.ObjectifyService.ofy; +import com.android.vts.util.TimeUtil; import com.android.vts.util.UrlUtil; import com.android.vts.util.UrlUtil.LinkDisplay; import com.google.appengine.api.datastore.Entity; @@ -32,10 +33,14 @@ 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 com.googlecode.objectify.annotation.OnLoad; import com.googlecode.objectify.annotation.Parent; import java.io.Serializable; import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; import java.util.logging.Level; @@ -51,7 +56,6 @@ import org.json.JSONArray; @com.googlecode.objectify.annotation.Entity(name = "TestRun") @Cache -@Data @NoArgsConstructor /** Entity describing test run information. */ public class TestRunEntity implements Serializable { @@ -130,22 +134,21 @@ public class TestRunEntity implements Serializable { public static final String HOST_NAME = "hostName"; public static final String PASS_COUNT = "passCount"; public static final String FAIL_COUNT = "failCount"; + public static final String HAS_CODE_COVERAGE = "hasCodeCoverage"; + public static final String HAS_COVERAGE = "hasCoverage"; public static final String TEST_CASE_IDS = "testCaseIds"; public static final String LOG_LINKS = "logLinks"; - public static final String HAS_COVERAGE = "hasCoverage"; - public static final String TOTAL_LINE_COUNT = "totalLineCount"; - public static final String COVERED_LINE_COUNT = "coveredLineCount"; public static final String API_COVERAGE_KEY_LIST = "apiCoverageKeyList"; public static final String TOTAL_API_COUNT = "totalApiCount"; public static final String COVERED_API_COUNT = "coveredApiCount"; @Ignore private Key key; - @Id @Getter @Setter private Long ID; + @Id @Getter @Setter private Long id; @Parent @Getter @Setter private com.googlecode.objectify.Key<?> testRunParent; - @Index @Getter @Setter private TestRunType type; + @Index @Getter @Setter private long type; @Index @Getter @Setter private long startTimestamp; @@ -161,7 +164,11 @@ public class TestRunEntity implements Serializable { @Index @Getter @Setter private long failCount; - @Index @Getter @Setter private boolean hasCoverage; + @Index private boolean hasCoverage; + + @Index @Getter @Setter private boolean hasCodeCoverage; + + private com.googlecode.objectify.Key<CodeCoverageEntity> codeCoverageEntityKey; @Index @Getter @Setter private long coveredLineCount; @@ -169,7 +176,7 @@ public class TestRunEntity implements Serializable { @Getter @Setter private List<Long> testCaseIds; - @Getter @Setter private List<String> links; + @Getter @Setter private List<String> logLinks; /** * Create a TestRunEntity object describing a test run. @@ -182,24 +189,19 @@ public class TestRunEntity implements Serializable { * @param hostName The name of host machine. * @param passCount The number of passing test cases in the run. * @param failCount The number of failing test cases in the run. - * @param testCaseIds A list of key IDs to the TestCaseRunEntity objects for the test run. - * @param links A list of links to resource files for the test run, or null if there aren't any. - * @param coveredLineCount The number of lines covered by the test run. - * @param totalLineCount The total number of executable lines by the test in the test run. */ public TestRunEntity( Key parentKey, - TestRunType type, + long type, long startTimestamp, long endTimestamp, String testBuildId, String hostName, long passCount, long failCount, + boolean hasCodeCoverage, List<Long> testCaseIds, - List<String> links, - long coveredLineCount, - long totalLineCount) { + List<String> logLinks) { this.key = KeyFactory.createKey(parentKey, KIND, startTimestamp); this.type = type; this.startTimestamp = startTimestamp; @@ -208,99 +210,132 @@ public class TestRunEntity implements Serializable { this.hostName = hostName; this.passCount = passCount; this.failCount = failCount; - this.testCaseIds = testCaseIds == null ? new ArrayList<Long>() : testCaseIds; - this.links = links == null ? new ArrayList<String>() : links; - this.coveredLineCount = coveredLineCount; - this.totalLineCount = totalLineCount; - this.hasCoverage = totalLineCount > 0; + this.hasCodeCoverage = hasCodeCoverage; + this.testName = parentKey.getName(); + this.codeCoverageEntityKey = getCodeCoverageEntityKey(); + this.testCaseIds = testCaseIds; + this.logLinks = logLinks; } /** - * Create a TestRunEntity object describing a test run. - * - * @param parentKey The key to the parent TestEntity. - * @param type The test run type (e.g. presubmit, postsubmit, other) - * @param startTimestamp The time in microseconds when the test run started. - * @param endTimestamp The time in microseconds when the test run ended. - * @param testBuildId The build ID of the VTS test build. - * @param hostName The name of host machine. - * @param passCount The number of passing test cases in the run. - * @param failCount The number of failing test cases in the run. - * @param testCaseIds A list of key IDs to the TestCaseRunEntity objects for the test run. - * @param links A list of links to resource files for the test run, or null if there aren't any. + * Called after the POJO is populated with data through objecitfy library */ - public TestRunEntity( - Key parentKey, - TestRunType type, - long startTimestamp, - long endTimestamp, - String testBuildId, - String hostName, - long passCount, - long failCount, - List<Long> testCaseIds, - List<String> links) { - this( - parentKey, - type, - startTimestamp, - endTimestamp, - testBuildId, - hostName, - passCount, - failCount, - testCaseIds, - links, - 0, - 0); + @OnLoad + private void onLoad() { + if (Objects.isNull(this.hasCodeCoverage)) { + this.hasCodeCoverage = this.hasCoverage; + this.save(); + } } public Entity toEntity() { Entity testRunEntity = new Entity(this.key); - testRunEntity.setProperty(TEST_NAME, this.key.getParent().getName()); - testRunEntity.setProperty(TYPE, this.type.getNumber()); + testRunEntity.setProperty(TEST_NAME, this.testName); + testRunEntity.setProperty(TYPE, this.type); testRunEntity.setProperty(START_TIMESTAMP, this.startTimestamp); testRunEntity.setUnindexedProperty(END_TIMESTAMP, this.endTimestamp); testRunEntity.setProperty(TEST_BUILD_ID, this.testBuildId.toLowerCase()); testRunEntity.setProperty(HOST_NAME, this.hostName.toLowerCase()); testRunEntity.setProperty(PASS_COUNT, this.passCount); testRunEntity.setProperty(FAIL_COUNT, this.failCount); + testRunEntity.setProperty(HAS_CODE_COVERAGE, this.hasCodeCoverage); testRunEntity.setUnindexedProperty(TEST_CASE_IDS, this.testCaseIds); - boolean hasCoverage = this.totalLineCount > 0 && this.coveredLineCount >= 0; - testRunEntity.setProperty(HAS_COVERAGE, hasCoverage); - if (hasCoverage) { - testRunEntity.setProperty(COVERED_LINE_COUNT, this.coveredLineCount); - testRunEntity.setProperty(TOTAL_LINE_COUNT, this.totalLineCount); - } - if (this.links != null && this.links.size() > 0) { - testRunEntity.setUnindexedProperty(LOG_LINKS, this.links); + if (this.logLinks != null && this.logLinks.size() > 0) { + testRunEntity.setUnindexedProperty(LOG_LINKS, this.logLinks); } return testRunEntity; } + /** Saving function for the instance of this class */ + public com.googlecode.objectify.Key<TestRunEntity> save() { + return ofy().save().entity(this).now(); + } + /** * Get key info from appengine based library. - * - * @param parentKey parent key. */ - public Key getOldKey(Key parentKey) { + public Key getKey() { + Key parentKey = KeyFactory.createKey(TestEntity.KIND, testName); return KeyFactory.createKey(parentKey, KIND, startTimestamp); } - /** Get ApiCoverageEntity from key info */ - public Optional<List<ApiCoverageEntity>> getApiCoverageEntityList() { + /** Getter hasCodeCoverage value */ + public boolean getHasCodeCoverage() { + return this.hasCodeCoverage; + } + + /** Getter DateTime string from startTimestamp */ + public String getStartDateTime() { + return TimeUtil.getDateTimeString(this.startTimestamp); + } + + /** Getter DateTime string from startTimestamp */ + public String getEndDateTime() { + return TimeUtil.getDateTimeString(this.endTimestamp); + } + + /** find TestRun entity by ID and test name */ + public static TestRunEntity getByTestNameId(String testName, long id) { + com.googlecode.objectify.Key testKey = + com.googlecode.objectify.Key.create(TestEntity.class, testName); + return ofy().load().type(TestRunEntity.class).parent(testKey).id(id).now(); + } + + /** Get CodeCoverageEntity Key to generate Key by combining key info */ + private com.googlecode.objectify.Key getCodeCoverageEntityKey() { + com.googlecode.objectify.Key testRunKey = this.getOfyKey(); + return com.googlecode.objectify.Key.create( + testRunKey, CodeCoverageEntity.class, this.startTimestamp); + } + + /** Get ApiCoverageEntity Key from the parent key */ + private com.googlecode.objectify.Key getOfyKey() { com.googlecode.objectify.Key testKey = com.googlecode.objectify.Key.create( - TestEntity.class, this.key.getParent().getName()); - com.googlecode.objectify.Key apiCoverageKey = - com.googlecode.objectify.Key.create(testKey, TestRunEntity.class, startTimestamp); + TestEntity.class, this.testName); + com.googlecode.objectify.Key testRunKey = + com.googlecode.objectify.Key.create( + testKey, TestRunEntity.class, this.startTimestamp); + return testRunKey; + } + /** Get ApiCoverageEntity from key info */ + public Optional<List<ApiCoverageEntity>> getApiCoverageEntityList() { + com.googlecode.objectify.Key testRunKey = this.getOfyKey(); List<ApiCoverageEntity> apiCoverageEntityList = - ofy().load().type(ApiCoverageEntity.class).ancestor(apiCoverageKey).list(); + ofy().load().type(ApiCoverageEntity.class).ancestor(testRunKey).list(); return Optional.ofNullable(apiCoverageEntityList); } /** + * Get CodeCoverageEntity instance from codeCoverageEntityKey value. + */ + public CodeCoverageEntity getCodeCoverageEntity() { + if (this.hasCodeCoverage) { + CodeCoverageEntity codeCoverageEntity = + ofy().load() + .type(CodeCoverageEntity.class) + .filterKey(this.codeCoverageEntityKey) + .first() + .now(); + if (Objects.isNull(codeCoverageEntity)) { + codeCoverageEntity = + new CodeCoverageEntity( + this.getKey(), coveredLineCount, totalLineCount); + codeCoverageEntity.save(); + return codeCoverageEntity; + } else { + return codeCoverageEntity; + } + } else { + logger.log( + Level.WARNING, + "The hasCodeCoverage value is false. Please check the code coverage entity key"); + return null; + } + } + + /** * Convert an Entity object to a TestRunEntity. * * @param e The entity to process. @@ -315,27 +350,29 @@ public class TestRunEntity implements Serializable { || !e.hasProperty(TEST_BUILD_ID) || !e.hasProperty(HOST_NAME) || !e.hasProperty(PASS_COUNT) - || !e.hasProperty(FAIL_COUNT) - || !e.hasProperty(TEST_CASE_IDS)) { + || !e.hasProperty(FAIL_COUNT)) { logger.log(Level.WARNING, "Missing test run attributes in entity: " + e.toString()); return null; } try { - TestRunType type = TestRunType.fromNumber((int) (long) e.getProperty(TYPE)); + long type = (long) e.getProperty(TYPE); long startTimestamp = (long) e.getProperty(START_TIMESTAMP); long endTimestamp = (long) e.getProperty(END_TIMESTAMP); String testBuildId = (String) e.getProperty(TEST_BUILD_ID); String hostName = (String) e.getProperty(HOST_NAME); long passCount = (long) e.getProperty(PASS_COUNT); long failCount = (long) e.getProperty(FAIL_COUNT); + boolean hasCodeCoverage = false; + if (e.hasProperty(HAS_CODE_COVERAGE)) { + hasCodeCoverage = (boolean) e.getProperty(HAS_CODE_COVERAGE); + } else { + hasCodeCoverage = (boolean) e.getProperty(HAS_COVERAGE); + } List<Long> testCaseIds = (List<Long>) e.getProperty(TEST_CASE_IDS); - List<String> links = null; - long coveredLineCount = 0; - long totalLineCount = 0; - if (e.hasProperty(TOTAL_LINE_COUNT) && e.hasProperty(COVERED_LINE_COUNT)) { - coveredLineCount = (long) e.getProperty(COVERED_LINE_COUNT); - totalLineCount = (long) e.getProperty(TOTAL_LINE_COUNT); + if (Objects.isNull(testCaseIds)) { + testCaseIds = new ArrayList<>(); } + List<String> links = new ArrayList<>(); if (e.hasProperty(LOG_LINKS)) { links = (List<String>) e.getProperty(LOG_LINKS); } @@ -348,10 +385,9 @@ public class TestRunEntity implements Serializable { hostName, passCount, failCount, + hasCodeCoverage, testCaseIds, - links, - coveredLineCount, - totalLineCount); + links); } catch (ClassCastException exception) { // Invalid cast logger.log(Level.WARNING, "Error parsing test run entity.", exception); @@ -359,19 +395,62 @@ public class TestRunEntity implements Serializable { return null; } + /** Get JsonFormat logLinks */ + public JsonElement getJsonLogLinks() { + List<String> logLinks = this.getLogLinks(); + List<JsonElement> links = new ArrayList<>(); + if (logLinks != null && logLinks.size() > 0) { + for (String rawUrl : logLinks) { + UrlUtil.LinkDisplay validatedLink = UrlUtil.processUrl(rawUrl); + if (validatedLink == null) { + logger.log(Level.WARNING, "Invalid logging URL : " + rawUrl); + continue; + } + String[] logInfo = new String[] {validatedLink.name, validatedLink.url}; + links.add(new Gson().toJsonTree(logInfo)); + } + } + return new Gson().toJsonTree(links); + } + public JsonObject toJson() { + Map<String, TestCoverageStatusEntity> testCoverageStatusMap = TestCoverageStatusEntity + .getTestCoverageStatusMap(); + JsonObject json = new JsonObject(); - json.add(TEST_NAME, new JsonPrimitive(this.key.getParent().getName())); + json.add(TEST_NAME, new JsonPrimitive(this.testName)); json.add(TEST_BUILD_ID, new JsonPrimitive(this.testBuildId)); json.add(HOST_NAME, new JsonPrimitive(this.hostName)); json.add(PASS_COUNT, new JsonPrimitive(this.passCount)); json.add(FAIL_COUNT, new JsonPrimitive(this.failCount)); json.add(START_TIMESTAMP, new JsonPrimitive(this.startTimestamp)); json.add(END_TIMESTAMP, new JsonPrimitive(this.endTimestamp)); - if (this.totalLineCount > 0 && this.coveredLineCount >= 0) { - json.add(COVERED_LINE_COUNT, new JsonPrimitive(this.coveredLineCount)); - json.add(TOTAL_LINE_COUNT, new JsonPrimitive(this.totalLineCount)); + + // Overwrite the coverage value with newly update value from user decision + if (this.hasCodeCoverage) { + CodeCoverageEntity codeCoverageEntity = this.getCodeCoverageEntity(); + if (testCoverageStatusMap.containsKey(this.testName)) { + TestCoverageStatusEntity testCoverageStatusEntity = + testCoverageStatusMap.get(this.testName); + + if (testCoverageStatusEntity.getUpdatedCoveredLineCount() > 0) { + codeCoverageEntity.setCoveredLineCount( + testCoverageStatusEntity.getUpdatedCoveredLineCount()); + } + if (testCoverageStatusEntity.getUpdatedTotalLineCount() > 0) { + codeCoverageEntity.setTotalLineCount( + testCoverageStatusEntity.getUpdatedTotalLineCount()); + } + } + + long totalLineCount = codeCoverageEntity.getTotalLineCount(); + long coveredLineCount = codeCoverageEntity.getCoveredLineCount(); + if (totalLineCount > 0 && coveredLineCount >= 0) { + json.add(CodeCoverageEntity.COVERED_LINE_COUNT, new JsonPrimitive(coveredLineCount)); + json.add(CodeCoverageEntity.TOTAL_LINE_COUNT, new JsonPrimitive(totalLineCount)); + } } + Optional<List<ApiCoverageEntity>> apiCoverageEntityOptionList = this.getApiCoverageEntityList(); if (apiCoverageEntityOptionList.isPresent()) { @@ -398,9 +477,10 @@ public class TestRunEntity implements Serializable { } } - if (this.links != null && this.links.size() > 0) { + List<String> logLinks = this.getLogLinks(); + if (logLinks != null && logLinks.size() > 0) { List<JsonElement> links = new ArrayList<>(); - for (String rawUrl : this.links) { + for (String rawUrl : logLinks) { LinkDisplay validatedLink = UrlUtil.processUrl(rawUrl); if (validatedLink == null) { logger.log(Level.WARNING, "Invalid logging URL : " + rawUrl); @@ -410,7 +490,7 @@ public class TestRunEntity implements Serializable { links.add(new Gson().toJsonTree(logInfo)); } if (links.size() > 0) { - json.add(LOG_LINKS, new Gson().toJsonTree(links)); + json.add(this.LOG_LINKS, new Gson().toJsonTree(links)); } } return json; |