I am a beginner with erlang, and i write a basic gen server program as follows, I want to know, how to test the server so i can know it works well.
-module(gen_server_test).
-behaviour(gen_server).
-export([start_link/0]).
-export([alloc/0, free/1]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
gen_server:start_link({local, gen_server_test}, ch3, [], []).
alloc() ->
gen_server:call(gen_server_test, alloc).
free(Ch) ->
gen_server:cast(gen_server_test, {free, Ch}).
init(_Args) ->
{ok, channels()}.
handle_call(alloc, _From, Chs) ->
{Ch, Chs2} = alloc(Chs),
{reply, Ch, Chs2}.
handle_cast({free, Ch}, Chs) ->
io:format(Ch),
io:format(Chs),
Chs2 = free(),
{noreply, Chs2}.
free() ->
io:format("free").
channels() ->
io:format("channels").
alloc(chs) ->
io:format("alloc chs").
BTW: The program can be compiled, and it is not a good program, I just want to print something to make sure it works :)
The beauty of a gen_server implementing module is that it is just a callback module. One need not even have to spawn the underlying gen_server process to test it.
All you need to do is have your test framework (usually eunit) to invoke all the handle_call/cast/info functions by injecting it with different inputs (different gen_server states, different input messages) etc. and ensure it returns the correct response tuple (for eg. {reply, ok, NewState} or {noreply, NewState} etc.)
Ofcourse, this wouldnt work perfectly if your callback functions arn't pure functions. For eg., in your handle_call function, if you are sending a message to another process for eg., or if you are modifying an ets table. In which case, you have to ensure that all the required processes and tables are pre-created before running the test.
You could try one of the following:
Use the erlang shell and invoke the commands manually. Make sure the source or .beam file is in the Erlang path (parameter -pz, like this: erl -pz <path here>)
Write an EUnit test case
PS: I think you have an error in your code, because you seem to start the module ch3 as the server, not the gen_server_test module.
Related
If I have a group of gen servers called lock, can I call a function say
hello() ->
io:format("Hello, world!~n").
from the Pid of individual processes of that gen_server instead of generic lock:hello().
I tried Pid=<0.91.0> (so the Pid is return when i start a chld in my supervisor), and Pid:hello(). gives a bad argument is it impossible to do this??
Is it a better idea to send a message instead to call that function??
You can call gen_server:call(Pid, TuplePatternThatMatchesOnCallback)
-behaviour(gen_server).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
...
hello() ->
gen_server:call(Pid, hello).
handle_call(hello, _From, _State) ->
Reply = io:format("Hello, world!~n")
{reply, Reply, State}.
There is no Pid:Function API in Erlang.
In both cases calling gen server will serialize the call, providing you are using gen_server API. But going with function call you can choose synchronous reply.
If the hello is just placed in gen_server module (without gen_server:call) it will be executed in context of calling process, not gen_server one's.
When you call a function in a gen_server module, the function is not executed in the gen_server process. It is executed in the caller process.
If you want the gen_server process to do something, you should use the gen_server:call or the gen_server:cast functions:
For example, the gen_server:call/2 function will take a pid and a message that will be sent along with the call. The gen_server will then run it's handle_call function in the gen_server process.
Normally, you would have functions in the same module that defines the gen_server that will do the gen_server:call so that the caller will not have to care. That creates a clean API for others and hides the gen_server specific stuff.
It may be a little bit tricky to get all the pieces together but it's simple once you have. Check out this chapter of LYSE:
http://learnyousomeerlang.com/clients-and-servers
You can call the function hello from anywhere you want. If you call it 1000 times from 1000 processes, each process will be executing the function in parallel not interfering with each other. You just call it like that lock:hello(). from each one of those processes, so you call a specific function hello that is defined in a specific module lock and which takes zero arguments.
Probably there is something you didn't mention in your question?
Here is a simple UDP server:
-module(kvstore_udpserver).
-author("mylesmcdonnell").
%% API
-export([start/0]).
start() ->
spawn(fun() -> server(2346) end).
server(Port) ->
{ok, Socket} = gen_udp:open(Port, [binary]),
loop(Socket).
loop(Socket) ->
receive
{udp, Socket, Host, Port, Bin} ->
case binary_to_term(Bin) of
{store, Value} ->
io:format("kvstore_udpserver:{store, Value}~n"),
gen_udp:send(Socket,Host,Port,term_to_binary(kvstore:store(Value)));
{retrieve, Key} ->
io:format("kvstore_udpserver:{retrieve, Value}~n"),
gen_udp:send(Socket,Host,Port,term_to_binary(kvstore:retrieve(Key)))
end,
loop(Socket)
end.
How can I restructure this so that
a) It, or at least the relevant part of it, is a gen_server so that I can add to the supervision tree
b) increase concurrency by handling each message in a separate process.
I have reimplemented the sockserv example from Learn You Some Erlang for my TCP server but I'm struggling to determine a similar model for UDP.
For a):
You need to delcare the gen_server behaviour and implement all the callback functions (this is obvious, but it's worth calling out explicitly). If you have rebar installed, you can use the command rebar create template=simplesrv srvid=your_server_name to add the boilerplate functions.
You'd probably want to move the server starting business logic (the gen_udp:open/2 call) to your server's init/1 function. (The init is required by the gen_server behaviour. You can also start your loop/1 function there.
You'd probably want to make sure the udp server is closed by the module's terminate/2 function.
Move the business logic for handling requests that come in from parsing the messages to your loop/1 function into handle_call/3 or handle_cast/2 in your module (see below).
For b):
You have a few options, but basically, whenever you receive a message, you can use gen_server:cast/2 (if you don't care about the response) or gen_server:call/2,3 if you do. The casts or calls will be handled by the handle_cast/2 or handle_call/3 functions in your module.
Casts are inherently non-blocking and the answers to this question have a good design pattern for handling call operations asynchronously in gen_servers. You can crib from that.
Some of my application dependencies are used only if a given parameter is set. I need to know what is the best approach for starting those dependencies. I'm using Erlang R14B04 and I cannot use a different version.
I have two alternatives. The first one:
%% file myapp.erl
start() ->
dep1:start(),
dep2:start(),
application:start(myapp),
case application:get_env(myapp, use_app3) ->
true ->
dep3:start()
_ ->
ok
end.
start(Type, StartArgs) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
The second alernative:
%% file myapp.erl
start() ->
dep1:start(),
dep2:start(),
application:start(myapp).
start(Type, StartArgs) ->
case application:get_env(myapp, use_app3) ->
true ->
dep3:start()
_ ->
ok
end.
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
Which one is the best approach to solve the problem?
I would say the first is a better choice. start/0 seems to have the concern of starting relevant applications, while start/2 starts the current application's supervision tree.
These are two separate concerns, so putting the conditional logic in start/2 seems like it would dirty up your code a bit.
I notice that in the first example, you're starting the third app after your own app. In the second example, you're starting the third app before your own app. Which does your application need to happen first?
I'm trying to get an OTP supervisor to start child workers which will (eventually) connect to remote servers. I used Rebar to create a template test application and I'm trying to get the supervisor to fire off function 'hi' in module 'foo'. it compiles OK and runs:
Eshell V5.8.5 (abort with ^G)
1> test_app:start(1,1).
{ok,<0.34.0>}
but when I try to start the worker it goes pear shaped with this error:
2> test_sup:start_foo().
{error,{badarg,{foo,{foo,start_link,[]},
permanent,5000,worker,
[foo]}}}
The problem seems similar, but not the same, to this question: Erlang - Starting a child from the supervisor module
Any ideas?
test_app.erl
-module(test_app).
-behaviour(application).net
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
test_sup:start_link().
stop(_State) ->
ok.
Test_sup.erl:
-module(test_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1, start_foo/0]).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
{ok, { {one_for_one, 5, 10}, []} }.
start_foo()->
supervisor:check_childspecs(?CHILD(foo, worker)),
supervisor:start_child(?MODULE, ?CHILD(foo, permanent)).
foo.erl:
-module(foo).
-export([hi/0]).
hi()->
io:format("worker ~n").
You check the childspec using the macro call ?CHILD(foo, worker) while you try to start the child with the macro using the macro call ?CHILD(foo, permanent). The second argument of the CHILD macro is the process type which should be either worker or supervisor. So the first macro call is correct. The value permanent is a value for the restart type, which you have already set to permanent, so the second call is wrong and you get a badarg error.
Note: It is quite common that library functions generate badarg errors as well, not just from built-in functions. It is not always obvious why it is a badarg.
I think that Robert answer is incomplete, after replacing permanent by worker you still have an error returned by supervisor:check_childspecs(?CHILD(foo, worker)),, I don't know why.
[edit]
The problem of bard arg comes from ... badarg :o)
check_childspecs extepect a list of child_specs, the correct syntax is supervisor:check_childspecs([?CHILD(foo, worker)]), and then it works fine. the following code is updated.
[end of edit]
But you will get also an error because the supervisor will try to launch the function foo:start_link that does not exist in the foo module.
the following code print an error, but seems to work properly.
-module(foo).
-export([hi/0,start_link/0,loop/0]).
start_link() ->
{ok,spawn_link(?MODULE,loop,[])}.
hi()->
io:format("worker ~n").
loop() ->
receive
_ -> ok
end.
-module(test_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1, start_foo/0]).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
{ok, { {one_for_one, 5, 10}, []} }.
start_foo()->
io:format("~p~n",[supervisor:check_childspecs([?CHILD(foo, worker)])]),
supervisor:start_child(?MODULE, ?CHILD(foo, worker)).
[edit]
answering to David comment
in my code the loop/0 does not loop at all, on the receive block, the process waits for any message, and as soon as it receives one, the process dies returning the value ok. So as long as the worker process does not receive any message, it keeps living, which is nice when you make some test with supervisors :o).
On the opposite, the hi/0 function simply prints 'worker' on the console and finishes. As the restart strategy of the supervisor is one_for_one, the max restart is 5 and the child process is permanent, the supervisor will try to start the hi process 5 times, printing five time 'worker' on the console, and then it will give up and terminate itself with an error message ** exception error: shutdown
Generally you should choose permanent for never ending processes (main server of an application for example). For process that normally die as soon as they have done their job, you should use temporary. I never used transient but I read that it should be used for process that must complete a task before dying.
I have these code
start() ->
spawn(?MODULE, init, [self()]).
init(From) ->
spawn(?MODULE, broadcast, []).
broadcast() ->
Msg = "helloworld",
timer:sleep(10000),
broadcast().
When I test these code in Erlang shell, it give me undef error, I need to export broadcast function, I am just refuse
Code
spawn(?MODULE, init, [self()]).
means you will spawn process which initial call will be ?MODULE:init(self()) or more precisely equivalent of apply(?MODULE,init,[self()]). ?MODULE is macro evaluated to current module name but anyway It is external function call so this function have to be exported even there is ?MODULE used. In contrary
spawn(fun() -> init(self()) end).
is spawn with initial call to the func fun() -> init(self()) end which calls init/1 with result of function self(). It is local call which means init/1 may not be exported. There is another issue with it when self() is performed inside new process so you have to write
Self = self(), spawn(fun() -> init(Self) end).
to achieve same effect as in spawn(?MODULE, init, [self()]) where self() is evaluated as parameter of spawn/3.
well, the function broadcast is executed in a process. This function must therefore be accessible to all processes. Even though the same piece of source code, in the same module, spawns a process which goes to execute a function from the same module, that function must be exported out of that module to make it accessible.
That brings me to the difference between spawn(fun() -> broadcast() end). and spawn(?MODULE, broadcast, []). The later is called Spawning with MFA. In this method, the function must be exported out of the module so that it can be executed. The former is however unique, its a fun.
To understand this method: spawn(fun() -> broadcast() end)., we need to compare it with this one: spawn(fun() -> ?MODULE:broadcast() end). . Now, lets talk about the later of the two
spawn(fun() -> ?MODULE:broadcast() end). Now, here, if the function broadcast IS NOT exported in the module: ?MODULE, the process will crash. Note that in this case, the function is in the very module in which this piece of source code is written. spawn(fun() -> broadcast() end).In this case, the function must be in the very module in which this piece of source code is written. However, my thinking is this, the compiler converts this to the one above so that the spawned process is told that the function you are looking for is in module ?MODULE.I am not really a guru at compilers or run time systems, but i guess you will use this answer. My Strong advice is that in most of your source code, use this spawn(fun() -> ?MODULE:broadcast() end). or spawn(fun() -> some_module:broadcast() end). even though the piece of code or the function resides in that same very module than this: spawn(fun() -> broadcast() end).. From my personal experience the code becomes manageable and understandable. I get this nice illusion that a spawned process has to go and find the function from the specified module, and then execute with the given arguments.
Look more carefully at the warnings:
test.erl:8: Warning: function init/1 is unused
test.erl:8: Warning: variable 'From' is unused
test.erl:11: Warning: function broadcast/0 is unused
test.erl:12: Warning: variable 'Msg' is unused
The compiler thinks that your other functions are unused and never compiles them. Try this instead:
start() ->
spawn(fun() -> init(self()) end).
init(From) ->
spawn(fun() -> broadcast() end).