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

Fix flakey SDK test cases #101

Merged
merged 9 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
16 changes: 3 additions & 13 deletions .github/actions/run-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,14 @@ inputs:
kotest-tag:
description: >
The Kotest Tag to use when executing the tests. Check Tag.kt for valid options. Different Tags might require the
Databroker to be started in a different mode. Currently only unsecured mode (no tls, no authentication) is
supported.
default: '!CustomDatabroker'
Databroker to be started in a different mode.
default: ''

runs:
using: "composite"
steps:
- name: "Run Docker Container of Databroker in detached mode"
run: docker run --pull=always --rm --publish 55556:55556/tcp --detach --name databroker ghcr.io/eclipse/kuksa.val/databroker:${{ inputs.databroker-version }} --port 55556 --insecure
shell: bash

- name: Run 'test' with Gradle Wrapper
run: ./gradlew test -Dkotest.tags="${{ inputs.kotest-tag}}"
run: ./gradlew test -Ddatabroker.tag="${{ inputs.databroker-version }}" -Dkotest.tags="${{ inputs.kotest-tag}}"
shell: bash

- name: Upload Test Reports
Expand All @@ -51,8 +46,3 @@ runs:
path: ${{ github.workspace }}/build/reports/jacoco/jacocoRootReport/html/*
if-no-files-found: error
retention-days: 14

- name: "Stop Docker Container of Databroker"
if: always()
run: docker stop databroker
shell: bash
2 changes: 1 addition & 1 deletion .github/workflows/daily_integration_main-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
with:
upload-test-reports: true
databroker-version: master
kotest-tag: "Integration & DefaultDatabroker"
kotest-tag: "Integration"
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ detekt = "1.23.5"
datastore = "1.0.0"
constraintlayoutCompose = "1.0.1"
datastorePreferences = "1.0.0"
dockerJavaCore = "3.3.6"
dokka = "1.9.10"
gson = "2.10.1"
kotlin = "1.9.22"
Expand Down Expand Up @@ -34,6 +35,8 @@ androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "d
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
androidx-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata", version.ref = "runtimeLivedata" }
docker-java-core = { module = "com.github.docker-java:docker-java-core", version.ref = "dockerJavaCore" }
docker-java-transport-httpclient5 = { module = "com.github.docker-java:docker-java-transport-httpclient5", version.ref = "dockerJavaCore" }
grpc-okhttp = { group = "io.grpc", name = "grpc-okhttp", version.ref = "grpc" }
grpc-protobuf = { group = "io.grpc", name = "grpc-protobuf-lite", version.ref = "grpc" }
grpc-stub = { group = "io.grpc", name = "grpc-stub", version.ref = "grpc" }
Expand Down
3 changes: 3 additions & 0 deletions kuksa-sdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ dependencies {
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.kotest)
testImplementation(libs.mockk)

testImplementation(libs.docker.java.core)
testImplementation(libs.docker.java.transport.httpclient5)
}

publish {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023 - 2024 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,22 +14,32 @@
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package org.eclipse.kuksa.connectivity.authentication

import io.grpc.StatusRuntimeException
import io.kotest.assertions.nondeterministic.eventually
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.instanceOf
import org.eclipse.kuksa.connectivity.databroker.DataBrokerConnectorProvider
import org.eclipse.kuksa.connectivity.databroker.DataBrokerException
import org.eclipse.kuksa.connectivity.databroker.docker.DockerDatabrokerContainer
import org.eclipse.kuksa.connectivity.databroker.docker.DockerSecureDatabrokerContainer
import org.eclipse.kuksa.connectivity.databroker.request.FetchRequest
import org.eclipse.kuksa.connectivity.databroker.request.SubscribeRequest
import org.eclipse.kuksa.connectivity.databroker.request.UpdateRequest
import org.eclipse.kuksa.mocking.FriendlyVssPathListener
import org.eclipse.kuksa.proto.v1.Types
import org.eclipse.kuksa.test.TestResourceFile
import org.eclipse.kuksa.test.kotest.Authentication
import org.eclipse.kuksa.test.kotest.CustomDatabroker
import org.eclipse.kuksa.test.kotest.Insecure
import org.eclipse.kuksa.test.kotest.Integration
import java.io.InputStream
import org.eclipse.kuksa.test.kotest.Secure
import org.eclipse.kuksa.test.kotest.SecureDatabroker
import org.eclipse.kuksa.test.kotest.eventuallyConfiguration
import kotlin.random.Random
import kotlin.random.nextInt

Expand All @@ -38,17 +48,32 @@ import kotlin.random.nextInt

// ./gradlew clean test -Dkotest.tags="Authentication"
class DataBrokerConnectorAuthenticationTest : BehaviorSpec({
tags(Integration, Authentication, Insecure, CustomDatabroker)
tags(Integration, Authentication, Secure, SecureDatabroker)

var databrokerContainer: DockerDatabrokerContainer? = null
beforeSpec {
databrokerContainer = DockerSecureDatabrokerContainer()
.apply {
start()
}
}

afterSpec {
databrokerContainer?.stop()
}

val random = Random(System.nanoTime())

given("A DataBrokerConnectorProvider") {
val dataBrokerConnectorProvider = DataBrokerConnectorProvider()
val speedVssPath = "Vehicle.Speed"

and("an insecure DataBrokerConnector with a READ_WRITE_ALL JWT") {
val jwtFileStream = JwtType.READ_WRITE_ALL.asInputStream()
val dataBrokerConnector = dataBrokerConnectorProvider.createInsecure(jwtFileStream = jwtFileStream)
and("a secure DataBrokerConnector with a READ_WRITE_ALL JWT") {
val jwtFile = JwtType.READ_WRITE_ALL

val dataBrokerConnector = dataBrokerConnectorProvider.createSecure(
jwtFileStream = jwtFile.asInputStream(),
)

and("a successfully established connection") {
val connection = dataBrokerConnector.connect()
Expand Down Expand Up @@ -76,9 +101,11 @@ class DataBrokerConnectorAuthenticationTest : BehaviorSpec({
}
}

and("an insecure DataBrokerConnector with a READ_ALL JWT") {
val jwtFileStream = JwtType.READ_ALL.asInputStream()
val dataBrokerConnector = dataBrokerConnectorProvider.createInsecure(jwtFileStream = jwtFileStream)
and("a secure DataBrokerConnector with a READ_ALL JWT") {
val jwtFile = JwtType.READ_ALL
val dataBrokerConnector = dataBrokerConnectorProvider.createSecure(
jwtFileStream = jwtFile.asInputStream(),
)

and("a successfully established connection") {
val connection = dataBrokerConnector.connect()
Expand All @@ -105,9 +132,11 @@ class DataBrokerConnectorAuthenticationTest : BehaviorSpec({
}
}

and("an insecure DataBrokerConnector with a READ_WRITE_ALL_VALUES_ONLY JWT") {
val jwtFileStream = JwtType.READ_WRITE_ALL_VALUES_ONLY.asInputStream()
val dataBrokerConnector = dataBrokerConnectorProvider.createInsecure(jwtFileStream = jwtFileStream)
and("a secure DataBrokerConnector with a READ_WRITE_ALL_VALUES_ONLY JWT") {
val jwtFile = JwtType.READ_WRITE_ALL_VALUES_ONLY
val dataBrokerConnector = dataBrokerConnectorProvider.createSecure(
jwtFileStream = jwtFile.asInputStream(),
)

and("a successfully established connection") {
val connection = dataBrokerConnector.connect()
Expand Down Expand Up @@ -157,20 +186,71 @@ class DataBrokerConnectorAuthenticationTest : BehaviorSpec({
}
}
}
}
})

// The tokens provided here might need to be updated irregularly
// see: https://github.com/eclipse/kuksa.val/tree/master/jwt
// The tokens only work when the Databroker is started using the correct public key: jwt.key.pub
enum class JwtType(private val fileName: String) {
READ_WRITE_ALL("actuate-provide-all.token"), // ACTUATOR_TARGET and VALUE
READ_WRITE_ALL_VALUES_ONLY("provide-all.token"), // VALUE
READ_ALL("read-all.token"),
;

fun asInputStream(): InputStream {
val resourceFile = TestResourceFile(fileName)
return resourceFile.inputStream()
and("a secure DataBrokerConnector with no JWT") {
val dataBrokerConnector = dataBrokerConnectorProvider.createSecure(
jwtFileStream = null,
)

`when`("Trying to connect") {
val result = runCatching {
dataBrokerConnector.connect()
}

then("The connection should be successful") {
result.getOrNull() shouldNotBe null
}

val connection = result.getOrNull()!!

`when`("Reading the VALUE of Vehicle.Speed") {
val fetchRequest = FetchRequest(speedVssPath)
val fetchResult = runCatching {
connection.fetch(fetchRequest)
}

then("An error should occur") {
val exception = fetchResult.exceptionOrNull()
exception shouldNotBe null
exception shouldBe instanceOf(DataBrokerException::class)
exception!!.message shouldContain "UNAUTHENTICATED"
}
}

`when`("Writing the VALUE of Vehicle.Speed") {
val nextFloat = random.nextFloat() * 100F
val datapoint = Types.Datapoint.newBuilder().setFloat(nextFloat).build()
val updateRequest = UpdateRequest(speedVssPath, datapoint)

val updateResult = runCatching {
connection.update(updateRequest)
}

then("An error should occur") {
val exception = updateResult.exceptionOrNull()
exception shouldNotBe null
exception shouldBe instanceOf(DataBrokerException::class)
exception!!.message shouldContain "UNAUTHENTICATED"
}
}

`when`("Subscribing to the VALUE of Vehicle.Speed") {
val subscribeRequest = SubscribeRequest(speedVssPath)
val vssPathListener = FriendlyVssPathListener()

connection.subscribe(subscribeRequest, vssPathListener)

then("An error should occur") {
eventually(eventuallyConfiguration) {
vssPathListener.errors.size shouldBe 1

val exception = vssPathListener.errors.first()
exception shouldBe instanceOf(StatusRuntimeException::class)
exception.message shouldContain "UNAUTHENTICATED"
}
}
}
}
}
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2023 - 2024 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package org.eclipse.kuksa.connectivity.authentication

import org.eclipse.kuksa.test.TestResourceFile
import java.io.InputStream

// The tokens provided here might need to be updated irregularly
// see: https://github.com/eclipse/kuksa.val/tree/master/jwt
// The tokens only work when the Databroker is started using the correct public key: jwt.key.pub
enum class JwtType(private val fileName: String) {
READ_WRITE_ALL("authentication/actuate-provide-all.token"), // ACTUATOR_TARGET and VALUE
READ_WRITE_ALL_VALUES_ONLY("authentication/provide-all.token"), // VALUE
READ_ALL("authentication/read-all.token"),
;

fun asInputStream(): InputStream {
val resourceFile = TestResourceFile(fileName)
return resourceFile.inputStream()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023 - 2024 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,17 +14,14 @@
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package org.eclipse.kuksa.connectivity.databroker

import java.util.concurrent.TimeUnit

object DataBrokerConfig {
const val HOST = "127.0.0.1"
const val PORT = 55556
const val DATABROKER_HOST = "127.0.0.1"

// low timeout should be okay, since we are testing against a local service
const val TIMEOUT_SECONDS = 3L
val TIMEOUT_UNIT = TimeUnit.SECONDS
}
const val DATABROKER_TIMEOUT_SECONDS = 5L
val DATABROKER_TIMEOUT_UNIT = TimeUnit.SECONDS
Loading
Loading