Browse Source
#7: Add unit tests to OAuthDatasource See merge request funkwhale/funkwhale-android!47enhancement/speed-up-pipelines
Ryan Harg
3 years ago
21 changed files with 465 additions and 131 deletions
@ -1,51 +1,82 @@
@@ -1,51 +1,82 @@
|
||||
image: jangrewe/gitlab-ci-android |
||||
|
||||
stages: |
||||
- build |
||||
- deploy |
||||
variables: |
||||
JACOCO_CSV_LOCATION: '$CI_PROJECT_DIR/app/build/reports/jacoco/testDebugUnitTestCoverage/testDebugUnitTestCoverage.csv' |
||||
|
||||
stages: |
||||
- test |
||||
- visualize |
||||
- build |
||||
- deploy |
||||
|
||||
.build: |
||||
.gradle-default: |
||||
stage: build |
||||
before_script: |
||||
- export GRADLE_USER_HOME=$(pwd)/.gradle |
||||
- chmod +x ./gradlew |
||||
- mkdir -p .android && touch .android/repositories.cfg |
||||
- export GRADLE_USER_HOME=$(pwd)/.gradle |
||||
- chmod +x ./gradlew |
||||
- mkdir -p .android && touch .android/repositories.cfg |
||||
script: |
||||
- echo "Overwrite me" |
||||
- echo "Overwrite me" |
||||
|
||||
cache: |
||||
key: ${CI_PROJECT_ID} |
||||
paths: |
||||
- .gradle/ |
||||
- .gradle/ |
||||
|
||||
.build: |
||||
extends: .gradle-default |
||||
artifacts: |
||||
paths: |
||||
- app/build/outputs/apk/debug/app-debug.apk |
||||
|
||||
test: |
||||
extends: .gradle-default |
||||
stage: test |
||||
script: |
||||
- ./gradlew test testDebugUnitTestCoverage |
||||
- awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print covered, "/", instructions, " instructions covered"; print 100*covered/instructions, "% covered" }' $JACOCO_CSV_LOCATION |
||||
artifacts: |
||||
reports: |
||||
junit: app/build/test-results/test**/TEST-*.xml |
||||
paths: |
||||
- app/build/outputs/apk/debug/app-debug.apk |
||||
- app/build/reports/jacoco/testDebugUnitTestCoverage/testDebugUnitTestCoverage.xml |
||||
|
||||
coverage: |
||||
stage: visualize |
||||
image: gjrtimmer/jacoco2cobertura:1.0.8 |
||||
script: |
||||
# convert report from jacoco to cobertura, use relative project path |
||||
- 'python /opt/cover2cover.py app/build/reports/jacoco/testDebugUnitTestCoverage/testDebugUnitTestCoverage.xml $CI_PROJECT_DIR/app/src/main/java > app/build/reports/cobertura.xml' |
||||
needs: [ "test" ] |
||||
dependencies: |
||||
- test |
||||
artifacts: |
||||
reports: |
||||
cobertura: app/build/reports/cobertura.xml |
||||
|
||||
build-develop: |
||||
extends: .build |
||||
script: |
||||
- echo -n $SIGNING_KEY_STORE | base64 -d > app/android.keystore |
||||
- ./gradlew assembleDebug -Psigning.store=android.keystore -Psigning.store_passphrase=$SIGNING_KEY_PASS -Psigning.key_passphrase=$SIGNING_KEY_PASS |
||||
- echo -n $SIGNING_KEY_STORE | base64 -d > app/android.keystore |
||||
- ./gradlew assembleDebug -Psigning.store=android.keystore -Psigning.store_passphrase=$SIGNING_KEY_PASS -Psigning.key_passphrase=$SIGNING_KEY_PASS |
||||
only: |
||||
- develop |
||||
- develop |
||||
|
||||
build-bleeding-edge: |
||||
extends: .build |
||||
script: |
||||
- ./gradlew assembleDebug |
||||
- ./gradlew assembleDebug |
||||
except: |
||||
- develop |
||||
- develop |
||||
|
||||
deploy-develop: |
||||
stage: deploy |
||||
only: |
||||
- develop |
||||
only: |
||||
- develop |
||||
script: |
||||
- eval `ssh-agent -s` |
||||
- ssh-add <(echo "$SSH_PRIVATE_KEY") |
||||
- scp -o StrictHostKeyChecking=no app/build/outputs/apk/debug/app-debug.apk fdroid@apps.funkwhale.audio:/srv/fdroid/fdroid/develop/repo/audio.funkwhale.ffa.dev-$CI_COMMIT_SHORT_SHA.apk |
||||
- ssh -o StrictHostKeyChecking=no fdroid@apps.funkwhale.audio 'docker run --rm -u $(id -u):$(id -g) -v /srv/fdroid/fdroid/develop:/repo registry.gitlab.com/fdroid/docker-executable-fdroidserver:master update' |
||||
- eval `ssh-agent -s` |
||||
- ssh-add <(echo "$SSH_PRIVATE_KEY") |
||||
- scp -o StrictHostKeyChecking=no app/build/outputs/apk/debug/app-debug.apk fdroid@apps.funkwhale.audio:/srv/fdroid/fdroid/develop/repo/audio.funkwhale.ffa.dev-$CI_COMMIT_SHORT_SHA.apk |
||||
- ssh -o StrictHostKeyChecking=no fdroid@apps.funkwhale.audio 'docker run --rm -u $(id -u):$(id -g) -v /srv/fdroid/fdroid/develop:/repo registry.gitlab.com/fdroid/docker-executable-fdroidserver:master update' |
||||
tags: |
||||
- shell |
||||
|
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
package audio.funkwhale.ffa.playback |
||||
|
||||
import android.content.Context |
||||
import android.net.Uri |
||||
import audio.funkwhale.ffa.utils.OAuth |
||||
import audio.funkwhale.util.MockKJUnitRunner |
||||
import com.google.android.exoplayer2.upstream.DataSpec |
||||
import com.google.android.exoplayer2.upstream.HttpDataSource |
||||
import com.google.android.exoplayer2.upstream.TransferListener |
||||
import io.mockk.every |
||||
import io.mockk.impl.annotations.InjectMockKs |
||||
import io.mockk.impl.annotations.MockK |
||||
import io.mockk.mockk |
||||
import io.mockk.verify |
||||
import org.junit.Test |
||||
import org.junit.runner.RunWith |
||||
import strikt.api.expectThat |
||||
import strikt.assertions.isEqualTo |
||||
|
||||
@RunWith(MockKJUnitRunner::class) |
||||
class OAuthDatasourceTest { |
||||
|
||||
@InjectMockKs |
||||
private lateinit var datasource: OAuthDatasource |
||||
|
||||
@MockK |
||||
private lateinit var context: Context |
||||
|
||||
@MockK |
||||
private lateinit var http: HttpDataSource |
||||
|
||||
@MockK |
||||
private lateinit var oAuth: OAuth |
||||
|
||||
private var dataSpec: DataSpec = DataSpec(Uri.EMPTY) |
||||
|
||||
@Test |
||||
fun `open() should set accessToken and delegate to http dataSource`() { |
||||
every { http.open(any()) } returns 0 |
||||
every { oAuth.tryRefreshAccessToken(any(), any()) } returns true |
||||
every { oAuth.state().accessToken } returns "accessToken" |
||||
|
||||
datasource.open(dataSpec) |
||||
verify { http.open(dataSpec) } |
||||
verify { http.setRequestProperty("Authorization", "Bearer accessToken") } |
||||
} |
||||
|
||||
@Test |
||||
fun `close() should delegate to http dataSource`() { |
||||
datasource.close() |
||||
verify { http.close() } |
||||
} |
||||
|
||||
@Test |
||||
fun `addTransferListener() should delegate to http dataSource`() { |
||||
val transferListener = mockk<TransferListener>() |
||||
datasource.addTransferListener(transferListener) |
||||
verify { http.addTransferListener(transferListener) } |
||||
} |
||||
|
||||
@Test |
||||
fun `read() should delegate to http dataSource`() { |
||||
every { http.read(any(), any(), any()) } returns 0 |
||||
datasource.read("123".encodeToByteArray(), 1, 2) |
||||
verify { http.read("123".encodeToByteArray(), 1, 2) } |
||||
} |
||||
|
||||
@Test |
||||
fun `getUri() should delegate to http dataSource`() { |
||||
every { http.uri } returns Uri.EMPTY |
||||
val result = datasource.uri |
||||
verify { http.uri } |
||||
expectThat(result).isEqualTo(Uri.EMPTY) |
||||
} |
||||
} |
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
package audio.funkwhale.util |
||||
|
||||
import io.mockk.MockKAnnotations |
||||
import io.mockk.clearAllMocks |
||||
import org.junit.Test |
||||
import org.junit.runner.Description |
||||
import org.junit.runner.Runner |
||||
import org.junit.runner.notification.Failure |
||||
import org.junit.runner.notification.RunNotifier |
||||
import java.lang.reflect.Method |
||||
|
||||
class MockKJUnitRunner(private val testClass: Class<*>) : Runner() { |
||||
|
||||
private val methodDescriptions: MutableMap<Method, Description> = mutableMapOf() |
||||
|
||||
init { |
||||
// Build method/descriptions map |
||||
testClass.methods |
||||
.map { method -> |
||||
val annotation: Annotation? = method.getAnnotation(Test::class.java) |
||||
method to annotation |
||||
} |
||||
.filter { (_, annotation) -> |
||||
annotation != null |
||||
} |
||||
.map { (method, annotation) -> |
||||
val desc = Description.createTestDescription(testClass, method.name, annotation) |
||||
method to desc |
||||
} |
||||
.forEach { (method, desc) -> methodDescriptions[method] = desc } |
||||
} |
||||
|
||||
override fun getDescription(): Description { |
||||
val description = Description.createSuiteDescription( |
||||
testClass.name, *testClass.annotations |
||||
) |
||||
methodDescriptions.values.forEach { description.addChild(it) } |
||||
return description |
||||
} |
||||
|
||||
override fun run(notifier: RunNotifier?) { |
||||
val testObject = testClass.newInstance() |
||||
MockKAnnotations.init(testObject, relaxUnitFun = true) |
||||
|
||||
methodDescriptions |
||||
.onEach { (_, _) -> clearAllMocks() } |
||||
.onEach { (_, desc) -> notifier!!.fireTestStarted(desc) } |
||||
.forEach { (method, desc) -> |
||||
try { |
||||
method.invoke(testObject) |
||||
} catch (e: Throwable) { |
||||
notifier!!.fireTestFailure(Failure(desc, e.cause)) |
||||
} finally { |
||||
notifier!!.fireTestFinished(desc) |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue