aboutsummaryrefslogtreecommitdiff
path: root/learn-you-some-erlang/m8ball
diff options
context:
space:
mode:
Diffstat (limited to 'learn-you-some-erlang/m8ball')
-rw-r--r--learn-you-some-erlang/m8ball/Emakefile2
-rw-r--r--learn-you-some-erlang/m8ball/config/a.config9
-rw-r--r--learn-you-some-erlang/m8ball/config/b.config9
-rw-r--r--learn-you-some-erlang/m8ball/config/c.config9
-rw-r--r--learn-you-some-erlang/m8ball/ebin/m8ball.app13
-rw-r--r--learn-you-some-erlang/m8ball/logs/.track-this0
-rw-r--r--learn-you-some-erlang/m8ball/src/m8ball.erl24
-rw-r--r--learn-you-some-erlang/m8ball/src/m8ball_server.erl46
-rw-r--r--learn-you-some-erlang/m8ball/src/m8ball_sup.erl16
-rw-r--r--learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE.erl32
-rw-r--r--learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/backup.config9
-rw-r--r--learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/main.config9
-rw-r--r--learn-you-some-erlang/m8ball/test/m8ball.spec5
-rw-r--r--learn-you-some-erlang/m8ball/test/m8ball_dist.spec20
-rw-r--r--learn-you-some-erlang/m8ball/test/m8ball_server_SUITE.erl45
15 files changed, 248 insertions, 0 deletions
diff --git a/learn-you-some-erlang/m8ball/Emakefile b/learn-you-some-erlang/m8ball/Emakefile
new file mode 100644
index 0000000..b203ea3
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/Emakefile
@@ -0,0 +1,2 @@
+{["src/*", "test/*"],
+ [{i,"include"}, {outdir, "ebin"}]}.
diff --git a/learn-you-some-erlang/m8ball/config/a.config b/learn-you-some-erlang/m8ball/config/a.config
new file mode 100644
index 0000000..983d5e1
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/config/a.config
@@ -0,0 +1,9 @@
+[{kernel,
+ [{distributed, [{m8ball,
+ 5000,
+ [a@ferdmbp, {b@ferdmbp, c@ferdmbp}]}]},
+ {sync_nodes_mandatory, [b@ferdmbp, c@ferdmbp]},
+ {sync_nodes_timeout, 30000}
+ ]
+ }
+].
diff --git a/learn-you-some-erlang/m8ball/config/b.config b/learn-you-some-erlang/m8ball/config/b.config
new file mode 100644
index 0000000..2d0ccfc
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/config/b.config
@@ -0,0 +1,9 @@
+[{kernel,
+ [{distributed, [{m8ball,
+ 5000,
+ [a@ferdmbp, {b@ferdmbp, c@ferdmbp}]}]},
+ {sync_nodes_mandatory, [a@ferdmbp, c@ferdmbp]},
+ {sync_nodes_timeout, 30000}
+ ]
+ }
+].
diff --git a/learn-you-some-erlang/m8ball/config/c.config b/learn-you-some-erlang/m8ball/config/c.config
new file mode 100644
index 0000000..3dd3609
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/config/c.config
@@ -0,0 +1,9 @@
+[{kernel,
+ [{distributed, [{m8ball,
+ 5000,
+ [a@ferdmbp, {b@ferdmbp, c@ferdmbp}]}]},
+ {sync_nodes_mandatory, [a@ferdmbp, b@ferdmbp]},
+ {sync_nodes_timeout, 30000}
+ ]
+ }
+].
diff --git a/learn-you-some-erlang/m8ball/ebin/m8ball.app b/learn-you-some-erlang/m8ball/ebin/m8ball.app
new file mode 100644
index 0000000..352c1d4
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/ebin/m8ball.app
@@ -0,0 +1,13 @@
+{application, m8ball,
+ [{vsn, "1.0.0"},
+ {description, "Answer vital questions"},
+ {modules, [m8ball, m8ball_sup, m8ball_server]},
+ {applications, [stdlib, kernel, crypto]},
+ {registered, [m8ball, m8ball_sup, m8ball_server]},
+ {mod, {m8ball, []}},
+ {env, [
+ {answers, {<<"Yes">>, <<"No">>, <<"Doubtful">>,
+ <<"I don't like your tone">>, <<"Of course">>,
+ <<"Of course not">>, <<"*backs away slowly and runs away*">>}}
+ ]}
+ ]}.
diff --git a/learn-you-some-erlang/m8ball/logs/.track-this b/learn-you-some-erlang/m8ball/logs/.track-this
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/logs/.track-this
diff --git a/learn-you-some-erlang/m8ball/src/m8ball.erl b/learn-you-some-erlang/m8ball/src/m8ball.erl
new file mode 100644
index 0000000..041601b
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/src/m8ball.erl
@@ -0,0 +1,24 @@
+-module(m8ball).
+-behaviour(application).
+-export([start/2, stop/1]).
+-export([ask/1]).
+
+%%%%%%%%%%%%%%%%%
+%%% CALLBACKS %%%
+%%%%%%%%%%%%%%%%%
+
+%% start({failover, Node}, Args) is only called
+%% when a start_phase key is defined.
+start(normal, []) ->
+ m8ball_sup:start_link();
+start({takeover, _OtherNode}, []) ->
+ m8ball_sup:start_link().
+
+stop(_State) ->
+ ok.
+
+%%%%%%%%%%%%%%%%%
+%%% INTERFACE %%%
+%%%%%%%%%%%%%%%%%
+ask(Question) ->
+ m8ball_server:ask(Question).
diff --git a/learn-you-some-erlang/m8ball/src/m8ball_server.erl b/learn-you-some-erlang/m8ball/src/m8ball_server.erl
new file mode 100644
index 0000000..4e821ad
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/src/m8ball_server.erl
@@ -0,0 +1,46 @@
+-module(m8ball_server).
+-behaviour(gen_server).
+-export([start_link/0, stop/0, ask/1]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+%%%%%%%%%%%%%%%%%
+%%% INTERFACE %%%
+%%%%%%%%%%%%%%%%%
+start_link() ->
+ gen_server:start_link({global, ?MODULE}, ?MODULE, [], []).
+
+stop() ->
+ gen_server:call({global, ?MODULE}, stop).
+
+ask(_Question) -> % the question doesn't matter!
+ gen_server:call({global, ?MODULE}, question).
+
+%%%%%%%%%%%%%%%%%
+%%% CALLBACKS %%%
+%%%%%%%%%%%%%%%%%
+init([]) ->
+ <<A:32, B:32, C:32>> = crypto:rand_bytes(12),
+ random:seed(A,B,C),
+ {ok, []}.
+
+handle_call(question, _From, State) ->
+ {ok, Answers} = application:get_env(m8ball, answers),
+ Answer = element(random:uniform(tuple_size(Answers)), Answers),
+ {reply, Answer, State};
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
+handle_call(_Call, _From, State) ->
+ {noreply, State}.
+
+handle_cast(_Cast, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/learn-you-some-erlang/m8ball/src/m8ball_sup.erl b/learn-you-some-erlang/m8ball/src/m8ball_sup.erl
new file mode 100644
index 0000000..ca5e426
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/src/m8ball_sup.erl
@@ -0,0 +1,16 @@
+-module(m8ball_sup).
+-behaviour(supervisor).
+-export([start_link/0, init/1]).
+
+start_link() ->
+ supervisor:start_link({global,?MODULE}, ?MODULE, []).
+
+init([]) ->
+ {ok, {{one_for_one, 1, 10},
+ [{m8ball,
+ {m8ball_server, start_link, []},
+ permanent,
+ 5000,
+ worker,
+ [m8ball_server]
+ }]}}.
diff --git a/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE.erl b/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE.erl
new file mode 100644
index 0000000..3afba6e
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE.erl
@@ -0,0 +1,32 @@
+-module(dist_m8ball_SUITE).
+-include_lib("common_test/include/ct.hrl").
+-export([all/0, groups/0, init_per_group/2, end_per_group/2]).
+-export([can_contact/1]).
+
+all() -> [{group, main}, {group, backup}].
+
+groups() -> [{main,
+ [],
+ [can_contact]},
+ {backup,
+ [],
+ [can_contact]}].
+
+init_per_group(main, Config) ->
+ application:start(crypto),
+ application:start(m8ball),
+ Config;
+init_per_group(backup, Config) ->
+ application:start(crypto),
+ application:start(m8ball),
+ Config.
+
+end_per_group(main, _Config) ->
+ %application:stop(m8ball),
+ ok;
+end_per_group(backup, _Config) ->
+ %application:stop(m8ball),
+ ok.
+
+can_contact(_Config) ->
+ <<_/binary>> = m8ball:ask(<<"Some Question">>).
diff --git a/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/backup.config b/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/backup.config
new file mode 100644
index 0000000..7fbe260
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/backup.config
@@ -0,0 +1,9 @@
+[{kernel,
+ [{distributed, [{m8ball,
+ 5000,
+ ['a@li101-172.members.linode.com', 'b@li101-172.members.linode.com']}]},
+ {sync_nodes_mandatory, ['a@li101-172.members.linode.com']},
+ {sync_nodes_timeout, 5000}
+ ]
+ }
+].
diff --git a/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/main.config b/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/main.config
new file mode 100644
index 0000000..bcac447
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/main.config
@@ -0,0 +1,9 @@
+[{kernel,
+ [{distributed, [{m8ball,
+ 5000,
+ ['a@li101-172.members.linode.com', 'b@li101-172.members.linode.com']}]},
+ {sync_nodes_mandatory, ['b@li101-172.members.linode.com']},
+ {sync_nodes_timeout, 5000}
+ ]
+ }
+].
diff --git a/learn-you-some-erlang/m8ball/test/m8ball.spec b/learn-you-some-erlang/m8ball/test/m8ball.spec
new file mode 100644
index 0000000..51d9cf3
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/test/m8ball.spec
@@ -0,0 +1,5 @@
+{include, "../include/"}.
+{alias, root, "/home/ferd/code/learn-you-some-erlang/m8ball/test"}.
+{logdir, "/home/ferd/code/learn-you-some-erlang/m8ball/logs"}.
+
+{suites, root, all}.
diff --git a/learn-you-some-erlang/m8ball/test/m8ball_dist.spec b/learn-you-some-erlang/m8ball/test/m8ball_dist.spec
new file mode 100644
index 0000000..c49a6ca
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/test/m8ball_dist.spec
@@ -0,0 +1,20 @@
+{node, master, 'ct@li101-172.members.linode.com'}.
+{node, a, 'a@li101-172.members.linode.com'}.
+{node, b, 'b@li101-172.members.linode.com'}.
+
+{init, a, [{node_start, [{monitor_master, true},
+ {boot_timeout, 10000},
+ {erl_flags, "-pa /home/ferd/code/learn-you-some-erlang/m8ball/ebin/ "
+ "-config /home/ferd/code/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/main.config"}]}]}.
+{init, b, [{node_start, [{monitor_master, true},
+ {boot_timeout, 10000},
+ {erl_flags, "-pa /home/ferd/code/learn-you-some-erlang/m8ball/ebin/ "
+ "-config /home/ferd/code/learn-you-some-erlang/m8ball/test/dist_m8ball_SUITE_data/backup.config"}]}]}.
+
+{include, "../include/"}.
+{alias, root, "/home/ferd/code/learn-you-some-erlang/m8ball/test"}.
+{logdir, "/home/ferd/code/learn-you-some-erlang/m8ball/logs"}.
+{logdir, master, "/home/ferd/code/learn-you-some-erlang/m8ball/logs"}.
+
+{groups, a, root, dist_m8ball_SUITE, main}.
+{groups, b, root, dist_m8ball_SUITE, backup}.
diff --git a/learn-you-some-erlang/m8ball/test/m8ball_server_SUITE.erl b/learn-you-some-erlang/m8ball/test/m8ball_server_SUITE.erl
new file mode 100644
index 0000000..6bc4156
--- /dev/null
+++ b/learn-you-some-erlang/m8ball/test/m8ball_server_SUITE.erl
@@ -0,0 +1,45 @@
+-module(m8ball_server_SUITE).
+-include_lib("common_test/include/ct.hrl").
+-export([all/0, init_per_testcase/2, end_per_testcase/2]).
+-export([random_answer/1, binary_answer/1, determined_answers/1,
+ reload_answers/1]).
+
+all() -> [random_answer, binary_answer, determined_answers,
+ reload_answers].
+
+init_per_testcase(_Test, Config) ->
+ Answers = [<<"Outlook not so good">>,
+ <<"I don't think so">>,
+ <<"Yes, definitely">>,
+ <<"STOP SHAKING ME">>],
+ application:set_env(m8ball, answers, list_to_tuple(Answers)),
+ m8ball_server:start_link(),
+ [{answers, Answers} | Config].
+
+end_per_testcase(_Test, _Config) ->
+ m8ball_server:stop().
+
+%% The answer should come from the config
+random_answer(_Config) ->
+ Answers1 = [m8ball_server:ask("Dummy question") || _ <- lists:seq(1,15)],
+ Answers2 = [m8ball_server:ask("Dummy question") || _ <- lists:seq(1,15)],
+ true = 1 < length(sets:to_list(sets:from_list(Answers1))),
+ true = Answers1 =/= Answers2.
+
+binary_answer(_Config) ->
+ Answers = [m8ball_server:ask("Dummy question") || _ <- lists:seq(1,15)],
+ L = length(Answers),
+ L = length(lists:filter(fun erlang:is_binary/1, Answers)).
+
+determined_answers(Config) ->
+ Answers = ?config(answers, Config),
+ Res = [m8ball_server:ask("Dummy question") || _ <- lists:seq(1,15)],
+ true = lists:all(fun(X) -> lists:member(X, Answers) end, Res).
+
+reload_answers(_Config) ->
+ Ref = make_ref(),
+ application:set_env(m8ball, answers, {Ref}),
+ [Ref,Ref,Ref] = [m8ball_server:ask("Question") || _ <- lists:seq(1,3)].
+
+
+%% NOTE: do distributed testing in m8ball_SUITE or something