Project Reactor test never completes - project-reactor

I have created a simple Kafka consumer that returns a Flux of objects (the received messages) and I'm trying to test it using the StepVerifier.
In my test, I do something like that:
Flux<Pojo> flux = consumer.start();
StepVerifier.create(flux)
.expectNextMatches(p -> p.getList().size() == 3)
.verifyComplete();
The assertion works ok (if I change the value from 3 to something else, the test fails). But, if the assertion passes, than the test never exit.
I have also tried to use the verify method like so:
StepVerifier.create(flux)
.expectNextMatches(f -> f.getEntitlements().size() == 3)
.expectComplete()
.verify(Duration.ofSeconds(3));
In this case, I get this error:
java.lang.AssertionError: VerifySubscriber timed out on false
Any idea what I'm doing wrong?

The Kafka Flux is probably infinite, so it never emits the onComplete signal, which the test waits for. You can call .thenCancel().verify() if you're only interested in testing that first value.

Related

anylogic agent communication and message sending

In my model, I have some agents;
"Demand" agent,
"EnergyProducer1" agent
"EnergyProducer2" agent.
When my hourly energy demands are created in the Main agent with a function, the priority for satisfying this demand is belongs to "EnergyProducer1" agent. In this agent, I have a function that calculate energy production based on some situtations. The some part of the inside of this function is following;
**" if (statechartA.isStateActive(Operating.busy)) && ( main.heatLoadDemandPerHour >= heatPowerNominal) {
producedHeatPower = heatPowerNominal;
naturalGasConsumptionA = naturalGasConsumptionNominal;
send("boilerWorking",boiler);
} else ..... "**
Here my question is related to 4th line of the code. If my agent1 fails to satisfy the hourly demand, I have to say agent2 that " to satisfy rest of demand". If I send this message to agent2, its statechart will be active and the function of agent2 will be working. My question is that this all situations will be realized at the same hour ??? İf it is not, is accessing variables and parameters of other agent2 more appropiaote way???
I hope I could explain my problem.
thanks for your help in advance...
**Edited question...
As a general comment on your question, within AnyLogic environment sending messages is alway preferable to directly accessing variable and parameters of another agent.
Specifically in the example presented the send() function will schedule message delivery the next instance after the completion of the current function.
Update: A message in AnyLogic can be any Java class. Sending strings such as "boilerWorking" used in the example is good for general control, however if more information needs to be shared (such as a double value) then it is good practice to create a new Java class (let's call is ModelMessage and follow these instructions) with at least two properties msgStr and msgVal. With this new class sending a message changes from this:
...
send("boilerWorking", boiler);
...
to this:
...
send(new ModelMessage("boilerWorking",42.0), boiler);
...
and firing transitions in the statechart has to be changed to use if expression is true with expression being msg.msgString == "boilerWorking".
More information about Agent communication is available here.

How to test if msg was send to GenServer process

I'm running GenServer as a background job which is rescheduled each interval by Process.send_after(self(), :work, #interval).
This job is started by Supervisor when Application starts.
It's working perfectly, but now I want to test if my GenServer module is really spawning new process each interval.
How can I test it?
EDIT
I found that :sys.get_status(pid) can be use to fetch some data about process, but I would really like to use something like receive do ... end
EDIT 2
handle_info/2 function:
#impl true
def handle_info(:work, state) do
do_smt()
schedule_worker()
{:noreply, state}
end
schedule_worker/0 function:
defp schedule_worker do
Process.send_after(self(), :work, #interval)
end
There's something missing in your message. From what you have posted we can understand that every #interval milliseconds a :work message is sent. You are not telling us what the handle_info/2 is supposed to do when the message is dispatched.
Once this is defined, you can definitely write a test to assert that a message has been received by using the assert_received assertion.
I would test do_smt() by using Mock library and writing a test that makes as assertion like the following:
with_mock(MyModule, [do_stm_else: fn -> :ok]) do
do_smt()
assert_called MyModule.do_stm_else()
end
In this way, you have called the function that the task should execute, so you can assume that the task creation is being called.
If you want to let the do_stm_else function communicate with your test (in this scenario it looks a bit overengineered) you should:
get the pid of the test by calling self()
Pass the pid to the mock function to get it used
use assert_receive to verify that the communication has occurred
pid = self()
with_mock(MyModule, [do_stm_else: fn ->
Process.send(pid, :msg)
]) do
do_smt()
assert_called MyModule.do_stm_else()
end
assert_receive(:msg)
Please note that I had no time to check this, you should spend a bit to investigate.

What is wrong with my gen_statem fsm implementation?

I am implementing a gen_fsm using the gen_statem module and when i am trying to check its state as a handle_event_function i get the following error:
> ** exception error: {function_clause,
> {gen_statem,call,[{ok,<0.139.0>},state,0]}}
> in function gen:do_for_proc/2
> called as gen:do_for_proc({ok,<0.139.0>},#Fun<gen.0.9801092>)
> in call from gen_statem:'-call_clean/4-fun-0-'/5 (gen_statem.erl, line 637) 25> c("C:/Erlang/Genserv/fsm.erl").
Below is my code which is separated into :
-mandatory methods for the fsm to work
-api that the client can use (state change,get the state,start)
- generic handlers for when client demands something related to state
-state implementations
Module
-module(fsm).
-record(state,{
current="None",
intvCount=0,
jobCount=0
}).
-export([init/1,terminate/3,callback_mode/0,code_change/4]).
-export([state/1,start/0,hire/2,fire/2,interview/2]).
-export([sitting_home/3,interviewing/3,working/3]).
-behaviour(gen_statem).
%API
start()->
gen_statem:start_link(?MODULE,[],[]).
state(PID)->
gen_statem:call(PID,state,0).
hire(PID,Company)->
gen_statem:call(PID,{hire,Company},0).
fire(PID,Company)->
gen_statem:call(PID,{fire,Company},0).
interview(PID,Company)->
gen_state:call(PID,{intv,Company},0).
%mandatory
code_change(V,State,Data,Extra)->{ok,State,Data}.
callback_mode() ->
[state_functions,handle_event_function].
init([])->
{ok,sitting_home,#state{current="None",jobCount=0,intvCount=0}}.
terminate(Reasom,State,Data)->
void.
% Generic handlers
handle_event({call,From},state,State)->
{keep_state,State,[{reply,From,State}]};
handle_event(_,_,State)->
{keep_state,State}.
% State implementations
sitting_home({call,From},{intv,Company},State=#state{intvCount=C})->
{next_state,interviewing,State#state{intvCount=C+1},[{reply,From,"Interviewing by:"++Company}]};
sitting_home(EventType,Event,State)->
handle_event(EventType,Event,State).
interviewing({call,From},{rejected,Company},State)->
{next_state,sitting_home,State,[{reply,From,"rejected by:"++Company}]};
interviewing({call,From},{accepted,Company},State=#state{jobCount=J})->
{next_state,
working,
State#state{jobCount=J+1,current=Company},
[{reply,From,"accepted offer from:"++Company}]
};
interviewing(EventType,Event,State)->
handle_event(EventType,Event,State).
working({call,From},{fire,Company},State=#state{current=C})->
{next_state,working,State#state{current="None"},[{reply,From,"Got fired from"++Company}]};
working(EventType,Event,State)->
handle_event(EventType,Event,State).
Usage
FSM_PID=fsm:start().
fsm:state(PID). //crashes when demanding state
fsm:hire(PID,"Some Company").
fsm:start() returns the tuple {ok,Pid}. You cannot use directly the return of the function in your next call. Instead you must do something like:
{ok,P} = fsm:start().
fsm:state(P).
Then you will experience other troubles, the first one is that you specify a timeout of 0, so you will get a timeout error. You will have to change this, and continue debugging :o)
[edit]
You don't need to specify the Pid, it is done in background by the gen_statem code, the gen_statem:call function is executed in the caller context so it still has access to the caller Pid.
In fact it is a little more complex, depending if you specify a timeout or not, the gen_statem:call/3 will spawn a process to call the gen:call/4 function or will directly call it, thus the Pid sent to the state machine will be either the spawned function's one or the caller's one.
The gen:call/4 also add a Reference in the message to the state machine to "sign" the answer and guaranty that an incoming message from any other part of the application will not be interpreted as the answer.
This is a general pattern in erlang (and programming) to hide as much as possible the system mechanism in interface function. Just as you do in the function state/1

How do I access the value of the counter in a process?

In this program, I cannot for the life of me figure out how to access the value of the counter in a process.
-module(counter).
-export([start/0,loop/1,increment/1,value/1,stop/1]).
%% First the interface functions.
start() ->
spawn(counter, loop, [0]).
increment(Counter) ->
Counter ! increment.
value(Counter) ->
Counter ! {self(),value},
receive
{Counter,Value} ->
Value
end.
stop(Counter) ->
Counter ! stop.
%% The counter loop.
loop(Val) ->
receive
increment ->
loop(Val + 1);
{From,value} ->
From ! {self(),Val},
loop(Val);
stop -> % No recursive call here
true;
Other -> % All other messages
loop(Val)
end.
I assume it's:
{From,value} ->
From ! {self(),Val},
loop(Val);
which returns the value of the counter, but every time I use PID ! {PID,value}, or something similar to that it returns the thing after !, e.g. {<0.57.0>, value}.
TL;DR
You shouldn't use ! operator explicitly, it is considered an anti-pattern. You could run into some problems with typos in atoms or some bad data, just like you did this time.
To ensure correct communication with you one usually create some wrapper functions witch handle correct data format and communication with process. Function just like increment/1 value/1 and stop/1. In fact if you would use those, you would get expected results; in your case, assuming that PID is your counter, just call counter:value(PID).
Let me explain
There are few thing you seem to getting little bit wrong.
First of all ! will send message to another process. And that's all it does. Since everything in Erlang is expression (needs to return something, have a value) each call to ! will return right hand side of !. PID ! ok. will return ok, no matter what (there is slight chance that it will fail, but lets no go there). You send your message, and go on with your life, or execution.
Than, some process after receiving your message might decide to send you some message back. In case of {From, value} it will, in case of increment it wont. If you are expecting to get message back you need to wait for it and retrieve it from your mailbox. receive clause will do both waiting and retrieving. So if you decise to use ! on your own you should fallow it with receive with correct pattern match. You can see that value/1 function does just that.
Third thing is correct use of process ID's. I guess you started your counter correctly and you have it's Pid, and you can send messages to it with !. But if you expect it to send something back it needs to know your process ID, your address if you will. So you should have called PID ! {MyPid, values}. How to get MyPid? With self() function. Again, just like in value/1 function.
And last thing many people get wrong at the begging. counter module is just a file with some functions, it's not whole actor/process, and it's not an object. Fact that some value/1 and stop/1 are implemented in it, it doesn't mean that they will be run on counter actor/process. They are functions like any other, and if you call them they will be evaluated in your actor/process, on your stack (same goes for calling them from shell, shell is just another actor). You can spawn new process and tell it to run loop/1 function, but that's all it does. All increment/1 value/1 and stop/1 calls will be executed "on your side".
If this is somewhat confusing try to imagine some simpler function inside counter module, like
add(A, B) ->
A + B.
You can execute it from shell even without any counter process started. It will be created in your process, on your stack, it will add two numbers and return result.
This is important because when you call counter:value(Counter). it will execute Counter ! {self(),value}, "on your side", on your process, so self() will return Pid of your process, not the Pid of counter.
In theory you don't need to know this if you are just using those wrapper function (API or interface if you will), but since you are learning Erlang I would guess you will soon have to write such wrapper. Understanding what happens where is crucial then. Just remember that there is no magic in modules, no secret binding or special execution. Those are just plain old functions and they will be behaving just like in any other language. Only spawn, receive and maybe ! are little different.

How do I get $resource to resolve its promise in test environment

I have a controller that needs to run several asynchronous methods that interact with the data on the client and make no calls to the server. I have one method working fine in the browser, but I want to drive the methods with tests and I can't get it to work in the test environment (Karma and Mocha). The reason is that the empty array that $resource.query() returns never gets populated in the test environment because the promise doesn't get resolved. Here is my beforeEach in the test suite.
beforeEach(inject(function($rootScope, $controller, scheduleService){
scope = $rootScope.$new();
sc = $controller('scheduleCtrl', {
$scope: scope, service: scheduleService
});
scope.$apply();
}));
scheduleCtrl has a property schedule that is assigned to the result of Resource.query() in it's constructor. I can see the three returned objects loaded into the MockHttpExpectation.
But when I go to run the test sc.schedule is an still an empty array, so the test fails. How do I get the Resource.query() to resolve in the test?
Resource.query() works with promisses, which is a assync process.
It happens that your test execute before the assynchronous request have completed and before array gets populated.
You could use $httpBackend so you can call expect after $httpBackend.flush().
Or you could retrieve the $promisse returned from Resource.query().$promisse on your test and do the expectation inside its implementation.
Ex:
$scope.promisse = Resource.query().$promisse;
sc.promisse(function(values) {
expect(values.length).not.toBe(0);
});

Resources