diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | src/couchdb/couch_config.erl | 186 | ||||
-rwxr-xr-x | test/etap/031-doc-to-json.t | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/040-util.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/050-stream.t | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/060-kt-merging.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/061-kt-missing-leaves.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/062-kt-remove-leaves.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/063-kt-get-leaves.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/064-kt-counting.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/065-kt-stemming.t | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | test/etap/070-couch-db.t | 0 | ||||
-rwxr-xr-x | test/etap/080-config-get-set.t | 116 | ||||
-rw-r--r-- | test/etap/081-config-override.1.ini | 5 | ||||
-rw-r--r-- | test/etap/081-config-override.2.ini | 5 | ||||
-rwxr-xr-x | test/etap/081-config-override.t | 200 | ||||
-rwxr-xr-x | test/etap/082-config-register.t | 75 | ||||
-rwxr-xr-x | test/etap/083-config-no-files.t | 43 |
18 files changed, 553 insertions, 85 deletions
diff --git a/Makefile.am b/Makefile.am index bb4b4d24..2ba55310 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,10 +36,10 @@ README.gz: $(top_srcdir)/README THANKS.gz: $(top_srcdir)/THANKS -gzip -9 < $< > $@ -check: all +check: dev prove test/etap/*.t -cover: all +cover: dev rm -f cover/*.coverdata COVER=1 COVER_BIN=./src/couchdb/ prove test/etap/*.t SRC=./src/couchdb/ \ diff --git a/src/couchdb/couch_config.erl b/src/couchdb/couch_config.erl index dcdbc9eb..9a2e739a 100644 --- a/src/couchdb/couch_config.erl +++ b/src/couchdb/couch_config.erl @@ -10,42 +10,47 @@ % License for the specific language governing permissions and limitations under % the License. -%% @doc Reads CouchDB's ini file and gets queried for configuration parameters. -%% This module is initialized with a list of ini files that it -%% consecutively reads Key/Value pairs from and saves them in an ets -%% table. If more an one ini file is specified, the last one is used to -%% write changes that are made with store/2 back to that ini file. +% Reads CouchDB's ini file and gets queried for configuration parameters. +% This module is initialized with a list of ini files that it consecutively +% reads Key/Value pairs from and saves them in an ets table. If more an one +% ini file is specified, the last one is used to write changes that are made +% with store/2 back to that ini file. -module(couch_config). +-behaviour(gen_server). + -include("couch_db.hrl"). --behaviour(gen_server). --export([start_link/1, init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). --export([all/0, get/1, get/2, get/3, delete/2, set/3, set/4, register/1, - register/2, load_ini_file/1]). --record(config, - {notify_funs=[], - write_filename="" - }). +-export([start_link/1, stop/0]). +-export([all/0, get/1, get/2, get/3, set/3, set/4, delete/2, delete/3]). +-export([register/1, register/2]). +-export([parse_ini_file/1]). -%% Public API %% +-export([init/1, terminate/2, code_change/3]). +-export([handle_call/3, handle_cast/2, handle_info/2]). + +-record(config, { + notify_funs=[], + write_filename=undefined +}). -%% @type etstable() = integer(). start_link(IniFiles) -> gen_server:start_link({local, ?MODULE}, ?MODULE, IniFiles, []). +stop() -> + gen_server:cast(?MODULE, stop). + + all() -> - lists:sort(ets:tab2list(?MODULE)). + lists:sort(gen_server:call(?MODULE, all)). + get(Section) when is_binary(Section) -> ?MODULE:get(?b2l(Section)); get(Section) -> - Matches = ets:match(?MODULE, {{Section, '$1'}, '$2'}), - [{Key, Value} || [Key, Value] <- Matches]. - + gen_server:call(?MODULE, {get, Section}). get(Section, Key) -> ?MODULE:get(Section, Key, undefined). @@ -53,21 +58,28 @@ get(Section, Key) -> get(Section, Key, Default) when is_binary(Section) and is_binary(Key) -> ?MODULE:get(?b2l(Section), ?b2l(Key), Default); get(Section, Key, Default) -> - case ets:lookup(?MODULE, {Section, Key}) of - [] -> Default; - [{_,Result}] -> Result - end. + gen_server:call(?MODULE, {get, Section, Key, Default}). + set(Section, Key, Value) -> - set(Section, Key, Value, true). + ?MODULE:set(Section, Key, Value, true). set(Section, Key, Value, Persist) when is_binary(Section) and is_binary(Key) -> - set(?b2l(Section), ?b2l(Key), Value, Persist); + ?MODULE:set(?b2l(Section), ?b2l(Key), Value, Persist); set(Section, Key, Value, Persist) -> - gen_server:call(?MODULE, {set, [{{Section, Key}, Value}], Persist}). + gen_server:call(?MODULE, {set, Section, Key, Value, Persist}). + +delete(Section, Key) when is_binary(Section) and is_binary(Key) -> + delete(?b2l(Section), ?b2l(Key)); delete(Section, Key) -> - set(Section, Key, ""). + delete(Section, Key, true). + +delete(Section, Key, Persist) when is_binary(Section) and is_binary(Key) -> + delete(?b2l(Section), ?b2l(Key), Persist); +delete(Section, Key, Persist) -> + ?MODULE:set(Section, Key, "", Persist). + register(Fun) -> ?MODULE:register(Fun, self()). @@ -75,54 +87,78 @@ register(Fun) -> register(Fun, Pid) -> gen_server:call(?MODULE, {register, Fun, Pid}). -%% Private API %% -%% @spec init(List::list([])) -> {ok, Tab::etsatable()} -%% @doc Creates a new ets table of the type "set". init(IniFiles) -> - ets:new(?MODULE, [named_table, set, protected]), + ets:new(?MODULE, [named_table, set, private]), lists:map(fun(IniFile) -> {ok, ParsedIniValues} = parse_ini_file(IniFile), ets:insert(?MODULE, ParsedIniValues) end, IniFiles), - {ok, #config{write_filename=lists:last(IniFiles)}}. - -handle_call({set, KVs, Persist}, _From, Config) -> - lists:map( - fun({{Section, Key}, Value}=KV) -> - true = ets:insert(?MODULE, KV), - if Persist -> - ok = couch_config_writer:save_to_file(KV, - Config#config.write_filename); - true -> ok - end, - [catch F(Section, Key, Value) - || {_Pid, F} <- Config#config.notify_funs] - end, KVs), - {reply, ok, Config}; + WriteFile = case length(IniFiles) > 0 of + true -> lists:last(IniFiles); + _ -> undefined + end, + {ok, #config{write_filename=WriteFile}}. + +terminate(_Reason, _State) -> + ok. + + +handle_call(all, _From, Config) -> + Resp = lists:sort((ets:tab2list(?MODULE))), + {reply, Resp, Config}; +handle_call({get, Section}, _From, Config) -> + Matches = ets:match(?MODULE, {{Section, '$1'}, '$2'}), + Resp = [{Key, Value} || [Key, Value] <- Matches], + {reply, Resp, Config}; +handle_call({get, Section, Key, Default}, _From, Config) -> + Resp = case ets:lookup(?MODULE, {Section, Key}) of + [] -> Default; + [{_, Match}] -> Match + end, + {reply, Resp, Config}; +handle_call({set, Sec, Key, Val, Persist}, _From, Config) -> + true = ets:insert(?MODULE, {{Sec, Key}, Val}), + case {Persist, Config#config.write_filename} of + {true, undefined} -> + ok; + {true, FileName} -> + couch_config_writer:save_to_file({{Sec, Key}, Val}, FileName); + _ -> + ok + end, + [catch F(Sec, Key, Val) || {_Pid, F} <- Config#config.notify_funs], + {reply, ok, Config}; handle_call({register, Fun, Pid}, _From, #config{notify_funs=PidFuns}=Config) -> erlang:monitor(process, Pid), % convert 1 and 2 arity to 3 arity - Fun2 = - if is_function(Fun, 1) -> - fun(Section, _Key, _Value) -> Fun(Section) end; - is_function(Fun, 2) -> - fun(Section, Key, _Value) -> Fun(Section, Key) end; - is_function(Fun, 3) -> - Fun + Fun2 = + case Fun of + _ when is_function(Fun, 1) -> + fun(Section, _Key, _Value) -> Fun(Section) end; + _ when is_function(Fun, 2) -> + fun(Section, Key, _Value) -> Fun(Section, Key) end; + _ when is_function(Fun, 3) -> + Fun end, - {reply, ok, Config#config{notify_funs=[{Pid, Fun2}|PidFuns]}}. + {reply, ok, Config#config{notify_funs=[{Pid, Fun2} | PidFuns]}}. + + +handle_cast(stop, State) -> + {stop, normal, State}; +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info({'DOWN', _, _, DownPid, _}, #config{notify_funs=PidFuns}=Config) -> + % remove any funs registered by the downed process + FilteredPidFuns = [{Pid,Fun} || {Pid,Fun} <- PidFuns, Pid /= DownPid], + {noreply, Config#config{notify_funs=FilteredPidFuns}}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. -%% @spec load_ini_file(IniFile::filename()) -> ok -%% @doc Parses an ini file and stores Key/Value Pairs into the ets table. -load_ini_file(IniFile) -> - {ok, KVs} = parse_ini_file(IniFile), - gen_server:call(?MODULE, {set, KVs, false}). -%% @spec load_ini_file(IniFile::filename()) -> {ok, [KV]} -%% KV = {{Section::string(), Key::string()}, Value::String()} -%% @throws {startup_error, Msg::string()} parse_ini_file(IniFile) -> IniFilename = couch_util:abs_pathname(IniFile), IniBin = @@ -130,7 +166,8 @@ parse_ini_file(IniFile) -> {ok, IniBin0} -> IniBin0; {error, enoent} -> - Msg = ?l2b(io_lib:format("Couldn't find server configuration file ~s.", [IniFilename])), + Fmt = "Couldn't find server configuration file ~s.", + Msg = ?l2b(io_lib:format(Fmt, [IniFilename])), ?LOG_ERROR("~s~n", [Msg]), throw({startup_error, Msg}) end, @@ -156,25 +193,12 @@ parse_ini_file(IniFile) -> {AccSectionName, AccValues}; {ok, [ValueName|LineValues]} -> % yeehaw, got a line! RemainingLine = couch_util:implode(LineValues, "="), - {ok, [LineValue | _Rest]} = regexp:split(RemainingLine, " ;|\t;"), % removes comments - {AccSectionName, [{{AccSectionName, ValueName}, LineValue} | AccValues]} + {ok, [LineValue | _Rest]} = + regexp:split(RemainingLine, " ;|\t;"), % removes comments + {AccSectionName, + [{{AccSectionName, ValueName}, LineValue} | AccValues]} end end end, {"", []}, Lines), {ok, ParsedIniValues}. -% Unused gen_server behaviour API functions that we need to declare. - -%% @doc Unused -handle_cast(foo, State) -> {noreply, State}. - -handle_info({'DOWN', _, _, DownPid, _}, #config{notify_funs=PidFuns}=Config) -> - % remove any funs registered by the downed process - FilteredPidFuns = [{Pid,Fun} || {Pid,Fun} <- PidFuns, Pid /= DownPid], - {noreply, Config#config{notify_funs=FilteredPidFuns}}. - -%% @doc Unused -terminate(_Reason, _State) -> ok. - -%% @doc Unused -code_change(_OldVersion, State, _Extra) -> {ok, State}. diff --git a/test/etap/031-doc-to-json.t b/test/etap/031-doc-to-json.t index 37b23848..37ee9946 100755 --- a/test/etap/031-doc-to-json.t +++ b/test/etap/031-doc-to-json.t @@ -9,7 +9,7 @@ main(_) -> code:add_pathz("src/couchdb"), - etap:plan(unknown), + etap:plan(12), case (catch test()) of ok -> etap:end_tests(); diff --git a/test/etap/040-util.t b/test/etap/040-util.t index a6b7df33..a6b7df33 100644..100755 --- a/test/etap/040-util.t +++ b/test/etap/040-util.t diff --git a/test/etap/050-stream.t b/test/etap/050-stream.t index 41aa9754..dab2d50c 100644..100755 --- a/test/etap/050-stream.t +++ b/test/etap/050-stream.t @@ -3,7 +3,7 @@ main(_) -> code:add_pathz("src/couchdb"), - etap:plan(unknown), + etap:plan(13), case (catch test()) of ok -> etap:end_tests(); diff --git a/test/etap/060-kt-merging.t b/test/etap/060-kt-merging.t index 004e004f..004e004f 100644..100755 --- a/test/etap/060-kt-merging.t +++ b/test/etap/060-kt-merging.t diff --git a/test/etap/061-kt-missing-leaves.t b/test/etap/061-kt-missing-leaves.t index c5ee1222..c5ee1222 100644..100755 --- a/test/etap/061-kt-missing-leaves.t +++ b/test/etap/061-kt-missing-leaves.t diff --git a/test/etap/062-kt-remove-leaves.t b/test/etap/062-kt-remove-leaves.t index 566efa06..566efa06 100644..100755 --- a/test/etap/062-kt-remove-leaves.t +++ b/test/etap/062-kt-remove-leaves.t diff --git a/test/etap/063-kt-get-leaves.t b/test/etap/063-kt-get-leaves.t index 9e366ff8..9e366ff8 100644..100755 --- a/test/etap/063-kt-get-leaves.t +++ b/test/etap/063-kt-get-leaves.t diff --git a/test/etap/064-kt-counting.t b/test/etap/064-kt-counting.t index dd00cedd..dd00cedd 100644..100755 --- a/test/etap/064-kt-counting.t +++ b/test/etap/064-kt-counting.t diff --git a/test/etap/065-kt-stemming.t b/test/etap/065-kt-stemming.t index 0de69482..0de69482 100644..100755 --- a/test/etap/065-kt-stemming.t +++ b/test/etap/065-kt-stemming.t diff --git a/test/etap/070-couch-db.t b/test/etap/070-couch-db.t index da1f28ab..da1f28ab 100644..100755 --- a/test/etap/070-couch-db.t +++ b/test/etap/070-couch-db.t diff --git a/test/etap/080-config-get-set.t b/test/etap/080-config-get-set.t new file mode 100755 index 00000000..4824b2aa --- /dev/null +++ b/test/etap/080-config-get-set.t @@ -0,0 +1,116 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +default_config() -> + "etc/couchdb/default_dev.ini". + +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. + +test() -> + % start couch_config with default + couch_config:start_link([default_config()]), + + + % Check that we can get values + + + etap:fun_is( + fun(List) -> length(List) > 0 end, + couch_config:all(), + "Data was loaded from the INI file." + ), + + etap:fun_is( + fun(List) -> length(List) > 0 end, + couch_config:get("daemons"), + "There are settings in the [daemons] section of the INI file." + ), + + etap:is( + couch_config:get("httpd_design_handlers", "_view"), + "{couch_httpd_view, handle_view_req}", + "The {httpd_design_handlers, view} is the expected default." + ), + + etap:is( + couch_config:get("httpd", "foo", "bar"), + "bar", + "Returns the default when key doesn't exist in config." + ), + + etap:is( + couch_config:get("httpd", "foo"), + undefined, + "The default default is the atom 'undefined'." + ), + + etap:is( + couch_config:get("httpd", "port", "bar"), + "5984", + "Only returns the default when the config setting does not exist." + ), + + + % Check that setting values works. + + + ok = couch_config:set("log", "level", "severe", false), + + etap:is( + couch_config:get("log", "level"), + "severe", + "Non persisted changes take effect." + ), + + etap:is( + couch_config:get("new_section", "bizzle"), + undefined, + "Section 'new_section' does not exist." + ), + + ok = couch_config:set("new_section", "bizzle", "bang", false), + + etap:is( + couch_config:get("new_section", "bizzle"), + "bang", + "New section 'new_section' was created for a new key/value pair." + ), + + + % Check that deleting works + + + ok = couch_config:delete("new_section", "bizzle", false), + etap:is( + couch_config:get("new_section", "bizzle"), + "", + "Deleting sets the value to \"\"" + ), + + + % Check ge/set/delete binary strings + + ok = couch_config:set(<<"foo">>, <<"bar">>, <<"baz">>, false), + etap:is( + couch_config:get(<<"foo">>, <<"bar">>), + <<"baz">>, + "Can get and set with binary section and key values." + ), + ok = couch_config:delete(<<"foo">>, <<"bar">>, false), + etap:is( + couch_config:get(<<"foo">>, <<"bar">>), + "", + "Deleting with binary section/key pairs sets the value to \"\"" + ), + + ok. diff --git a/test/etap/081-config-override.1.ini b/test/etap/081-config-override.1.ini new file mode 100644 index 00000000..f11da1f3 --- /dev/null +++ b/test/etap/081-config-override.1.ini @@ -0,0 +1,5 @@ +[couchdb] +max_dbs_open=10 + +[httpd] +port=4895 diff --git a/test/etap/081-config-override.2.ini b/test/etap/081-config-override.2.ini new file mode 100644 index 00000000..bb67b629 --- /dev/null +++ b/test/etap/081-config-override.2.ini @@ -0,0 +1,5 @@ +[httpd] +port = 80 + +[fizbang] +unicode = normalized
\ No newline at end of file diff --git a/test/etap/081-config-override.t b/test/etap/081-config-override.t new file mode 100755 index 00000000..1d66b58e --- /dev/null +++ b/test/etap/081-config-override.t @@ -0,0 +1,200 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +default_config() -> + "etc/couchdb/default_dev.ini". + +local_config_1() -> + "test/etap/081-config-override.1.ini". + +local_config_2() -> + "test/etap/081-config-override.2.ini". + +local_config_write() -> + "test/etap/temp.081". + +% Run tests and wait for the config gen_server to shutdown. +run_tests(IniFiles, Tests) -> + {ok, Pid} = couch_config:start_link(IniFiles), + erlang:monitor(process, Pid), + Tests(), + couch_config:stop(), + receive + {'DOWN', _, _, Pid, _} -> ok; + _Other -> etap:diag("OTHER: ~p~n", [_Other]) + after + 1000 -> throw({timeout_error, config_stop}) + end. + +main(_) -> + code:add_pathz("src/couchdb"), + etap:plan(17), + + case (catch test()) of + ok -> + etap:end_tests(); + Other -> + etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), + etap:bail(Other) + end, + ok. + +test() -> + + CheckStartStop = fun() -> ok end, + run_tests([default_config()], CheckStartStop), + + CheckDefaults = fun() -> + etap:is( + couch_config:get("couchdb", "max_dbs_open"), + "100", + "{couchdb, max_dbs_open} is 100 by defualt." + ), + + etap:is( + couch_config:get("httpd","port"), + "5984", + "{httpd, port} is 5984 by default" + ), + + etap:is( + couch_config:get("fizbang", "unicode"), + undefined, + "{fizbang, unicode} is undefined by default" + ) + end, + + run_tests([default_config()], CheckDefaults), + + + % Check that subsequent files override values appropriately + + CheckOverride = fun() -> + etap:is( + couch_config:get("couchdb", "max_dbs_open"), + "10", + "{couchdb, max_dbs_open} was overriden with the value 10" + ), + + etap:is( + couch_config:get("httpd", "port"), + "4895", + "{httpd, port} was overriden with the value 4895" + ) + end, + + run_tests([default_config(), local_config_1()], CheckOverride), + + + % Check that overrides can create new sections + + CheckOverride2 = fun() -> + etap:is( + couch_config:get("httpd", "port"), + "80", + "{httpd, port} is overriden with the value 80" + ), + + etap:is( + couch_config:get("fizbang", "unicode"), + "normalized", + "{fizbang, unicode} was created by override INI file" + ) + end, + + run_tests([default_config(), local_config_2()], CheckOverride2), + + + % Check that values can be overriden multiple times + + CheckOverride3 = fun() -> + etap:is( + couch_config:get("httpd", "port"), + "80", + "{httpd, port} value was taken from the last specified INI file." + ) + end, + + run_tests( + [default_config(), local_config_1(), local_config_2()], + CheckOverride3 + ), + + % Check persistence to last file. + + % Empty the file in case it exists. + {ok, Fd} = file:open(local_config_write(), write), + ok = file:truncate(Fd), + ok = file:close(Fd), + + % Open and write a value + CheckCanWrite = fun() -> + etap:is( + couch_config:get("httpd", "port"), + "5984", + "{httpd, port} is still 5984 by default" + ), + + etap:is( + couch_config:set("httpd", "port", "8080"), + ok, + "Writing {httpd, port} is kosher." + ), + + etap:is( + couch_config:get("httpd", "port"), + "8080", + "{httpd, port} was updated to 8080 successfully." + ), + + etap:is( + couch_config:delete("httpd", "bind_address"), + ok, + "Deleting {httpd, bind_address} succeeds" + ), + + etap:is( + couch_config:get("httpd", "bind_address"), + "", + "{httpd, bind_address} was actually deleted." + ) + end, + + run_tests([default_config(), local_config_write()], CheckCanWrite), + + % Open and check where we don't expect persistence. + + CheckDidntWrite = fun() -> + etap:is( + couch_config:get("httpd", "port"), + "5984", + "{httpd, port} was not persisted to the primary INI file." + ), + + etap:is( + couch_config:get("httpd", "bind_address"), + "127.0.0.1", + "{httpd, bind_address} was not deleted form the primary INI file." + ) + end, + + run_tests([default_config()], CheckDidntWrite), + + % Open and check we have only the persistence we expect. + CheckDidWrite = fun() -> + etap:is( + couch_config:get("httpd", "port"), + "8080", + "{httpd, port} is still 8080 after reopening the config." + ), + + etap:is( + couch_config:get("httpd", "bind_address"), + "", + "{httpd, bind_address} is still \"\" after reopening." + ) + end, + + run_tests([local_config_write()], CheckDidWrite), + + ok. diff --git a/test/etap/082-config-register.t b/test/etap/082-config-register.t new file mode 100755 index 00000000..9f454984 --- /dev/null +++ b/test/etap/082-config-register.t @@ -0,0 +1,75 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +default_config() -> + "etc/couchdb/default_dev.ini". + +main(_) -> + code:add_pathz("src/couchdb"), + etap:plan(5), + case (catch test()) of + ok -> + etap:end_tests(); + Other -> + etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), + etap:bail(Other) + end, + ok. + +test() -> + couch_config:start_link([default_config()]), + + etap:is( + couch_config:get("httpd", "port"), + "5984", + "{httpd, port} is 5984 by default." + ), + + ok = couch_config:set("httpd", "port", "4895", false), + + etap:is( + couch_config:get("httpd", "port"), + "4895", + "{httpd, port} changed to 4895" + ), + + SentinelFunc = fun() -> + % Ping/Pong to make sure we wait for this + % process to die + receive {ping, From} -> From ! pong end + end, + SentinelPid = spawn(SentinelFunc), + + couch_config:register( + fun("httpd", "port", Value) -> + etap:is(Value, "8080", "Registered function got notification.") + end, + SentinelPid + ), + + ok = couch_config:set("httpd", "port", "8080", false), + + % Implicitly checking that we *don't* call the function + etap:is( + couch_config:get("httpd", "bind_address"), + "127.0.0.1", + "{httpd, bind_address} is not '0.0.0.0'" + ), + ok = couch_config:set("httpd", "bind_address", "0.0.0.0", false), + + % Ping-Pong kill process + SentinelPid ! {ping, self()}, + receive + _Any -> ok + after 1000 -> + throw({timeout_error, registered_pid}) + end, + + ok = couch_config:set("httpd", "port", "80", false), + etap:is( + couch_config:get("httpd", "port"), + "80", + "Implicitly test that the function got de-registered" + ), + + ok.
\ No newline at end of file diff --git a/test/etap/083-config-no-files.t b/test/etap/083-config-no-files.t new file mode 100755 index 00000000..2e4d8e71 --- /dev/null +++ b/test/etap/083-config-no-files.t @@ -0,0 +1,43 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +default_config() -> + "etc/couchdb/default_dev.ini". + +main(_) -> + code:add_pathz("src/couchdb"), + etap:plan(3), + case (catch test()) of + ok -> + etap:end_tests(); + Other -> + etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), + etap:bail(Other) + end, + ok. + +test() -> + couch_config:start_link([]), + + etap:fun_is( + fun(KVPairs) -> length(KVPairs) == 0 end, + couch_config:all(), + "No INI files specified returns 0 key/value pairs." + ), + + ok = couch_config:set("httpd", "port", "80", false), + + etap:is( + couch_config:get("httpd", "port"), + "80", + "Created a new non-persisted k/v pair." + ), + + ok = couch_config:set("httpd", "bind_address", "127.0.0.1"), + etap:is( + couch_config:get("httpd", "bind_address"), + "127.0.0.1", + "Asking for a persistent key/value pair doesn't choke." + ), + + ok.
\ No newline at end of file |