Skip to content

Instantly share code, notes, and snippets.

@davisp
Created June 25, 2009 02:11
Show Gist options
  • Save davisp/135646 to your computer and use it in GitHub Desktop.
Save davisp/135646 to your computer and use it in GitHub Desktop.
diff --git a/.gitignore b/.gitignore
index ea1f975..70788fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+
+# copied from jChirs .gitignore
*.beam
*.gz
*.tpl
@@ -6,6 +8,7 @@
*.m4
*.in
*.in~
+
erl_crash.dump
configure
autom4te.cache
@@ -27,7 +30,9 @@ etc/launchd/Makefile
etc/logrotate.d/Makefile
libtool
share/Makefile
+
src/couchdb/.deps/*
+
src/couchdb/Makefile
src/mochiweb/Makefile
stamp-h1
@@ -35,8 +40,10 @@ test/.deps/
test/Makefile
var/Makefile
+
# for make
+
bin/couchdb
bin/couchdb.1
bin/couchjs
@@ -44,7 +51,9 @@ bin/couchjs.1
etc/couchdb/default.ini
etc/launchd/org.apache.couchdb.plist
etc/logrotate.d/couchdb
+
src/couchdb/.libs/*
+
src/couchdb/couch.app
src/couchdb/couch_erl_driver.la
src/couchdb/couchjs
@@ -52,18 +61,22 @@ src/couchdb/edoc-info
src/couchdb/erlang.png
src/couchdb/stylesheet.css
test/local.ini
+
share/server/main.js
# for make dev
+
bin/.deps/
bin/couchjs_dev
bin/couchpw
etc/couchdb/default_dev.ini
etc/couchdb/local_dev.ini
utils/run
+
tmp
+
# for make check
test/etap/temp.*
@@ -71,3 +84,4 @@ test/etap/temp.*
# for make cover
cover/*
+
diff --git a/src/couchdb/couch_task_status.erl b/src/couchdb/couch_task_status.erl
index a0ef490..384d673 100644
--- a/src/couchdb/couch_task_status.erl
+++ b/src/couchdb/couch_task_status.erl
@@ -19,7 +19,7 @@
% 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,
+-export([start_link/0,stop/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]).
-include("couch_db.hrl").
@@ -27,6 +27,9 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+stop() ->
+ gen_server:cast(?MODULE, stop).
+
to_binary(L) when is_list(L) ->
?l2b(L);
to_binary(B) when is_binary(B) ->
@@ -57,11 +60,7 @@ update(Format, Data) ->
% 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)].
+ gen_server:call(?MODULE,{all}).
init([]) ->
% read configuration settings and register for configuration changes
@@ -80,14 +79,26 @@ handle_call({add_task,Type,TaskName,StatusText}, {From, _}, Server) ->
{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(tasks_by_pid)],
+ {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}.
+ {noreply, Server};
+
+handle_cast(stop, State) ->
+ {stop, normal, State}.
handle_info({'DOWN', _MonitorRef, _Type, Pid, _Info}, Server) ->
+ %% should we also erlang:demonitor(_MonitorRef), ?
ets:delete(tasks_by_pid, Pid),
{noreply, Server}.
diff --git a/test/etap/090-task-status.t b/test/etap/090-task-status.t
new file mode 100755
index 0000000..de7a28a
--- /dev/null
+++ b/test/etap/090-task-status.t
@@ -0,0 +1,136 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+main(_) ->
+ code:add_pathz("src/couchdb"),
+ etap:plan(12),
+
+ 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} ->
+ couch_task_status:add_task("type","task","init"),
+ From ! {ok, self()},
+ loop();
+ {update, Status, From} ->
+ couch_task_status:update(Status),
+ From ! {ok, self()},
+ loop();
+ {update_frequency, Msecs, From} ->
+ couch_task_status:set_update_frequency(Msecs),
+ From ! {ok, self()},
+ loop();
+ {done, From} ->
+ From ! {ok, self()}
+ end.
+
+call(Pid, Command) ->
+ Pid ! {Command, self()},
+ wait().
+
+call(Pid, Command, Arg) ->
+ Pid ! {Command, Arg, self()},
+ wait().
+
+wait() ->
+ receive
+ _ -> ok
+ after 1000 ->
+ etap:is(true, false, "Timed out waiting for pid to respond.")
+ 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),
+ % add the first
+ call(Pid1,add),
+
+ etap:is(length(couch_task_status:all()),1,"one task is running."),
+ etap:is(check_status(Pid1,couch_task_status:all()),<<"init">>,
+ "status should be initialized."),
+
+ call(Pid1,update,"running"),
+
+ etap:is(check_status(Pid1,couch_task_status:all()),<<"running">>,
+ "status should be running."),
+
+ call(Pid2,add),
+ etap:is(length(couch_task_status:all()),2,"two tasks are running."),
+ etap:is(check_status(Pid2,couch_task_status:all()),<<"init">>,
+ "status of second should be initialized."),
+ call(Pid2,update,"running"),
+ etap:is(check_status(Pid2,couch_task_status:all()),<<"running">>,
+ "status should be running."),
+
+
+ call(Pid3,add),
+ etap:is(length(couch_task_status:all()),3,"two tasks are running."),
+ etap:is(check_status(Pid3,couch_task_status:all()),<<"init">>,
+ "status of second should be initialized."),
+ call(Pid3,update,"running"),
+ etap:is(check_status(Pid3,couch_task_status:all()),<<"running">>,
+ "status should be running."),
+
+
+ call(Pid3,update_frequency,500),
+ call(Pid3,update,"still running"),
+ etap:is(check_status(Pid3,couch_task_status:all()),<<"still running">>,
+ "status should be running."),
+
+ call(Pid3,update,"are we there yet daddy"),
+ etap:is(check_status(Pid3,couch_task_status:all()),<<"still running">>,
+ "no we're not there yet."),
+
+ call(Pid3,update_frequency,0),
+ call(Pid3,update,"are we there"),
+ etap:is(check_status(Pid3,couch_task_status:all()),<<"are we there">>,
+ "status should now be are we there."),
+
+
+ call(Pid1,done),
+ etap:is(length(couch_task_status:all()),2,"two tasks are running."),
+
+ call(Pid2,done),
+ etap:is(length(couch_task_status:all()),1,"one tasks is running."),
+ call(Pid3,done),
+ etap:is(length(couch_task_status:all()),0,"no tasks are running."),
+
+ % test gen_server stop
+ erlang:monitor(process, TaskStatusPid),
+ couch_task_status:stop(),
+ receive
+ {'DOWN', _, _, TaskStatusPid, _} ->
+ etap:diag("task_status stopped",[]),
+ ok;
+ _Other -> etap:diag("OTHER: ~p~n", [_Other])
+ after
+ 1000 -> throw({timeout_error, task_status_stop})
+ end,
+
+ ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment