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 static com.googlecode.objectify.ObjectifyService.ofy;
20 
21 import com.google.appengine.api.datastore.Entity;
22 import com.googlecode.objectify.Key;
23 import com.googlecode.objectify.annotation.Cache;
24 import com.googlecode.objectify.annotation.Id;
25 import com.googlecode.objectify.annotation.Index;
26 import java.util.Collection;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33 import java.util.stream.Collectors;
34 import lombok.EqualsAndHashCode;
35 import lombok.Getter;
36 import lombok.NoArgsConstructor;
37 import lombok.Setter;
38 
39 @com.googlecode.objectify.annotation.Entity(name = "TestCoverageStatus")
40 @EqualsAndHashCode(of = "testName")
41 @Cache
42 @NoArgsConstructor
43 /** Entity describing test coverage status. */
44 public class TestCoverageStatusEntity implements DashboardEntity {
45 
46     protected static final Logger logger =
47             Logger.getLogger(TestCoverageStatusEntity.class.getName());
48 
49     public static final String KIND = "TestCoverageStatus";
50 
51     // Property keys
52     public static final String TOTAL_LINE_COUNT = "totalLineCount";
53     public static final String COVERED_LINE_COUNT = "coveredLineCount";
54     public static final String UPDATED_TIMESTAMP = "updatedTimestamp";
55     public static final String DEVICE_INFO_ID = "deviceInfoId";
56 
57     /** TestCoverageStatusEntity name field */
58     @Id @Getter @Setter String testName;
59 
60     /** TestCoverageStatusEntity coveredLineCount field */
61     @Index @Getter @Setter long coveredLineCount;
62 
63     /** TestCoverageStatusEntity totalLineCount field */
64     @Index @Getter @Setter long totalLineCount;
65 
66     /** TestCoverageStatusEntity updatedTimestamp field */
67     @Index @Getter @Setter long updatedTimestamp;
68 
69     /** TestCoverageStatusEntity DeviceInfo Entity ID reference field */
70     @Index @Getter @Setter long deviceInfoId;
71 
72     /** TestCoverageStatusEntity updatedCoveredLineCount field */
73     @Index @Getter @Setter long updatedCoveredLineCount;
74 
75     /** TestCoverageStatusEntity updatedTotalLineCount field */
76     @Index @Getter @Setter long updatedTotalLineCount;
77 
78     /** TestCoverageStatusEntity updatedDate field */
79     @Index @Getter @Setter Date updatedDate;
80 
81     /**
82      * Create a TestCoverageStatusEntity object with status metadata.
83      *
84      * @param testName The name of the test.
85      * @param timestamp The timestamp indicating the most recent test run event in the test state.
86      * @param coveredLineCount The number of lines covered.
87      * @param totalLineCount The total number of lines.
88      */
TestCoverageStatusEntity( String testName, long timestamp, long coveredLineCount, long totalLineCount, long deviceInfoId)89     public TestCoverageStatusEntity(
90             String testName,
91             long timestamp,
92             long coveredLineCount,
93             long totalLineCount,
94             long deviceInfoId) {
95         this.testName = testName;
96         this.updatedTimestamp = timestamp;
97         this.coveredLineCount = coveredLineCount;
98         this.totalLineCount = totalLineCount;
99         this.deviceInfoId = deviceInfoId;
100     }
101 
102     /** find TestCoverageStatus entity by ID */
findById(String testName)103     public static TestCoverageStatusEntity findById(String testName) {
104         return ofy().load().type(TestCoverageStatusEntity.class).id(testName).now();
105     }
106 
107     /** Get all TestCoverageStatusEntity List */
getTestCoverageStatusMap()108     public static Map<String, TestCoverageStatusEntity> getTestCoverageStatusMap() {
109         List<TestCoverageStatusEntity> testCoverageStatusEntityList = getAllTestCoverage();
110 
111         Map<String, TestCoverageStatusEntity> testCoverageStatusMap =
112                 testCoverageStatusEntityList.stream()
113                         .collect(Collectors.toMap(t -> t.getTestName(), t -> t));
114         return testCoverageStatusMap;
115     }
116 
117     /** Get all DeviceInfoEntity List by TestCoverageStatusEntities' key list */
getDeviceInfoEntityKeyList( List<TestCoverageStatusEntity> testCoverageStatusEntityList)118     public static List<Key<DeviceInfoEntity>> getDeviceInfoEntityKeyList(
119             List<TestCoverageStatusEntity> testCoverageStatusEntityList) {
120         return testCoverageStatusEntityList
121                 .stream()
122                 .map(
123                         testCoverageStatusEntity -> {
124                             com.googlecode.objectify.Key testKey =
125                                     com.googlecode.objectify.Key.create(
126                                             TestEntity.class,
127                                             testCoverageStatusEntity.getTestName());
128                             com.googlecode.objectify.Key testRunKey =
129                                     com.googlecode.objectify.Key.create(
130                                             testKey,
131                                             TestRunEntity.class,
132                                             testCoverageStatusEntity.getUpdatedTimestamp());
133                             return com.googlecode.objectify.Key.create(
134                                     testRunKey,
135                                     DeviceInfoEntity.class,
136                                     testCoverageStatusEntity.getDeviceInfoId());
137                         })
138                 .collect(Collectors.toList());
139     }
140 
141     /** Get all TestCoverageStatusEntity List */
getAllTestCoverage()142     public static List<TestCoverageStatusEntity> getAllTestCoverage() {
143         return ofy().load().type(TestCoverageStatusEntity.class).list();
144     }
145 
146     /** Get all TestCoverageStatusEntities' Branch List */
getBranchSet( List<TestCoverageStatusEntity> testCoverageStatusEntityList)147     public static Set<String> getBranchSet(
148             List<TestCoverageStatusEntity> testCoverageStatusEntityList) {
149         List<com.googlecode.objectify.Key<DeviceInfoEntity>> deviceInfoEntityKeyList =
150                 getDeviceInfoEntityKeyList(testCoverageStatusEntityList);
151 
152         Collection<DeviceInfoEntity> deviceInfoEntityList =
153                 ofy().load().keys(() -> deviceInfoEntityKeyList.iterator()).values();
154 
155         Set<String> branchSet =
156                 deviceInfoEntityList
157                         .stream()
158                         .map(deviceInfoEntity -> deviceInfoEntity.getBranch())
159                         .collect(Collectors.toSet());
160         return branchSet;
161     }
162 
163     /** Get all TestCoverageStatusEntities' Device List */
getDeviceSet( List<TestCoverageStatusEntity> testCoverageStatusEntityList)164     public static Set<String> getDeviceSet(
165             List<TestCoverageStatusEntity> testCoverageStatusEntityList) {
166         List<com.googlecode.objectify.Key<DeviceInfoEntity>> deviceInfoEntityKeyList =
167                 getDeviceInfoEntityKeyList(testCoverageStatusEntityList);
168 
169         Collection<DeviceInfoEntity> deviceInfoEntityList =
170                 ofy().load().keys(() -> deviceInfoEntityKeyList.iterator()).values();
171 
172         Set<String> deviceSet =
173                 deviceInfoEntityList
174                         .stream()
175                         .map(deviceInfoEntity -> deviceInfoEntity.getBuildFlavor())
176                         .collect(Collectors.toSet());
177         return deviceSet;
178     }
179 
180     /** TestRunEntity function to get the related TestRunEntity from id value */
getTestRunEntity()181     public TestRunEntity getTestRunEntity() {
182         com.googlecode.objectify.Key testKey =
183                 com.googlecode.objectify.Key.create(TestEntity.class, this.testName);
184         return ofy().load()
185                 .type(TestRunEntity.class)
186                 .parent(testKey)
187                 .id(this.updatedTimestamp)
188                 .now();
189     }
190 
191     /** Saving function for the instance of this class */
192     @Override
save()193     public Key<TestCoverageStatusEntity> save() {
194         this.updatedDate = new Date();
195         return ofy().save().entity(this).now();
196     }
197 
toEntity()198     public Entity toEntity() {
199         Entity testEntity = new Entity(KIND, this.testName);
200         testEntity.setProperty(UPDATED_TIMESTAMP, this.updatedTimestamp);
201         testEntity.setProperty(COVERED_LINE_COUNT, this.coveredLineCount);
202         testEntity.setProperty(TOTAL_LINE_COUNT, this.totalLineCount);
203         return testEntity;
204     }
205 
206     /**
207      * Convert an Entity object to a TestCoverageStatusEntity.
208      *
209      * @param e The entity to process.
210      * @return TestCoverageStatusEntity object with the properties from e processed, or null if
211      *     incompatible.
212      */
213     @SuppressWarnings("unchecked")
fromEntity(Entity e)214     public static TestCoverageStatusEntity fromEntity(Entity e) {
215         if (!e.getKind().equals(KIND)
216                 || e.getKey().getName() == null
217                 || !e.hasProperty(UPDATED_TIMESTAMP)
218                 || !e.hasProperty(COVERED_LINE_COUNT)
219                 || !e.hasProperty(TOTAL_LINE_COUNT)
220                 || !e.hasProperty(DEVICE_INFO_ID)) {
221             logger.log(Level.WARNING, "Missing test attributes in entity: " + e.toString());
222             return null;
223         }
224         String testName = e.getKey().getName();
225         long timestamp = 0;
226         long coveredLineCount = -1;
227         long totalLineCount = -1;
228         long deviceInfoId = 0;
229         try {
230             timestamp = (long) e.getProperty(UPDATED_TIMESTAMP);
231             coveredLineCount = (Long) e.getProperty(COVERED_LINE_COUNT);
232             totalLineCount = (Long) e.getProperty(TOTAL_LINE_COUNT);
233             deviceInfoId = (Long) e.getProperty(DEVICE_INFO_ID);
234         } catch (ClassCastException exception) {
235             // Invalid contents or null values
236             logger.log(Level.WARNING, "Error parsing test entity.", exception);
237             return null;
238         }
239         return new TestCoverageStatusEntity(
240                 testName, timestamp, coveredLineCount, totalLineCount, deviceInfoId);
241     }
242 }
243