Skip to content

Commit

Permalink
#835 Added printing Android devices list
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Adamczyk committed Jul 14, 2020
1 parent 38e965e commit 95298a2
Show file tree
Hide file tree
Showing 17 changed files with 295 additions and 48 deletions.
2 changes: 2 additions & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
- [#862](https://github.com/Flank/flank/pull/862) Added printing outcome details. ([piotradamczyk5](https://github.com/piotradamczyk5), [jan-gogo](https://github.com/jan-gogo))
- [#876](https://github.com/Flank/flank/pull/876) Added --directories-to-pull validation and avoid making request with empty toolStepResult. ([piotradamczyk5](https://github.com/piotradamczyk5))
- [#875](https://github.com/Flank/flank/pull/875) Enhance permission denied exception logs. ([adamfilipow92](https://github.com/adamfilipow92), [pawelpasterz](https://github.com/pawelpasterz))
- [#876](https://github.com/Flank/flank/pull/876) Added option to print Android available devices to test against. ([piotradamczyk5](https://github.com/piotradamczyk5))
-
-

## v20.06.2
Expand Down
3 changes: 3 additions & 0 deletions test_runner/docs/ascii/flank.jar_-android.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ flank.jar
*doctor*::
Verifies flank firebase is setup correctly

*models*::
Information about available models

// end::picocli-generated-man-section-commands[]

// end::picocli-generated-full-manpage[]
3 changes: 3 additions & 0 deletions test_runner/docs/ascii/flank.jar_-firebase-test-android.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ flank.jar
*doctor*::
Verifies flank firebase is setup correctly

*models*::
Information about available models

// end::picocli-generated-man-section-commands[]

// end::picocli-generated-full-manpage[]
41 changes: 14 additions & 27 deletions test_runner/src/main/kotlin/ftl/android/AndroidCatalog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ftl.android

import com.google.api.services.testing.model.AndroidDevice
import com.google.api.services.testing.model.AndroidDeviceCatalog
import ftl.environment.asPrintableTable
import ftl.gc.GcTesting
import ftl.http.executeWithRetry

Expand All @@ -14,42 +15,28 @@ object AndroidCatalog {
private val modelMap: MutableMap<String, List<String>> = mutableMapOf()
private val versionMap: MutableMap<String, List<String>> = mutableMapOf()

private fun androidDeviceCatalog(projectId: String): AndroidDeviceCatalog {
val cached = catalogMap[projectId]
if (cached != null) return cached

val newCatalog = GcTesting.get.testEnvironmentCatalog()
private fun deviceCatalog(projectId: String) = catalogMap.getOrPut(projectId) {
GcTesting.get.testEnvironmentCatalog()
.get("android")
.setProjectId(projectId)
.executeWithRetry().androidDeviceCatalog
catalogMap[projectId] = newCatalog
return newCatalog
.executeWithRetry()
.androidDeviceCatalog
}

fun androidModelIds(projectId: String): List<String> {
val cached = modelMap[projectId]
if (cached != null) return cached
fun devicesCatalogAsTable(projectId: String) = deviceCatalog(projectId).models.asPrintableTable()

val newModels = androidDeviceCatalog(projectId).models.map { it.id }
modelMap[projectId] = newModels
return newModels
}
fun androidModelIds(projectId: String) =
modelMap.getOrPut(projectId) { deviceCatalog(projectId).models.map { it.id } }

fun androidVersionIds(projectId: String): List<String> {
val cached = versionMap[projectId]
if (cached != null) return cached

val newVersions = androidDeviceCatalog(projectId).versions.map { it.id }
versionMap[projectId] = newVersions
return newVersions
}
fun androidVersionIds(projectId: String) =
versionMap.getOrPut(projectId) { deviceCatalog(projectId).versions.map { it.id } }

fun supportedDeviceConfig(modelId: String, versionId: String, projectId: String): DeviceConfigCheck {
val foundModel = androidDeviceCatalog(projectId).models.find { it.id == modelId } ?: return UnsupportedModelId

val foundModel = deviceCatalog(projectId).models.find { it.id == modelId } ?: return UnsupportedModelId
if (!androidVersionIds(projectId).contains(versionId)) return UnsupportedVersionId

val supportedVersionIds = foundModel.supportedVersionIds
supportedVersionIds?.let {
foundModel.supportedVersionIds?.let {
if (!it.contains(versionId)) return IncompatibleModelVersion
} ?: return UnsupportedModelId

Expand All @@ -58,7 +45,7 @@ object AndroidCatalog {

fun isVirtualDevice(device: AndroidDevice?, projectId: String): Boolean {
val modelId = device?.androidModelId ?: return false
val form = androidDeviceCatalog(projectId).models.find { it.id == modelId }?.form ?: "PHYSICAL"
val form = deviceCatalog(projectId).models.find { it.id == modelId }?.form ?: "PHYSICAL"
return form == "VIRTUAL"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ftl.cli.firebase.test

import ftl.cli.firebase.test.android.AndroidDoctorCommand
import ftl.cli.firebase.test.android.AndroidRunCommand
import ftl.cli.firebase.test.android.models.AndroidModelsCommand
import picocli.CommandLine
import picocli.CommandLine.Command

Expand All @@ -10,7 +11,8 @@ import picocli.CommandLine.Command
synopsisHeading = "",
subcommands = [
AndroidRunCommand::class,
AndroidDoctorCommand::class
AndroidDoctorCommand::class,
AndroidModelsCommand::class
],
usageHelpAutoWidth = true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ftl.cli.firebase.test.android

import ftl.args.AndroidArgs
import ftl.cli.firebase.test.processValidation
import ftl.config.FtlConstants
import ftl.doctor.Doctor.validateYaml
import java.nio.file.Paths
import picocli.CommandLine.Command
Expand All @@ -28,7 +29,7 @@ class AndroidDoctorCommand : Runnable {
}

@Option(names = ["-c", "--config"], description = ["YAML config file path"])
var configPath: String = "./flank.yml"
var configPath: String = FtlConstants.defaultAndroidConfig

@Option(names = ["-h", "--help"], usageHelp = true, description = ["Prints this help message"])
var usageHelpRequested: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ftl.cli.firebase.test.android.models

import picocli.CommandLine

@CommandLine.Command(
name = "models",
headerHeading = "",
synopsisHeading = "%n",
descriptionHeading = "%n@|bold,underline Description:|@%n%n",
parameterListHeading = "%n@|bold,underline Parameters:|@%n",
optionListHeading = "%n@|bold,underline Options:|@%n",
header = ["Information about available models"],
description = ["Information about available models. For example prints list of available models to test against"],
subcommands = [AndroidModelsListCommand::class],
usageHelpAutoWidth = true
)
class AndroidModelsCommand : Runnable {
override fun run() {
CommandLine.usage(AndroidModelsCommand(), System.out)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ftl.cli.firebase.test.android.models

import ftl.android.AndroidCatalog
import ftl.args.AndroidArgs
import ftl.config.FtlConstants
import picocli.CommandLine
import java.nio.file.Paths

@CommandLine.Command(
name = "list",
headerHeading = "",
synopsisHeading = "%n",
descriptionHeading = "%n@|bold,underline Description:|@%n%n",
parameterListHeading = "%n@|bold,underline Parameters:|@%n",
optionListHeading = "%n@|bold,underline Options:|@%n",
header = ["Print current list of devices available to test against"],
description = ["Print current list of Android devices available to test against"],
usageHelpAutoWidth = true
)
class AndroidModelsListCommand : Runnable {
override fun run() {
val config = AndroidArgs.load(Paths.get(configPath))
println(AndroidCatalog.devicesCatalogAsTable(config.project))
}

@CommandLine.Option(names = ["-c", "--config"], description = ["YAML config file path"])
var configPath: String = FtlConstants.defaultAndroidConfig

@CommandLine.Option(names = ["-h", "--help"], usageHelp = true, description = ["Prints this help message"])
var usageHelpRequested: Boolean = false
}
38 changes: 38 additions & 0 deletions test_runner/src/main/kotlin/ftl/environment/ListAndroidDevices.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ftl.environment

import com.google.api.services.testing.model.AndroidModel
import ftl.util.SystemOutColor
import ftl.util.applyColorsUsing
import ftl.util.buildTable

fun List<AndroidModel>.asPrintableTable() = createTestEnvironmentInfo().createAndroidDevicesTable()

private fun List<AndroidModel>.createTestEnvironmentInfo() =
fold(mutableMapOf<String, MutableList<String>>()) { devicesInfo, androidDevice ->
devicesInfo.apply {
getOrCreateList(MODEL_ID).add(androidDevice.codename.orUnknown())
getOrCreateList(MAKE).add(androidDevice.manufacturer.orUnknown())
getOrCreateList(MODEL_NAME).add(androidDevice.name.orUnknown())
getOrCreateList(FORM).add(androidDevice.form.orUnknown())
getOrCreateList(RESOLUTION).add(androidDevice.resolution)
getOrCreateList(OS_VERSION_IDS).add(androidDevice.supportedVersionIds?.joinToString().orEmpty())
getOrCreateList(TAGS).add(androidDevice.tags?.joinToString().orEmpty())
}
}

private fun TestEnvironmentInfo.createAndroidDevicesTable() = buildTable(
createTableColumnFor(MODEL_ID),
createTableColumnFor(MAKE),
createTableColumnFor(MODEL_NAME),
createTableColumnFor(FORM).applyColorsUsing(formToSystemOutColorMapper),
createTableColumnFor(RESOLUTION),
createTableColumnFor(OS_VERSION_IDS),
createTableColumnFor(TAGS).applyColorsUsing(tagToSystemOutColorMapper)
)

private val AndroidModel.resolution
get() = if (screenX == null || screenY == null) "UNKNOWN" else "$screenY x $screenX"

private val formToSystemOutColorMapper: (String) -> SystemOutColor = {
if (it == PHYSICAL_DEVICE) SystemOutColor.YELLOW else SystemOutColor.BLUE
}
30 changes: 30 additions & 0 deletions test_runner/src/main/kotlin/ftl/environment/TestEnvironmentInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ftl.environment

import ftl.util.SystemOutColor
import ftl.util.TableColumn

typealias TestEnvironmentInfo = MutableMap<String, MutableList<String>>

internal fun TestEnvironmentInfo.getOrCreateList(key: String) = getOrPut(key) { mutableListOf() }

internal fun TestEnvironmentInfo.createTableColumnFor(key: String) = TableColumn(key, getValue(key))

internal val tagToSystemOutColorMapper: (String) -> SystemOutColor = {
when {
it.contains("deprecated=") -> SystemOutColor.RED
it == "default" -> SystemOutColor.GREEN
it == "beta" -> SystemOutColor.YELLOW
else -> SystemOutColor.DEFAULT
}
}

internal fun String?.orUnknown() = this ?: "UNKNOWN"

const val MODEL_ID = "MODEL_ID"
const val MAKE = "MAKE"
const val MODEL_NAME = "MODEL_NAME"
const val FORM = "FORM"
const val RESOLUTION = "RESOLUTION"
const val OS_VERSION_IDS = "OS_VERSION_IDS"
const val TAGS = "TAGS"
const val PHYSICAL_DEVICE = "PHYSICAL"
14 changes: 6 additions & 8 deletions test_runner/src/main/kotlin/ftl/util/LogTableBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import com.google.common.annotations.VisibleForTesting
data class TableColumn(
val header: String,
val data: List<String>,
val columnSize: Int = ((data + header).maxBy { it.length }?.length ?: 0) + DEFAULT_COLUMN_PADDING,
val dataColor: List<SystemOutColor> = listOf()
val dataColor: List<SystemOutColor> = listOf(),
val columnSize: Int = ((data + header).maxBy { it.length }?.length ?: 0) + DEFAULT_COLUMN_PADDING
)

private data class DataWithSize(
Expand Down Expand Up @@ -47,7 +47,7 @@ private fun StringBuilder.startTable(rowSizes: List<Int>) {
endChar = START_TABLE_END_CHAR,
rowSizes = rowSizes
)
newLine()
appendln()
}

private fun StringBuilder.rowSeparator(rowSizes: List<Int>) {
Expand All @@ -57,7 +57,7 @@ private fun StringBuilder.rowSeparator(rowSizes: List<Int>) {
endChar = MIDDLE_TABLE_END_CHAR,
rowSizes = rowSizes
)
newLine()
appendln()
}

private fun StringBuilder.appendData(tableColumns: Array<out TableColumn>) {
Expand Down Expand Up @@ -99,7 +99,7 @@ private fun StringBuilder.appendDataRow(data: List<DataWithSize>) {
append(data.center(size))
append(TABLE_VERTICAL_LINE)
}
newLine()
appendln()
}

private fun String.center(columnSize: Int): String? {
Expand All @@ -109,6 +109,4 @@ private fun String.center(columnSize: Int): String? {
)
}

private fun StringBuilder.newLine() {
append(System.lineSeparator())
}
inline fun TableColumn.applyColorsUsing(mapper: (String) -> SystemOutColor) = copy(dataColor = data.map(mapper))
7 changes: 4 additions & 3 deletions test_runner/src/main/kotlin/ftl/util/SystemOutColor.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package ftl.util

enum class SystemOutColor(val ansiCode: String) {
enum class SystemOutColor(private val ansiCode: String) {
DEFAULT("\u001B[0m"),
RED("\u001B[31m"),
BLUE("\u001B[34m"),
GREEN("\u001B[32m");
GREEN("\u001B[32m"),
YELLOW("\u001B[33m"),
BLUE("\u001B[34m");

fun applyTo(value: String) = ansiCode + value + DEFAULT.ansiCode

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ class AndroidCommandTest {
val output = systemOutRule.log.normalizeLineEnding()
Truth.assertThat(output).startsWith(
"android [COMMAND]\n" +
"Commands:\n" +
" run Run tests on Firebase Test Lab\n" +
" doctor Verifies flank firebase is setup correctly\n"
"Commands:\n" +
" run Run tests on Firebase Test Lab\n" +
" doctor Verifies flank firebase is setup correctly\n" +
" models Information about available models"
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ftl.cli.firebase.test.android.models

import com.google.common.truth.Truth
import ftl.test.util.TestHelper.normalizeLineEnding
import org.junit.Rule
import org.junit.Test
import org.junit.contrib.java.lang.system.SystemOutRule

class AndroidModelsCommandTest {
@Rule
@JvmField
val systemOutRule: SystemOutRule = SystemOutRule().enableLog().muteForSuccessfulTests()

@Test
fun androidModelsCommandPrintsHelp() {
AndroidModelsCommand().run()
val output = systemOutRule.log.normalizeLineEnding()
Truth.assertThat(output).startsWith(
"Information about available models\n\n" +
"models [COMMAND]\n\n" +
"Description:\n\n" +
"Information about available models. For example prints list of available models\n" +
"to test against\n" +
"Commands:\n" +
" list Print current list of devices available to test against"
)
}
}
Loading

0 comments on commit 95298a2

Please sign in to comment.