I'm giving up on the tests for now. We are seeing random failures… (#1737)

* I'm giving up on the tests for now.  We are seeing random failures consistantly now.  We need a better way to takle this.

* ktLint
This commit is contained in:
Justin Bassett 2021-09-30 21:37:19 -04:00 committed by GitHub
parent d7c167e3c5
commit 577c679ef1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 0 additions and 2047 deletions

View file

@ -59,33 +59,6 @@ jobs:
- name: Validate Lint
run: ./gradlew lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2.3.0
with:
distribution: 'adopt'
java-version: '11'
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Mock google-services.json
run: |
cp .github/mock-google-services.json app/google-services.json
cp .github/mock-google-services.json wear/google-services.json
- name: Validate Tests
run: ./gradlew test
pr_build:
runs-on: ubuntu-latest
steps:

View file

@ -165,13 +165,6 @@ dependencies {
implementation("androidx.biometric:biometric:1.1.0")
implementation("androidx.webkit:webkit:1.4.0")
testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.17")
testImplementation("org.spekframework.spek2:spek-runner-junit5:2.0.15")
testImplementation("org.assertj:assertj-core:3.20.2")
testImplementation("io.mockk:mockk:1.12.0")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.1")
testImplementation("org.altbeacon:android-beacon-library:2.19.2")
implementation("com.google.android.exoplayer:exoplayer-core:2.15.1")
implementation("com.google.android.exoplayer:exoplayer-hls:2.15.1")
implementation("com.google.android.exoplayer:exoplayer-ui:2.15.1")

View file

@ -1,82 +0,0 @@
package io.homeassistant.companion.android.launch
import io.homeassistant.companion.android.common.data.authentication.AuthenticationRepository
import io.homeassistant.companion.android.common.data.authentication.SessionState
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.mockk.coEvery
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
object LaunchPresenterImplSpec : Spek({
beforeEachTest {
Dispatchers.setMain(Dispatchers.Unconfined)
}
afterEachTest {
Dispatchers.resetMain()
}
describe("launch presenter") {
val authenticationUseCase by memoized { mockk<AuthenticationRepository>() }
val integrationUseCase by memoized { mockk<IntegrationRepository>() }
val view by memoized { mockk<LaunchView>(relaxUnitFun = true) }
val presenter by memoized { LaunchPresenterImpl(view, authenticationUseCase, integrationUseCase) }
describe("anonymous state") {
beforeEachTest {
coEvery { authenticationUseCase.getSessionState() } returns SessionState.ANONYMOUS
}
describe("on view ready") {
beforeEachTest {
presenter.onViewReady()
}
it("should display the onboarding") {
verify { view.displayOnBoarding(false) }
}
}
}
describe("connected state") {
beforeEachTest {
coEvery { authenticationUseCase.getSessionState() } returns SessionState.CONNECTED
coEvery { integrationUseCase.isRegistered() } returns true
coEvery { authenticationUseCase.isLockEnabled() } returns false
}
describe("on view ready") {
beforeEachTest {
presenter.onViewReady()
}
it("should display the webview") {
verify { view.displayWebview() }
}
}
}
describe("connected state but not integrated") {
beforeEachTest {
coEvery { authenticationUseCase.getSessionState() } returns SessionState.CONNECTED
coEvery { integrationUseCase.isRegistered() } returns false
}
describe("on view ready") {
beforeEachTest {
presenter.onViewReady()
}
it("should display the integration view") {
verify { view.displayOnBoarding(true) }
}
}
}
}
})

View file

@ -1,82 +0,0 @@
package io.homeassistant.companion.android.onboarding.authentication
import android.net.Uri
import io.homeassistant.companion.android.common.data.authentication.AuthenticationRepository
import io.mockk.Called
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.assertj.core.api.Assertions.assertThat
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.net.URL
object AuthenticationPresenterImplSpec : Spek({
beforeEachTest {
Dispatchers.setMain(Dispatchers.Unconfined)
}
afterEachTest {
Dispatchers.resetMain()
}
describe("authentication presenter") {
val authenticationUseCase by memoized { mockk<AuthenticationRepository>(relaxUnitFun = true) }
val view by memoized { mockk<AuthenticationView>(relaxUnitFun = true) }
val presenter by memoized { AuthenticationPresenterImpl(view, authenticationUseCase) }
describe("on view ready") {
beforeEachTest {
coEvery {
authenticationUseCase.buildAuthenticationUrl("homeassistant://auth-callback")
} returns URL("https://demo.home-assistant.io/auth/authorize?response_type=code&client_id=https://home-assistant.io/android&redirect_uri=homeassistant://auth-callback")
presenter.onViewReady()
}
it("should load auth url") {
verify { view.loadUrl("https://demo.home-assistant.io/auth/authorize?response_type=code&client_id=https://home-assistant.io/android&redirect_uri=homeassistant://auth-callback") }
}
}
describe("on redirect url with callback url") {
var allowRedirect: Boolean? = null
beforeEachTest {
mockkStatic(Uri::class)
every { Uri.parse("homeassistant://auth-callback?code=123456") } returns mockk {
every { getQueryParameter("code") } returns "123456"
}
allowRedirect = presenter.onRedirectUrl("homeassistant://auth-callback?code=123456")
}
it("should open the webview") {
coVerify { authenticationUseCase.registerAuthorizationCode("123456") }
verify { view.openWebview() }
assertThat(allowRedirect).isTrue()
}
}
describe("on redirect wrong url") {
var allowRedirect: Boolean? = null
beforeEachTest {
mockkStatic(Uri::class)
every { Uri.parse("homeassistant://auth-callback") } returns mockk {
every { getQueryParameter("code") } returns null
}
allowRedirect = presenter.onRedirectUrl("homeassistant://auth-callback")
}
it("should not open the webview") {
coVerify { authenticationUseCase wasNot Called }
verify { view wasNot Called }
assertThat(allowRedirect).isFalse()
}
}
}
})

View file

@ -1,75 +0,0 @@
package io.homeassistant.companion.android.onboarding.integration
import android.os.Build
import io.homeassistant.companion.android.BuildConfig
import io.homeassistant.companion.android.common.data.integration.DeviceRegistration
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.mockk.coEvery
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
object MobileAppIntegrationPresenterImplSpec : Spek({
beforeEachTest {
Dispatchers.setMain(Dispatchers.Unconfined)
}
afterEachTest {
Dispatchers.resetMain()
}
describe("presenter") {
val integrationUseCase by memoized { mockk<IntegrationRepository>(relaxUnitFun = true) }
val view by memoized { mockk<MobileAppIntegrationView>(relaxUnitFun = true) }
val presenter by memoized { MobileAppIntegrationPresenterBase(view, integrationUseCase) }
describe("on registration success") {
val deviceRegistration = DeviceRegistration(
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
Build.MODEL ?: "UNKNOWN"
)
beforeEachTest {
coEvery { integrationUseCase.registerDevice(deviceRegistration) } just runs
}
describe("register") {
beforeEachTest {
presenter.onRegistrationAttempt(true, Build.MODEL ?: "UNKNOWN")
}
it("should register successfully") {
// TODO: As part of our swap away from dagger we need to inject the Coroutine Scope in to get this to pass
// coVerify {
// view.showLoading()
// integrationUseCase.registerDevice(deviceRegistration)
// view.deviceRegistered()
// }
}
}
}
describe("on registration failed") {
beforeEachTest {
coEvery { integrationUseCase.registerDevice(any()) } throws Exception()
}
describe("register") {
beforeEachTest {
presenter.onRegistrationAttempt(false, Build.MODEL ?: "UNKNOWN")
}
it("should fail") {
// TODO: Fix issues with scopes...
// coVerifyAll {
// view.showLoading()
// integrationUseCase.registerDevice(any())
// view.showError()
// }
// coVerify(inverse = true) { view.deviceRegistered() }
}
}
}
}
})

View file

@ -1,104 +0,0 @@
package io.homeassistant.companion.android.webview
import android.net.Uri
import io.homeassistant.companion.android.common.data.authentication.AuthenticationRepository
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.homeassistant.companion.android.common.data.prefs.PrefsRepository
import io.homeassistant.companion.android.common.data.url.UrlRepository
import io.mockk.coEvery
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.runs
import io.mockk.verify
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.net.URL
@ExperimentalCoroutinesApi
object WebViewPresenterImplSpec : Spek({
beforeEachTest {
Dispatchers.setMain(Dispatchers.Unconfined)
}
afterEachTest {
Dispatchers.resetMain()
}
describe("presenter") {
val urlUseCase by memoized { mockk<UrlRepository>(relaxUnitFun = true) }
val authenticationUseCase by memoized { mockk<AuthenticationRepository>(relaxUnitFun = true) }
val integrationUseCase by memoized { mockk<IntegrationRepository>(relaxUnitFun = true) }
val themesUseCase by memoized { mockk<PrefsRepository>(relaxUnitFun = true) }
val view by memoized { mockk<WebView>(relaxUnitFun = true) }
val presenter by memoized { WebViewPresenterImpl(view, urlUseCase, authenticationUseCase, integrationUseCase) }
describe("on view ready empty query ") {
beforeEachTest {
coEvery { urlUseCase.getUrl() } returns URL("https://demo.home-assistant.io/")
mockkStatic(Uri::class)
every { Uri.parse("https://demo.home-assistant.io/") } returns mockk {
every {
buildUpon().appendQueryParameter("external_auth", "1").build().toString()
} returns "https://demo.home-assistant.io?external_auth=1"
}
presenter.onViewReady(null)
}
it("should load the url") {
verify { view.loadUrl("https://demo.home-assistant.io?external_auth=1") }
}
}
describe("on get external auth on success") {
beforeEachTest {
coEvery { authenticationUseCase.retrieveExternalAuthentication(false) } returns "{\"access_token\":\"ABCDEFGH\",\"expires_in\":1800}"
presenter.onGetExternalAuth("externalAuthSetToken", false)
}
it("should set external auth") {
verify { view.setExternalAuth("externalAuthSetToken(true, {\"access_token\":\"ABCDEFGH\",\"expires_in\":1800})") }
}
}
describe("on get external auth on error") {
beforeEachTest {
coEvery { authenticationUseCase.retrieveExternalAuthentication(false) } throws Exception()
presenter.onGetExternalAuth("externalAuthSetToken", false)
}
it("should not crash") {
verify { view.setExternalAuth("externalAuthSetToken(false)") }
}
}
describe("on revoke external auth on success") {
beforeEachTest {
coEvery { authenticationUseCase.revokeSession() } just runs
presenter.onRevokeExternalAuth("externalAuthRevokeToken")
}
it("should set external auth") {
verify { view.setExternalAuth("externalAuthRevokeToken(true)") }
verify { view.openOnBoarding() }
}
}
describe("on revoke external auth on error") {
beforeEachTest {
coEvery { authenticationUseCase.revokeSession() } throws Exception()
presenter.onRevokeExternalAuth("externalAuthRevokeToken")
}
it("should set external auth") {
verify { view.setExternalAuth("externalAuthRevokeToken(false)") }
}
}
}
})

View file

@ -35,10 +35,4 @@ dependencies {
implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.5")
implementation("org.altbeacon:android-beacon-library:2.19.2")
testImplementation("com.squareup.okhttp3:mockwebserver:4.9.1")
testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.17")
testImplementation("org.spekframework.spek2:spek-runner-junit5:2.0.15")
testImplementation("org.assertj:assertj-core:3.20.2")
testImplementation("io.mockk:mockk:1.12.0")
}

View file

@ -1,73 +0,0 @@
package io.homeassistant.companion.android.common.data
import io.homeassistant.companion.android.common.data.url.UrlRepository
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import java.io.IOException
import java.net.URL
class HomeAssistantMockService<T>(private val c: Class<T>) {
private val mockServer: MockWebServer = MockWebServer()
private val homeAssistantRetrofit = HomeAssistantRetrofit(object : UrlRepository {
override suspend fun getApiUrls(): Array<URL> {
return arrayOf(getUrl()!!)
}
override suspend fun saveRegistrationUrls(
cloudHookUrl: String?,
remoteUiUrl: String?,
webhookId: String
) {
}
override suspend fun getUrl(isInternal: Boolean?): URL? {
return mockServer.url("/").toUrl()
}
override suspend fun saveUrl(url: String, isInternal: Boolean?) {
}
override suspend fun getHomeWifiSsids(): Set<String> {
return emptySet()
}
override suspend fun saveHomeWifiSsids(ssid: Set<String>) {
}
override suspend fun isInternal(): Boolean {
return true
}
}).retrofit
fun get(): T {
return homeAssistantRetrofit.create(c)
}
fun getMockServer() = mockServer
fun enqueueResponse(code: Int, file: String? = null) {
val mockResponse = MockResponse()
if (file != null) {
mockResponse.setBody(getJsonFromFile(file))
}
mockServer.enqueue(mockResponse.setResponseCode(code))
}
fun takeRequest() = mockServer.takeRequest()
private fun getJsonFromFile(file: String): String {
val inputStreamResponse = this.javaClass.classLoader?.getResourceAsStream(file)!!
val size: Int
return try {
size = inputStreamResponse.available()
val buffer = ByteArray(size)
inputStreamResponse.read(buffer)
inputStreamResponse.close()
String(buffer)
} catch (e: IOException) {
throw RuntimeException()
}
}
}

View file

@ -1,310 +0,0 @@
package io.homeassistant.companion.android.common.data.authentication.impl
import io.homeassistant.companion.android.common.data.LocalStorage
import io.homeassistant.companion.android.common.data.authentication.AuthorizationException
import io.homeassistant.companion.android.common.data.authentication.SessionState
import io.homeassistant.companion.android.common.data.url.UrlRepository
import io.mockk.Called
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.coVerifyAll
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.catchThrowable
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.net.URL
object AuthenticationRepositoryImplSpec : Spek({
describe("a repository") {
val localStorage by memoized { mockk<LocalStorage>(relaxUnitFun = true) }
val authenticationService by memoized { mockk<AuthenticationService>(relaxUnitFun = true) }
val urlRepository by memoized { mockk<UrlRepository>(relaxed = true) }
val repository by memoized {
AuthenticationRepositoryImpl(
authenticationService,
localStorage,
urlRepository
)
}
describe("get token on success") {
beforeEachTest {
coEvery {
authenticationService.getToken(
"authorization_code",
"123456",
"https://home-assistant.io/android"
)
} returns mockk {
every { accessToken } returns "ABCDEFGH"
every { expiresIn } returns 1800
every { refreshToken } returns "IJKLMNOPQRST"
every { tokenType } returns "Bearer"
}
}
describe("register authorization code") {
beforeEachTest {
runBlocking {
repository.registerAuthorizationCode("123456")
}
}
it("should save the token and url") {
coVerifyAll {
localStorage.putString("access_token", "ABCDEFGH")
localStorage.putLong("expires_date", 1547605320)
localStorage.putString("refresh_token", "IJKLMNOPQRST")
localStorage.putString("token_type", "Bearer")
}
}
}
}
describe("get token on error") {
beforeEachTest {
coEvery {
authenticationService.getToken(any(), any(), any())
} throws Exception()
}
describe("register authorization code") {
beforeEachTest {
catchThrowable {
runBlocking {
repository.registerAuthorizationCode("123456")
}
}
}
it("shouldn't save data") {
verify { localStorage wasNot Called }
}
}
}
describe("build auth url") {
lateinit var authenticationUrl: URL
beforeEachTest {
coEvery { urlRepository.getUrl() } returns URL("https://demo.home-assistant.io/")
authenticationUrl =
runBlocking { repository.buildAuthenticationUrl("homeassistant://auth-callback") }
}
it("should return the authentication url") {
assertThat(authenticationUrl).isEqualTo(URL("https://demo.home-assistant.io/auth/authorize?response_type=code&client_id=https://home-assistant.io/android&redirect_uri=homeassistant://auth-callback"))
}
}
describe("connected user with valid access token") {
beforeEachTest {
coEvery { urlRepository.getUrl() } returns URL("https://demo.home-assistant.io/")
coEvery { localStorage.getString("access_token") } returns "ABCDEFGH"
coEvery { localStorage.getLong("expires_date") } returns 1547605320
coEvery { localStorage.getString("refresh_token") } returns "IJKLMNOPQRST"
coEvery { localStorage.getString("token_type") } returns "Bearer"
}
describe("get session state") {
lateinit var sessionState: SessionState
beforeEachTest {
sessionState = runBlocking {
repository.getSessionState()
}
}
it("should be connected") {
assertThat(sessionState).isEqualTo(SessionState.CONNECTED)
}
}
describe("retrieve external authentication") {
lateinit var externalAuth: String
beforeEachTest {
externalAuth = runBlocking {
repository.retrieveExternalAuthentication(false)
}
}
it("should serialize the external authentication saved") {
assertThat(externalAuth).isEqualTo("{\"access_token\":\"ABCDEFGH\",\"expires_in\":1800}")
}
}
describe("revoke session") {
beforeEachTest {
runBlocking {
repository.revokeSession()
}
}
it("should call the service") {
coVerify {
authenticationService.revokeToken("IJKLMNOPQRST", "revoke")
urlRepository.saveUrl("", true)
urlRepository.saveUrl("", false)
urlRepository.saveHomeWifiSsids(emptySet())
}
}
it("should delete the session") {
coVerify {
localStorage.putString("access_token", null)
localStorage.putLong("expires_date", null)
localStorage.putString("refresh_token", null)
localStorage.putString("token_type", null)
}
}
}
describe("build bearer token") {
lateinit var token: String
beforeEachTest {
token = runBlocking { repository.buildBearerToken() }
}
it("should return a valid bearer token") {
assertThat(token).isEqualTo("Bearer ABCDEFGH")
}
}
}
describe("connected user with expired access token") {
beforeEachTest {
coEvery { localStorage.getString("url") } returns "https://demo.home-assistant.io/"
coEvery { localStorage.getString("access_token") } returns "ABCDEFGH"
coEvery { localStorage.getLong("expires_date") } returns 1599276837 - 1800
coEvery { localStorage.getString("refresh_token") } returns "IJKLMNOPQRST"
coEvery { localStorage.getString("token_type") } returns "Bearer"
coEvery {
authenticationService.refreshToken(
"refresh_token",
"IJKLMNOPQRST",
"https://home-assistant.io/android"
)
} returns mockk {
every { isSuccessful } returns true
every { body() } returns mockk {
every { accessToken } returns "HGFEDCBA"
every { expiresIn } returns 1800
every { refreshToken } returns null
every { tokenType } returns "Bearer"
}
}
}
describe("retrieve external authentication") {
lateinit var externalAuth: String
beforeEachTest {
externalAuth = runBlocking {
repository.retrieveExternalAuthentication(false)
}
}
it("should save the token") {
coVerify {
localStorage.putString("access_token", "HGFEDCBA")
localStorage.putLong("expires_date", 1547605320)
localStorage.putString("refresh_token", "IJKLMNOPQRST")
localStorage.putString("token_type", "Bearer")
}
}
it("should serialize the refresh external authentication") {
assertThat(externalAuth).isEqualTo("{\"access_token\":\"HGFEDCBA\",\"expires_in\":1800}")
}
}
describe("build bearer token") {
lateinit var token: String
beforeEachTest {
token = runBlocking { repository.buildBearerToken() }
}
it("should refresh the token") {
coVerify {
authenticationService.refreshToken(
"refresh_token",
"IJKLMNOPQRST",
"https://home-assistant.io/android"
)
}
}
it("should return a valid bearer token") {
assertThat(token).isEqualTo("Bearer HGFEDCBA")
}
}
}
describe("anonymous user") {
beforeEachTest {
coEvery { localStorage.getString("url") } returns null
coEvery { localStorage.getString("access_token") } returns null
coEvery { localStorage.getLong("expires_date") } returns null
coEvery { localStorage.getString("refresh_token") } returns null
coEvery { localStorage.getString("token_type") } returns null
}
describe("get session state") {
lateinit var sessionState: SessionState
beforeEachTest {
sessionState = runBlocking {
repository.getSessionState()
}
}
it("should be anonymous") {
assertThat(sessionState).isEqualTo(SessionState.ANONYMOUS)
}
}
describe("retrieve external authentication") {
lateinit var thrown: Throwable
beforeEachTest {
thrown = catchThrowable {
runBlocking {
repository.retrieveExternalAuthentication(false)
}
}
}
it("throw an exception") {
assertThat(thrown).isInstanceOf(AuthorizationException::class.java)
}
}
describe("revoke session") {
lateinit var thrown: Throwable
beforeEachTest {
thrown = catchThrowable {
runBlocking {
repository.revokeSession()
}
}
}
it("should throw an exception") {
assertThat(thrown).isInstanceOf(AuthorizationException::class.java)
}
}
describe("build bearer token") {
lateinit var thrown: Throwable
beforeEachTest {
thrown = catchThrowable {
runBlocking {
repository.buildBearerToken()
}
}
}
it("should throw an exception") {
assertThat(thrown).isInstanceOf(AuthorizationException::class.java)
}
}
}
}
})

View file

@ -1,129 +0,0 @@
package io.homeassistant.companion.android.common.data.authentication.impl
import io.homeassistant.companion.android.common.data.HomeAssistantMockService
import io.homeassistant.companion.android.common.data.authentication.impl.entities.Token
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.RecordedRequest
import org.assertj.core.api.Assertions.assertThat
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
object AuthenticationServiceSpec : Spek({
describe("an authentication service") {
val mockService by memoized { HomeAssistantMockService(AuthenticationService::class.java) }
describe("authorization code on success") {
lateinit var token: Token
lateinit var request: RecordedRequest
beforeEachTest {
mockService.enqueueResponse(200, "authentication/authorization_code.json")
token = runBlocking {
mockService.get().getToken(
AuthenticationService.GRANT_TYPE_CODE,
"12345",
AuthenticationService.CLIENT_ID
)
}
request = mockService.takeRequest()
}
it("should create a query") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/auth/token")
assertThat(request.body.readUtf8())
.contains("grant_type=authorization_code")
.contains("code=12345")
.contains("client_id=https%3A%2F%2Fhome-assistant.io%2Fandroid")
}
it("should deserialize the payload") {
assertThat(token.accessToken).isEqualTo("ABCDEFGH")
assertThat(token.expiresIn).isEqualTo(1800)
assertThat(token.refreshToken).isEqualTo("IJKLMNOPQRST")
assertThat(token.tokenType).isEqualTo("Bearer")
}
}
describe("refresh token on success") {
lateinit var token: Token
lateinit var request: RecordedRequest
beforeEachTest {
mockService.enqueueResponse(200, "authentication/refresh_token.json")
token = runBlocking {
mockService.get().refreshToken(
AuthenticationService.GRANT_TYPE_REFRESH,
"IJKLMNOPQRST",
AuthenticationService.CLIENT_ID
).body()!!
}
request = mockService.takeRequest()
}
it("should create a query") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/auth/token")
assertThat(request.body.readUtf8())
.contains("grant_type=refresh_token")
.contains("refresh_token=IJKLMNOPQRST")
.contains("client_id=https%3A%2F%2Fhome-assistant.io%2Fandroid")
}
it("should deserialize the payload") {
assertThat(token.accessToken).isEqualTo("ABCDEFGH")
assertThat(token.expiresIn).isEqualTo(1800)
assertThat(token.refreshToken).isNull()
assertThat(token.tokenType).isEqualTo("Bearer")
}
}
describe("refresh token on failure") {
lateinit var errorBody: String
lateinit var request: RecordedRequest
beforeEachTest {
mockService.enqueueResponse(400, "authentication/refresh_token_error.json")
errorBody = runBlocking {
mockService.get().refreshToken(
AuthenticationService.GRANT_TYPE_REFRESH,
"IJKLMNOPQRST",
AuthenticationService.CLIENT_ID
).errorBody()?.string()!!
}
request = mockService.takeRequest()
}
it("should create a query") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/auth/token")
assertThat(request.body.readUtf8())
.contains("grant_type=refresh_token")
.contains("refresh_token=IJKLMNOPQRST")
.contains("client_id=https%3A%2F%2Fhome-assistant.io%2Fandroid")
}
it("should contain error") {
assertThat(errorBody).contains("\"error\": \"invalid_grant\"")
}
}
describe("revoke token on success") {
lateinit var request: RecordedRequest
beforeEachTest {
mockService.enqueueResponse(200)
runBlocking {
mockService.get()
.revokeToken("IJKLMNOPQRST", AuthenticationService.REVOKE_ACTION)
}
request = mockService.takeRequest()
}
it("should create a query") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/auth/token")
assertThat(request.body.readUtf8())
.contains("token=IJKLMNOPQRST")
.contains("action=revoke")
}
}
}
})

View file

@ -1,28 +0,0 @@
package io.homeassistant.companion.android.common.data.authentication.impl
import org.assertj.core.api.Assertions.assertThat
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
object SessionSpec : Spek({
describe("an expired session") {
val session by memoized { Session("", System.currentTimeMillis() / 1000 - 1800, "", "") }
it("should be expired") {
assertThat(session.isExpired()).isTrue()
}
}
describe("an valid session") {
val session by memoized { Session("", System.currentTimeMillis() / 1000 + 1800, "", "") }
it("should be valid") {
assertThat(session.isExpired()).isFalse()
}
it("should be valid") {
assertThat(session.expiresIn()).isEqualTo(1800)
}
}
})

View file

@ -1,820 +0,0 @@
package io.homeassistant.companion.android.common.data.integration.impl
import io.homeassistant.companion.android.common.data.LocalStorage
import io.homeassistant.companion.android.common.data.authentication.AuthenticationRepository
import io.homeassistant.companion.android.common.data.integration.DeviceRegistration
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.IntegrationException
import io.homeassistant.companion.android.common.data.integration.UpdateLocation
import io.homeassistant.companion.android.common.data.integration.ZoneAttributes
import io.homeassistant.companion.android.common.data.integration.impl.entities.EntityResponse
import io.homeassistant.companion.android.common.data.integration.impl.entities.IntegrationRequest
import io.homeassistant.companion.android.common.data.integration.impl.entities.RegisterDeviceRequest
import io.homeassistant.companion.android.common.data.integration.impl.entities.ServiceCallRequest
import io.homeassistant.companion.android.common.data.integration.impl.entities.UpdateLocationRequest
import io.homeassistant.companion.android.common.data.url.UrlRepository
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.coVerifyAll
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.runBlocking
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.catchThrowable
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import retrofit2.Response
import java.net.URL
import java.util.Calendar
import java.util.HashMap
import kotlin.properties.Delegates
object IntegrationRepositoryImplSpec : Spek({
describe("a repository") {
val localStorage by memoized { mockk<LocalStorage>(relaxUnitFun = true) }
val integrationService by memoized { mockk<IntegrationService>(relaxUnitFun = true) }
val authenticationRepository by memoized { mockk<AuthenticationRepository>(relaxUnitFun = true) }
val urlRepository by memoized { mockk<UrlRepository>(relaxUnitFun = true) }
val repository by memoized {
IntegrationRepositoryImpl(
integrationService,
authenticationRepository,
urlRepository,
localStorage,
"manufacturer",
"model",
"osVersion",
"deviceId"
)
}
describe("registerDevicePre 0.104.0") {
beforeEachTest {
val deviceRegistration = DeviceRegistration(
"appVersion",
"deviceName",
"pushToken"
)
val registerDeviceRequest =
RegisterDeviceRequest(
"io.homeassistant.companion.android",
"Home Assistant",
deviceRegistration.appVersion,
deviceRegistration.deviceName,
"manufacturer",
"model",
"Android",
"osVersion",
false,
hashMapOf(
"push_url" to "https://mobile-apps.home-assistant.io/api/sendPush/android/v1",
"push_token" to (deviceRegistration.pushToken ?: "push_token")
),
"deviceId"
)
coEvery { localStorage.getString("app_version") } returns "app_version"
coEvery { localStorage.getString("device_name") } returns "device_name"
coEvery { localStorage.getString("push_token") } returns "push_token"
coEvery { integrationService.discoveryInfo("ABC123") } returns mockk {
every { version } returns "0.104.0"
}
coEvery {
integrationService.registerDevice("ABC123", registerDeviceRequest)
} returns mockk {
every { cloudhookUrl } returns "https://home-assistant.io/1/"
every { remoteUiUrl } returns "https://home-assistant.io/2/"
every { secret } returns "ABCDE"
every { webhookId } returns "FGHIJ"
}
coEvery { authenticationRepository.buildBearerToken() } returns "ABC123"
runBlocking {
repository.registerDevice(deviceRegistration)
}
}
it("should save response data") {
coVerify {
urlRepository.saveRegistrationUrls(
"https://home-assistant.io/1/",
"https://home-assistant.io/2/",
"FGHIJ"
)
localStorage.putString("secret", "ABCDE")
}
}
it("should save registration data") {
coVerify {
localStorage.putString("app_version", "appVersion")
localStorage.putString("device_name", "deviceName")
localStorage.putString("push_token", "pushToken")
}
}
}
describe("registerDevice") {
beforeEachTest {
val deviceRegistration = DeviceRegistration(
"appVersion",
"deviceName",
"pushToken"
)
val registerDeviceRequest =
RegisterDeviceRequest(
"io.homeassistant.companion.android",
"Home Assistant",
deviceRegistration.appVersion,
deviceRegistration.deviceName,
"manufacturer",
"model",
"Android",
"osVersion",
false,
hashMapOf(
"push_url" to "https://mobile-apps.home-assistant.io/api/sendPush/android/v1",
"push_token" to (deviceRegistration.pushToken ?: "push_token")
),
null
)
coEvery { localStorage.getString("app_version") } returns "app_version"
coEvery { localStorage.getString("device_name") } returns "device_name"
coEvery { localStorage.getString("push_token") } returns "push_token"
coEvery {
integrationService.registerDevice("ABC123", registerDeviceRequest)
} returns mockk {
every { cloudhookUrl } returns "https://home-assistant.io/1/"
every { remoteUiUrl } returns "https://home-assistant.io/2/"
every { secret } returns "ABCDE"
every { webhookId } returns "FGHIJ"
}
coEvery { authenticationRepository.buildBearerToken() } returns "ABC123"
runBlocking {
repository.registerDevice(deviceRegistration)
}
}
it("should save response data") {
coVerify {
urlRepository.saveRegistrationUrls(
"https://home-assistant.io/1/",
"https://home-assistant.io/2/",
"FGHIJ"
)
localStorage.putString("secret", "ABCDE")
}
}
it("should save registration data") {
coVerify {
localStorage.putString("app_version", "appVersion")
localStorage.putString("device_name", "deviceName")
localStorage.putString("push_token", "pushToken")
}
}
}
describe("updateRegistration") {
val deviceRegistration = DeviceRegistration(
"appVersion",
"deviceName",
"pushToken"
)
val registerDeviceRequest =
RegisterDeviceRequest(
null,
null,
deviceRegistration.appVersion,
deviceRegistration.deviceName,
"manufacturer",
"model",
null,
"osVersion",
null,
hashMapOf(
"push_url" to "https://mobile-apps.home-assistant.io/api/sendPush/android/v1",
"push_token" to (deviceRegistration.pushToken ?: "push_token")
),
null
)
beforeEachTest {
coEvery {
integrationService.callWebhook(
any(),
IntegrationRequest(
"update_registration",
registerDeviceRequest
)
)
} returns Response.success(null)
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com"),
URL("http://example.com")
)
coEvery { localStorage.getString("app_version") } returns "app_version"
coEvery { localStorage.getString("device_name") } returns "device_name"
coEvery { localStorage.getString("push_token") } returns "push_token"
runBlocking {
repository.updateRegistration(deviceRegistration)
}
}
it("should call the service") {
coVerify {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
IntegrationRequest(
"update_registration",
registerDeviceRequest
)
)
}
}
it("should persist the registration") {
coVerify {
localStorage.putString("app_version", "appVersion")
localStorage.putString("device_name", "deviceName")
localStorage.putString("push_token", "pushToken")
}
}
}
describe("is registered") {
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com"),
URL("http://example.com")
)
}
describe("isRegistered") {
var isRegistered by Delegates.notNull<Boolean>()
beforeEachTest {
runBlocking { isRegistered = repository.isRegistered() }
}
it("should return true when webhook has a value") {
assertThat(isRegistered).isTrue()
}
}
}
describe("is not registered") {
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf()
}
describe("isRegistered") {
var isRegistered by Delegates.notNull<Boolean>()
beforeEachTest {
runBlocking { isRegistered = repository.isRegistered() }
}
it("should return false when webhook has no value") {
assertThat(isRegistered).isFalse()
}
}
}
describe("location updated") {
describe("updateLocation cloud url") {
val location = UpdateLocation(
arrayOf(45.0, -45.0),
0,
1,
2,
3,
4
)
val integrationRequest =
IntegrationRequest(
"update_location",
UpdateLocationRequest(
location.gps,
location.gpsAccuracy,
location.speed,
location.altitude,
location.course,
location.verticalAccuracy
)
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
any(), // "http://example.com/api/webhook/FGHIJ",
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.updateLocation(location) }
}
it("should call the service.") {
coVerify {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
integrationRequest
)
}
}
}
describe("updateLocation remote ui url") {
val location = UpdateLocation(
arrayOf(45.0, -45.0),
0,
1,
2,
3,
4
)
val integrationRequest =
IntegrationRequest(
"update_location",
UpdateLocationRequest(
location.gps,
location.gpsAccuracy,
location.speed,
location.altitude,
location.course,
location.verticalAccuracy
)
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://better.com/api/webhook/FGHIJ"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
any(), // "http://example.com/api/webhook/FGHIJ",
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.updateLocation(location) }
}
it("should call the service.") {
coVerify {
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
integrationRequest
)
}
}
}
describe("updateLocation auth url") {
val location = UpdateLocation(
arrayOf(45.0, -45.0),
0,
1,
2,
3,
4
)
val integrationRequest =
IntegrationRequest(
"update_location",
UpdateLocationRequest(
location.gps,
location.gpsAccuracy,
location.speed,
location.altitude,
location.course,
location.verticalAccuracy
)
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://example.com/api/webhook/FGHIJ")
)
coEvery {
integrationService.callWebhook(
any(), // "http://example.com/api/webhook/FGHIJ",
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.updateLocation(location) }
}
it("should call the service.") {
coVerify {
integrationService.callWebhook(
"http://example.com/api/webhook/FGHIJ".toHttpUrl(),
integrationRequest
)
}
}
}
describe("updateLocation fail then succeeds") {
val location = UpdateLocation(
arrayOf(45.0, -45.0),
0,
1,
2,
3,
4
)
val integrationRequest =
IntegrationRequest(
"update_location",
UpdateLocationRequest(
location.gps,
location.gpsAccuracy,
location.speed,
location.altitude,
location.course,
location.verticalAccuracy
)
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com/api/webhook/FGHIJ"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
coEvery {
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.updateLocation(location) }
}
it("should call service 2 times") {
coVerifyAll {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
integrationRequest
)
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
integrationRequest
)
}
}
}
describe("updateLocation failure") {
val location = UpdateLocation(
arrayOf(45.0, -45.0),
0,
1,
2,
3,
4
)
lateinit var thrown: Throwable
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
coEvery {
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
coEvery {
integrationService.callWebhook(
"http://example.com/api/webhook/FGHIJ".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
thrown = catchThrowable { runBlocking { repository.updateLocation(location) } }
}
it("should throw an exception") {
assertThat(thrown).isInstanceOf(IntegrationException::class.java)
}
}
}
describe("call a service") {
describe("callService cloud url") {
val domain = "light"
val service = "toggle"
val serviceDataMap = hashMapOf<String, Any>("entity_id" to "light.dummy_light")
val serviceCallRequest =
ServiceCallRequest(
domain,
service,
serviceDataMap
)
val integrationRequest =
IntegrationRequest(
"call_service",
serviceCallRequest
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
any(), // "http://example.com/api/webhook/FGHIJ",
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.callService(domain, service, serviceDataMap) }
}
it("should call the service.") {
coVerify {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
integrationRequest
)
}
}
}
describe("callService remote ui url") {
val domain = "light"
val service = "toggle"
val serviceDataMap = hashMapOf<String, Any>("entity_id" to "light.dummy_light")
val serviceCallRequest =
ServiceCallRequest(
domain,
service,
serviceDataMap
)
val integrationRequest =
IntegrationRequest(
"call_service",
serviceCallRequest
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://better.com/api/webhook/FGHIJ"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
any(), // "http://example.com/api/webhook/FGHIJ",
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.callService(domain, service, serviceDataMap) }
}
it("should call the service.") {
coVerify {
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
integrationRequest
)
}
}
}
describe("callService auth url") {
val domain = "light"
val service = "toggle"
val serviceDataMap = hashMapOf<String, Any>("entity_id" to "light.dummy_light")
val serviceCallRequest =
ServiceCallRequest(
domain,
service,
serviceDataMap
)
val integrationRequest =
IntegrationRequest(
"call_service",
serviceCallRequest
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://example.com/api/webhook/FGHIJ")
)
coEvery {
integrationService.callWebhook(
any(), // "http://example.com/api/webhook/FGHIJ",
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.callService(domain, service, serviceDataMap) }
}
it("should call the service.") {
coVerify {
integrationService.callWebhook(
"http://example.com/api/webhook/FGHIJ".toHttpUrl(),
integrationRequest
)
}
}
}
describe("callService fail then succeeds") {
val domain = "light"
val service = "toggle"
val serviceDataMap = hashMapOf<String, Any>("entity_id" to "light.dummy_light")
val serviceCallRequest =
ServiceCallRequest(
domain,
service,
serviceDataMap
)
val integrationRequest =
IntegrationRequest(
"call_service",
serviceCallRequest
)
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com/api/webhook/FGHIJ"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
coEvery {
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
any() // integrationRequest
)
} returns Response.success(null)
runBlocking { repository.callService(domain, service, serviceDataMap) }
}
it("should call service 2 times") {
coVerifyAll {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
integrationRequest
)
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
integrationRequest
)
}
}
}
describe("callService failure") {
val domain = "light"
val service = "toggle"
val serviceDataMap = hashMapOf<String, Any>("entity_id" to "light.dummy_light")
lateinit var thrown: Throwable
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/hook/id"),
URL("http://better.com"),
URL("http://example.com")
)
coEvery {
integrationService.callWebhook(
"http://best.com/hook/id".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
coEvery {
integrationService.callWebhook(
"http://better.com/api/webhook/FGHIJ".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
coEvery {
integrationService.callWebhook(
"http://example.com/api/webhook/FGHIJ".toHttpUrl(),
any() // integrationRequest
)
} returns mockk {
every { isSuccessful } returns false
}
thrown = catchThrowable {
runBlocking {
repository.callService(
domain,
service,
serviceDataMap
)
}
}
}
it("should throw an exception") {
assertThat(thrown).isInstanceOf(IntegrationException::class.java)
}
}
}
describe("get zones") {
beforeEachTest {
coEvery { urlRepository.getApiUrls() } returns arrayOf(
URL("http://best.com/"),
URL("http://better.com"),
URL("http://example.com")
)
coEvery { localStorage.getString("webhook_id") } returns "FGHIJ"
}
describe("getZones") {
val entities =
EntityResponse(
"entityId",
"state",
ZoneAttributes(
false,
0.0,
1.1,
2.2F,
"fName",
"icon"
),
Calendar.getInstance(),
Calendar.getInstance(),
HashMap()
)
var zones: Array<Entity<ZoneAttributes>>? = null
beforeEachTest {
coEvery { integrationService.getZones(any(), any()) } returns arrayOf(entities)
runBlocking { zones = repository.getZones() }
}
it("should return true when webhook has a value") {
assertThat(zones).isNotNull
assertThat(zones!!.size).isEqualTo(1)
assertThat(zones!![0]).isNotNull
assertThat(zones!![0].entityId).isEqualTo(entities.entityId)
}
}
}
}
})

View file

@ -1,126 +0,0 @@
package io.homeassistant.companion.android.common.data.integration.impl
import io.homeassistant.companion.android.common.data.HomeAssistantMockService
import io.homeassistant.companion.android.common.data.integration.impl.entities.IntegrationRequest
import io.homeassistant.companion.android.common.data.integration.impl.entities.RegisterDeviceRequest
import io.homeassistant.companion.android.common.data.integration.impl.entities.RegisterDeviceResponse
import io.homeassistant.companion.android.common.data.integration.impl.entities.ServiceCallRequest
import io.homeassistant.companion.android.common.data.integration.impl.entities.UpdateLocationRequest
import kotlinx.coroutines.runBlocking
import okhttp3.ResponseBody
import okhttp3.mockwebserver.RecordedRequest
import org.assertj.core.api.Assertions.assertThat
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import retrofit2.Response
object IntegrationServiceSpec : Spek({
describe("an integration service") {
val mockService by memoized { HomeAssistantMockService(IntegrationService::class.java) }
lateinit var request: RecordedRequest
describe("registerDevice") {
lateinit var registrationResponse: RegisterDeviceResponse
beforeEachTest {
val registrationRequest =
RegisterDeviceRequest(
"appId",
"appName",
"appVersion",
"deviceName",
"manufacturer",
"model",
"osName",
"osVersion",
false,
null,
"deviceId"
)
mockService.enqueueResponse(200, "integration/register.json")
registrationResponse = runBlocking {
mockService.get().registerDevice("123", registrationRequest)
}
request = mockService.takeRequest()
}
it("should serialize request") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/api/mobile_app/registrations")
assertThat(request.body.readUtf8())
.contains("\"app_id\":\"appId\"")
}
it("should deserialize the response") {
assertThat(registrationResponse.webhookId).isEqualTo("ABC")
}
}
describe("updateLocation") {
lateinit var response: Response<ResponseBody>
beforeEachTest {
val updateLocationRequest =
UpdateLocationRequest(
arrayOf(45.0, -45.0),
0,
1,
2,
3,
4
)
val integrationRequest =
IntegrationRequest(
"update_location",
updateLocationRequest
)
mockService.enqueueResponse(200, "integration/empty.json")
response = runBlocking {
mockService.get().callWebhook(mockService.getMockServer().url("/path/to/hook"), integrationRequest)
}
request = mockService.takeRequest()
}
it("should serialize request") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/path/to/hook")
}
it("should return success") {
assertThat(response.isSuccessful).isTrue()
}
}
describe("callService") {
lateinit var response: Response<ResponseBody>
beforeEachTest {
val domain = "light"
val service = "toggle"
val serviceDataMap = hashMapOf<String, Any>("entity_id" to "light.dummy_light")
val serviceCallRequest =
ServiceCallRequest(
domain,
service,
serviceDataMap
)
val integrationRequest =
IntegrationRequest(
"call_service",
serviceCallRequest
)
mockService.enqueueResponse(200, "integration/empty.json")
response = runBlocking {
mockService.get().callWebhook(mockService.getMockServer().url("/path/to/hook"), integrationRequest)
}
request = mockService.takeRequest()
}
it("should serialize request") {
assertThat(request.method).isEqualTo("POST")
assertThat(request.path).isEqualTo("/path/to/hook")
}
it("should return success") {
assertThat(response.isSuccessful).isTrue()
}
}
}
})

View file

@ -1,158 +0,0 @@
package io.homeassistant.companion.android.common.data.url
import io.homeassistant.companion.android.common.data.LocalStorage
import io.homeassistant.companion.android.common.data.MalformedHttpUrlException
import io.homeassistant.companion.android.common.data.wifi.WifiHelper
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.coVerifyAll
import io.mockk.mockk
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.net.URL
object UrlRepositoryImplSpec : Spek({
describe("a repository") {
val localStorage by memoized { mockk<LocalStorage>(relaxUnitFun = true) }
val wifiHelper by memoized { mockk<WifiHelper>(relaxed = true) }
val repository by memoized { UrlRepositoryImpl(localStorage, wifiHelper) }
mapOf(
"https://demo.home-assistant.io:8123/lovelace/0/default_view?home_assistant=1&true=false" to "https://demo.home-assistant.io:8123/",
"https://demo.home-assistant.io/lovelace/0/default_view?home_assistant=1&true=false" to "https://demo.home-assistant.io/",
"https://demo.home-assistant.io" to "https://demo.home-assistant.io/",
"https://192.168.1.1:8123/lovelace/0" to "https://192.168.1.1:8123/",
"https://192.168.1.1:8123" to "https://192.168.1.1:8123/",
"https://192.168.1.1" to "https://192.168.1.1/"
).forEach {
describe("save valid url \"${it.key}\"") {
beforeEachTest {
runBlocking { repository.saveUrl(it.key, false) }
}
it("should save url") {
coVerifyAll { localStorage.putString("remote_url", it.value) }
}
}
}
listOf(
"home assistant",
"http://192.168..132:8123",
"http://....:8123",
"http://......",
"ftp://192.168.1.1"
).forEach {
describe("save invalid url \"$it\"") {
lateinit var throwable: Throwable
beforeEachTest {
runBlocking {
try {
repository.saveUrl(it, false)
} catch (e: Exception) {
throwable = e
}
}
}
it("shouldn't save url") {
coVerify(exactly = 0) {
localStorage.putString("remote_url", any())
}
}
it("should throw an exception") {
Assertions.assertThat(throwable).isInstanceOf(MalformedHttpUrlException::class.java)
}
}
}
describe("get instance url") {
describe("remote set, get internal") {
var url: URL? = null
beforeEachTest {
coEvery { localStorage.getString("remote_url") } returns "https://demo.home-assistant.io/"
coEvery { localStorage.getString("local_url") } returns null
url = runBlocking {
repository.getUrl(true)
}
}
it("should return the remote url") {
Assertions.assertThat(url).isNull()
}
}
describe("remote set, get external") {
lateinit var url: URL
beforeEachTest {
coEvery { localStorage.getString("remote_url") } returns "https://demo.home-assistant.io/"
coEvery { localStorage.getString("local_url") } returns null
url = runBlocking {
repository.getUrl(false)
}!!
}
it("should return the remote url") {
Assertions.assertThat(url).isEqualTo(URL("https://demo.home-assistant.io/"))
}
}
describe("local set, get internal") {
var url: URL? = null
beforeEachTest {
coEvery { localStorage.getString("remote_url") } returns null
coEvery { localStorage.getString("local_url") } returns "https://demo.home-assistant.io/"
url = runBlocking {
repository.getUrl(false)
}
}
it("should return the local url") {
Assertions.assertThat(url).isNull()
}
}
describe("local set, get external") {
lateinit var url: URL
beforeEachTest {
coEvery { localStorage.getString("remote_url") } returns null
coEvery { localStorage.getString("local_url") } returns "https://demo.home-assistant.io/"
url = runBlocking {
repository.getUrl(true)
}!!
}
it("should return the local url") {
Assertions.assertThat(url).isEqualTo(URL("https://demo.home-assistant.io/"))
}
}
describe("both set, get internal") {
lateinit var url: URL
beforeEachTest {
coEvery { localStorage.getString("remote_url") } returns "https://demo2.home-assistant.io/"
coEvery { localStorage.getString("local_url") } returns "https://demo.home-assistant.io/"
url = runBlocking {
repository.getUrl(true)
}!!
}
it("should return the local url") {
Assertions.assertThat(url).isEqualTo(URL("https://demo.home-assistant.io/"))
}
}
describe("both set, get external") {
lateinit var url: URL
beforeEachTest {
coEvery { localStorage.getString("remote_url") } returns "https://demo2.home-assistant.io/"
coEvery { localStorage.getString("local_url") } returns "https://demo.home-assistant.io/"
url = runBlocking {
repository.getUrl(false)
}!!
}
it("should return the local url") {
Assertions.assertThat(url).isEqualTo(URL("https://demo2.home-assistant.io/"))
}
}
}
}
})

View file

@ -1,6 +0,0 @@
{
"access_token": "ABCDEFGH",
"expires_in": 1800,
"refresh_token": "IJKLMNOPQRST",
"token_type": "Bearer"
}

View file

@ -1,5 +0,0 @@
{
"access_token": "ABCDEFGH",
"expires_in": 1800,
"token_type": "Bearer"
}

View file

@ -1,3 +0,0 @@
{
"error": "invalid_grant"
}

View file

@ -1,3 +0,0 @@
{
}

View file

@ -1,3 +0,0 @@
{
"webhook_id": "ABC"
}