Skip to content

Commit

Permalink
Merge pull request #101 from boschglobal/fix-85
Browse files Browse the repository at this point in the history
Fix flakey SDK test cases
  • Loading branch information
Chrylo authored Mar 18, 2024
2 parents c44fa83 + 86f4816 commit fbc54b7
Show file tree
Hide file tree
Showing 34 changed files with 811 additions and 284 deletions.
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"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="kuksa-vss-core:UnitTests" type="GradleRunConfiguration" factoryName="Gradle">
<configuration default="false" name="All Tests" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
Expand All @@ -10,14 +10,15 @@
</option>
<option name="taskNames">
<list>
<option value=":vss-core:test" />
<option value="test" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="kuksa-sdk:UnitTests" type="GradleRunConfiguration" factoryName="Gradle">
<configuration default="false" name="Functional Tests" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
Expand All @@ -10,14 +10,15 @@
</option>
<option name="taskNames">
<list>
<option value=":kuksa-sdk:testDebugUnitTest" />
<option value="test" />
</list>
</option>
<option name="vmOptions" value="-Dkotest.tags=&quot;Unit&quot;" />
<option name="vmOptions" value="-Dkotest.tags=&quot;Functional&quot;" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="kuksa-sdk:IntegrationTests" type="GradleRunConfiguration" factoryName="Gradle">
<configuration default="false" name="Integration Tests" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
Expand All @@ -10,10 +10,10 @@
</option>
<option name="taskNames">
<list>
<option value=":kuksa-sdk:testDebugUnitTest" />
<option value="test" />
</list>
</option>
<option name="vmOptions" value="-Dkotest.tags=&quot;Integration &amp; DefaultDatabroker&quot;" />
<option name="vmOptions" value="-Dkotest.tags=&quot;Integration&quot;" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
Expand Down
3 changes: 2 additions & 1 deletion .run/All UnitTests.run.xml → .run/Unit Tests.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All UnitTests" type="GradleRunConfiguration" factoryName="Gradle">
<configuration default="false" name="Unit Tests" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
Expand All @@ -18,6 +18,7 @@
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
23 changes: 0 additions & 23 deletions .run/app_UnitTests.run.xml

This file was deleted.

23 changes: 0 additions & 23 deletions .run/kuksa-vss-processor_UnitTests.run.xml

This file was deleted.

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.DataBrokerDockerContainer
import org.eclipse.kuksa.connectivity.databroker.docker.SecureDataBrokerDockerContainer
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: DataBrokerDockerContainer? = null
beforeSpec {
databrokerContainer = SecureDataBrokerDockerContainer()
.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"
}
}
}
}
}
}
}
})
Loading

0 comments on commit fbc54b7

Please sign in to comment.