-
Notifications
You must be signed in to change notification settings - Fork 1
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
Run Integration Tests on GitHub Actions #55
Changes from all commits
8d38659
b972b1b
31a44a5
6b88d1a
79eb2c0
85f9a28
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,7 +56,9 @@ class DataBrokerConnectionTest : BehaviorSpec({ | |
dataBrokerConnection.subscribe(property, propertyListener) | ||
|
||
then("The #onPropertyChanged method is triggered") { | ||
verify(timeout = 100L) { propertyListener.onPropertyChanged(any(), any(), any()) } | ||
verify(timeout = 100L) { | ||
propertyListener.onPropertyChanged(any(), any(), any()) | ||
} | ||
} | ||
|
||
`when`("The observed Property changes") { | ||
|
@@ -70,24 +72,16 @@ class DataBrokerConnectionTest : BehaviorSpec({ | |
then("The #onPropertyChanged callback is triggered with the new value") { | ||
val capturingSlot = slot<Types.DataEntry>() | ||
|
||
verify { propertyListener.onPropertyChanged(any(), any(), capture(capturingSlot)) } | ||
verify(timeout = 100) { | ||
propertyListener.onPropertyChanged(any(), any(), capture(capturingSlot)) | ||
} | ||
|
||
val dataEntry = capturingSlot.captured | ||
val capturedDatapoint = dataEntry.value | ||
val float = capturedDatapoint.float | ||
|
||
assertEquals(newValue, float, 0.0001f) | ||
} | ||
|
||
`when`("The same value is set again") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I remember this was a system test, when executing "feed Vehicle.Speed 100" twice, the observer was only triggered once. But for some reason this behavior suddenly changed? Funnily this test still ran through successfully on friday. Since it's no longer relevant I removed the test |
||
clearMocks(propertyListener) | ||
|
||
dataBrokerConnection.update(property, datapoint) | ||
|
||
then("The #onPropertyChangedCallback should NOT be triggered again") { | ||
verify(exactly = 0) { propertyListener.onPropertyChanged(any(), any(), any()) } | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -160,11 +154,15 @@ class DataBrokerConnectionTest : BehaviorSpec({ | |
} | ||
|
||
`when`("Subscribing to the specification") { | ||
val specificationListener = mockk<VssSpecificationListener<VssDriver>>(relaxed = true) | ||
val specificationListener = | ||
mockk<VssSpecificationListener<VssDriver>>(relaxed = true) | ||
dataBrokerConnection.subscribe(specification, listener = specificationListener) | ||
|
||
then("The #onSpecificationChanged method is triggered") { | ||
verify(timeout = 100L) { specificationListener.onSpecificationChanged(any()) } | ||
verify( | ||
timeout = 100L, | ||
exactly = 1, | ||
) { specificationListener.onSpecificationChanged(any()) } | ||
} | ||
|
||
and("The initial value is different from the default for a child") { | ||
|
@@ -174,11 +172,13 @@ class DataBrokerConnectionTest : BehaviorSpec({ | |
dataBrokerConnection.update(property, datapoint) | ||
|
||
then("Every child property has been updated with the correct value") { | ||
val capturingSlots = mutableListOf<VssDriver>() | ||
val capturingList = mutableListOf<VssDriver>() | ||
|
||
verify(exactly = 2) { specificationListener.onSpecificationChanged(capture(capturingSlots)) } | ||
verify(timeout = 100, exactly = 2) { | ||
specificationListener.onSpecificationChanged(capture(capturingList)) | ||
} | ||
|
||
val updatedDriver = capturingSlots[1] | ||
val updatedDriver = capturingList.last() | ||
val heartRate = updatedDriver.heartRate | ||
|
||
heartRate.value shouldBe newHeartRateValue | ||
|
@@ -194,9 +194,11 @@ class DataBrokerConnectionTest : BehaviorSpec({ | |
then("The subscribed Specification should be updated") { | ||
val capturingSlots = mutableListOf<VssDriver>() | ||
|
||
verify(exactly = 3) { specificationListener.onSpecificationChanged(capture(capturingSlots)) } | ||
verify(timeout = 100, exactly = 3) { | ||
specificationListener.onSpecificationChanged(capture(capturingSlots)) | ||
} | ||
|
||
val updatedDriver = capturingSlots[2] | ||
val updatedDriver = capturingSlots.last() | ||
val heartRate = updatedDriver.heartRate | ||
|
||
heartRate.value shouldBe newHeartRateValue | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ import io.mockk.clearMocks | |
import io.mockk.every | ||
import io.mockk.mockk | ||
import io.mockk.verify | ||
import kotlinx.coroutines.delay | ||
import org.eclipse.kuksa.DataBrokerTransporter | ||
import org.eclipse.kuksa.PropertyListener | ||
import org.eclipse.kuksa.VssSpecificationListener | ||
|
@@ -48,7 +49,8 @@ class DataBrokerSubscriberTest : BehaviorSpec({ | |
connector.connect() | ||
|
||
and("An Instance of DataBrokerSubscriber") { | ||
val databrokerTransporter = DataBrokerTransporter(dataBrokerConnectorProvider.managedChannel) | ||
val databrokerTransporter = | ||
DataBrokerTransporter(dataBrokerConnectorProvider.managedChannel) | ||
val classUnderTest = DataBrokerSubscriber(databrokerTransporter) | ||
|
||
`when`("Subscribing using VSS_PATH to Vehicle.Speed with FIELD_VALUE") { | ||
|
@@ -61,15 +63,13 @@ class DataBrokerSubscriberTest : BehaviorSpec({ | |
databrokerTransporter.updateRandomFloatValue(vssPath) | ||
|
||
then("The PropertyListener is notified about the change") { | ||
verify(timeout = 100L) { | ||
verify(timeout = 100L, exactly = 2) { | ||
wba2hi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
propertyListener.onPropertyChanged(vssPath, fieldValue, any()) | ||
} | ||
} | ||
} | ||
|
||
`when`("Subscribing the same PropertyListener to a different vssPath") { | ||
clearMocks(propertyListener) | ||
|
||
val otherVssPath = "Vehicle.ADAS.CruiseControl.SpeedSet" | ||
classUnderTest.subscribe(otherVssPath, fieldValue, propertyListener) | ||
|
||
|
@@ -78,19 +78,17 @@ class DataBrokerSubscriberTest : BehaviorSpec({ | |
databrokerTransporter.updateRandomFloatValue(otherVssPath) | ||
|
||
then("The Observer is notified about both changes") { | ||
verify(timeout = 100L) { | ||
verify(timeout = 100L, exactly = 3) { | ||
lukasmittag marked this conversation as resolved.
Show resolved
Hide resolved
|
||
propertyListener.onPropertyChanged(vssPath, fieldValue, any()) | ||
} | ||
verify(timeout = 100L) { | ||
verify(timeout = 100L, exactly = 2) { | ||
lukasmittag marked this conversation as resolved.
Show resolved
Hide resolved
|
||
propertyListener.onPropertyChanged(otherVssPath, fieldValue, any()) | ||
} | ||
} | ||
} | ||
} | ||
|
||
`when`("Subscribing multiple (different) PropertyListener to $vssPath") { | ||
clearMocks(propertyListener) | ||
|
||
val propertyListenerMocks = mutableListOf<PropertyListener>() | ||
repeat(10) { | ||
val otherPropertyListenerMock = mockk<PropertyListener>(relaxed = true) | ||
|
@@ -102,11 +100,11 @@ class DataBrokerSubscriberTest : BehaviorSpec({ | |
and("When the FIELD_VALUE of Vehicle.Speed is updated") { | ||
val randomFloatValue = databrokerTransporter.updateRandomFloatValue(vssPath) | ||
|
||
then("The PropertyListener is only notified once") { | ||
then("Each PropertyListener is only notified once") { | ||
propertyListenerMocks.forEach { propertyListenerMock -> | ||
val dataEntries = mutableListOf<DataEntry>() | ||
|
||
verify(timeout = 100L) { | ||
verify(timeout = 100L, exactly = 2) { | ||
lukasmittag marked this conversation as resolved.
Show resolved
Hide resolved
|
||
propertyListenerMock.onPropertyChanged(vssPath, fieldValue, capture(dataEntries)) | ||
} | ||
|
||
|
@@ -123,9 +121,10 @@ class DataBrokerSubscriberTest : BehaviorSpec({ | |
|
||
and("When the FIELD_VALUE of Vehicle.Speed is updated") { | ||
databrokerTransporter.updateRandomFloatValue(vssPath) | ||
delay(100) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since exactly = 0 is always fullfilled, the timeout does not apply here. We therefore have to apply the delay because a) so that the verification is correctly "checked" after the asynchronously behavior would have run through and b) if we don't delay here the next test case in line 145ff is influenced,... (it fails because it receives three onPropertyChanged callbacks... => 1 from subscription, one from the update here and one from the update in the next testcase) A bit unhappy with all the special edge cases we have for testing the DataBroker#subscribe functionality :( |
||
|
||
then("The PropertyListener is not notified") { | ||
verify(timeout = 100L, exactly = 0) { | ||
verify(exactly = 0) { | ||
propertyListener.onPropertyChanged(vssPath, fieldValue, any()) | ||
} | ||
} | ||
|
@@ -146,7 +145,7 @@ class DataBrokerSubscriberTest : BehaviorSpec({ | |
then("The PropertyListener is only notified once") { | ||
val dataEntries = mutableListOf<DataEntry>() | ||
|
||
verify(timeout = 100L) { | ||
verify(timeout = 100L, exactly = 2) { | ||
lukasmittag marked this conversation as resolved.
Show resolved
Hide resolved
|
||
propertyListenerMock.onPropertyChanged(vssPath, fieldValue, capture(dataEntries)) | ||
} | ||
|
||
|
@@ -159,30 +158,54 @@ 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) | ||
classUnderTest.subscribe(specification, Types.Field.FIELD_VALUE, specificationObserverMock) | ||
val specificationObserverMock = | ||
mockk<VssSpecificationListener<VssDriver.VssHeartRate>>(relaxed = true) | ||
classUnderTest.subscribe( | ||
specification, | ||
Types.Field.FIELD_VALUE, | ||
specificationObserverMock, | ||
) | ||
|
||
and("The value of Vehicle.Driver.HeartRate changes") { | ||
databrokerTransporter.updateRandomFloatValue(specification.vssPath) | ||
val randomIntValue = | ||
databrokerTransporter.updateRandomUint32Value(specification.vssPath) | ||
|
||
then("The Observer should be triggered") { | ||
verify(timeout = 100) { specificationObserverMock.onSpecificationChanged(any()) } | ||
val vssHeartRates = mutableListOf<VssDriver.VssHeartRate>() | ||
verify(timeout = 100, exactly = 2) { | ||
specificationObserverMock.onSpecificationChanged(capture(vssHeartRates)) | ||
} | ||
|
||
val count = vssHeartRates.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) | ||
classUnderTest.subscribe(specification, Types.Field.FIELD_VALUE, specificationObserverMock) | ||
classUnderTest.subscribe(specification, Types.Field.FIELD_VALUE, specificationObserverMock) | ||
val specificationObserverMock = | ||
mockk<VssSpecificationListener<VssDriver.VssHeartRate>>(relaxed = true) | ||
classUnderTest.subscribe( | ||
specification, | ||
Types.Field.FIELD_VALUE, | ||
specificationObserverMock, | ||
) | ||
classUnderTest.subscribe( | ||
specification, | ||
Types.Field.FIELD_VALUE, | ||
specificationObserverMock, | ||
) | ||
|
||
and("The value of Vehicle.Driver.HeartRate changes") { | ||
val randomIntValue = databrokerTransporter.updateRandomUint32Value(specification.vssPath) | ||
val randomIntValue = | ||
databrokerTransporter.updateRandomUint32Value(specification.vssPath) | ||
|
||
then("The Observer is only notified once") { | ||
val heartRates = mutableListOf<VssDriver.VssHeartRate>() | ||
|
||
verify(timeout = 100) { specificationObserverMock.onSpecificationChanged(capture(heartRates)) } | ||
verify(timeout = 100, exactly = 2) { | ||
specificationObserverMock.onSpecificationChanged(capture(heartRates)) | ||
} | ||
|
||
val count = heartRates.count { it.value == randomIntValue } | ||
count shouldBe 1 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
While DataBrokerConnection#fetch and DataBrokerConnection#update are running synchronously the observers of the | ||
corresponding SubscriptionChannels run asynchronously. Between the update executed using #updateRandomXXXValue | ||
here and the propagation to the subscribed observers a small timeframe may pass. Therefore things like this most | ||
likely won't work because of the behavior described above: | ||
``` | ||
subscribe("Vehicle.Speed", observer) | ||
updateRandomFloatValue("Vehicle.Speed") | ||
verify { observer.onPropertyChanged("Vehicle.Speed", any())} | ||
``` | ||
|
||
Keep in mind, that when calling DataBrokerConnection#subscribe an initial update with the current value is send, | ||
to the subscribing observer, meaning that checking for a successful update requires at least two calls to the | ||
#onPropertyChanged method. One for the initial update and one for the consecutive, real update of the value. | ||
|
||
Using verify(timeout = 100\[, exactly = 1\]) alone won't fix this issue, because "exactly = 1" will always be | ||
fulfilled by the initial update mentioned above. It therefore needs to be something like | ||
verify(timeout = 100, exactly = 2) if an update is expected. | ||
|
||
A better example therefore would be: | ||
``` | ||
subscribe("Vehicle.Speed", observer) // triggers first #onPropertyChanged with initial value | ||
val value = updateRandomFloatValue() // triggers second #onPropertyChanged with updated value | ||
|
||
val dataEntries = mutableListOf<DataEntry>() | ||
|
||
verify (timeout = 100, exactly = 2) { // initial update + "updateRandomFloatValue") | ||
observer.onPropertyChanged("Vehicle.Speed", capture(dataEntries)) | ||
} | ||
|
||
val count = dataEntries.count { it.value.float == randomFloatValue } | ||
count shouldBe 1 | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fine for this PR, but in the long run,
shall we test again "latest" (i.e. latest "release") or "Master" (bleeding edge) or fixed versions, or a combination thereof? wdyt @wba2hi @lukasmittag ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The best behavior would probably be to test against the "latest released version", so that we have a consistent behavior for us and "3rd parties" using our sdk and the corresponding databroker.
Edit: eclipse/kuksa.val#688 this already part of the latest release? Otherwise we get issues with #61 :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should opt either for just master or a combination of master and latest. Because I think most of our documentation uses master and so we should test against it. For the future maybe we should change the documentation there too and then only test against latest (once we have a stable release process and release cycle time).