Permalink
Browse files

initial offline table can be fill from a csv file

  • Loading branch information...
1 parent 65fbba6 commit 55fc3250fc5f6b1892703d6bf343ee19045988c2 @nniclausse nniclausse committed Feb 25, 2013
View
@@ -96,7 +96,7 @@
<!--CUT DEF section 1 --><H1 ALIGN=center>Tsung User’s manual</H1><DIV CLASS="center">
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Version:</TD><TD ALIGN=left NOWRAP>1.5.0</TD></TR>
-<TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Date :</TD><TD ALIGN=left NOWRAP>February 22, 2013</TD></TR>
+<TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Date :</TD><TD ALIGN=left NOWRAP>February 25, 2013</TD></TR>
</TABLE>
</DIV><!--TOC section Contents-->
<H2 CLASS="section"><!--SEC ANCHOR -->Contents</H2><!--SEC END --><UL CLASS="toc"><LI CLASS="li-toc">
@@ -1471,7 +1471,8 @@ <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc54">6.5.1</A>  XMPP/J
</LI><LI CLASS="li-itemize">domain = erlang-projects.org
</LI><LI CLASS="li-itemize">username = tsunguser
</LI><LI CLASS="li-itemize">passwd = sesame
-</LI></UL><P>You can also set the <TT>muc_service</TT> here (see previous example).</P><!--TOC subsubsection HTTP options-->
+</LI></UL><P>Other options are available if you prefer to use a CSV file for
+username/password, see  <A HREF="#sec:read-user-jabber-csv">6.6.3</A>.</P><P>You can also set the <TT>muc_service</TT> here (see previous example).</P><!--TOC subsubsection HTTP options-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc55">6.5.2</A>  HTTP options</H4><!--SEC END --><P>For HTTP, you can set the <TT>UserAgent</TT> values
(<B>available since Tsung 1.1.0</B>), using a probability for each
value (the sum of all probabilities must be equal to 100)</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
@@ -2077,7 +2078,9 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->VHost</H5><!--SEC END --><P>VHost suppor
</TABLE></TD></TR>
</TABLE><P>When each client starts a session, it chooses randomly a domain (each domain has the
same probability).</P><!--TOC paragraph Reading usernames and password from a CSV file-->
-<H5 CLASS="paragraph"><!--SEC ANCHOR -->Reading usernames and password from a CSV file</H5><!--SEC END --><P>Since version 1.4.0, you can now use a CSV file to store the usernames
+<H5 CLASS="paragraph"><!--SEC ANCHOR -->Reading usernames and password from a CSV file</H5><!--SEC END --><P>
+<A NAME="sec:read-user-jabber-csv"></A>
+Since version 1.4.0, you can now use a CSV file to store the usernames
and password.</P><P>Configure the CSV file:
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
@@ -2143,7 +2146,7 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->Reading usernames and password from a CS
</TABLE><P>Moreover (since <B>1.5.0</B>), when using chat messages to random or offline users, you
should disable the default users (not from CSV) by setting
<TT>userid_max</TT> to <FONT COLOR=purple>0</FONT> and by setting the fileid for
-random users (also used for pubsub) server:
+offline and random users (also used for pubsub):
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
@@ -2153,6 +2156,7 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->Reading usernames and password from a CS
</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim"> &lt;options&gt;
&lt;option type="ts_jabber" name="userid_max" value="0" /&gt;
&lt;option type="ts_jabber" name="random_from_fileid" value='userdb'/&gt;
+ &lt;option type="ts_jabber" name="offline_from_fileid" value='userdb'/&gt;
&lt;option type="ts_jabber" name="delimiter" value=";"/&gt;
&lt;/options&gt;
</PRE></TD></TR>
@@ -2163,7 +2167,7 @@ <H5 CLASS="paragraph"><!--SEC ANCHOR -->Reading usernames and password from a CS
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
-</TABLE><P>The username should be the first entry in the each CSV line (the
+</TABLE><P>The username (resp. passwd) should be the first (resp. second) entry in the each CSV line (the
delimiter is by default <FONT COLOR=purple>";"</FONT> and can be overriden).</P><!--TOC paragraph raw XML-->
<H5 CLASS="paragraph"><!--SEC ANCHOR -->raw XML</H5><!--SEC END --><P>
You can send raw XML data to the server using the <TT>raw</TT> type:
View
@@ -1186,6 +1186,10 @@ \subsubsection{XMPP/Jabber options}
\item passwd = sesame
\end{itemize}
+Other options are available if you prefer to use a CSV file for
+username/password, see ~\ref{sec:read-user-jabber-csv}.
+
+
You can also set the \varname{muc\_service} here (see previous example).
\subsubsection{HTTP options}
@@ -1671,7 +1675,7 @@ \subsubsection{Jabber/XMPP}
same probability).
\paragraph{Reading usernames and password from a CSV file}
-
+\label{sec:read-user-jabber-csv}
Since version 1.4.0, you can now use a CSV file to store the usernames
and password.
@@ -1720,16 +1724,17 @@ \subsubsection{Jabber/XMPP}
Moreover (since \strong{1.5.0}), when using chat messages to random or offline users, you
should disable the default users (not from CSV) by setting
\varname{userid\_max} to \userinput{0} and by setting the fileid for
-random users (also used for pubsub) server:
+offline and random users (also used for pubsub):
\begin{Verbatim}
<options>
<option type="ts_jabber" name="userid_max" value="0" />
<option type="ts_jabber" name="random_from_fileid" value='userdb'/>
+ <option type="ts_jabber" name="offline_from_fileid" value='userdb'/>
<option type="ts_jabber" name="delimiter" value=";"/>
</options>
\end{Verbatim}
-The username should be the first entry in the each CSV line (the
+The username (resp. passwd) should be the first (resp. second) entry in the each CSV line (the
delimiter is by default \userinput{";"} and can be overriden).
\paragraph{raw XML}
@@ -1 +1 @@
-user1
+user1;sesame
@@ -33,7 +33,7 @@ config_file_server2_test()->
config_file_server3_test()->
myset_env(),
- ?assertMatch({ok,<< "user1">> }, ts_file_server:get_next_line(user)).
+ ?assertMatch({ok,<< "user1;sesame">> }, ts_file_server:get_next_line(user)).
config_file_server4_test()->
myset_env(),
@@ -184,6 +184,8 @@ get_unique_user_defined_test()-> % this test must be runned just after get_offli
Res = "<message id='3' to='tsung1@domain.org' type='chat'><body>hello</body></message>",
?assertEqual(Res, binary_to_list(Msg) ).
+
+
get_unique_test()->
ts_user_server:reset(2),
Id=ts_user_server:get_idle(),
@@ -209,9 +211,31 @@ get_random_user_defined_test()->
Res = "<message id='6' to='user1@domain.org' type='chat'><body>hello</body></message>",
?assertEqual(Res, binary_to_list(Msg) ).
+get_offline_user_defined_offline_test()->
+ Id = xmpp,
+ ts_user_server:set_offline_fileid(Id),
+ ts_user_server:reset(0),
+ User1 = "tsung1",
+ Pwd = "sesame",
+ ts_user_server:add_to_connected({User1,Pwd}),
+ ts_user_server:add_to_online(default, ts_jabber_common:set_id(user_defined,User1, Pwd) ),
+ Msg = ts_jabber_common:get_message(#jabber{type = 'chat', prefix="prefix", data="hello", dest = offline, user_server=default, domain="domain.org"}),
+ Res = "<message id='7' to='user1@domain.org' type='chat'><body>hello</body></message>",
+ ?assertEqual(Res, binary_to_list(Msg) ).
+get_offline_user_defined_no_offline_test()->
+ ts_user_server:reset(0),
+ User1 = "user1",
+ Pwd = "sesame",
+ ts_user_server:add_to_connected({User1,Pwd}),
+ ts_user_server:add_to_online(default, ts_jabber_common:set_id(user_defined,User1, Pwd) ),
+ Msg = ts_jabber_common:get_message(#jabber{type = 'chat', prefix="prefix", data="hello", dest = offline, user_server=default, domain="domain.org"}),
+ %% Res = "<message id='8' to='user1@domain.org' type='chat'><body>hello</body></message>",
+ Res = "",
+ ts_user_server:set_offline_fileid(undefined),
+ ?assertEqual(Res, binary_to_list(Msg) ).
myset_env()->
myset_env(0).
@@ -23,7 +23,7 @@ next_test() ->
ts_user_server:reset(100),
ts_user_server:get_idle(),
B=ts_user_server:get_idle(),
- ?assertMatch(B,2).
+ ?assertEqual(2,B).
remove_test() ->
myset_env(),
@@ -33,7 +33,7 @@ remove_test() ->
B=ts_user_server:get_idle(),
ts_user_server:remove_connected(B),
C=ts_user_server:get_idle(),
- ?assertMatch(C,3).
+ ?assertEqual(3,C).
full_offline_test() ->
myset_env(),
@@ -65,8 +65,8 @@ full_free_offline_refull_test() ->
{error,no_free_userid}=ts_user_server:get_idle(),
ts_user_server:remove_connected(A),
ts_user_server:remove_connected(B),
- A=ts_user_server:get_idle(),
- ?assertMatch(B,ts_user_server:get_idle()).
+ B=ts_user_server:get_idle(),
+ ?assertEqual(A,ts_user_server:get_idle()).
full_huge_offline_test() ->
myset_env(),
@@ -111,4 +111,6 @@ online_full_test() ->
?assertMatch({error,no_online},ts_user_server:get_online(B)).
myset_env()->
- application:set_env(stdlib,debug_level,0).
+ myset_env(0).
+myset_env(A)->
+ application:set_env(stdlib,debug_level,A).
@@ -199,6 +199,12 @@ parse_config(Element = #xmlElement{name=option}, Conf = #config{session_tab = Ta
ts_user_server:set_random_fileid(FileId),
Conf;
+ "offline_from_fileid" ->
+ FileId = ts_config:getAttr(atom,Element#xmlElement.attributes, value, none),
+ ?LOGF("set offline fileid to ~p~n",[FileId],?WARN),
+
+ ts_user_server:set_offline_fileid(FileId),
+ Conf;
"fileid_delimiter" ->
D = ts_config:getAttr(string,Element#xmlElement.attributes, value, ";"),
ts_user_server:set_fileid_delimiter(D),
@@ -269,7 +269,7 @@ handle_call(get_id, _From, State=#state{random_server_id = Id, delimiter=D}) whe
{ok, Line} ->
[Val|_] = ts_utils:split(Line,D),
{reply, {binary_to_list(Val), unused}, State}; %% FIXME: use binaries in jabber_common everywhere and remove the binary_to_list call here.
- Else ->
+ _Else ->
{reply, {error, userid_max_zero }, State}
end;
handle_call(get_id, _From, State=#state{userid_max = 0}) ->
@@ -281,13 +281,12 @@ handle_call(get_id, _From, State) ->
%%Get one id in the users whos have to be connected
handle_call(get_idle, _From, State=#state{offline=Offline,connected=Connected}) ->
- case State#state.last_offline of
- undefined ->
+ case ets_iterator_next(Offline, State#state.last_offline ) of
+ {error, empty_ets} ->
?LOG("No more free users !~n", ?WARN),
{reply, {error, no_free_userid}, State};
- Key when is_integer(Key) ->
- {ok,NextOffline} = ets_iterator_del(Offline,Key,State#state.last_offline),
- ?DebugF("New nextoffline is ~p~n",[NextOffline]),
+ {ok, Key} ->
+ NextOffline = ets_iterator_del(Offline, Key, State#state.last_offline),
ets:insert(Connected, {Key,1}),
case State#state.first_client of
undefined ->
@@ -296,10 +295,7 @@ handle_call(get_idle, _From, State=#state{offline=Offline,connected=Connected})
_Id ->
{reply, Key, State#state{last_connected=Key,
last_offline=NextOffline}}
- end;
- Error ->
- ?LOGF("Error when get idle ~p~n",[Error],?ERR),
- {reply, {error, no_free_userid}, State}
+ end
end;
%%Get one offline id
@@ -308,11 +304,11 @@ handle_call(get_offline, _From, State=#state{offline=Offline,last_offline=Prev})
{error, _Reason} ->
{reply, {error, no_offline}, State};
{ok, {Next,Pwd}} ->
- ?DebugF("Choose (next is user defined) offline user ~p~n",[Prev]),
- {reply, {ok, Prev}, State#state{last_offline={Next,Pwd}}};
+ ?DebugF("Choose (next is user defined) offline user ~p~n",[Next]),
+ {reply, {ok, {Next,Pwd}}, State#state{last_offline={Next,Pwd}}};
{ok, Next} ->
?DebugF("Choose offline user ~p~n",[Prev]),
- {reply, {ok, Prev}, State#state{last_offline=Next}}
+ {reply, {ok, Next}, State#state{last_offline=Next}}
end;
handle_call(get_first, _From, State) ->
@@ -325,13 +321,9 @@ handle_call({reset, NFin}, _From, State) ->
?LOGF("Reset offline and online lists (maxid=~p)~n",[NFin],?NOTICE),
fill_offline(NFin, Offline, {State#state.offline_server_id, State#state.delimiter}),
- First = case ets:first(Offline) of
- '$end_of_table' -> undefined; % empty offline; can happen if we only use usernames from external file
- Val -> Val
- end,
State2 = State#state{offline = Offline,
first_client = undefined,
- last_offline = First,
+ last_offline = undefined,
connected = Connected,
last_connected = undefined,
last_online = undefined,
@@ -374,23 +366,25 @@ handle_cast({remove_connected, Id}, State=#state{online=Online,offline=Offline,c
{noreply, LastOnline} = ets_delete_online(Online,Id,State),
ets:delete(Connected,Id),
ets:insert(Offline, {Id,2}),
- case State#state.last_offline of
- undefined -> % Offline table was empty
+ case {State#state.last_offline,ets:first(Offline)} of
+ {undefined, Id} ->
+ %% if we don't set last_offline, the next get_idle will
+ %% respond with Id again. If possible we prefer to use
+ %% another offline user
{noreply, State#state{last_online=LastOnline, last_offline=Id}};
- _ ->
+ _Else ->
{noreply, State#state{last_online=LastOnline}}
end;
%% user_defined user case
-handle_cast({add_to_connected, Id}, State=#state{connected=Connected, first_client=First}) ->
- ?LOGF("Add ~p to connected list~n",[Id],?DEB),
+handle_cast({add_to_connected, Id}, State=#state{connected=Connected, offline=Offline,first_client=First}) ->
ets:insert(Connected, {Id,1}),
- %% FIXME: remove from offline if offline fileid is defined
+ NextOffline = ets_iterator_del(Offline, Id, State#state.last_offline),
case First of
undefined ->
- {noreply, State#state{last_connected=Id, first_client=Id}};
+ {noreply, State#state{last_connected=Id, first_client=Id, last_offline=NextOffline}};
_ ->
- {noreply, State#state{last_connected=Id}}
+ {noreply, State#state{last_connected=Id,last_offline=NextOffline}}
end;
handle_cast({add_to_online, Id}, State=#state{online=Online, connected=Connected}) ->
@@ -461,8 +455,8 @@ fill_offline(0, Offline, {FileId, Delimiter})->
{ok, Data} ->
?LOGF("offline user from csv ~p",[Data],?DEB),
Fun = fun(Line) ->
- User=hd(ts_utils:split(Line,Delimiter)),
- ets:insert(Offline,{{User,""},1})
+ [User,Pwd| _]= ts_utils:split(Line,Delimiter),
+ ets:insert(Offline,{{binary_to_list(User),binary_to_list(Pwd)},1})
end,
lists:foreach(Fun, Data),
ok;
@@ -478,27 +472,29 @@ fill_offline(N, Tab, Opts) when is_integer(N) ->
%%% Func: ets_iterator_del/3
%%% Args: Ets, Key, Iterator
%%% Purpose: delete entry Key from Ets, update iterator if needed
-%%% Returns: {ok, Key} or {ok, undefined}
+%%% Returns: Key:: integer | {string(),string()}|undefined
%%%----------------------------------------------------------------------
-% iterator equal key:it will no longer be valid
+%% iterator equal key:it will no longer be valid
ets_iterator_del(Ets, Key, Key) ->
- Next = ets:next(Ets,Key),
+ Last = ets:prev(Ets,Key),
ets:delete(Ets,Key),
- case Next of
+ case Last of
'$end_of_table' ->
case ets:first(Ets) of
'$end_of_table' ->
- {ok, undefined};
+ undefined;
+ Key ->
+ undefined;
NewIter ->
- {ok, NewIter}
+ NewIter
end;
NewIter ->
- {ok, NewIter}
+ NewIter
end;
ets_iterator_del(Ets, Key, Iterator) ->
ets:delete(Ets,Key),
- {ok, Iterator}.
+ Iterator.
%%%----------------------------------------------------------------------
%%% Func: ets_iterator_next/2
@@ -512,7 +508,7 @@ ets_iterator_next(Ets, Iterator) ->
%%%----------------------------------------------------------------------
%%% Func: ets_iterator_next/3
%%% Args: Ets, Iterator, Key
-%%% Purpose: get next key, must be different from 'Key'
+%%% Purpose: get next key, should be different from 'Key', if possible
%%%----------------------------------------------------------------------
ets_iterator_next(Ets, undefined, Key) ->
case ets:first(Ets) of
@@ -521,7 +517,8 @@ ets_iterator_next(Ets, undefined, Key) ->
Key ->
case ets:next(Ets,Key) of
'$end_of_table' ->
- {error, empty_ets};
+ %% Key is the only entry of offline table
+ {ok, Key};
Iter ->
{ok, Iter}
end;
@@ -548,7 +545,7 @@ ets_delete_online(Online,Id,State) ->
[] ->
{noreply, State#state.last_online};
[_|_] ->
- {ok, LastOnline} = ets_iterator_del(Online,Id,State#state.last_online),
+ LastOnline = ets_iterator_del(Online,Id,State#state.last_online),
%% reset the last_online entries if it's equal to Id
case State#state.last_online of
Id ->

0 comments on commit 55fc325

Please sign in to comment.