blob: d070fcc42b7f15cd4c667c9d10bd9d5c837acb4c [file] [log] [blame]
Julien Desprez093c3f62018-05-21 16:23:37 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may 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 implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.tradefed.result.proto;
17
Julien Desprez5035aa62019-07-27 17:11:57 -070018import com.android.tradefed.config.Option;
Julien Desprez093c3f62018-05-21 16:23:37 -070019import com.android.tradefed.config.OptionClass;
20import com.android.tradefed.invoker.IInvocationContext;
21import com.android.tradefed.log.LogUtil.CLog;
22import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
Julien Desprez8ee09232020-02-06 10:30:11 -080023import com.android.tradefed.result.FailureDescription;
Julien Desprez093c3f62018-05-21 16:23:37 -070024import com.android.tradefed.result.ILogSaverListener;
25import com.android.tradefed.result.ITestInvocationListener;
Julien Desprez093c3f62018-05-21 16:23:37 -070026import com.android.tradefed.result.LogFile;
27import com.android.tradefed.result.TestDescription;
Julien Desprezed8bd9b2018-07-13 08:50:20 -070028import com.android.tradefed.result.proto.LogFileProto.LogFileInfo;
29import com.android.tradefed.result.proto.TestRecordProto.ChildReference;
30import com.android.tradefed.result.proto.TestRecordProto.DebugInfo;
Julien Desprez221aaf12020-02-27 14:17:03 -080031import com.android.tradefed.result.proto.TestRecordProto.DebugInfoContext;
Julien Desprezed8bd9b2018-07-13 08:50:20 -070032import com.android.tradefed.result.proto.TestRecordProto.TestRecord;
33import com.android.tradefed.result.proto.TestRecordProto.TestStatus;
Julien Desprez5035aa62019-07-27 17:11:57 -070034import com.android.tradefed.result.retry.ISupportGranularResults;
Julien Desprez093c3f62018-05-21 16:23:37 -070035import com.android.tradefed.testtype.suite.ModuleDefinition;
Julien Desprezed5b04d2020-04-09 10:50:43 -070036import com.android.tradefed.util.SerializationUtil;
Julien Desprezdbc1f172018-12-21 12:14:33 -080037import com.android.tradefed.util.StreamUtil;
Julien Desprez093c3f62018-05-21 16:23:37 -070038
Julien Desprez221aaf12020-02-27 14:17:03 -080039import com.google.common.base.Strings;
Julien Desprez093c3f62018-05-21 16:23:37 -070040import com.google.protobuf.Any;
41import com.google.protobuf.Timestamp;
Julien Desprez093c3f62018-05-21 16:23:37 -070042
Julien Desprezed5b04d2020-04-09 10:50:43 -070043import java.io.IOException;
Julien Desprez093c3f62018-05-21 16:23:37 -070044import java.util.HashMap;
45import java.util.Map;
46import java.util.Stack;
47import java.util.UUID;
48
49/**
50 * Result reporter build a {@link TestRecord} protobuf with all the results inside. Should be
51 * extended to handle what to do with the final proto in {@link #processFinalProto(TestRecord)}.
52 */
53@OptionClass(alias = "proto-reporter")
Julien Desprez5035aa62019-07-27 17:11:57 -070054public abstract class ProtoResultReporter
55 implements ITestInvocationListener, ILogSaverListener, ISupportGranularResults {
56
57 @Option(
58 name = "enable-granular-attempts",
59 description =
60 "Whether or not to allow this reporter receiving granular attempts. Feature flag."
61 )
62 private boolean mReportGranularResults = true;
Julien Desprez093c3f62018-05-21 16:23:37 -070063
64 private Stack<TestRecord.Builder> mLatestChild;
65 private TestRecord.Builder mInvocationRecordBuilder;
66 private long mInvocationStartTime;
Julien Desprezf066b702018-11-07 11:10:08 -080067 private IInvocationContext mContext;
Julien Desprez093c3f62018-05-21 16:23:37 -070068
Julien Desprezdbc1f172018-12-21 12:14:33 -080069 private Throwable mInvocationFailure = null;
Julien Desprez7fc54252020-04-30 15:08:45 -070070 private FailureDescription mInvocationFailureDescription = null;
Julien Desprez079ab2f2019-03-12 10:03:45 -070071 /** Whether or not a testModuleStart had currently been called. */
72 private boolean mModuleInProgress = false;
Julien Desprezdbc1f172018-12-21 12:14:33 -080073
Julien Desprez5035aa62019-07-27 17:11:57 -070074 @Override
75 public boolean supportGranularResults() {
76 return mReportGranularResults;
77 }
78
Julien Desprez093c3f62018-05-21 16:23:37 -070079 /**
80 * Handling of the partial invocation test record proto after {@link
81 * #invocationStarted(IInvocationContext)} occurred.
82 *
83 * @param invocationStartRecord The partial proto populated after the invocationStart.
Julien Desprez329294b2018-07-25 10:16:59 -070084 * @param invocationContext The invocation {@link IInvocationContext}.
Julien Desprez093c3f62018-05-21 16:23:37 -070085 */
Julien Desprez329294b2018-07-25 10:16:59 -070086 public void processStartInvocation(
87 TestRecord invocationStartRecord, IInvocationContext invocationContext) {}
Julien Desprez093c3f62018-05-21 16:23:37 -070088
89 /**
90 * Handling of the final proto with all results.
91 *
92 * @param finalRecord The finalized proto with all the invocation results.
93 */
94 public void processFinalProto(TestRecord finalRecord) {}
95
96 /**
97 * Handling of the partial module record proto after {@link
98 * #testModuleStarted(IInvocationContext)} occurred.
99 *
100 * @param moduleStartRecord The partial proto representing the module.
101 */
102 public void processTestModuleStarted(TestRecord moduleStartRecord) {}
103
104 /**
105 * Handling of the finalized module record proto after {@link #testModuleEnded()} occurred.
106 *
107 * @param moduleRecord The finalized proto representing the module.
108 */
109 public void processTestModuleEnd(TestRecord moduleRecord) {}
110
111 /**
112 * Handling of the partial test run record proto after {@link #testRunStarted(String, int)}
113 * occurred.
114 *
115 * @param runStartedRecord The partial proto representing the run.
116 */
117 public void processTestRunStarted(TestRecord runStartedRecord) {}
118
119 /**
120 * Handling of the finalized run record proto after {@link #testRunEnded(long, HashMap)}
121 * occurred.
122 *
123 * @param runRecord The finalized proto representing the run.
Julien Desprez1bece772019-05-20 12:15:11 -0700124 * @param moduleInProgress whether or not a module is in progress.
Julien Desprez093c3f62018-05-21 16:23:37 -0700125 */
Julien Desprez1bece772019-05-20 12:15:11 -0700126 public void processTestRunEnded(TestRecord runRecord, boolean moduleInProgress) {}
Julien Desprez093c3f62018-05-21 16:23:37 -0700127
128 /**
129 * Handling of the partial test case record proto after {@link #testStarted(TestDescription,
130 * long)} occurred.
131 *
132 * @param testCaseStartedRecord The partial proto representing the test case.
133 */
134 public void processTestCaseStarted(TestRecord testCaseStartedRecord) {}
135
136 /**
137 * Handling of the finalized test case record proto after {@link #testEnded(TestDescription,
138 * long, HashMap)} occurred.
139 *
140 * @param testCaseRecord The finalized proto representing a test case.
141 */
142 public void processTestCaseEnded(TestRecord testCaseRecord) {}
143
144 // Invocation events
145
146 @Override
147 public final void invocationStarted(IInvocationContext context) {
148 mLatestChild = new Stack<>();
149 mInvocationRecordBuilder = TestRecord.newBuilder();
150 // Set invocation unique id
151 mInvocationRecordBuilder.setTestRecordId(UUID.randomUUID().toString());
152
153 // Populate start time of invocation
154 mInvocationStartTime = System.currentTimeMillis();
155 Timestamp startTime = createTimeStamp(mInvocationStartTime);
156 mInvocationRecordBuilder.setStartTime(startTime);
Julien Desprez50706022018-07-18 15:41:44 -0700157 mInvocationRecordBuilder.setDescription(Any.pack(context.toProto()));
Julien Desprez093c3f62018-05-21 16:23:37 -0700158
Julien Desprezf066b702018-11-07 11:10:08 -0800159 mContext = context;
160
Julien Desprez093c3f62018-05-21 16:23:37 -0700161 // Put the invocation record at the bottom of the stack
162 mLatestChild.add(mInvocationRecordBuilder);
163
164 // Send the invocation proto with the currently set information to indicate the beginning
165 // of the invocation.
166 TestRecord startInvocationProto = mInvocationRecordBuilder.build();
167 try {
Julien Desprez329294b2018-07-25 10:16:59 -0700168 processStartInvocation(startInvocationProto, context);
Julien Desprez093c3f62018-05-21 16:23:37 -0700169 } catch (RuntimeException e) {
170 CLog.e("Failed to process invocation started:");
171 CLog.e(e);
172 }
173 }
174
175 @Override
Julien Desprezdbc1f172018-12-21 12:14:33 -0800176 public void invocationFailed(Throwable cause) {
177 mInvocationFailure = cause;
178 }
179
180 @Override
Julien Desprez7fc54252020-04-30 15:08:45 -0700181 public void invocationFailed(FailureDescription failure) {
182 mInvocationFailureDescription = failure;
183 }
184
185 @Override
Julien Desprez093c3f62018-05-21 16:23:37 -0700186 public final void invocationEnded(long elapsedTime) {
Julien Desprez079ab2f2019-03-12 10:03:45 -0700187 if (mModuleInProgress) {
188 // If we had a module in progress, and a new module start occurs, complete the call
189 testModuleEnded();
190 }
Julien Desprez093c3f62018-05-21 16:23:37 -0700191 // Populate end time of invocation
192 Timestamp endTime = createTimeStamp(mInvocationStartTime + elapsedTime);
193 mInvocationRecordBuilder.setEndTime(endTime);
Julien Desprezf066b702018-11-07 11:10:08 -0800194 // Update the context in case it changed
195 mInvocationRecordBuilder.setDescription(Any.pack(mContext.toProto()));
Julien Desprez093c3f62018-05-21 16:23:37 -0700196
Julien Desprez7fc54252020-04-30 15:08:45 -0700197 DebugInfo invocationFailure = handleInvocationFailure();
198 if (invocationFailure != null) {
199 mInvocationRecordBuilder.setDebugInfo(invocationFailure);
Julien Desprezdbc1f172018-12-21 12:14:33 -0800200 }
201
Julien Desprez093c3f62018-05-21 16:23:37 -0700202 // Finalize the protobuf handling: where to put the results.
203 TestRecord record = mInvocationRecordBuilder.build();
204 try {
205 processFinalProto(record);
206 } catch (RuntimeException e) {
207 CLog.e("Failed to process invocation ended:");
208 CLog.e(e);
209 }
210 }
211
212 // Module events (optional when there is no suite)
213
214 @Override
215 public final void testModuleStarted(IInvocationContext moduleContext) {
Julien Desprez079ab2f2019-03-12 10:03:45 -0700216 if (mModuleInProgress) {
217 // If we had a module in progress, and a new module start occurs, complete the call
218 testModuleEnded();
219 }
Julien Desprez093c3f62018-05-21 16:23:37 -0700220 TestRecord.Builder moduleBuilder = TestRecord.newBuilder();
221 moduleBuilder.setParentTestRecordId(mInvocationRecordBuilder.getTestRecordId());
222 moduleBuilder.setTestRecordId(
223 moduleContext.getAttributes().get(ModuleDefinition.MODULE_ID).get(0));
224 moduleBuilder.setStartTime(createTimeStamp(System.currentTimeMillis()));
Julien Desprez50706022018-07-18 15:41:44 -0700225 moduleBuilder.setDescription(Any.pack(moduleContext.toProto()));
Julien Desprez093c3f62018-05-21 16:23:37 -0700226 mLatestChild.add(moduleBuilder);
Julien Desprez079ab2f2019-03-12 10:03:45 -0700227 mModuleInProgress = true;
Julien Desprez093c3f62018-05-21 16:23:37 -0700228 try {
229 processTestModuleStarted(moduleBuilder.build());
230 } catch (RuntimeException e) {
231 CLog.e("Failed to process invocation ended:");
232 CLog.e(e);
233 }
234 }
235
236 @Override
237 public final void testModuleEnded() {
238 TestRecord.Builder moduleBuilder = mLatestChild.pop();
Julien Desprez079ab2f2019-03-12 10:03:45 -0700239 mModuleInProgress = false;
Julien Desprez093c3f62018-05-21 16:23:37 -0700240 moduleBuilder.setEndTime(createTimeStamp(System.currentTimeMillis()));
241 TestRecord.Builder parentBuilder = mLatestChild.peek();
242
243 // Finalize the module and track it in the child
244 TestRecord moduleRecord = moduleBuilder.build();
245 parentBuilder.addChildren(createChildReference(moduleRecord));
246 try {
247 processTestModuleEnd(moduleRecord);
248 } catch (RuntimeException e) {
249 CLog.e("Failed to process test module end:");
250 CLog.e(e);
251 }
252 }
253
254 // Run events
255
256 @Override
257 public final void testRunStarted(String runName, int testCount) {
Julien Desprezb18ff872018-08-16 10:34:28 -0700258 testRunStarted(runName, testCount, 0);
259 }
260
261 @Override
262 public void testRunStarted(String runName, int testCount, int attemptNumber) {
Julien Desprezbd1f3762019-04-19 14:57:00 -0700263 testRunStarted(runName, testCount, attemptNumber, System.currentTimeMillis());
264 }
265
266 @Override
267 public void testRunStarted(String runName, int testCount, int attemptNumber, long startTime) {
Julien Desprez093c3f62018-05-21 16:23:37 -0700268 TestRecord.Builder runBuilder = TestRecord.newBuilder();
269 TestRecord.Builder parent = mLatestChild.peek();
270 runBuilder.setParentTestRecordId(parent.getTestRecordId());
271 runBuilder.setTestRecordId(runName);
272 runBuilder.setNumExpectedChildren(testCount);
Julien Desprezbd1f3762019-04-19 14:57:00 -0700273 runBuilder.setStartTime(createTimeStamp(startTime));
Julien Desprezb18ff872018-08-16 10:34:28 -0700274 runBuilder.setAttemptId(attemptNumber);
Julien Desprez093c3f62018-05-21 16:23:37 -0700275
276 mLatestChild.add(runBuilder);
277 try {
278 processTestRunStarted(runBuilder.build());
279 } catch (RuntimeException e) {
280 CLog.e("Failed to process invocation ended:");
281 CLog.e(e);
282 }
283 }
284
285 @Override
286 public final void testRunFailed(String errorMessage) {
287 TestRecord.Builder current = mLatestChild.peek();
288 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
289 debugBuilder.setErrorMessage(errorMessage);
290 if (TestStatus.UNKNOWN.equals(current.getStatus())) {
291 current.setDebugInfo(debugBuilder.build());
292 } else {
293 // We are in a test case and we need the run parent.
294 TestRecord.Builder test = mLatestChild.pop();
295 TestRecord.Builder run = mLatestChild.peek();
296 run.setDebugInfo(debugBuilder.build());
297 // Re-add the test
298 mLatestChild.add(test);
299 }
300 }
301
302 @Override
Julien Desprez8ee09232020-02-06 10:30:11 -0800303 public final void testRunFailed(FailureDescription failure) {
304 TestRecord.Builder current = mLatestChild.peek();
305 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
306 debugBuilder.setErrorMessage(failure.toString());
307 if (failure.getFailureStatus() != null) {
308 debugBuilder.setFailureStatus(failure.getFailureStatus());
309 }
Julien Desprez221aaf12020-02-27 14:17:03 -0800310 DebugInfoContext.Builder debugContext = DebugInfoContext.newBuilder();
311 if (failure.getActionInProgress() != null) {
312 debugContext.setActionInProgress(failure.getActionInProgress().toString());
313 }
314 if (!Strings.isNullOrEmpty(failure.getDebugHelpMessage())) {
315 debugContext.setDebugHelpMessage(failure.getDebugHelpMessage());
316 }
317 debugBuilder.setDebugInfoContext(debugContext.build());
318
Julien Desprez8ee09232020-02-06 10:30:11 -0800319 if (TestStatus.UNKNOWN.equals(current.getStatus())) {
320 current.setDebugInfo(debugBuilder.build());
321 } else {
322 // We are in a test case and we need the run parent.
323 TestRecord.Builder test = mLatestChild.pop();
324 TestRecord.Builder run = mLatestChild.peek();
325 run.setDebugInfo(debugBuilder.build());
326 // Re-add the test
327 mLatestChild.add(test);
328 }
329 }
330
331 @Override
Julien Desprez093c3f62018-05-21 16:23:37 -0700332 public final void testRunEnded(long elapsedTimeMillis, HashMap<String, Metric> runMetrics) {
333 TestRecord.Builder runBuilder = mLatestChild.pop();
Julien Desprezbd1f3762019-04-19 14:57:00 -0700334 long startTime = timeStampToMillis(runBuilder.getStartTime());
335 runBuilder.setEndTime(createTimeStamp(startTime + elapsedTimeMillis));
Julien Desprez093c3f62018-05-21 16:23:37 -0700336 runBuilder.putAllMetrics(runMetrics);
337 TestRecord.Builder parentBuilder = mLatestChild.peek();
338
339 // Finalize the run and track it in the child
340 TestRecord runRecord = runBuilder.build();
341 parentBuilder.addChildren(createChildReference(runRecord));
342 try {
Julien Desprez1bece772019-05-20 12:15:11 -0700343 processTestRunEnded(runRecord, mModuleInProgress);
Julien Desprez093c3f62018-05-21 16:23:37 -0700344 } catch (RuntimeException e) {
345 CLog.e("Failed to process test run end:");
346 CLog.e(e);
347 }
348 }
349
350 // test case events
351
352 @Override
Julien Desprez329294b2018-07-25 10:16:59 -0700353 public final void testStarted(TestDescription test) {
354 testStarted(test, System.currentTimeMillis());
355 }
356
357 @Override
Julien Desprez093c3f62018-05-21 16:23:37 -0700358 public final void testStarted(TestDescription test, long startTime) {
359 TestRecord.Builder testBuilder = TestRecord.newBuilder();
360 TestRecord.Builder parent = mLatestChild.peek();
361 testBuilder.setParentTestRecordId(parent.getTestRecordId());
362 testBuilder.setTestRecordId(test.toString());
363 testBuilder.setStartTime(createTimeStamp(startTime));
364 testBuilder.setStatus(TestStatus.PASS);
365
366 mLatestChild.add(testBuilder);
367 try {
368 processTestCaseStarted(testBuilder.build());
369 } catch (RuntimeException e) {
370 CLog.e("Failed to process invocation ended:");
371 CLog.e(e);
372 }
373 }
374
375 @Override
Julien Desprez329294b2018-07-25 10:16:59 -0700376 public void testEnded(TestDescription test, HashMap<String, Metric> testMetrics) {
377 testEnded(test, System.currentTimeMillis(), testMetrics);
378 }
379
380 @Override
Julien Desprez093c3f62018-05-21 16:23:37 -0700381 public final void testEnded(
382 TestDescription test, long endTime, HashMap<String, Metric> testMetrics) {
383 TestRecord.Builder testBuilder = mLatestChild.pop();
384 testBuilder.setEndTime(createTimeStamp(endTime));
385 testBuilder.putAllMetrics(testMetrics);
386 TestRecord.Builder parentBuilder = mLatestChild.peek();
387
388 // Finalize the run and track it in the child
389 TestRecord testCaseRecord = testBuilder.build();
390 parentBuilder.addChildren(createChildReference(testCaseRecord));
391 try {
392 processTestCaseEnded(testCaseRecord);
393 } catch (RuntimeException e) {
394 CLog.e("Failed to process test case end:");
395 CLog.e(e);
396 }
397 }
398
399 @Override
400 public final void testFailed(TestDescription test, String trace) {
401 TestRecord.Builder testBuilder = mLatestChild.peek();
402
403 testBuilder.setStatus(TestStatus.FAIL);
404 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
405 // FIXME: extract the error message from the trace
406 debugBuilder.setErrorMessage(trace);
407 debugBuilder.setTrace(trace);
408 testBuilder.setDebugInfo(debugBuilder.build());
409 }
410
411 @Override
Julien Desprez8ee09232020-02-06 10:30:11 -0800412 public final void testFailed(TestDescription test, FailureDescription failure) {
413 TestRecord.Builder testBuilder = mLatestChild.peek();
414
415 testBuilder.setStatus(TestStatus.FAIL);
416 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
417 // FIXME: extract the error message from the trace
418 debugBuilder.setErrorMessage(failure.toString());
419 debugBuilder.setTrace(failure.toString());
420 if (failure.getFailureStatus() != null) {
421 debugBuilder.setFailureStatus(failure.getFailureStatus());
422 }
Julien Desprez221aaf12020-02-27 14:17:03 -0800423 DebugInfoContext.Builder debugContext = DebugInfoContext.newBuilder();
424 if (failure.getActionInProgress() != null) {
425 debugContext.setActionInProgress(failure.getActionInProgress().toString());
426 }
427 if (!Strings.isNullOrEmpty(failure.getDebugHelpMessage())) {
428 debugContext.setDebugHelpMessage(failure.getDebugHelpMessage());
429 }
430 debugBuilder.setDebugInfoContext(debugContext.build());
431
Julien Desprez8ee09232020-02-06 10:30:11 -0800432 testBuilder.setDebugInfo(debugBuilder.build());
433 }
434
435 @Override
Julien Desprez093c3f62018-05-21 16:23:37 -0700436 public final void testIgnored(TestDescription test) {
437 TestRecord.Builder testBuilder = mLatestChild.peek();
438 testBuilder.setStatus(TestStatus.IGNORED);
439 }
440
441 @Override
442 public final void testAssumptionFailure(TestDescription test, String trace) {
443 TestRecord.Builder testBuilder = mLatestChild.peek();
444
445 testBuilder.setStatus(TestStatus.ASSUMPTION_FAILURE);
446 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
447 // FIXME: extract the error message from the trace
448 debugBuilder.setErrorMessage(trace);
449 debugBuilder.setTrace(trace);
450 testBuilder.setDebugInfo(debugBuilder.build());
451 }
452
Julien Desprez53af5fe2020-02-19 10:31:38 -0800453 @Override
454 public final void testAssumptionFailure(TestDescription test, FailureDescription failure) {
455 TestRecord.Builder testBuilder = mLatestChild.peek();
456
457 testBuilder.setStatus(TestStatus.ASSUMPTION_FAILURE);
458 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
459 // FIXME: extract the error message from the trace
460 debugBuilder.setErrorMessage(failure.toString());
461 debugBuilder.setTrace(failure.toString());
462 if (failure.getFailureStatus() != null) {
463 debugBuilder.setFailureStatus(failure.getFailureStatus());
464 }
465 testBuilder.setDebugInfo(debugBuilder.build());
466 }
467
Julien Desprez093c3f62018-05-21 16:23:37 -0700468 // log events
469
470 @Override
Julien Desprez093c3f62018-05-21 16:23:37 -0700471 public final void logAssociation(String dataName, LogFile logFile) {
472 TestRecord.Builder current = mLatestChild.peek();
473 Map<String, Any> fullmap = new HashMap<>();
Joseph Murphye87b17f2019-12-06 17:53:33 -0800474 fullmap.putAll(current.getArtifactsMap());
Julien Desprez093c3f62018-05-21 16:23:37 -0700475 Any any = Any.pack(createFileProto(logFile));
476 fullmap.put(dataName, any);
477 current.putAllArtifacts(fullmap);
478 }
479
480 private ChildReference createChildReference(TestRecord record) {
Julien Despreza49034d2018-07-24 10:07:10 -0700481 ChildReference.Builder child = ChildReference.newBuilder();
482 child.setTestRecordId(record.getTestRecordId());
483 child.setInlineTestRecord(record);
484 return child.build();
Julien Desprez093c3f62018-05-21 16:23:37 -0700485 }
486
487 /** Create and populate Timestamp as recommended in the javadoc of the Timestamp proto. */
488 private Timestamp createTimeStamp(long currentTimeMs) {
489 return Timestamp.newBuilder()
490 .setSeconds(currentTimeMs / 1000)
491 .setNanos((int) ((currentTimeMs % 1000) * 1000000))
492 .build();
493 }
494
Julien Desprezbd1f3762019-04-19 14:57:00 -0700495 private long timeStampToMillis(Timestamp stamp) {
496 return stamp.getSeconds() * 1000L + (stamp.getNanos() / 1000000L);
497 }
498
Julien Desprez093c3f62018-05-21 16:23:37 -0700499 private LogFileInfo createFileProto(LogFile logFile) {
500 LogFileInfo.Builder logFileBuilder = LogFileInfo.newBuilder();
501 logFileBuilder
502 .setPath(logFile.getPath())
Julien Desprez093c3f62018-05-21 16:23:37 -0700503 .setIsText(logFile.isText())
Julien Despreza49034d2018-07-24 10:07:10 -0700504 .setLogType(logFile.getType().toString())
Julien Desprez093c3f62018-05-21 16:23:37 -0700505 .setIsCompressed(logFile.isCompressed())
506 .setSize(logFile.getSize());
Julien Desprez329294b2018-07-25 10:16:59 -0700507 // Url can be null so avoid NPE by checking it before setting the proto
508 if (logFile.getUrl() != null) {
509 logFileBuilder.setUrl(logFile.getUrl());
510 }
Julien Desprez093c3f62018-05-21 16:23:37 -0700511 return logFileBuilder.build();
512 }
Julien Desprez7fc54252020-04-30 15:08:45 -0700513
514 private DebugInfo handleInvocationFailure() {
515 DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
516 Throwable baseException = null;
517 if (mInvocationFailureDescription != null) {
518 baseException = mInvocationFailureDescription.getCause();
519 }
520 if (baseException == null) {
521 baseException = mInvocationFailure;
522 }
523 // TODO: Handle FailureDescription without getCause.
524 if (baseException == null) {
525 // No invocation failure
526 return null;
527 }
528
529 if (baseException.getMessage() != null) {
530 debugBuilder.setErrorMessage(baseException.getMessage());
531 }
532 debugBuilder.setTrace(StreamUtil.getStackTrace(baseException));
533 if (mInvocationFailureDescription != null
534 && mInvocationFailureDescription.getFailureStatus() != null) {
535 debugBuilder.setFailureStatus(mInvocationFailureDescription.getFailureStatus());
536 }
537 DebugInfoContext.Builder debugContext = DebugInfoContext.newBuilder();
538 try {
539 debugContext.setErrorType(SerializationUtil.serializeToString(baseException));
540 } catch (IOException e) {
541 CLog.e("Failed to serialize the invocation failure:");
542 CLog.e(e);
543 }
544 debugBuilder.setDebugInfoContext(debugContext);
545
546 return debugBuilder.build();
547 }
Julien Desprez093c3f62018-05-21 16:23:37 -0700548}