blob: a68ace398f57ac7c06124f974566ba2d51c9b4a1 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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.server.wm.flicker
import android.util.Log
import com.android.server.wm.flicker.FlickerRunResult.Companion.RunStatus
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.nio.file.Path
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
class RunResultArtifacts(_filePath: Path) {
init {
_filePath.parent.toFile().mkdirs()
_filePath.toFile().createNewFile()
}
var path = _filePath
private set
private var archiveLocked = false
private val zipOutputStream by lazy { openZipOutputStream() }
private fun openZipOutputStream(): ZipOutputStream {
return ZipOutputStream(BufferedOutputStream(
FileOutputStream(path.toFile()), BUFFER_SIZE))
}
internal val traceName = path.fileName ?: "UNNAMED_TRACE"
var status: RunStatus = RunStatus.UNDEFINED
internal set(value) {
if (field != value) {
require(value != RunStatus.UNDEFINED) {
"Can't set status to UNDEFINED after being defined"
}
require(!field.isFailure) {
"Status of run already set to a failed status $field " +
"and can't be changed to $value."
}
field = value
syncFileWithStatus()
}
}
private fun syncFileWithStatus() {
// Since we don't expect this to run in a multi-threaded context this is fine
val localTraceFile = path
try {
val newFileName = "${status.prefix}_$traceName"
val dst = localTraceFile.resolveSibling(newFileName)
Utils.renameFile(localTraceFile, dst)
path = dst
} catch (e: IOException) {
Log.e(FLICKER_TAG, "Unable to update file status $this", e)
}
}
internal fun addFile(file: File, nameInArchive: String = file.name) {
require(!archiveLocked) { "Archive is locked. Can't add to it." }
val fi = FileInputStream(file)
val inputStream = BufferedInputStream(fi, BUFFER_SIZE)
inputStream.use {
val entry = ZipEntry(nameInArchive)
zipOutputStream.putNextEntry(entry)
val data = ByteArray(BUFFER_SIZE)
var count: Int = it.read(data, 0, BUFFER_SIZE)
while (count != -1) {
zipOutputStream.write(data, 0, count)
count = it.read(data, 0, BUFFER_SIZE)
}
}
zipOutputStream.closeEntry()
file.delete()
}
internal fun lock() {
if (!archiveLocked) {
zipOutputStream.close()
archiveLocked = true
}
}
internal fun getFileBytes(fileName: String): ByteArray {
require (archiveLocked) { "Can't get files from archive before it is closed" }
val tmpBuffer = ByteArray(BUFFER_SIZE)
val zipInputStream: ZipInputStream
try {
zipInputStream =
ZipInputStream(
BufferedInputStream(FileInputStream(path.toFile()), BUFFER_SIZE))
} catch (e: Throwable) {
return ByteArray(0)
}
val outByteArray = ByteArrayOutputStream()
var foundFile = false
try {
var zipEntry: ZipEntry? = zipInputStream.nextEntry
while (zipEntry != null) {
if (zipEntry.name == fileName) {
val outputStream = BufferedOutputStream(outByteArray, BUFFER_SIZE)
try {
var size = zipInputStream.read(tmpBuffer, 0, BUFFER_SIZE)
while (size > 0) {
outputStream.write(tmpBuffer, 0, size)
size = zipInputStream.read(tmpBuffer, 0, BUFFER_SIZE)
}
zipInputStream.closeEntry()
} finally {
outputStream.flush()
outputStream.close()
}
foundFile = true
break
}
zipEntry = zipInputStream.nextEntry
}
} finally {
zipInputStream.closeEntry()
zipInputStream.close()
}
require(foundFile) { "$fileName not found in archive..." }
return outByteArray.toByteArray()
}
companion object {
private const val BUFFER_SIZE = 2048
}
}