Skip to content

Commit

Permalink
chore: Fix Flickering Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wba2hi committed Feb 1, 2024
1 parent 6fa50d3 commit 80d0f75
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package org.eclipse.kuksa

import io.grpc.ConnectivityState
import io.grpc.ManagedChannel
import io.kotest.assertions.nondeterministic.eventually
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
Expand All @@ -31,6 +32,7 @@ import io.mockk.slot
import io.mockk.verify
import kotlinx.coroutines.runBlocking
import org.eclipse.kuksa.databroker.DataBrokerConnectorProvider
import org.eclipse.kuksa.mocking.FriendlyVssSpecificationListener
import org.eclipse.kuksa.model.Property
import org.eclipse.kuksa.proto.v1.KuksaValV1
import org.eclipse.kuksa.proto.v1.Types
Expand All @@ -41,6 +43,7 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import kotlin.random.Random
import kotlin.time.Duration.Companion.seconds

class DataBrokerConnectionTest : BehaviorSpec({
tags(Integration)
Expand Down Expand Up @@ -161,14 +164,12 @@ class DataBrokerConnectionTest : BehaviorSpec({
}

`when`("Subscribing to the specification") {
val specificationListener =
mockk<VssSpecificationListener<VssDriver>>(relaxed = true)
val specificationListener = FriendlyVssSpecificationListener<VssDriver>()
dataBrokerConnection.subscribe(specification, listener = specificationListener)

then("The #onSpecificationChanged method is triggered") {
val capturingList = mutableListOf<VssDriver>()
verify(timeout = 100L, exactly = 1) {
specificationListener.onSpecificationChanged(capture(capturingList))
eventually(1.seconds) {
specificationListener.updatedSpecifications.size shouldBe 1
}
}

Expand All @@ -179,13 +180,11 @@ class DataBrokerConnectionTest : BehaviorSpec({
dataBrokerConnection.update(property, datapoint)

then("Every child property has been updated with the correct value") {
val capturingList = mutableListOf<VssDriver>()

verify(timeout = 100, exactly = 2) {
specificationListener.onSpecificationChanged(capture(capturingList))
eventually(1.seconds) {
specificationListener.updatedSpecifications.size shouldBe 2
}

val updatedDriver = capturingList.last()
val updatedDriver = specificationListener.updatedSpecifications.last()
val heartRate = updatedDriver.heartRate

heartRate.value shouldBe newHeartRateValue
Expand All @@ -199,13 +198,11 @@ class DataBrokerConnectionTest : BehaviorSpec({
dataBrokerConnection.update(property, datapoint)

then("The subscribed Specification should be updated") {
val capturingSlots = mutableListOf<VssDriver>()

verify(timeout = 100, exactly = 3) {
specificationListener.onSpecificationChanged(capture(capturingSlots))
eventually(1.seconds) {
specificationListener.updatedSpecifications.size shouldBe 3
}

val updatedDriver = capturingSlots.last()
val updatedDriver = specificationListener.updatedSpecifications.last()
val heartRate = updatedDriver.heartRate

heartRate.value shouldBe newHeartRateValue
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 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.mocking

import org.eclipse.kuksa.PropertyListener
import org.eclipse.kuksa.proto.v1.KuksaValV1

class FriendlyPropertyListener : PropertyListener {
val updates = mutableListOf<List<KuksaValV1.EntryUpdate>>()
val errors = mutableListOf<Throwable>()
override fun onPropertyChanged(entryUpdates: List<KuksaValV1.EntryUpdate>) {
updates.add(entryUpdates)
}

override fun onError(throwable: Throwable) {
errors.add(throwable)
}

fun reset() {
updates.clear()
errors.clear()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 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.mocking

import org.eclipse.kuksa.VssSpecificationListener
import org.eclipse.kuksa.vsscore.model.VssSpecification

class FriendlyVssSpecificationListener<T : VssSpecification> : VssSpecificationListener<T> {
val updatedSpecifications = mutableListOf<T>()
val errors = mutableListOf<Throwable>()
override fun onSpecificationChanged(vssSpecification: T) {
updatedSpecifications.add(vssSpecification)
}

override fun onError(throwable: Throwable) {
errors.add(throwable)
}

fun reset() {
updatedSpecifications.clear()
errors.clear()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ import io.mockk.verify
import kotlinx.coroutines.delay
import org.eclipse.kuksa.DataBrokerTransporter
import org.eclipse.kuksa.PropertyListener
import org.eclipse.kuksa.VssSpecificationListener
import org.eclipse.kuksa.databroker.DataBrokerConnectorProvider
import org.eclipse.kuksa.extensions.toggleBoolean
import org.eclipse.kuksa.extensions.updateRandomFloatValue
import org.eclipse.kuksa.extensions.updateRandomUint32Value
import org.eclipse.kuksa.mocking.FriendlyPropertyListener
import org.eclipse.kuksa.mocking.FriendlyVssSpecificationListener
import org.eclipse.kuksa.pattern.listener.MultiListener
import org.eclipse.kuksa.pattern.listener.count
import org.eclipse.kuksa.proto.v1.KuksaValV1
import org.eclipse.kuksa.proto.v1.Types
import org.eclipse.kuksa.test.kotest.Insecure
import org.eclipse.kuksa.test.kotest.Integration
Expand Down Expand Up @@ -163,10 +163,10 @@ class DataBrokerSubscriberTest : BehaviorSpec({
}

`when`("Subscribing multiple (different) PropertyListener to $vssPath") {
val propertyListenerMocks = mutableListOf<PropertyListener>()
val friendlyPropertyListeners = mutableListOf<FriendlyPropertyListener>()
repeat(10) {
val otherPropertyListenerMock = mockk<PropertyListener>(relaxed = true)
propertyListenerMocks.add(otherPropertyListenerMock)
val otherPropertyListenerMock = FriendlyPropertyListener()
friendlyPropertyListeners.add(otherPropertyListenerMock)

classUnderTest.subscribe(vssPath, fieldValue, otherPropertyListenerMock)
}
Expand All @@ -175,14 +175,13 @@ class DataBrokerSubscriberTest : BehaviorSpec({
val randomFloatValue = databrokerTransporter.updateRandomFloatValue(vssPath)

then("Each PropertyListener is only notified once") {
propertyListenerMocks.forEach { propertyListenerMock ->
val dataEntries = mutableListOf<List<KuksaValV1.EntryUpdate>>()

verify(timeout = 100L, exactly = 2) {
propertyListenerMock.onPropertyChanged(capture(dataEntries))
friendlyPropertyListeners.forEach { friendlyPropertyListener ->
eventually(1.seconds) {
friendlyPropertyListener.updates.size shouldBe 2
}

val count = dataEntries.count { it[0].entry.value.float == randomFloatValue }
val count = friendlyPropertyListener.updates
.count { it[0].entry.value.float == randomFloatValue }
count shouldBe 1
}
}
Expand All @@ -209,21 +208,20 @@ class DataBrokerSubscriberTest : BehaviorSpec({
`when`("Subscribing the same PropertyListener twice using VSS_PATH to Vehicle.Speed with FIELD_VALUE") {
val vssPath = "Vehicle.Speed"
val fieldValue = Types.Field.FIELD_VALUE
val propertyListenerMock = mockk<PropertyListener>(relaxed = true)
classUnderTest.subscribe(vssPath, fieldValue, propertyListenerMock)
classUnderTest.subscribe(vssPath, fieldValue, propertyListenerMock)
val friendlyPropertyListener = FriendlyPropertyListener()
classUnderTest.subscribe(vssPath, fieldValue, friendlyPropertyListener)
classUnderTest.subscribe(vssPath, fieldValue, friendlyPropertyListener)

and("When the FIELD_VALUE of Vehicle.Speed is updated") {
val randomFloatValue = databrokerTransporter.updateRandomFloatValue(vssPath)

then("The PropertyListener is only notified once") {
val dataEntries = mutableListOf<List<KuksaValV1.EntryUpdate>>()

verify(timeout = 100L, exactly = 2) {
propertyListenerMock.onPropertyChanged(capture(dataEntries))
eventually(1.seconds) {
friendlyPropertyListener.updates.size shouldBe 2
}

val count = dataEntries.count { it[0].entry.value.float == randomFloatValue }
val count = friendlyPropertyListener.updates
.count { it[0].entry.value.float == randomFloatValue }
count shouldBe 1
}
}
Expand All @@ -232,33 +230,31 @@ class DataBrokerSubscriberTest : BehaviorSpec({
val specification = VssDriver.VssHeartRate()

`when`("Subscribing using VssSpecification to Vehicle.Driver.HeartRate with Field FIELD_VALUE") {
val specificationObserverMock =
mockk<VssSpecificationListener<VssDriver.VssHeartRate>>(relaxed = true)
val friendlyVssSpecificationListener = FriendlyVssSpecificationListener<VssDriver.VssHeartRate>()
classUnderTest.subscribe(
specification,
Types.Field.FIELD_VALUE,
specificationObserverMock,
friendlyVssSpecificationListener,
)

and("The value of Vehicle.Driver.HeartRate changes") {
val randomIntValue =
databrokerTransporter.updateRandomUint32Value(specification.vssPath)

then("The Observer should be triggered") {
val vssHeartRates = mutableListOf<VssDriver.VssHeartRate>()
verify(timeout = 100, exactly = 2) {
specificationObserverMock.onSpecificationChanged(capture(vssHeartRates))
eventually(1.seconds) {
friendlyVssSpecificationListener.updatedSpecifications.size shouldBe 2
}

val count = vssHeartRates.count { it.value == randomIntValue }
val count = friendlyVssSpecificationListener.updatedSpecifications
.count { it.value == randomIntValue }
count shouldBe 1
}
}
}

`when`("Subscribing the same SpecificationObserver twice to Vehicle.Driver.HeartRate") {
val specificationObserverMock =
mockk<VssSpecificationListener<VssDriver.VssHeartRate>>(relaxed = true)
val specificationObserverMock = FriendlyVssSpecificationListener<VssDriver.VssHeartRate>()
classUnderTest.subscribe(
specification,
Types.Field.FIELD_VALUE,
Expand All @@ -275,13 +271,11 @@ class DataBrokerSubscriberTest : BehaviorSpec({
databrokerTransporter.updateRandomUint32Value(specification.vssPath)

then("The Observer is only notified once") {
val heartRates = mutableListOf<VssDriver.VssHeartRate>()

verify(timeout = 100, exactly = 2) {
specificationObserverMock.onSpecificationChanged(capture(heartRates))
eventually(1.seconds) {
specificationObserverMock.updatedSpecifications.size shouldBe 2
}

val count = heartRates.count { it.value == randomIntValue }
val count = specificationObserverMock.updatedSpecifications.count { it.value == randomIntValue }
count shouldBe 1
}
}
Expand Down Expand Up @@ -349,20 +343,3 @@ class DataBrokerSubscriberTest : BehaviorSpec({
}
}
})

class FriendlyPropertyListener : PropertyListener {
val updates = mutableListOf<List<KuksaValV1.EntryUpdate>>()
val errors = mutableListOf<Throwable>()
override fun onPropertyChanged(entryUpdates: List<KuksaValV1.EntryUpdate>) {
updates.add(entryUpdates)
}

override fun onError(throwable: Throwable) {
errors.add(throwable)
}

fun reset() {
updates.clear()
errors.clear()
}
}

0 comments on commit 80d0f75

Please sign in to comment.