summaryrefslogtreecommitdiff
path: root/src/main/java/com/android/vts/entity/TestStatusEntity.java
blob: b703c6429d33071601fab58b09183916f9727f5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * 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 com.android.vts.entity.TestCaseRunEntity.TestCase;
import com.google.appengine.api.datastore.Entity;
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 java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import lombok.Data;
import lombok.NoArgsConstructor;

import static com.googlecode.objectify.ObjectifyService.ofy;

@com.googlecode.objectify.annotation.Entity(name = "TestStatus")
@Cache
@Data
@NoArgsConstructor
/** Entity describing test status. */
public class TestStatusEntity implements DashboardEntity {
    protected static final Logger logger = Logger.getLogger(TestStatusEntity.class.getName());

    public static final String KIND = "TestStatus";

    // Property keys
    public static final String PASS_COUNT = "passCount";
    public static final String FAIL_COUNT = "failCount";
    public static final String UPDATED_TIMESTAMP = "updatedTimestamp";

    protected static final String FAILING_IDS = "failingTestcaseIds";
    protected static final String FAILING_OFFSETS = "failingTestcaseOffsets";

    /** ID field */
    @Id private String testName;

    /** Failing Testcase ID List field */
    private List<Long> failingTestcaseIds;

    /** Failing Testcase Offsets List field */
    private List<Integer> failingTestcaseOffsets;

    /** pass count field */
    @Index private int passCount;

    /** fail count field */
    @Index private int failCount;

    /** updated timestamp field */
    @Index private long updatedTimestamp;

    @Ignore private List<TestCaseReference> failingTestCases;

    /** Object representing a reference to a test case. */
    public static class TestCaseReference {
        public final long parentId;
        public final int offset;

        /**
         * Create a test case reference.
         *
         * @param parentId The ID of the TestCaseRunEntity containing the test case.
         * @param offset The offset of the test case into the TestCaseRunEntity.
         */
        public TestCaseReference(long parentId, int offset) {
            this.parentId = parentId;
            this.offset = offset;
        }

        /**
         * Create a test case reference.
         *
         * @param testCase The TestCase to reference.
         */
        public TestCaseReference(TestCase testCase) {
            this(testCase.parentId, testCase.offset);
        }
    }

    /**
     * Create a TestEntity 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 passCount The number of tests passing up to the timestamp specified.
     * @param failCount The number of tests failing up to the timestamp specified.
     * @param failingTestCases The TestCaseReferences of the last observed failing test cases.
     */
    public TestStatusEntity(
        String testName,
        long timestamp,
        int passCount,
        int failCount,
        List<TestCaseReference> failingTestCases) {
        this.testName = testName;
        this.updatedTimestamp = timestamp;
        this.passCount = passCount;
        this.failCount = failCount;
        this.failingTestCases = failingTestCases;
    }

    /**
     * Create a TestEntity object without metadata.
     *
     * @param testName The name of the test.
     */
    public TestStatusEntity(String testName) {
        this(testName, 0, -1, -1, new ArrayList<TestCaseReference>());
    }

    /** Saving function for the instance of this class */
    @Override
    public com.googlecode.objectify.Key<TestStatusEntity> save() {
        return ofy().save().entity(this).now();
    }

    public Entity toEntity() {
        Entity testEntity = new Entity(KIND, this.testName);
        if (this.updatedTimestamp >= 0 && this.passCount >= 0 && this.failCount >= 0) {
            testEntity.setProperty(UPDATED_TIMESTAMP, this.updatedTimestamp);
            testEntity.setProperty(PASS_COUNT, this.passCount);
            testEntity.setProperty(FAIL_COUNT, this.failCount);
            if (this.failingTestCases.size() > 0) {
                List<Long> failingTestcaseIds = new ArrayList<>();
                List<Integer> failingTestcaseOffsets = new ArrayList<>();
                for (TestCaseReference testCase : this.failingTestCases) {
                    failingTestcaseIds.add(testCase.parentId);
                    failingTestcaseOffsets.add(testCase.offset);
                }
                testEntity.setUnindexedProperty(FAILING_IDS, failingTestcaseIds);
                testEntity.setUnindexedProperty(FAILING_OFFSETS, failingTestcaseOffsets);
            }
        }
        return testEntity;
    }

    /**
     * Convert an Entity object to a TestEntity.
     *
     * @param e The entity to process.
     * @return TestEntity object with the properties from e processed, or null if incompatible.
     */
    @SuppressWarnings("unchecked")
    public static TestStatusEntity fromEntity(Entity e) {
        if (!e.getKind().equals(KIND) || e.getKey().getName() == null) {
            logger.log(Level.WARNING, "Missing test attributes in entity: " + e.toString());
            return null;
        }
        String testName = e.getKey().getName();
        long timestamp = 0;
        int passCount = -1;
        int failCount = -1;
        List<TestCaseReference> failingTestCases = new ArrayList<>();
        try {
            if (e.hasProperty(UPDATED_TIMESTAMP)) {
                timestamp = (long) e.getProperty(UPDATED_TIMESTAMP);
            }
            if (e.hasProperty(PASS_COUNT)) {
                passCount = ((Long) e.getProperty(PASS_COUNT)).intValue();
            }
            if (e.hasProperty(FAIL_COUNT)) {
                failCount = ((Long) e.getProperty(FAIL_COUNT)).intValue();
            }
            if (e.hasProperty(FAILING_IDS) && e.hasProperty(FAILING_OFFSETS)) {
                List<Long> ids = (List<Long>) e.getProperty(FAILING_IDS);
                List<Long> offsets = (List<Long>) e.getProperty(FAILING_OFFSETS);
                if (ids.size() == offsets.size()) {
                    for (int i = 0; i < ids.size(); i++) {
                        failingTestCases.add(
                            new TestCaseReference(ids.get(i), offsets.get(i).intValue()));
                    }
                }
            }
        } catch (ClassCastException exception) {
            // Invalid contents or null values
            logger.log(Level.WARNING, "Error parsing test entity.", exception);
        }
        return new TestStatusEntity(testName, timestamp, passCount, failCount, failingTestCases);
    }
}