diff options
author | Paul Joseph Davis <davisp@apache.org> | 2010-11-05 23:14:02 +0000 |
---|---|---|
committer | Paul Joseph Davis <davisp@apache.org> | 2010-11-05 23:14:02 +0000 |
commit | c8785113522b8486fab0ba53f2043d94e9b1507f (patch) | |
tree | f6d1c35ab8ce540c172e8faf2464b9b08d3b2302 /test/etap | |
parent | c82960cdd8e84a4db0dbbefca425bbb49aeddfa3 (diff) |
Enable CouchDB to manage OS process daemons.
This is a simple feature that allows useres to configure CouchDB
so that it maintains a given OS level process alive. If the process
dies for any reason, CouchDB will restart it. If the process restarts
too often, then CouchDB will mark it has halted and not attempt
to restart it. The default max restart rate is three times in the
last five seconds. These parameters are adjustable.
Commands that are started in this manner will have access to a simple
API over stdio to request configuration parameters or to add log
statements to CouchDB's logs.
To configure an OS process as a CouchDB os_daemon, create a section
in your local.ini like such:
[os_daemons]
daemon_name = /path/to/command -with args
This will make CouchDB bring up the command and attempt to keep it
alive. To request a configuration parameter, an os_daemon can write
a simple JSON message to stdout like such:
["get", "os_daemons"]\n
which would return:
{"daemon_name": "/path/to/command -with args"}
Or:
["get", "os_daemons", "daemon_name"]\n
which would return:
"/path/to/command -with args"
There's no restriction on what configuration variables are visible.
There's also no method for altering the configuration.
If you would like your OS daemon to be restarted in the event that
the configuration changes, you can send the following messages:
["register", $(SECTION)]\n
When anyting in that section changes, your OS process will be
rebooted so it can pick up the new configuration settings. If you
want to listen for changes on a specific key, you can send something
like:
["register", $(SECTION), $(KEY)]\n
In this case, CouchDB will only restart your daemon if that exact
section/key pair changes, instead of anything in that entire section.
Logging commands look like:
["log", $(JSON_MESSAGE)]\n
Where $(JSON_MESSAGE) is arbitrary JSON data. These messages are
logged at the 'info' level. If you want to log at a different level
you can pass messages like such:
["log", $(JSON_MESSAGE), {"level": $(LEVEL)}]\n
Where $(LEVEL) is one of "debug", "info", or "error".
When implementing a daemon process to be managed by CouchDB you
should remember to use a method like checking the parent process
id or if stdin has been closed. These flags can tell you if
your daemon process has been orphaned so you can exit cleanly.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@1031875 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'test/etap')
-rwxr-xr-x | test/etap/170-os-daemons.es | 26 | ||||
-rwxr-xr-x | test/etap/170-os-daemons.t | 114 | ||||
-rwxr-xr-x | test/etap/171-os-daemons-config.es | 78 | ||||
-rwxr-xr-x | test/etap/171-os-daemons-config.t | 74 | ||||
-rw-r--r-- | test/etap/172-os-daemon-errors.1.es | 22 | ||||
-rwxr-xr-x | test/etap/172-os-daemon-errors.2.es | 16 | ||||
-rwxr-xr-x | test/etap/172-os-daemon-errors.3.es | 17 | ||||
-rwxr-xr-x | test/etap/172-os-daemon-errors.4.es | 17 | ||||
-rwxr-xr-x | test/etap/172-os-daemon-errors.t | 126 | ||||
-rwxr-xr-x | test/etap/173-os-daemon-cfg-register.es | 35 | ||||
-rwxr-xr-x | test/etap/173-os-daemon-cfg-register.t | 98 | ||||
-rw-r--r-- | test/etap/Makefile.am | 13 |
12 files changed, 635 insertions, 1 deletions
diff --git a/test/etap/170-os-daemons.es b/test/etap/170-os-daemons.es new file mode 100755 index 00000000..73974e90 --- /dev/null +++ b/test/etap/170-os-daemons.es @@ -0,0 +1,26 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +loop() -> + loop(io:read("")). + +loop({ok, _}) -> + loop(io:read("")); +loop(eof) -> + stop; +loop({error, Reason}) -> + throw({error, Reason}). + +main([]) -> + loop(). diff --git a/test/etap/170-os-daemons.t b/test/etap/170-os-daemons.t new file mode 100755 index 00000000..6feaa1bf --- /dev/null +++ b/test/etap/170-os-daemons.t @@ -0,0 +1,114 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-record(daemon, { + port, + name, + cmd, + kill, + status=running, + cfg_patterns=[], + errors=[], + buf=[] +}). + +config_files() -> + lists:map(fun test_util:build_file/1, [ + "etc/couchdb/default_dev.ini" + ]). + +daemon_cmd() -> + test_util:source_file("test/etap/170-os-daemons.es"). + +main(_) -> + test_util:init_code_path(), + + etap:plan(49), + 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(config_files()), + couch_os_daemons:start_link(), + + etap:diag("Daemons boot after configuration added."), + couch_config:set("os_daemons", "foo", daemon_cmd(), false), + timer:sleep(1000), + + {ok, [D1]} = couch_os_daemons:info([table]), + check_daemon(D1, "foo"), + + % Check table form + {ok, Tab1} = couch_os_daemons:info(), + [T1] = ets:tab2list(Tab1), + check_daemon(T1, "foo"), + + etap:diag("Daemons stop after configuration removed."), + couch_config:delete("os_daemons", "foo", false), + timer:sleep(500), + + {ok, []} = couch_os_daemons:info([table]), + {ok, Tab2} = couch_os_daemons:info(), + etap:is(ets:tab2list(Tab2), [], "As table returns empty table."), + + etap:diag("Adding multiple daemons causes both to boot."), + couch_config:set("os_daemons", "bar", daemon_cmd(), false), + couch_config:set("os_daemons", "baz", daemon_cmd(), false), + timer:sleep(500), + {ok, Daemons} = couch_os_daemons:info([table]), + lists:foreach(fun(D) -> + check_daemon(D) + end, Daemons), + + {ok, Tab3} = couch_os_daemons:info(), + lists:foreach(fun(D) -> + check_daemon(D) + end, ets:tab2list(Tab3)), + + etap:diag("Removing one daemon leaves the other alive."), + couch_config:delete("os_daemons", "bar", false), + timer:sleep(500), + + {ok, [D2]} = couch_os_daemons:info([table]), + check_daemon(D2, "baz"), + + % Check table version + {ok, Tab4} = couch_os_daemons:info(), + [T4] = ets:tab2list(Tab4), + check_daemon(T4, "baz"), + + ok. + +check_daemon(D) -> + check_daemon(D, D#daemon.name). + +check_daemon(D, Name) -> + BaseName = "170-os-daemons.es", + BaseLen = length(BaseName), + CmdLen = length(D#daemon.cmd), + CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), + + etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), + etap:is(D#daemon.name, Name, "Daemon name was set correctly."), + etap:is(CmdName, BaseName, "Command name was set correctly."), + etap:isnt(D#daemon.kill, undefined, "Kill command was set."), + etap:is(D#daemon.errors, [], "No errors occurred while booting."), + etap:is(D#daemon.buf, [], "No extra data left in the buffer."). diff --git a/test/etap/171-os-daemons-config.es b/test/etap/171-os-daemons-config.es new file mode 100755 index 00000000..96e051a3 --- /dev/null +++ b/test/etap/171-os-daemons-config.es @@ -0,0 +1,78 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +filename() -> + list_to_binary(test_util:source_file("test/etap/171-os-daemons-config.es")). + +read() -> + case io:get_line('') of + eof -> + stop; + Data -> + couch_util:json_decode(Data) + end. + +write(Mesg) -> + Data = iolist_to_binary(couch_util:json_encode(Mesg)), + io:format(binary_to_list(Data) ++ "\n", []). + +get_cfg(Section) -> + write([<<"get">>, Section]), + read(). + +get_cfg(Section, Name) -> + write([<<"get">>, Section, Name]), + read(). + +log(Mesg) -> + write([<<"log">>, Mesg]). + +log(Mesg, Level) -> + write([<<"log">>, Mesg, {[{<<"level">>, Level}]}]). + +test_get_cfg1() -> + FileName = filename(), + {[{<<"foo">>, FileName}]} = get_cfg(<<"os_daemons">>). + +test_get_cfg2() -> + FileName = filename(), + FileName = get_cfg(<<"os_daemons">>, <<"foo">>), + <<"sequential">> = get_cfg(<<"uuids">>, <<"algorithm">>). + +test_log() -> + log(<<"foobar!">>), + log(<<"some stuff!">>, <<"debug">>), + log(2), + log(true), + write([<<"log">>, <<"stuff">>, 2]), + write([<<"log">>, 3, null]), + write([<<"log">>, [1, 2], {[{<<"level">>, <<"debug">>}]}]), + write([<<"log">>, <<"true">>, {[]}]). + +do_tests() -> + test_get_cfg1(), + test_get_cfg2(), + test_log(), + loop(io:read("")). + +loop({ok, _}) -> + loop(io:read("")); +loop(eof) -> + init:stop(); +loop({error, _Reason}) -> + init:stop(). + +main([]) -> + test_util:init_code_path(), + do_tests(). diff --git a/test/etap/171-os-daemons-config.t b/test/etap/171-os-daemons-config.t new file mode 100755 index 00000000..e9dc3f32 --- /dev/null +++ b/test/etap/171-os-daemons-config.t @@ -0,0 +1,74 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-record(daemon, { + port, + name, + cmd, + kill, + status=running, + cfg_patterns=[], + errors=[], + buf=[] +}). + +config_files() -> + lists:map(fun test_util:build_file/1, [ + "etc/couchdb/default_dev.ini" + ]). + +daemon_cmd() -> + test_util:source_file("test/etap/171-os-daemons-config.es"). + +main(_) -> + test_util:init_code_path(), + + etap:plan(6), + 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(config_files()), + couch_config:set("log", "level", "debug", false), + couch_log:start_link(), + couch_os_daemons:start_link(), + + % "foo" is a required name by this test. + couch_config:set("os_daemons", "foo", daemon_cmd(), false), + timer:sleep(1000), + + {ok, [D1]} = couch_os_daemons:info([table]), + check_daemon(D1, "foo"), + + ok. + +check_daemon(D, Name) -> + BaseName = "171-os-daemons-config.es", + BaseLen = length(BaseName), + CmdLen = length(D#daemon.cmd), + CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), + + etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), + etap:is(D#daemon.name, Name, "Daemon name was set correctly."), + etap:is(CmdName, BaseName, "Command name was set correctly."), + etap:isnt(D#daemon.kill, undefined, "Kill command was set."), + etap:is(D#daemon.errors, [], "No errors occurred while booting."), + etap:is(D#daemon.buf, [], "No extra data left in the buffer."). diff --git a/test/etap/172-os-daemon-errors.1.es b/test/etap/172-os-daemon-errors.1.es new file mode 100644 index 00000000..a9defba1 --- /dev/null +++ b/test/etap/172-os-daemon-errors.1.es @@ -0,0 +1,22 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +% Please do not make this file executable as that's the error being tested. + +loop() -> + timer:sleep(5000), + loop(). + +main([]) -> + loop(). diff --git a/test/etap/172-os-daemon-errors.2.es b/test/etap/172-os-daemon-errors.2.es new file mode 100755 index 00000000..52de0401 --- /dev/null +++ b/test/etap/172-os-daemon-errors.2.es @@ -0,0 +1,16 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +main([]) -> + init:stop(). diff --git a/test/etap/172-os-daemon-errors.3.es b/test/etap/172-os-daemon-errors.3.es new file mode 100755 index 00000000..64229800 --- /dev/null +++ b/test/etap/172-os-daemon-errors.3.es @@ -0,0 +1,17 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +main([]) -> + timer:sleep(1000), + init:stop(). diff --git a/test/etap/172-os-daemon-errors.4.es b/test/etap/172-os-daemon-errors.4.es new file mode 100755 index 00000000..577f3410 --- /dev/null +++ b/test/etap/172-os-daemon-errors.4.es @@ -0,0 +1,17 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +main([]) -> + timer:sleep(2000), + init:stop(). diff --git a/test/etap/172-os-daemon-errors.t b/test/etap/172-os-daemon-errors.t new file mode 100755 index 00000000..287a0812 --- /dev/null +++ b/test/etap/172-os-daemon-errors.t @@ -0,0 +1,126 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-record(daemon, { + port, + name, + cmd, + kill, + status=running, + cfg_patterns=[], + errors=[], + buf=[] +}). + +config_files() -> + lists:map(fun test_util:build_file/1, [ + "etc/couchdb/default_dev.ini" + ]). + +bad_perms() -> + test_util:source_file("test/etap/172-os-daemon-errors.1.es"). + +die_on_boot() -> + test_util:source_file("test/etap/172-os-daemon-errors.2.es"). + +die_quickly() -> + test_util:source_file("test/etap/172-os-daemon-errors.3.es"). + +can_reboot() -> + test_util:source_file("test/etap/172-os-daemon-errors.4.es"). + +main(_) -> + test_util:init_code_path(), + + etap:plan(36), + 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(config_files()), + couch_os_daemons:start_link(), + + etap:diag("Daemon not executable."), + test_halts("foo", bad_perms(), 1000), + + etap:diag("Daemon dies on boot."), + test_halts("bar", die_on_boot(), 1000), + + etap:diag("Daemon dies quickly after boot."), + test_halts("baz", die_quickly(), 4000), + + etap:diag("Daemon dies, but not quickly enough to be halted."), + test_runs("bam", can_reboot()), + + ok. + +test_halts(Name, Cmd, Time) -> + couch_config:set("os_daemons", Name, Cmd ++ " 2> /dev/null", false), + timer:sleep(Time), + {ok, [D]} = couch_os_daemons:info([table]), + check_dead(D, Name, Cmd), + couch_config:delete("os_daemons", Name, false). + +test_runs(Name, Cmd) -> + couch_config:set("os_daemons", Name, Cmd, false), + + timer:sleep(1000), + {ok, [D1]} = couch_os_daemons:info([table]), + check_daemon(D1, Name, Cmd, 0), + + % Should reboot every two seconds. We're at 1s, so wait + % utnil 3s to be in the middle of the next invocation's + % life span. + timer:sleep(2000), + {ok, [D2]} = couch_os_daemons:info([table]), + check_daemon(D2, Name, Cmd, 1), + + % If the kill command changed, that means we rebooted the process. + etap:isnt(D1#daemon.kill, D2#daemon.kill, "Kill command changed."). + +check_dead(D, Name, Cmd) -> + BaseName = filename:basename(Cmd) ++ " 2> /dev/null", + BaseLen = length(BaseName), + CmdLen = length(D#daemon.cmd), + CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), + + etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), + etap:is(D#daemon.name, Name, "Daemon name was set correctly."), + etap:is(CmdName, BaseName, "Command name was set correctly."), + etap:isnt(D#daemon.kill, undefined, "Kill command was set."), + etap:is(D#daemon.status, halted, "Daemon has been halted."), + etap:is(D#daemon.errors, nil, "Errors have been disabled."), + etap:is(D#daemon.buf, nil, "Buffer has been switched off."). + +check_daemon(D, Name, Cmd, Errs) -> + BaseName = filename:basename(Cmd), + BaseLen = length(BaseName), + CmdLen = length(D#daemon.cmd), + CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), + + etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), + etap:is(D#daemon.name, Name, "Daemon name was set correctly."), + etap:is(CmdName, BaseName, "Command name was set correctly."), + etap:isnt(D#daemon.kill, undefined, "Kill command was set."), + etap:is(D#daemon.status, running, "Daemon still running."), + etap:is(length(D#daemon.errors), Errs, "Found expected number of errors."), + etap:is(D#daemon.buf, [], "No extra data left in the buffer."). + diff --git a/test/etap/173-os-daemon-cfg-register.es b/test/etap/173-os-daemon-cfg-register.es new file mode 100755 index 00000000..3d536dc7 --- /dev/null +++ b/test/etap/173-os-daemon-cfg-register.es @@ -0,0 +1,35 @@ +#! /usr/bin/env escript + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +write(Mesg) -> + Data = iolist_to_binary(couch_util:json_encode(Mesg)), + io:format(binary_to_list(Data) ++ "\n", []). + +cfg_register(Section) -> + write([<<"register">>, Section]). + +cfg_register(Section, Key) -> + write([<<"register">>, Section, Key]). + +wait(_) -> + init:stop(). + +do_tests() -> + cfg_register(<<"s1">>), + cfg_register(<<"s2">>, <<"k">>), + wait(io:read("")). + +main([]) -> + test_util:init_code_path(), + do_tests(). diff --git a/test/etap/173-os-daemon-cfg-register.t b/test/etap/173-os-daemon-cfg-register.t new file mode 100755 index 00000000..3ee2969a --- /dev/null +++ b/test/etap/173-os-daemon-cfg-register.t @@ -0,0 +1,98 @@ +#!/usr/bin/env escript +%% -*- erlang -*- + +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-record(daemon, { + port, + name, + cmd, + kill, + status=running, + cfg_patterns=[], + errors=[], + buf=[] +}). + +config_files() -> + lists:map(fun test_util:build_file/1, [ + "etc/couchdb/default_dev.ini" + ]). + +daemon_name() -> + "wheee". + +daemon_cmd() -> + test_util:source_file("test/etap/173-os-daemon-cfg-register.es"). + +main(_) -> + test_util:init_code_path(), + + etap:plan(27), + 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(config_files()), + couch_os_daemons:start_link(), + + DaemonCmd = daemon_cmd() ++ " 2> /dev/null", + + etap:diag("Booting the daemon"), + couch_config:set("os_daemons", daemon_name(), DaemonCmd, false), + timer:sleep(1000), + {ok, [D1]} = couch_os_daemons:info([table]), + check_daemon(D1, running), + + etap:diag("Daemon restarts when section changes."), + couch_config:set("s1", "k", "foo", false), + timer:sleep(1000), + {ok, [D2]} = couch_os_daemons:info([table]), + check_daemon(D2, running), + etap:isnt(D2#daemon.kill, D1#daemon.kill, "Kill command shows restart."), + + etap:diag("Daemon doesn't restart for ignored section key."), + couch_config:set("s2", "k2", "baz", false), + timer:sleep(1000), + {ok, [D3]} = couch_os_daemons:info([table]), + etap:is(D3, D2, "Same daemon info after ignored config change."), + + etap:diag("Daemon restarts for specific section/key pairs."), + couch_config:set("s2", "k", "bingo", false), + timer:sleep(1000), + {ok, [D4]} = couch_os_daemons:info([table]), + check_daemon(D4, running), + etap:isnt(D4#daemon.kill, D3#daemon.kill, "Kill command changed again."), + + ok. + +check_daemon(D, Status) -> + BaseName = filename:basename(daemon_cmd()) ++ " 2> /dev/null", + BaseLen = length(BaseName), + CmdLen = length(D#daemon.cmd), + CmdName = lists:sublist(D#daemon.cmd, CmdLen-BaseLen+1, BaseLen), + + etap:is(is_port(D#daemon.port), true, "Daemon port is a port."), + etap:is(D#daemon.name, daemon_name(), "Daemon name was set correctly."), + etap:is(CmdName, BaseName, "Command name was set correctly."), + etap:isnt(D#daemon.kill, undefined, "Kill command was set."), + etap:is(D#daemon.status, Status, "Daemon status is correct."), + etap:is(D#daemon.cfg_patterns, [{"s1"}, {"s2", "k"}], "Cfg patterns set"), + etap:is(D#daemon.errors, [], "No errors have occurred."), + etap:isnt(D#daemon.buf, nil, "Buffer is active."). diff --git a/test/etap/Makefile.am b/test/etap/Makefile.am index bdab95aa..26c214d9 100644 --- a/test/etap/Makefile.am +++ b/test/etap/Makefile.am @@ -66,4 +66,15 @@ EXTRA_DIST = \ 130-attachments-md5.t \ 140-attachment-comp.t \ 150-invalid-view-seq.t \ - 160-vhosts.t + 160-vhosts.t \ + 170-os-daemons.es \ + 170-os-daemons.t \ + 171-os-daemons-config.es \ + 171-os-daemons-config.t \ + 172-os-daemon-errors.1.es \ + 172-os-daemon-errors.2.es \ + 172-os-daemon-errors.3.es \ + 172-os-daemon-errors.4.es \ + 172-os-daemon-errors.t \ + 173-os-daemon-cfg-register.es \ + 173-os-daemon-cfg-register.t |