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