You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2009/06/25 05:59:48 UTC

svn commit: r788246 - in /couchdb/trunk: src/couchdb/couch_task_status.erl src/couchdb/couch_util.erl test/etap/090-task-status.t

Author: davisp
Date: Thu Jun 25 03:59:47 2009
New Revision: 788246

URL: http://svn.apache.org/viewvc?rev=788246&view=rev
Log:
Adding tests for couch_task_status.erl

Thanks Bob Dionne


Added:
    couchdb/trunk/test/etap/090-task-status.t   (with props)
Modified:
    couchdb/trunk/src/couchdb/couch_task_status.erl
    couchdb/trunk/src/couchdb/couch_util.erl

Modified: couchdb/trunk/src/couchdb/couch_task_status.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_task_status.erl?rev=788246&r1=788245&r2=788246&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_task_status.erl (original)
+++ couchdb/trunk/src/couchdb/couch_task_status.erl Thu Jun 25 03:59:47 2009
@@ -19,79 +19,106 @@
 % it will be automatically removed the tracking. To get the tasks list, use the
 % all/0 function
 
--export([start_link/0,init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,
-    code_change/3,add_task/3,update/1,update/2,all/0,set_update_frequency/1]).
+-export([start_link/0, stop/0]).
+-export([all/0, add_task/3, update/1, update/2, set_update_frequency/1]).
+
+-export([init/1, terminate/2, code_change/3]).
+-export([handle_call/3, handle_cast/2, handle_info/2]).
+
+-import(couch_util, [to_binary/1]).
 
 -include("couch_db.hrl").
-    
+
+
 start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 
-to_binary(L) when is_list(L) ->
-    ?l2b(L);
-to_binary(B) when is_binary(B) ->
-    B.
+
+stop() ->
+    gen_server:cast(?MODULE, stop).
+
+
+all() ->
+    gen_server:call(?MODULE, all).
+
 
 add_task(Type, TaskName, StatusText) ->
-    put(task_status_update, {{0,0,0}, 0}),
-    gen_server:call(?MODULE, {add_task, to_binary(Type),
-            to_binary(TaskName), to_binary(StatusText)}).
+    put(task_status_update, {{0, 0, 0}, 0}),
+    Msg = {
+        add_task,
+        to_binary(Type),
+        to_binary(TaskName),
+        to_binary(StatusText)
+    },
+    gen_server:call(?MODULE, Msg).
+
 
 set_update_frequency(Msecs) ->
-    put(task_status_update, {{0,0,0}, Msecs * 1000}).
+    put(task_status_update, {{0, 0, 0}, Msecs * 1000}).
+
 
 update(StatusText) ->
     update("~s", [StatusText]).
     
 update(Format, Data) ->
     {LastUpdateTime, Frequency} = get(task_status_update),
-    
     case timer:now_diff(Now = now(), LastUpdateTime) >= Frequency of
     true ->
         put(task_status_update, {Now, Frequency}),
-        gen_server:cast(?MODULE, {update_status, self(), ?l2b(io_lib:format(Format, Data))});
+        Msg = ?l2b(io_lib:format(Format, Data)),
+        gen_server:cast(?MODULE, {update_status, self(), Msg});
     false ->
         ok
     end.
-    
 
-% returns a list of proplists. Each proplist describes a running task.
-all() ->
-    [[{type,Type},
-        {task,Task},
-        {status,Status},
-        {pid,?l2b(pid_to_list(Pid))}] ||
-            {Pid, {Type,Task,Status}} <- ets:tab2list(tasks_by_pid)].
-    
+
 init([]) ->
     % read configuration settings and register for configuration changes
-    ets:new(tasks_by_pid, [ordered_set, protected, named_table]),
+    ets:new(?MODULE, [ordered_set, protected, named_table]),
     {ok, nil}.
 
+
 terminate(_Reason,_State) ->
     ok.
 
 
-handle_call({add_task,Type,TaskName,StatusText}, {From, _}, Server) ->
-    case ets:lookup(tasks_by_pid, From) of
+handle_call({add_task, Type, TaskName, StatusText}, {From, _}, Server) ->
+    case ets:lookup(?MODULE, From) of
     [] ->
-        true = ets:insert(tasks_by_pid, {From,{Type,TaskName,StatusText}}),
+        true = ets:insert(?MODULE, {From, {Type, TaskName, StatusText}}),
         erlang:monitor(process, From),
         {reply, ok, Server};
     [_] ->
         {reply, {add_task_error, already_registered}, Server}
-    end.
-    
+    end;
+handle_call(all, _, Server) ->
+    All = [
+        [
+            {type, Type},
+	        {task, Task},
+	        {status, Status},
+	        {pid, ?l2b(pid_to_list(Pid))}
+        ]
+        ||
+	    {Pid, {Type, Task, Status}} <- ets:tab2list(?MODULE)
+    ],
+    {reply, All, Server}.
+
+
 handle_cast({update_status, Pid, StatusText}, Server) ->
-    [{Pid, {Type,TaskName,_StatusText}}] = ets:lookup(tasks_by_pid, Pid),
-    true = ets:insert(tasks_by_pid, {Pid, {Type,TaskName,StatusText}}),
-    {noreply, Server}.
+    [{Pid, {Type, TaskName, _StatusText}}] = ets:lookup(?MODULE, Pid),
+    true = ets:insert(?MODULE, {Pid, {Type, TaskName, StatusText}}),
+    {noreply, Server};
+handle_cast(stop, State) ->
+    {stop, normal, State}.
+
 
 handle_info({'DOWN', _MonitorRef, _Type, Pid, _Info}, Server) ->
-    ets:delete(tasks_by_pid, Pid),
+    %% should we also erlang:demonitor(_MonitorRef), ?
+    ets:delete(?MODULE, Pid),
     {noreply, Server}.
 
+
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
-

Modified: couchdb/trunk/src/couchdb/couch_util.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_util.erl?rev=788246&r1=788245&r2=788246&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_util.erl (original)
+++ couchdb/trunk/src/couchdb/couch_util.erl Thu Jun 25 03:59:47 2009
@@ -13,11 +13,12 @@
 -module(couch_util).
 
 -export([start_driver/1,terminate_linked/1]).
--export([should_flush/0, should_flush/1, to_existing_atom/1, to_binary/1]).
+-export([should_flush/0, should_flush/1, to_existing_atom/1]).
 -export([new_uuid/0, rand32/0, implode/2, collate/2, collate/3]).
 -export([abs_pathname/1,abs_pathname/2, trim/1, ascii_lower/1]).
 -export([encodeBase64/1, decodeBase64/1, to_hex/1,parse_term/1,dict_find/3]).
 -export([file_read_size/1]).
+-export([to_binary/1, to_list/1]).
 
 -include("couch_db.hrl").
 -include_lib("kernel/include/file.hrl").
@@ -67,19 +68,6 @@
 to_digit(N)             -> $a + N-10.
 
 
-to_binary(V) when is_binary(V) ->
-    V;
-to_binary(V) when is_list(V) -> 
-    try list_to_binary(V)
-    catch
-        _ -> list_to_binary(io_lib:format("~p", [V]))
-    end;
-to_binary(V) when is_atom(V) ->
-    list_to_binary(atom_to_list(V));
-to_binary(V) ->
-    list_to_binary(io_lib:format("~p", [V])).
-
-
 parse_term(Bin) when is_binary(Bin)->
     parse_term(binary_to_list(Bin));
 parse_term(List) ->
@@ -301,3 +289,26 @@
             FileInfo#file_info.size;
         Error -> Error
     end.
+
+to_binary(V) when is_binary(V) ->
+    V;
+to_binary(V) when is_list(V) ->
+    try
+        list_to_binary(V)
+    catch
+        _ ->
+            list_to_binary(io_lib:format("~p", [V]))
+    end;
+to_binary(V) when is_atom(V) ->
+    list_to_binary(atom_to_list(V));
+to_binary(V) ->
+    list_to_binary(io_lib:format("~p", [V])).
+
+to_list(V) when is_list(V) ->
+    V;
+to_list(V) when is_binary(V) ->
+    binary_to_list(V);
+to_list(V) when is_atom(V) ->
+    atom_to_list(V);
+to_list(V) ->
+    lists:flatten(io_lib:format("~p", [V])).

Added: couchdb/trunk/test/etap/090-task-status.t
URL: http://svn.apache.org/viewvc/couchdb/trunk/test/etap/090-task-status.t?rev=788246&view=auto
==============================================================================
--- couchdb/trunk/test/etap/090-task-status.t (added)
+++ couchdb/trunk/test/etap/090-task-status.t Thu Jun 25 03:59:47 2009
@@ -0,0 +1,197 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+main(_) ->
+    code:add_pathz("src/couchdb"),
+    etap:plan(16),
+    case (catch test()) of
+        ok ->
+            etap:end_tests();
+        Other ->
+            etap:diag(io_lib:format("Test died abnormally: ~p", [Other])),
+            etap:bail(Other)
+    end,
+    ok.
+
+check_status(Pid,ListPropLists) ->
+    From = list_to_binary(pid_to_list(Pid)),
+    Element = lists:foldl(
+        fun(PropList,Acc) ->
+	        case proplists:get_value(pid,PropList) of
+			    From ->
+                    [PropList | Acc];
+				_ ->
+                    []
+			end
+		end,
+        [], ListPropLists
+    ),
+    proplists:get_value(status,hd(Element)).
+
+loop() ->
+    receive
+	{add, From} ->
+	    Resp = couch_task_status:add_task("type", "task", "init"),
+	    From ! {ok, self(), Resp},
+	    loop();
+	{update, Status, From} ->
+	    Resp = couch_task_status:update(Status),
+	    From ! {ok, self(), Resp},
+	    loop();
+	{update_frequency, Msecs, From} ->
+	    Resp = couch_task_status:set_update_frequency(Msecs),
+	    From ! {ok, self(), Resp},
+	    loop();
+	{done, From} ->
+	    From ! {ok, self(), ok}
+    end.
+
+call(Pid, Command) ->
+    Pid ! {Command, self()},
+    wait(Pid).
+
+call(Pid, Command, Arg) ->
+    Pid ! {Command, Arg, self()},
+    wait(Pid).
+
+wait(Pid) ->
+    receive
+        {ok, Pid, Msg} -> Msg
+    after 1000 ->
+        throw(timeout_error)
+    end.    
+
+test() ->   
+    {ok, TaskStatusPid} = couch_task_status:start_link(),
+    
+    TaskUpdater = fun() -> loop() end,
+    % create three updaters
+    Pid1 = spawn(TaskUpdater),
+    Pid2 = spawn(TaskUpdater),
+    Pid3 = spawn(TaskUpdater),
+
+    ok = call(Pid1, add),
+    etap:is(
+        length(couch_task_status:all()),
+        1,
+        "Started a task"
+    ),
+
+    etap:is(
+        call(Pid1, add),
+        {add_task_error, already_registered},
+        "Unable to register multiple tasks for a single Pid."
+    ),
+
+    etap:is(
+        check_status(Pid1, couch_task_status:all()),
+        <<"init">>,
+		"Task status was set to 'init'."
+    ),
+
+    call(Pid1,update,"running"),
+    etap:is(
+        check_status(Pid1,couch_task_status:all()),
+        <<"running">>,
+		"Status updated to 'running'."
+	),
+
+
+    call(Pid2,add),
+    etap:is(
+        length(couch_task_status:all()),
+        2,
+        "Started a second task."
+    ),
+    
+    etap:is(
+        check_status(Pid2, couch_task_status:all()),
+        <<"init">>,
+		"Second tasks's status was set to 'init'."
+	),
+	
+    call(Pid2, update, "running"),
+    etap:is(
+        check_status(Pid2, couch_task_status:all()),
+        <<"running">>,
+		"Second task's status updated to 'running'."
+	),
+
+
+    call(Pid3, add),
+    etap:is(
+        length(couch_task_status:all()),
+        3,
+        "Registered a third task."
+    ),
+    
+    etap:is(
+        check_status(Pid3, couch_task_status:all()),
+        <<"init">>,
+		"Third tasks's status was set to 'init'."
+	),
+	
+    call(Pid3, update, "running"),
+    etap:is(
+        check_status(Pid3, couch_task_status:all()),
+        <<"running">>,
+		"Third task's status updated to 'running'."
+	),
+
+
+    call(Pid3, update_frequency, 500),
+    call(Pid3, update, "still running"),
+    etap:is(
+        check_status(Pid3, couch_task_status:all()),
+        <<"still running">>,
+		"Third task's status updated to 'still running'."
+	),
+
+    call(Pid3, update, "skip this update"),
+    etap:is(
+        check_status(Pid3, couch_task_status:all()),
+        <<"still running">>,
+		"Status update dropped because of frequency limit."
+	),
+
+    call(Pid3, update_frequency, 0),
+    call(Pid3, update, "don't skip"),
+    etap:is(
+        check_status(Pid3, couch_task_status:all()),
+        <<"don't skip">>,
+		"Status updated after reseting frequency limit."
+	),
+
+
+    call(Pid1, done),
+    etap:is(
+        length(couch_task_status:all()),
+        2,
+        "First task finished."
+    ),
+    
+    call(Pid2, done),
+    etap:is(
+        length(couch_task_status:all()),
+        1,
+        "Second task finished."
+    ),
+    
+    call(Pid3, done),
+    etap:is(
+        length(couch_task_status:all()),
+        0,
+        "Third task finished."
+    ),
+
+    erlang:monitor(process, TaskStatusPid),
+    couch_task_status:stop(),
+    receive
+        {'DOWN', _, _, TaskStatusPid, _} ->
+            ok
+    after
+        1000 ->
+            throw(timeout_error)
+    end,
+
+    ok.

Propchange: couchdb/trunk/test/etap/090-task-status.t
------------------------------------------------------------------------------
    svn:executable = *