Flank / flank

:speedboat: Massively parallel Android and iOS test runner for Firebase Test Lab
https://firebase.community/
Apache License 2.0
665 stars 112 forks source link

Structural output of domain layer #1728

Open jan-goral opened 3 years ago

jan-goral commented 3 years ago

Motivation

Currently, flank is putting all output data directly to console, which is useful for command-line but not for different types of UI like the desktop.

Goal

API

/**
 * The abstraction which allows passing output from the domain to presentation.
 * Implement in domain top-level interfaces for getting access to outputting result structures.
 * @property out The reference to outputting result function.
 */
interface Output {
    val out: (Any) -> Unit
}

Steps

  1. Prepare a list of logs that can be displayed by command.
  2. Basing on a list of logs prepare corresponding structures.
  3. Extend domain top-level using Output interface
  4. Register A mapper in cli command.
  5. Replace all logLn occurrences with out function call
  6. Move the mapper to the proper package. (TODO - Consider which package is proper)

Hint

For step 2. If you have to add a new type that can be identified in the presentation layer as something that should be converted to the console log and you also have to decide where to place it, you can follow the rules:

Example

Based on ListAndroidOrientations

Step 1

  1. List<Orientation> - test_runner/src/main/kotlin/ftl/domain/ListAndroidOrientations.kt#L16

Step 2

List<Orientation> is a generic type that is losing parameter type info in runtime, so it's necessary to create a wrapping structure that could be resolved by type matching.

Add Orientaton.Available structure for representing list available orientations the specific platform

data class Orientation(
    val id: String,
    val name: String,
    val tags: List<String>,
) {
    data class Available(
        val platform: Platform,
        val list: List<Orientation>
    )

    interface Fetch : (String, Platform) -> Available
}

Step 3

Extend using the Output interface.

interface ListAndroidOrientations : Output {
    val configPath: String
}

Step 4

Add out implementation to AndroidOrientationsListCommand

class AndroidOrientationsListCommand :
    Runnable,
    ListAndroidOrientations {

    override fun run() = invoke()

    override val out = outputLogger {
        when (this) {
            is Orientation.Available -> list.toCliTable()
            else -> throwUnknownType()
        }
    }
}

Step 5

Replace logLn with out call

operator fun ListAndroidOrientations.invoke() {
    fetchOrientation(
        AndroidArgs.loadOrDefault(Paths.get(configPath)).project,
        Platform.ANDROID
    ).out()
}

Step 6

Consider the proper package for API structures to console output formatters - #1872 If issue #1872 isn't finished yet, place the formatters where you wish. This will be taken into account or refactored further.

Utils

fun outputLogger(map: Any.() -> String): Any.() -> Unit = {
    logLn(map())
}

fun Any.throwUnknownType(): Nothing =
    throw IllegalArgumentException(javaClass.toGenericString())
jan-goral commented 3 years ago

The commands grouped difficulty.

Simple

Average

Dragon