-
Notifications
You must be signed in to change notification settings - Fork 18
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
Stats collector; kotlin; mcumgr test mock framework #65
Conversation
Codecov Report
@@ Coverage Diff @@
## master #65 +/- ##
========================================
Coverage ? 13.1%
Complexity ? 92
========================================
Files ? 60
Lines ? 1869
Branches ? 179
========================================
Hits ? 245
Misses ? 1596
Partials ? 28
|
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.
This is a rather large PR with big changes making it hard to give it a good critique.
The title implies that it could've been broken out into 3 different PRs:
- Stats collector
- kotlin
- mcumgr test mock framework
mcumgr-core/src/main/java/io/runtime/mcumgr/managers/meta/StatisticsCollector.kt
Outdated
Show resolved
Hide resolved
/** | ||
* List the stat group names from the device and collect each which intersects with the filter. | ||
*/ | ||
fun collectAll(filter: Set<String>? = null, callback: StatCollectionCallback): Cancellable { |
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.
You pulled in the Coroutines dependency but then utilizing legacy data flow paradigms. Is it because tools that rely on this library don't support modern data flow?
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 coroutines is currently used in the unit tests, I can make it a testImplemetation
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 reason why the external API is not coroutines is to allow for people to use the traditional callbacks if they want (like we do...). Building coroutines support on top of this API would be very simple needed.
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.
If the plan is to make Coroutines a first class citizen, then perhaps it would be better to use Coroutines in the library then provide an "extension" library that wraps the Coroutine versions to provide the callback implementation?
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 would love to have coroutines as a first-class citizen. The issue I see is that the current architecture for mcumgr does not include it whatsoever; so any coroutines addition to the current major version 0.x.x would simply be at a wrapping-api level. The crux of coroutine support would be at the transport interface.
I think we should plan a v1.x.x with coroutines built in all the way down to the transport interface and beyond, with a callback based api-wrapper (essentially the opposite of what we would do now).
In the end, I think adding corountes would be great, just not so in this PR.
mcumgr-core/src/main/java/io/runtime/mcumgr/managers/meta/StatisticsCollector.kt
Show resolved
Hide resolved
mcumgr-core/src/main/java/io/runtime/mcumgr/managers/meta/StatisticsCollector.kt
Outdated
Show resolved
Hide resolved
The reason it's all in one is because each relies on another. In order to add the stats collector, we need kotlin support, and generally I would add the tests for a certain feature with the PR where that feature is added. So if we split it out we would have a few line PR to add kotlin w/out any kotlin code in the repo, then a PR to add the stats collector, then a PR to add the stats collector tests -- Each relying on the one before. You seemed to have gone through most of it ok. |
@twyatt Also, this is all already in the gateway SDK. I just wanted to pull it out into here for external use and as a base for additional unit tests. |
Co-Authored-By: Travis Wyatt <travis@juul.com>
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.
Was is the middle of reviewing when this was merged, so I'll just post these comments and you can take them or leave em.
@@ -26,19 +27,24 @@ android { | |||
|
|||
dependencies { | |||
|
|||
// Kotlin | |||
implementation "androidx.core:core-ktx:1.2.0" | |||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" |
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.
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | |
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" |
@Test | ||
fun `parse image without protected tlvs success`() { | ||
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-no-prot-tlv.img")!! | ||
?: throw IllegalStateException("input stream is null") |
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.
?: throw IllegalStateException("input stream is null") |
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-prot-tlv.img") | ||
?: throw IllegalStateException("input stream is null") |
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.
nitpick
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-prot-tlv.img") | |
?: throw IllegalStateException("input stream is null") | |
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-prot-tlv.img")!! |
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-no-prot-tlv.img")!! | ||
?: throw IllegalStateException("input stream is null") | ||
val imageData = toByteArray(inputStream) |
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.
nitpick: could make these more readable with a quick refactor.
fun String.readByteArray() =
McuMgrImageTest::class.java.classLoader!!
.getResourceAsStream(this)
.toByteArray()
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-no-prot-tlv.img")!! | |
?: throw IllegalStateException("input stream is null") | |
val imageData = toByteArray(inputStream) | |
val imageData = "slinky-no-prot-tlv.img".readByteArray() |
private fun toByteArray(inputStream: InputStream): ByteArray { | ||
val os = ByteArrayOutputStream() | ||
val buffer = ByteArray(1024) | ||
var len: Int | ||
while (inputStream.read(buffer).also { len = it } != -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.
nitpick
private fun toByteArray(inputStream: InputStream): ByteArray { | |
val os = ByteArrayOutputStream() | |
val buffer = ByteArray(1024) | |
var len: Int | |
while (inputStream.read(buffer).also { len = it } != -1) { | |
private fun InputStream.toByteArray(): ByteArray { | |
val os = ByteArrayOutputStream() | |
val buffer = ByteArray(1024) | |
var len: Int | |
while (read(buffer).also { len = it } != -1) { |
package io.runtime.mcumgr | ||
|
||
import io.runtime.mcumgr.image.McuMgrImage | ||
import org.junit.Test | ||
import java.io.ByteArrayOutputStream | ||
import java.io.InputStream | ||
|
||
class McuMgrImageTest { | ||
|
||
@Test | ||
fun `parse image without protected tlvs success`() { | ||
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-no-prot-tlv.img")!! | ||
?: throw IllegalStateException("input stream is null") | ||
val imageData = toByteArray(inputStream) | ||
McuMgrImage.fromBytes(imageData) | ||
} | ||
|
||
@Test | ||
fun `parse image with protected tlvs success`() { | ||
val inputStream = this::class.java.classLoader?.getResourceAsStream("slinky-prot-tlv.img") | ||
?: throw IllegalStateException("input stream is null") | ||
val imageData = toByteArray(inputStream) | ||
McuMgrImage.fromBytes(imageData) | ||
} | ||
|
||
private fun toByteArray(inputStream: InputStream): ByteArray { | ||
val os = ByteArrayOutputStream() | ||
val buffer = ByteArray(1024) | ||
var len: Int | ||
while (inputStream.read(buffer).also { len = it } != -1) { | ||
os.write(buffer, 0, len) | ||
} | ||
return os.toByteArray() | ||
} | ||
} |
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.
For readability, the combination of the above suggestions:
class McuMgrImageTest {
@Test
fun `parse image without protected tlvs success`() {
McuMgrImage.fromBytes("slinky-no-prot-tlv.img".readByteArray())
}
@Test
fun `parse image with protected tlvs success`() {
McuMgrImage.fromBytes("slinky-prot-tlv.img".readByteArray())
}
}
private fun String.readByteArray() =
McuMgrImageTest::class.java.classLoader!!
.getResourceAsStream(this)
.toByteArray()
private fun InputStream.toByteArray(): ByteArray {
val os = ByteArrayOutputStream()
val buffer = ByteArray(1024)
var len: Int
while (read(buffer).also { len = it } != -1) {
os.write(buffer, 0, len)
}
return os.toByteArray()
}
package io.runtime.mcumgr | ||
|
||
import io.runtime.mcumgr.image.McuMgrImage | ||
import org.junit.Test |
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.
import org.junit.Test | |
import kotlin.test.Test |
Ah sorry! Thanks! I will be making changes to build out the mock transport to support other groups and will take these comments into consideration. |
This PR is already large enough without refactoring a bit. So I will hold that to later changes when all the other mcumgr group managers are mocked out and tests added.
Adds the stats collector under the
managers/meta
package. This class is used to more-easily collect one or more statistics groups.The stats collector test comes with a simple mock transport which implements a regular server behavior. This mock transport currently only implements the stats group commands, but additional handlers are planned to test other group managers.