blob: de2e505f2a2c1dc09d5c2c62469df7ccd8d4f4ef [file] [log] [blame]
/*
* Copyright (c) 2017 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.entity;
import static com.googlecode.objectify.ObjectifyService.ofy;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
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.util.Date;
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;
@com.googlecode.objectify.annotation.Entity(name = "TestPlanRun")
@Cache
@Data
@NoArgsConstructor
/** Entity describing test plan run information. */
public class TestPlanRunEntity implements DashboardEntity {
protected static final Logger logger = Logger.getLogger(TestPlanRunEntity.class.getName());
private final String QUEUE_NAME = "coverageApiQueue";
public static final String KIND = "TestPlanRun";
private static final String COVERAGE_API_URL = "/api/coverage/api/sum";
// Property keys
public static final String TEST_PLAN_NAME = "testPlanName";
public static final String TYPE = "type";
public static final String START_TIMESTAMP = "startTimestamp";
public static final String END_TIMESTAMP = "endTimestamp";
public static final String TEST_BUILD_ID = "testBuildId";
public static final String PASS_COUNT = "passCount";
public static final String FAIL_COUNT = "failCount";
public static final String TOTAL_API_COUNT = "totalApiCount";
public static final String TOTAL_COVERED_API_COUNT = "coveredApiCount";
public static final String TEST_RUNS = "testRuns";
@Ignore public Key key;
@Id private Long id;
@Parent private com.googlecode.objectify.Key<TestPlanEntity> parent;
@Index private String testPlanName;
@Index private long type;
@Index private long startTimestamp;
@Index private long endTimestamp;
@Index private String testBuildId;
@Index private long passCount;
@Index private long failCount;
@Index private long totalApiCount;
@Index private long coveredApiCount;
@Ignore private List<Key> oldTestRuns;
private List<com.googlecode.objectify.Key<TestRunEntity>> testRuns;
/** When this record was created or updated */
@Index Date updated;
/**
* Create a TestPlanRunEntity object describing a test plan run.
*
* @param testPlanKey The key for the parent entity in the database.
* @param type The test run type (e.g. presubmit, postsubmit, other)
* @param startTimestamp The time in microseconds when the test plan run started.
* @param endTimestamp The time in microseconds when the test plan run ended.
* @param testBuildId The build ID of the VTS test build.
* @param passCount The number of passing test cases in the run.
* @param failCount The number of failing test cases in the run.
* @param testRuns A list of keys to the TestRunEntity objects for the plan run run.
*/
public TestPlanRunEntity(
Key testPlanKey,
String testPlanName,
long type,
long startTimestamp,
long endTimestamp,
String testBuildId,
long passCount,
long failCount,
long totalApiCount,
long coveredApiCount,
List<Key> testRuns) {
this.id = startTimestamp;
this.key = KeyFactory.createKey(testPlanKey, KIND, startTimestamp);
this.testPlanName = testPlanName;
this.type = type;
this.startTimestamp = startTimestamp;
this.endTimestamp = endTimestamp;
this.testBuildId = testBuildId;
this.passCount = passCount;
this.failCount = failCount;
this.totalApiCount = totalApiCount;
this.coveredApiCount = coveredApiCount;
this.oldTestRuns = testRuns;
this.testRuns =
testRuns.stream()
.map(
testRun -> {
com.googlecode.objectify.Key testParentKey =
com.googlecode.objectify.Key.create(
TestEntity.class,
testRun.getParent().getName());
return com.googlecode.objectify.Key.create(
testParentKey, TestRunEntity.class, testRun.getId());
})
.collect(Collectors.toList());
}
/**
* Create a TestPlanRunEntity object describing a test plan run.
*
* @param testPlanKey The key for the parent entity in the database.
* @param type The test run type (e.g. presubmit, postsubmit, other)
* @param startTimestamp The time in microseconds when the test plan run started.
* @param endTimestamp The time in microseconds when the test plan run ended.
* @param testBuildId The build ID of the VTS test build.
* @param passCount The number of passing test cases in the run.
* @param failCount The number of failing test cases in the run.
* @param testRuns A list of keys to the TestRunEntity objects for the plan run run.
*/
public TestPlanRunEntity(
com.googlecode.objectify.Key<TestPlanEntity> testPlanKey,
String testPlanName,
long type,
long startTimestamp,
long endTimestamp,
String testBuildId,
long passCount,
long failCount,
long totalApiCount,
long coveredApiCount,
List<com.googlecode.objectify.Key<TestRunEntity>> testRuns) {
this.id = startTimestamp;
this.parent = testPlanKey;
this.testPlanName = testPlanName;
this.type = type;
this.startTimestamp = startTimestamp;
this.endTimestamp = endTimestamp;
this.testBuildId = testBuildId;
this.passCount = passCount;
this.failCount = failCount;
this.totalApiCount = totalApiCount;
this.coveredApiCount = coveredApiCount;
this.testRuns = testRuns;
}
public Entity toEntity() {
Entity planRun = new Entity(this.key);
planRun.setProperty(TEST_PLAN_NAME, this.testPlanName);
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());
planRun.setProperty(PASS_COUNT, this.passCount);
planRun.setProperty(FAIL_COUNT, this.failCount);
if (this.oldTestRuns != null && this.oldTestRuns.size() > 0) {
planRun.setUnindexedProperty(TEST_RUNS, this.oldTestRuns);
}
return planRun;
}
/** Saving function for the instance of this class */
@Override
public com.googlecode.objectify.Key<TestPlanRunEntity> save() {
this.updated = new Date();
return ofy().save().entity(this).now();
}
/** Get UrlSafeKey from this class */
public String getUrlSafeKey() {
return this.getOfyKey().toUrlSafe();
}
/** Add a task to calculate the total number of coverage API */
public void addCoverageApiTask() {
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", this.getUrlSafeKey())
.method(TaskOptions.Method.POST));
}
}
/**
* Get key info from appengine based library.
*
* @param parentKey parent key.
*/
public Key getOldKey(Key parentKey) {
return KeyFactory.createKey(parentKey, KIND, startTimestamp);
}
/** Get key info from objecitfy library. */
public com.googlecode.objectify.Key getOfyKey() {
return com.googlecode.objectify.Key.create(
this.parent, TestPlanRunEntity.class, this.startTimestamp);
}
/**
* Convert an Entity object to a TestPlanRunEntity.
*
* @param e The entity to process.
* @return TestPlanRunEntity object with the properties from e processed, or null if
* incompatible.
*/
@SuppressWarnings("unchecked")
public static TestPlanRunEntity fromEntity(Entity e) {
if (!e.getKind().equals(KIND)
|| !e.hasProperty(TEST_PLAN_NAME)
|| !e.hasProperty(TYPE)
|| !e.hasProperty(START_TIMESTAMP)
|| !e.hasProperty(END_TIMESTAMP)
|| !e.hasProperty(TEST_BUILD_ID)
|| !e.hasProperty(PASS_COUNT)
|| !e.hasProperty(FAIL_COUNT)
|| !e.hasProperty(TEST_RUNS)) {
logger.log(Level.WARNING, "Missing test run attributes in entity: " + e.toString());
return null;
}
try {
String testPlanName = (String) e.getProperty(TEST_PLAN_NAME);
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);
long passCount = (long) e.getProperty(PASS_COUNT);
long failCount = (long) e.getProperty(FAIL_COUNT);
long totalApiCount =
e.hasProperty(TOTAL_API_COUNT) ? (long) e.getProperty(TOTAL_API_COUNT) : 0L;
long coveredApiCount =
e.hasProperty(TOTAL_COVERED_API_COUNT)
? (long) e.getProperty(TOTAL_COVERED_API_COUNT)
: 0L;
List<Key> oldTestRuns = (List<Key>) e.getProperty(TEST_RUNS);
return new TestPlanRunEntity(
e.getKey().getParent(),
testPlanName,
type,
startTimestamp,
endTimestamp,
testBuildId,
passCount,
failCount,
totalApiCount,
coveredApiCount,
oldTestRuns);
} catch (ClassCastException exception) {
// Invalid cast
logger.log(Level.WARNING, "Error parsing test plan run entity.", exception);
}
return null;
}
public JsonObject toJson() {
JsonObject json = new JsonObject();
json.add(TEST_PLAN_NAME, new JsonPrimitive(this.testPlanName));
json.add(TEST_BUILD_ID, new JsonPrimitive(this.testBuildId));
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));
return json;
}
}