1 /*
2  * Copyright (C) 2024 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  */
16 
17 package android.tools.traces.io
18 
19 import android.tools.Scenario
20 import android.tools.ScenarioBuilder
21 import android.tools.Tag
22 import android.tools.Timestamp
23 import android.tools.Timestamps
24 import android.tools.io.FLICKER_IO_TAG
25 import android.tools.io.ResultArtifactDescriptor
26 import android.tools.io.RunStatus
27 import android.tools.io.TraceType
28 import android.tools.io.TransitionTimeRange
29 import android.tools.withTracing
30 import android.util.Log
31 import java.io.File
32 
33 /** Helper class to create run result artifact files */
34 open class ResultWriter {
35     protected var scenario: Scenario = ScenarioBuilder().createEmptyScenario()
36     private var runStatus: RunStatus = RunStatus.UNDEFINED
37     private val files = mutableMapOf<ResultArtifactDescriptor, File>()
38     private var transitionStartTime = Timestamps.min()
39     private var transitionEndTime = Timestamps.max()
40     private var executionError: Throwable? = null
41     private var outputDir: File? = null
42 
43     /** Sets the artifact scenario to [_scenario] */
<lambda>null44     fun forScenario(_scenario: Scenario) = apply { scenario = _scenario }
45 
46     /** Sets the artifact transition start time to [time] */
<lambda>null47     fun setTransitionStartTime(time: Timestamp) = apply { transitionStartTime = time }
48 
49     /** Sets the artifact transition end time to [time] */
<lambda>null50     fun setTransitionEndTime(time: Timestamp) = apply { transitionEndTime = time }
51 
52     /** Sets the artifact status as successfully executed transition ([RunStatus.RUN_EXECUTED]) */
<lambda>null53     fun setRunComplete() = apply { runStatus = RunStatus.RUN_EXECUTED }
54 
55     /** Sets the dir where the artifact file will be stored to [dir] */
<lambda>null56     fun withOutputDir(dir: File) = apply { outputDir = dir }
57 
58     /**
59      * Sets the artifact status as failed executed transition ([RunStatus.RUN_FAILED])
60      *
61      * @param error that caused the transition to fail
62      */
<lambda>null63     fun setRunFailed(error: Throwable) = apply {
64         runStatus = RunStatus.RUN_FAILED
65         executionError = error
66     }
67 
68     /**
69      * Adds [artifact] to the result artifact
70      *
71      * @param traceType used when adding [artifact] to the result artifact
72      * @param tag used when adding [artifact] to the result artifact
73      */
<lambda>null74     fun addTraceResult(traceType: TraceType, artifact: File, tag: String = Tag.ALL) = apply {
75         Log.d(
76             FLICKER_IO_TAG,
77             "Add trace result file=$artifact type=$traceType tag=$tag scenario=$scenario"
78         )
79         val fileDescriptor = ResultArtifactDescriptor(traceType, tag)
80         files[fileDescriptor] = artifact
81     }
82 
83     /** @return writes the result artifact to disk and returns it */
writenull84     open fun write(): IResultData {
85         return withTracing("write") {
86             val outputDir = outputDir
87             requireNotNull(outputDir) { "Output dir not configured" }
88             require(!scenario.isEmpty) { "Scenario shouldn't be empty" }
89 
90             if (runStatus == RunStatus.UNDEFINED) {
91                 Log.w(FLICKER_IO_TAG, "Writing result with $runStatus run status")
92             }
93 
94             val artifact =
95                 ArtifactBuilder()
96                     .withScenario(scenario)
97                     .withOutputDir(outputDir)
98                     .withStatus(runStatus)
99                     .withFiles(files)
100                     .build()
101             ResultData(
102                 artifact,
103                 TransitionTimeRange(transitionStartTime, transitionEndTime),
104                 executionError
105             )
106         }
107     }
108 }
109