Starting a dependency based on a configuration argument in erlang - erlang

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?

Related

Testing Erlang applications based on cowboy using common test

I have an Erlang application based on Cowboy and I would like to test it.
Previously I used wooga's library etest_http for this kind of tasks, but I would like to start using common tests since I noticed that this is the way used in cowboy. I have tried to setup a very basic test but I am not able to run it properly.
Can anybody provide me a sample for testing the basic example echo_get and tell me what is the correct way to run the test from the console using the Makefile contained in the example?
The example make used only for build echo_get app. So to test echo_get app you can add test suite and call make && rebar -v 1 skip_deps=true ct (rebar should be in PATH) from shell.
Also you need etest and etest_http in your Erlang PATH or add it with rebar.config in your application. You can use httpc or curl with os:cmd/1 instead ehttp_test :)
test/my_test_SUITE.erl (full example)
-module(my_test_SUITE).
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
% etest macros
-include_lib ("etest/include/etest.hrl").
% etest_http macros
-include_lib ("etest_http/include/etest_http.hrl").
suite() ->
[{timetrap,{seconds,30}}].
init_per_suite(Config) ->
%% start your app or release here
%% for example start echo_get release
os:cmd("./_rel/bin/echo_get_example start"),
Config.
end_per_suite(_Config) ->
%% stop your app or release here
%% for example stop echo_get release
os:cmd("./_rel/bin/echo_get_example stop")
ok.
init_per_testcase(_TestCase, Config) ->
Config.
end_per_testcase(_TestCase, _Config) ->
ok.
all() ->
[my_test_case].
my_test_case(_Config) ->
Response = ?perform_get("http://localhost:8080/?echo=saymyname"),
?assert_status(200, Response),
?assert_body("saymyname", Response).
ok.
The following starts the hello_world application and its dependencies, but uses the most recently compiled versions rather than the one in ./_rel; that may or may not be what you want, but it does avoid the timer:sleep(1000)
-module(hello_world_SUITE).
-include_lib("common_test/include/ct.hrl").
-export([all/0, init_per_suite/1, end_per_suite/1]).
-export([http_get_hello_world/1]).
all() ->
[http_get_hello_world].
init_per_suite(Config) ->
{ok, App_Start_List} = start([hello_world]),
inets:start(),
[{app_start_list, App_Start_List}|Config].
end_per_suite(Config) ->
inets:stop(),
stop(?config(app_start_list, Config)),
Config.
http_get_hello_world(_Config) ->
{ok, {{_Version, 200, _ReasonPhrase}, _Headers, Body}} =
httpc:request(get, {"http://localhost:8080", []}, [], []),
Body = "Hello World!\n".
start(Apps) ->
{ok, do_start(_To_start = Apps, _Started = [])}.
do_start([], Started) ->
Started;
do_start([App|Apps], Started) ->
case application:start(App) of
ok ->
do_start(Apps, [App|Started]);
{error, {not_started, Dep}} ->
do_start([Dep|[App|Apps]], Started)
end.
stop(Apps) ->
_ = [ application:stop(App) || App <- Apps ],
ok.
Use https://github.com/extend/gun
to run the provided example (considering 'gun' in in 'user' folder):
ct_run -suite twitter_SUITE.erl -logdir ./results -pa /home/user/gun/deps/*/ebin /home/user/gun/ebin

Erlang, how to load applications with their dependencies

I have some apps in my cluster, I need to start some of them sometimes on different hosts.
The story is that the Erlang cluster is already running, so even though I have my .app resource file per application stating which applications should be started before mine, this only works to create a startup script, not to start an app in a already running node.
At the moment I have a custom routine that uses application:get_key(Application,applications) to extract the dependencies and start them separately before starting the given application.
I was wondering if there isn't a better way of doing this.
Since Erlang R16B02, there is also application:ensure_all_started.
Frankly, the standard tools for doing this in Erlang are unnecessarily annoying right now. I tend to put the following boiler-plate in my application callback module:
-module(myapp_app).
-export([start/0]).
start() -> a_start(myapp, permanent).
a_start(App, Type) ->
start_ok(App, Type, application:start(App, Type)).
start_ok(_App, _Type, ok) -> ok;
start_ok(_App, _Type, {error, {already_started, _App}}) -> ok;
start_ok(App, Type, {error, {not_started, Dep}}) ->
ok = a_start(Dep, Type),
a_start(App, Type);
start_ok(App, _Type, {error, Reason}) ->
erlang:error({app_start_failed, App, Reason}).
You can then add -s myapp_app to your erlang command line and this will start the app and all its dependencies recursively. Why this function isn't in the application module I don't know :)
There is a working example of this custom erlang app startup code in my Erlang Factory 2012 SFBay example app.
When starting the app outside of the startup script you do need to start the dependencies first. You could build the smarts to do this into the app itself so that when the app starts it will start any required dependencies before it needs them.
One place I've seen this done is in Mochiweb apps. The default app templates include code for loading dependencies on startup:
-module(some_app).
-export([start/0, stop/0]).
ensure_started(App) ->
case application:start(App) of
ok ->
ok;
{error, {already_started, App}} ->
ok
end.
%% #spec start() -> ok
%% #doc Start the some_app server.
start() ->
some_app_deps:ensure(),
ensure_started(crypto),
application:start(some_app).
%% #spec stop() -> ok
%% #doc Stop the some_app server.
stop() ->
application:stop(some_app).
If you write your app under "OTP Design Principles", you will have to make yourappname.app file, which will contains `applications' section. This section defines which other applications you want to be started before yours. Here is stated:
applications
All applications which must be started before this
application is started. systools uses this list to generate correct
boot scripts. Defaults to [], but note that all applications have
dependencies to at least kernel and stdlib.
So if you use releases, this dependency resolution will be solved by systools.

Need I export all functions in Erlang shell?

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).

How to test gen server in erlang?

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.

How to write a simple webserver in Erlang?

Using the default Erlang installation what is the minimum code needed to produce a "Hello world" producing web server?
Taking "produce" literally, here is a pretty small one. It doesn't even read the request (but does fork on every request, so it's not as minimal possible).
-module(hello).
-export([start/1]).
start(Port) ->
spawn(fun () -> {ok, Sock} = gen_tcp:listen(Port, [{active, false}]),
loop(Sock) end).
loop(Sock) ->
{ok, Conn} = gen_tcp:accept(Sock),
Handler = spawn(fun () -> handle(Conn) end),
gen_tcp:controlling_process(Conn, Handler),
loop(Sock).
handle(Conn) ->
gen_tcp:send(Conn, response("Hello World")),
gen_tcp:close(Conn).
response(Str) ->
B = iolist_to_binary(Str),
iolist_to_binary(
io_lib:fwrite(
"HTTP/1.0 200 OK\nContent-Type: text/html\nContent-Length: ~p\n\n~s",
[size(B), B])).
For a web server using only the built in libraries check out inets http_server.
When in need of some more power but still with simplicity you should check out the mochiweb library. You can google for loads of example code.
Do you actually want to write a web server in Erlang, or do you want an Erlang web server so that you can create dynamic web content using Erlang?
If the latter, try YAWS. If the former, have a look at the YAWS source code for inspiration
Another way, similar to the gen_tcp example above but with less code and already offered as a suggestion, is using the inets library.
%%%
%%% A simple "Hello, world" server in the Erlang.
%%%
-module(hello_erlang).
-export([
main/1,
run_server/0,
start/0
]).
main(_) ->
start(),
receive
stop -> ok
end.
run_server() ->
ok = inets:start(),
{ok, _} = inets:start(httpd, [
{port, 0},
{server_name, "hello_erlang"},
{server_root, "/tmp"},
{document_root, "/tmp"},
{bind_address, "localhost"}
]).
start() -> run_server().
Keep in mind, this exposes your /tmp directory.
To run, simply:
$ escript ./hello_erlang.erl
For a very easy to use webserver for building restful apps or such check out the gen_webserver behaviour: http://github.com/martinjlogan/gen_web_server.
Just one fix for Felix's answer and it addresses the issues Martin is seeing. Before closing a socket, all data being sent from the client should be received (using for example do_recv from gen_tcp description).
Otherwise there's a race condition for the browser/proxy sending the HTTP request being quick enough to send the http request before the socket is closed.

Resources