Unit testing infinite Flux speed of generation - testing

I have Flux, which generates event in some pace (in infinite manner). I would like to use StepVerifier that after 5 seconds there is at least 2 events generated. How can I verify this behavior using StepVerifier?
Sample flux for testing can look like this:
public fluxTest() {
final AtomicLong counter = new AtomicLong(0);
final Random rnd = new Random();
final Flux<String> randomIntervalEmitter = Flux.generate(generator -> {
try {
final long counterDivided = counter.get() % 12;
if (counterDivided > 0) {
TimeUnit.SECONDS.sleep(rnd.nextInt(1, 10));
} else {
TimeUnit.MILLISECONDS.sleep(rnd.nextInt(1, 50));
}
generator.next("asdf " + counterDivided);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
final Flux<String> regularDummyUpdate = Flux.interval(Duration.ofSeconds(5)).map(e -> "" + (88 + (System.currentTimeMillis() % 104)));
final Flux<String> stringFluxWithSomePace = randomIntervalEmitter.mergeWith(regularDummyUpdate);
stringFluxWithSomePace.subscribe(System.out::println);
}

As stated in javadoc of StepVerifier:
The verification must be triggered after the terminal expectations
(completion, error, cancellation) have been declared, by calling one
of the verify() methods.
So when I have infinite source, I need to trigger some terminal operation. Complete and Error is emitted from source (I am not changing it in any way for tests) and Cancel can be triggered by subscriber (StepVerifier). So using thenCancel() and verify() on StepVerifier, I can achieve to assert only on the beginning of the infinite stream.
final var sv = StepVerifier.create(stringFluxWithSomePace.log())
// in 23 seconds should at least some "heartbeat" come at least three times
.expectSubscription()
.expectNextCount(3)
.thenCancel()
.verify(Duration.ofSeconds(23));
Nice thing is, that after receiving any 3 items, stream is cancelled and test finished (in my case usually under a second).

Related

Kotlin: Is there a tool that allows me to control parallelism when executing suspend functions?

I'm trying to execute certain suspend function multiple times, in such a way that never more than N of these are being executed at the same time.
For those acquainted with Akka and Scala Streaming libraries, something like mapAsync.
I did my own implementation using one input channel (as in kotlin channels) and N output channels. But it seems cumbersome and not very efficient.
The code I'm currently using is somewhat like this:
val inChannel = Channel<T>()
val outChannels = (0..n).map{
Channel<T>()
}
launch{
var i = 0
for(t in inChannel){
outChannels[i].offer(t)
i = ((i+1)%n)
}
}
outChannels.forEach{outChannel ->
launch{
for(t in outChannel){
fn(t)
}
}
}
Of course it has error management and everything, but still...
Edit: I did the following test, and it failed.
test("Parallelism is correctly capped") {
val scope = CoroutineScope(Dispatchers.Default.limitedParallelism(3))
var num = 0
(1..100).map {
scope.launch {
num ++
println("started $it")
delay(Long.MAX_VALUE)
}
}
delay(500)
assertEquals(3,num)
}
You can use the limitedParallelism-function on a Dispatcher (experimental in v1.6.0), and use the returned dispatcher to call your asynchronous functions. The function returns a view over the original dispatcher which limits the parallelism to a limit you provide. You can use it like this:
val limit = 2 // Or some other number
val dispatcher = Dispatchers.Default
val limitedDispatcher = dispatcher.limitedParallelism(limit)
for (n in 0..100) {
scope.launch(limitedDispatcher) {
executeTask(n)
}
}
Your question, as asked, calls for #marstran's answer. If what you want is that no more than N coroutines are being actively executed at any given time (in parallel), then limitedParallelism is the way to go:
val maxThreads: Int = TODO("some max number of threads")
val limitedDispatcher = Dispatchers.Default.limitedParallelism(maxThreads)
elements.forEach { elt ->
scope.launch(limitedDispatcher) {
doSomething(elt)
}
}
Now, if what you want is to even limit concurrency, so that at most N coroutines are run concurrently (potentially interlacing), regardless of threads, you could use a Semaphore instead:
val maxConcurrency: Int = TODO("some max number of concurrency coroutines")
val semaphore = Semaphore(maxConcurrency)
elements.forEach { elt ->
scope.async {
semaphore.withPermit {
doSomething(elt)
}
}
}
You can also combine both approaches.
Other answers already explained that it depends whether you need to limit parallelism or concurrency. If you need to limit concurrency, then you can do this similarly to your original solution, but with only a single channel:
val channel = Channel<T>()
repeat(n) {
launch {
for(t in channel){
fn(t)
}
}
}
Also note that offer() in your example does not guarantee that the task will be ever executed. If the next consumer in the round robin is still occupied with the previous task, the new task is simply ignored.

Need to start a code line after react subscribe() functions end

val totalNumInst = TotalNumObj()
devSupportService.sendAllTalktalkMessages(naverId)
devSupportService.sendAllAutoDepositTalktalkMessages(naverId, totalNum)
logger.info("${totalNumInst.totalNum}")
Mono<>
.doOnSuccess { }
.subscribe()
First two lines execute several Mono<>.subscribe() functions. In each Mono<>'s .doOnSuccess{} the totalNum variable is increasing. At the last line, I added a log which shows totalNum. But the totalNum variable always shows the initial value, 0.
I need to leave a log which shows how many times does the Mono<>.subscribe() is executed.
Thank you for reading my question.
There are 2 ways of solving your issue. The blocking and non-blocking.
Blocking
create a countDownLatch, pass it to sendAllTalktalkMessages and sendAllAutoDepositTalktalkMessages, then wait for it being latched
val totalNumInst = TotalNumObj()
val latch = CountDownLatch(2)
devSupportService.sendAllTalktalkMessages(naverId, totalNumInst, latch)
devSupportService.sendAllAutoDepositTalktalkMessages(naverId, totalNumInst, latch)
if (!latch.await(30, TimeUnit.SECONDS)) {
throw TimeoutException("Waiting timed out")
}
logger.info("${totalNumInst.totalNum}")
And add latch.countDown() to each doOnSuccess (but I'd recommend to countDown in doFinally in case of the chain sending error signal)
Mono<>
.doOnSuccess { latch.countDown() }
.subscribe()
This is blocking solution, it is against reactive non-blocking concept.
Non-blocking
Make sendAllTalktalkMessages and sendAllAutoDepositTalktalkMessages returning Mono and zip them (moreover in that case you don't need to pass totalNumInst to them)
Mono.zip(
devSupportService.sendAllTalktalkMessages(naverId)
.map { 1 }
.onErrorResume { Mono.just(0) }
.defaultIfEmpty(0),
devSupportService.sendAllAutoDepositTalktalkMessages(naverId)
.map { 1 }
.onErrorResume { 0 }
.defaultIfEmpty(0)
) { counter1, counter2 -> counter1 + counter2 }
.subscribe { totalNum -> logger.info("$totalNum") }
in this realisation you count each success as 1 and each error or empty signal as 0.

How to "Catch" both a non-numeric and Incomplete ArrayList capacity

I created an ArrayList that has a capacity of 5 Ints. I can get the if statement to run if its less than 5 but I can't seem to get the else statement to "Catch" Non-Numerics. For example if I enter 1,2,3,Hello; it will print "Wrong number of sales provided."
fun main(){
val stats = ArrayList<Int>(5)
println("Enter your numbers: ")
try {
while (stats.size < 5) {
stats.add(readLine()!!.toInt())
}
}catch (e: NumberFormatException){
if (stats.size != 5){
println("The wrong number of sales provided.")
}else{
println("All inputs should be numeric.")
}
exitProcess(status = 1)
}
calStats(stats)
}
fun calStats(sales: Collection<Int>){
val min = sales.minOrNull()
val max = sales.maxOrNull()
println("Min: $min\nMax: $max\nRange: ${(max!! - min!!)}\nAverage: ${(BigDecimal(sales.average()).setScale(0, RoundingMode.FLOOR))} ")
}
The problem is how you are handling your exception, in fact since you are checking the size of your array first, if you enter 1,2,3,'Hello' and there are 4 elements in this list it will output the wrong message.
You should nest your try ... catch block inside the while loop.
Actually the if (stats.size != 5) control is reduntant since the while loop will execute until stats has a size of 5, unless the NumberFormatException is thrown.
Try to edit your code like this:
fun main() {
val stats = ArrayList<Int>(5)
println("Enter your numbers: ")
while (stats.size < 5) {
try {
stats.add(readLine()!!.toInt())
} catch (e: NumberFormatException) {
println("All inputs should be numeric.")
exitProcess(status = 1)
}
}
calStats(stats)
}
Your logic loops through, reading lines and adding them until you've collected 5 values. As soon as it fails at parsing one of those lines as an Int, it throws a NumberFormatException and you hit the catch block.
The first thing the catch block does is check how many values you've successfully added to the stats list. If it's not exactly 5, it prints the "wrong number" error instead of the "inputs need to be numeric" one.
But if you think about it, the size is never going to be 5 when you hit the catch block - if you've added 5 items successfully, the while loop ends and there's no way it's going to throw. If you have 4 items and the 5th one fails, it doesn't get added, so you have 4 items when you hit the catch block.
If you need to do it this way, you probably want to keep a counter of how many lines you've read and refer to that. But you'll still throw once you hit the first non-numeric value (even if there's 5 of them to be read in total) and the counter will show how far you've got, not how many there are.
Probably the easiest way is to read in 5 lines to a list, and then transform them to Ints and add those to your collection. That way you can check if you have less than 5 before you start, and handle that case separately.
Something like
// create a list by calling readline() 5 times - produces null at EOF
val lines = List(5) { readLine() }
if (lines.contains(null)) { // handle your "not enough items" here }
// parse all lines as Ints - any that fail will be null
val stats = lines.map { it.toIntOrNull() } // or map(String::toIntOrNull)
if (stats.contains(null)) { // handle bad values here }
Kotlin's style tries to avoid exceptions, which is why you have functions like toIntOrNull alongside toInt - it lets you use nulls as a "failure value" that you can handle in normal code. But you can always throw an exception if you want (e.g. when you get a null line) and handle it in your catch block.

random corrupted data in serial Arduino

I have issue to read serial data from Arduino Uno in UWP C#. Sometimes when I start app I get corrupted data.
But in arduino monitor always is good.
Corrupted data is like this:
57
5
But should be 557.
Arduino codes:
String digx, digx2, digx3, digx1 ;
void setup() {
delay(500);
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A1);
sensorValue = map(sensorValue, 0, 1024, 0, 999);
digx1 = String(sensorValue % 10);
digx2 = String((sensorValue / 10) % 10);
digx3 = String((sensorValue / 100) % 10);
digx = (digx3 + digx2 + digx1);
Serial.println(digx);
Serial.flush();
delay(100);
}
And windows universal codes:
public sealed partial class MainPage : Page
{
public DataReader dataReader;
public SerialDevice serialPort;
private string data;
private async void InitializeConnection()
{
var aqs = SerialDevice.GetDeviceSelectorFromUsbVidPid(0x2341, 0x0043);
var info = await DeviceInformation.FindAllAsync(aqs);
serialPort = await SerialDevice.FromIdAsync(info[0].Id);
Thread.Sleep(100);
serialPort.DataBits = 8;
serialPort.BaudRate = 9600;
serialPort.Parity = SerialParity.None;
serialPort.Handshake = SerialHandshake.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
Thread.Sleep(100);
dataReader = new DataReader(serialPort.InputStream);
while (true)
{
await ReadAsync();
}
}
private async Task ReadAsync()
{
try
{
uint readBufferLength = 5;
dataReader.InputStreamOptions = InputStreamOptions.Partial;
//dataReader.UnicodeEncoding = UnicodeEncoding.Utf8;
var loadAsyncTask = dataReader.LoadAsync(readBufferLength).AsTask();
var ReadAsyncBytes = await loadAsyncTask;
if (ReadAsyncBytes > 0)
{
data = dataReader.ReadString(ReadAsyncBytes);
serialValue.Text = data;
}
}
catch (Exception e)
{
}
}
}
My idea was if it happened, Program skip that data. I tried different buffer length but more or less than 5 will always receive incorrect.
Thanks for any help.
Two methods that can fix your problem.
Method1: Make your UART communication robust
That there is no chance of an error but this is a tricky and time-consuming task in the case of windows software communicating with Arduino.
But still have some tricks which can help you because I have tried them and some of them work but please don't ask for the reason why it works.
Change your UART baud rate from 9600 to something else (mine if works perfect at 38400).
Replace Serial.begin(9600); to Serial.begin(38400,SERIAL_8N1)where 8 is data bit, 1 is stop bit and N is parity none in SERIAL_8N1. And you can also try different settings in data bit, stop bit, and parity. check here
don't send data after converting it into a string Serial.println(digx);. Send data in form of bytes array use Serial.write(digx,len);. check here
Method2: Add CRC Packet
At the end of each data packet and then send. When it reaches the windows software first fetch all UART data then calculate CRC from that data and then just compare calculated CRC and received CRC.If CRC matches then the data is correct and if not then ignore data and wait for new data.
you can check for CRC calculation its direct formula base implement and for little head start check this library by vinmenn.
I used two things to fix the problem,
1. In Windows codes added SerialDevice.IsDataTerminalReadyEnabled = true property to read bytes with correct order. From Microsoft docs
Here's a link!
2. As dharmik helped, I used array and send it with Serial.write(array, arrayLength) in Arduino and read them with dataReader.ReadBytes(array[]) and right buffer size in Windows app.
And result is so stable even with much lower Delays.

how to suspend for 200 ticks while delay 400 ticks in vxworks

I'm trying to code a program in vxworks. When a task total delay is 400 ticks, it was suspended at the 100th tick for 20 ticks, then resume to delay.
My main code is like the following:
void DelaySuspend (int level)
{
int tid, suspend_start,suspend_end,i;
suspend_start = vxTicks + 100;
suspend_end = vxTicks + 120;
i = vxTicks;
/* myfunction has taskDelay(400)*/
tid = taskSpawn("tMytask",200,0,2000,(FUNCPTR)myfunction,0,0,0,0,0,0,0,0,0,0);
/* tick between vxTicks+100 and vxTicks+120,suspend tMytask*/
while (i<suspend_start)
{
i=tickGet();
}
while (i <= suspend_end &&i >= suspend_start)
{
i = tickGet();
taskSuspend(tid);
}
}
What I want is to verify total delay time(or tick) doesn't change even I suspend the task for some time. I know the answer but just try to program it to show how vxWorks does it.
I am still not 100% clear on what you are trying to do, but calling taskSuspend in a loop like that isn't going to suspend the task any more. I am guessing you want something like this:
void DelaySuspend (int level)
{
int tid, suspend_start,suspend_end,i;
suspend_start = vxTicks + 100;
suspend_end = vxTicks + 120;
i = vxTicks;
/* myfunction has taskDelay(400)*/
tid = taskSpawn("tMytask",200,0,2000,(FUNCPTR)myfunction,0,0,0,0,0,0,0,0,0,0);
/* tick between vxTicks+100 and vxTicks+120,suspend tMytask*/
while (i<suspend_start)
{
i=tickGet();
}
taskSuspend(tid);
while (i <= suspend_end &&i >= suspend_start)
{
i = tickGet();
}
}
I just pulled the taskSuspend out of the loop, maybe you also want a taskResume in there after the loop or something? I am not sure what you are attempting to accomplish.
Whatever the case, there are probably better ways to do whatever you want, in general using taskSuspend is a bad idea because you have no idea what the task is doing when you suspend it. So for example if the suspended task is doing File I/O when you suspend it, and it has the file system mutex, then you cannot do any file I/O until you resume that task...
In general it is much better to block on a taskDelay/semaphore/mutex/message queue than use taskSuspend. I understand that this is just a test, and as such doing this may be ok, but if this test becomes production code, then you are asking for problems.