1 /* 2 * Copyright (c) 2017 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you 5 * may not use this file except in compliance with the License. You may 6 * obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 * implied. See the License for the specific language governing 14 * permissions and limitations under the License. 15 */ 16 17 package com.android.vts.entity; 18 19 import com.google.appengine.api.datastore.Entity; 20 import com.google.appengine.api.datastore.KeyFactory; 21 import com.googlecode.objectify.annotation.Cache; 22 import com.googlecode.objectify.annotation.Id; 23 import com.googlecode.objectify.annotation.Ignore; 24 import com.googlecode.objectify.annotation.OnLoad; 25 import java.util.ArrayList; 26 import java.util.List; 27 import lombok.Data; 28 import lombok.extern.slf4j.Slf4j; 29 30 import static com.googlecode.objectify.ObjectifyService.ofy; 31 32 @com.googlecode.objectify.annotation.Entity(name = "TestCaseRun") 33 @Cache 34 @Data 35 @Slf4j 36 /** Entity describing the execution of a test case. */ 37 public class TestCaseRunEntity implements DashboardEntity { 38 39 public static final String KIND = "TestCaseRun"; 40 41 // Property keys 42 public static final String TEST_CASE_NAME = "testCaseName"; 43 public static final String RESULT = "result"; 44 public static final String TEST_CASE_NAMES = "testCaseNames"; 45 public static final String RESULTS = "results"; 46 public static final String SYSTRACE_URL = "systraceUrl"; 47 48 // Maximum number of test cases in the entity. 49 private static final int SIZE_LIMIT = 500; 50 51 @Id 52 private Long id; 53 54 private List<Integer> results; 55 56 private List<String> testCaseNames; 57 58 @Ignore 59 public final List<TestCase> testCases; 60 61 @Ignore 62 private String systraceUrl; 63 64 /** 65 * Class describing an individual test case run. 66 */ 67 public static class TestCase { 68 public final long parentId; 69 public final int offset; 70 public final String name; 71 public final int result; 72 73 /** 74 * Create a test case run. 75 * @param parentId The ID of the TestCaseRunEntity containing the test case. 76 * @param offset The offset of the TestCase into the TestCaseRunEntity. 77 * @param name The name of the test case. 78 * @param result The result of the test case. 79 */ TestCase(long parentId, int offset, String name, int result)80 public TestCase(long parentId, int offset, String name, int result) { 81 this.parentId = parentId; 82 this.offset = offset; 83 this.name = name; 84 this.result = result; 85 } 86 } 87 88 /** 89 * Create a TestCaseRunEntity. 90 */ TestCaseRunEntity()91 public TestCaseRunEntity() { 92 this.results = new ArrayList<>(); 93 this.testCaseNames = new ArrayList<>(); 94 this.testCases = new ArrayList<>(); 95 this.systraceUrl = null; 96 } 97 98 /** 99 * Create a TestCaseRunEntity with the specified id. 100 * @param id The entity id. 101 */ TestCaseRunEntity(long id)102 public TestCaseRunEntity(long id) { 103 this.id = id; 104 this.results = new ArrayList<>(); 105 this.testCaseNames = new ArrayList<>(); 106 this.testCases = new ArrayList<>(); 107 this.systraceUrl = null; 108 } 109 110 /** 111 * Determine if the TestCaseRunEntity is full. 112 * @return True if the entity is full, false otherwise. 113 */ isFull()114 public boolean isFull() { 115 return this.testCases.size() >= SIZE_LIMIT; 116 } 117 118 /** 119 * Set the systrace url. 120 * @param url The systrace url, or null. 121 */ setSystraceUrl(String url)122 private void setSystraceUrl(String url) { 123 this.systraceUrl = url; 124 } 125 126 /** 127 * Get the systrace url. 128 * returns The systrace url, or null. 129 */ getSystraceUrl()130 public String getSystraceUrl() { 131 return this.systraceUrl; 132 } 133 134 /** 135 * Called after the POJO is populated with data through objecitfy library 136 */ 137 @OnLoad onLoad()138 private void onLoad() { 139 if (testCaseNames.size() == results.size()) { 140 for (int index = 0; index < testCaseNames.size(); index++) { 141 String name = testCaseNames.get(index); 142 int result = results.get(index).intValue(); 143 this.testCases.add(new TestCase(this.id, this.testCases.size(), name, result)); 144 } 145 } 146 } 147 148 /** 149 * Add a test case to the test case run entity. 150 * @param name The name of the test case. 151 * @param result The result of the test case. 152 * @return true if added, false otherwise. 153 */ addTestCase(String name, int result)154 public boolean addTestCase(String name, int result) { 155 if (this.isFull()) { 156 return false; 157 } else { 158 this.testCaseNames.add(name); 159 this.results.add(result); 160 return true; 161 } 162 } 163 164 /** Saving function for the instance of this class */ 165 @Override save()166 public com.googlecode.objectify.Key<TestCaseRunEntity> save() { 167 return ofy().save().entity(this).now(); 168 } 169 toEntity()170 public Entity toEntity() { 171 Entity testCaseRunEntity; 172 if (this.id >= 0) { 173 testCaseRunEntity = new Entity(KeyFactory.createKey(KIND, id)); 174 } else { 175 testCaseRunEntity = new Entity(KIND); 176 } 177 178 if (this.testCases.size() > 0) { 179 List<String> testCaseNames = new ArrayList<>(); 180 List<Integer> results = new ArrayList<>(); 181 for (TestCase testCase : this.testCases) { 182 testCaseNames.add(testCase.name); 183 results.add(testCase.result); 184 } 185 testCaseRunEntity.setUnindexedProperty(TEST_CASE_NAMES, testCaseNames); 186 testCaseRunEntity.setUnindexedProperty(RESULTS, results); 187 } 188 if (systraceUrl != null) { 189 testCaseRunEntity.setUnindexedProperty(SYSTRACE_URL, this.systraceUrl); 190 } 191 192 return testCaseRunEntity; 193 } 194 195 /** 196 * Convert an Entity object to a TestCaseRunEntity. 197 * 198 * @param e The entity to process. 199 * @return TestCaseRunEntity object with the properties from e, or null if incompatible. 200 */ 201 @SuppressWarnings("unchecked") fromEntity(Entity e)202 public static TestCaseRunEntity fromEntity(Entity e) { 203 if (!e.getKind().equals(KIND)) { 204 log.warn("Wrong kind: " + e.getKey()); 205 return null; 206 } 207 try { 208 TestCaseRunEntity testCaseRun = new TestCaseRunEntity(e.getKey().getId()); 209 if (e.hasProperty(TEST_CASE_NAMES) && e.hasProperty(RESULTS)) { 210 List<String> testCaseNames = (List<String>) e.getProperty(TEST_CASE_NAMES); 211 List<Long> results = (List<Long>) e.getProperty(RESULTS); 212 if (testCaseNames.size() == results.size()) { 213 for (int i = 0; i < testCaseNames.size(); i++) { 214 testCaseRun.addTestCase(testCaseNames.get(i), results.get(i).intValue()); 215 } 216 } 217 } 218 if (e.hasProperty(TEST_CASE_NAME) && e.hasProperty(RESULT)) { 219 testCaseRun.addTestCase( 220 (String) e.getProperty(TEST_CASE_NAME), (int) (long) e.getProperty(RESULT)); 221 } 222 if (e.hasProperty(SYSTRACE_URL)) { 223 String systraceUrl = (String) e.getProperty(SYSTRACE_URL); 224 testCaseRun.setSystraceUrl(systraceUrl); 225 } 226 return testCaseRun; 227 } catch (ClassCastException exception) { 228 // Invalid cast 229 log.warn("Error parsing test case run entity.", exception); 230 } 231 return null; 232 } 233 } 234