Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#932 Added tests for flank scripts #946

Merged
merged 4 commits into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/flank-scripts-macos_workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: flank-scripts-macos-workflow

on:
push:
branches:
- master
pull_request:
branches: [master]
paths:
- flank-scripts/**

jobs:
build:
runs-on: macos-latest

steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Gradle check
uses: eskatos/gradle-command-action@v1
with:
gradle-executable: "./flank-scripts/gradlew"
arguments: "-p flank-scripts check"
2 changes: 2 additions & 0 deletions .github/workflows/macos_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on:
pull_request:
branches:
- '*'
paths:
- '!flank-scripts/**'

jobs:
build:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ubuntu-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on:
pull_request:
branches:
- '*'
paths:
- '!flank-scripts/**'

jobs:
build:
Expand Down
23 changes: 23 additions & 0 deletions flank-scripts/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
kotlin(Kotlin.PLUGIN_JVM) version Versions.KOTLIN_VERSION
kotlin(Kotlin.PLUGIN_SERIALIZATION) version Versions.KOTLIN_VERSION
id(PLUGIN_SHADOW_JAR) version Versions.SHADOW_JAR
id(DETEKT_PLUGIN) version Versions.DETEKT
}

val artifactID = "flankScripts"
Expand Down Expand Up @@ -34,11 +35,33 @@ repositories {
maven(url = "https://kotlin.bintray.com/kotlinx")
}

detekt {
input = files("src/main/kotlin", "src/test/kotlin")
config = files("../config/detekt.yml")
reports {
xml {
enabled = false
}
html {
enabled = true
}
}
}

tasks["check"].dependsOn(tasks["detekt"])

dependencies {
implementation(kotlin("stdlib"))
implementation(Kotlin.KOTLIN_SERIALIZATION)
implementation(Fuel.CORE)
implementation(Fuel.KOTLINX_SERIALIZATION)
implementation(Fuel.COROUTINES)
implementation(CLIKT)

detektPlugins(DETEKT_FORMATTING)

testImplementation(JUNIT)
testImplementation(MOCKK)
testImplementation(TRUTH)
testImplementation(SYSTEM_RULES)
}
7 changes: 7 additions & 0 deletions flank-scripts/buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ object Fuel {
const val COROUTINES = "com.github.kittinunf.fuel:fuel-coroutines:${Versions.FUEL}"
const val KOTLINX_SERIALIZATION = "com.github.kittinunf.fuel:fuel-kotlinx-serialization:${Versions.FUEL}"
}

const val TRUTH = "com.google.truth:truth:${Versions.TRUTH}"
const val MOCKK = "io.mockk:mockk:${Versions.MOCKK}"
const val JUNIT = "junit:junit:${Versions.JUNIT}"
const val SYSTEM_RULES = "com.github.stefanbirkner:system-rules:${Versions.SYSTEM_RULES}"
const val DETEKT_PLUGIN = "io.gitlab.arturbosch.detekt"
const val DETEKT_FORMATTING = "io.gitlab.arturbosch.detekt:detekt-formatting:${Versions.DETEKT}"
10 changes: 10 additions & 0 deletions flank-scripts/buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,14 @@ object Versions {
const val KOTLINX_SERIALIZATION = "0.20.0"
const val FUEL = "2.2.3"
const val CLIKT = "2.8.0"
// https://github.com/google/truth/releases
const val TRUTH = "1.0"
// https://github.com/mockk/mockk
const val MOCKK = "1.10.0"
const val JUNIT = "4.13"
// https://github.com/stefanbirkner/system-rules/releases
const val SYSTEM_RULES = "1.19.0"

// https://github.com/detekt/detekt/releases
const val DETEKT = "1.1.0" // version must be same as flank cause they share config with each other
}
1 change: 1 addition & 0 deletions flank-scripts/src/main/kotlin/flank/scripts/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.github.ajalt.clikt.core.subcommands
import flank.scripts.release.ReleaseCommand

class Main : CliktCommand(name = "flankScripts") {
@Suppress("EmptyFunctionBlock")
override fun run() {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package flank.scripts.exceptions
import flank.scripts.release.hub.GitHubErrorResponse
import flank.scripts.release.updatebugsnag.BugSnagResponse

sealed class FlankScriptsExceptions() : Exception()
sealed class FlankScriptsExceptions : Exception()

class GitHubException(private val body: GitHubErrorResponse) : FlankScriptsExceptions() {
class GitHubException(val body: GitHubErrorResponse) : FlankScriptsExceptions() {
override fun toString(): String {
return "Error while doing GitHub request, because of ${body.message}, more info at ${body.documentationUrl}"
}
}

class BugsnagException(private val body: BugSnagResponse) : FlankScriptsExceptions() {
class BugsnagException(val body: BugSnagResponse) : FlankScriptsExceptions() {
override fun toString(): String {
return "Error while doing Bugnsag request, because of ${body.errors.joinToString()}"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ class ReleaseCommand : CliktCommand(name = "release", help = "Contains all relea
)
}

@Suppress("EmptyFunctionBlock")
override fun run() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import flank.scripts.utils.toJson
suspend fun updateBugsnag(bugsnagApiKey: String, appVersion: String, githubWorkflowUrl: String) =
httpRequest(createRequestBody(bugsnagApiKey, appVersion, githubWorkflowUrl))

private suspend fun httpRequest(jsonString: String) =
Fuel.post(BUGNSAG_URL)
.jsonBody(jsonString)
.awaitResult(BugSnagResponseDeserializer)
.mapClientError { it.toBugsnagException() }

private fun createRequestBody(bugsnagApiKey: String, appVersion: String, githubWorkflowUrl: String) =
BugSnagRequest(
apiKey = bugsnagApiKey,
Expand All @@ -20,12 +26,6 @@ private fun createRequestBody(bugsnagApiKey: String, appVersion: String, githubW
metadata = mapOf("github_actions_build_url" to githubWorkflowUrl)
).toJson(BugSnagRequest.serializer())

private suspend fun httpRequest(jsonString: String) =
Fuel.post(BUGNSAG_URL)
.jsonBody(jsonString)
.awaitResult(BugSnagResponseDeserializer)
.mapClientError { it.toBugsnagException() }

private fun githubActionsSourceControl(appVersion: String) = SourceControl(
"github",
REPOSITORY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fun List<String>.runCommand(retryCount: Int = 0) =

fun String.runCommand(retryCount: Int = 0) = split(" ").toList().runCommand(retryCount)

private fun ProcessBuilder.startWithRetry(retryCount: Int): Int {
internal fun ProcessBuilder.startWithRetry(retryCount: Int): Int {
var retryTries = 0
var processResponse: Int
do {
Expand All @@ -25,9 +25,9 @@ private fun ProcessBuilder.startWithRetry(retryCount: Int): Int {
}

private fun shouldRetry(
processResponse: Int,
retryCount: Int,
retryTries: Int
processResponse: Int,
retryCount: Int,
retryTries: Int
) = processResponse != 0 && processResponse != EXCEPTION_WHEN_CALLING_COMMAND_CODE && retryTries < retryCount

const val SUCCESS = 0
Expand Down
59 changes: 59 additions & 0 deletions flank-scripts/src/test/kotlin/flank/scripts/FuelTestRunner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package flank.scripts

import com.github.kittinunf.fuel.core.Client
import com.github.kittinunf.fuel.core.FuelManager
import com.github.kittinunf.fuel.core.Request
import com.github.kittinunf.fuel.core.Response
import com.github.kittinunf.fuel.core.requests.DefaultBody
import flank.scripts.release.updatebugsnag.BugSnagRequest
import flank.scripts.release.updatebugsnag.BugSnagResponse
import flank.scripts.utils.toJson
import flank.scripts.utils.toObject
import org.junit.runners.BlockJUnit4ClassRunner
import org.junit.runners.model.Statement

class FuelTestRunner(klass: Class<*>) : BlockJUnit4ClassRunner(klass) {

override fun withBeforeClasses(statement: Statement?): Statement {
startMockClient()
return super.withBeforeClasses(statement)
}

private fun startMockClient() {
FuelManager.instance.client = object : Client {
override fun executeRequest(request: Request): Response {
return when (request.url.toString()) {
"https://api.github.com/repos/Flank/flank/git/refs/tags/success" -> request.buildResponse("", 200)
"https://api.github.com/repos/Flank/flank/git/refs/tags/failure" -> request.buildResponse(githubErrorBody, 422)
"https://build.bugsnag.com/" -> {
val body = request.body.asString("application/json").toObject(BugSnagRequest.serializer())
if (body.apiKey == "success") {
request.buildResponse(body = BugSnagResponse("success")
.toJson(BugSnagResponse.serializer()), statusCode = 200)
} else {
request.buildResponse(
body = BugSnagResponse(
status = "failure",
errors = listOf("errors")
).toJson(BugSnagResponse.serializer()), statusCode = 422)
}
}
else -> Response(request.url)
}
}
}
}

private fun Request.buildResponse(body: String, statusCode: Int) =
Response(url, statusCode = statusCode, responseMessage = body, body = DefaultBody(
{ body.byteInputStream() },
{ body.length.toLong() }
))
}

private val githubErrorBody = """
{
"message": "Bad credentials",
"documentation_url": "https://developer.github.com/v3"
}
""".trimIndent()
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package flank.scripts.exceptions

import com.github.kittinunf.fuel.core.FuelError
import com.github.kittinunf.result.Result
import com.github.kittinunf.result.failure
import com.google.common.truth.Truth.assertThat
import io.mockk.every
import io.mockk.mockk
import org.junit.Test

class FlankScriptsExceptionMappersTest {

@Test
fun `Should properly map client error`() {
// given
val fuelMockedError = mockk<FuelError> {
every { response.statusCode } returns 404
}
val result: Result<Any, FuelError> = Result.error(fuelMockedError)
val expectedException = Exception("test")

// when
val (_, actualException) = result.mapClientError { expectedException }

// then
assertThat(actualException).isEqualTo(expectedException)
}

@Test
fun `Should not map error when it is different than client error`() {
// given
val fuelMockedError = mockk<FuelError> {
every { response.statusCode } returns 500
}
val result: Result<Any, FuelError> = Result.error(fuelMockedError)
val testException = Exception("test")

// when
val actual = result.mapClientError { testException }

// then
assertThat(actual).isEqualTo(result)
actual.failure {
assertThat(it).isNotEqualTo(testException)
}
}

@Test
fun `Should not map error when response is success`() {
// given
val result: Result<Any, FuelError> = Result.success("")
val testException = Exception("test")

// when
val actual = result.mapClientError { testException }

// then
assertThat(actual).isEqualTo(result)
actual.failure {
assertThat(it).isNotEqualTo(testException)
}
}

@Test
fun `Should properly map github exception from json body`() {
// given
val mockedFuelError = """
{
"message": "Bad credentials",
"documentation_url": "https://developer.github.com/v3"
}
""".trimIndent().toMockFuelError()
val expectedMessage = "Bad credentials"
val expectedUrl = "https://developer.github.com/v3"
val expectedToString = "Error while doing GitHub request, because of $expectedMessage, more info at $expectedUrl"

// when
val gitHubException = mockedFuelError.toGithubException()

// then
assertThat(gitHubException.body.message).isEqualTo(expectedMessage)
assertThat(gitHubException.body.documentationUrl).isEqualTo(expectedUrl)
assertThat(gitHubException.toString()).isEqualTo(expectedToString)
}

@Test
fun `Should properly map bugsnag exception from json body`() {
// given
val mockedFuelError = """
{
"errors": [
"Missing app version"
],
"status": "error"
}
""".trimIndent().toMockFuelError()
val expectedErrors = listOf("Missing app version")
val expectedStatus = "error"
val expectedMessage = "Error while doing Bugnsag request, because of Missing app version"

// when
val bugsnagException = mockedFuelError.toBugsnagException()

// then
assertThat(bugsnagException.body.errors).isEqualTo(expectedErrors)
assertThat(bugsnagException.body.status).isEqualTo(expectedStatus)
assertThat(bugsnagException.toString()).isEqualTo(expectedMessage)
}

private fun String.toMockFuelError() = mockk<FuelError> {
every { response.body().asString(any()) } returns this@toMockFuelError
}
}
Loading