Skip to content
This repository was archived by the owner on May 25, 2021. It is now read-only.

Conversation

@hdiedrich
Copy link

chttpd hardcoded handlers are replaced with with dynamic url handlers,
which are functions in a dynamically created module, assembled from
priv/chttpd_handler.cfg files from all interested applications.

For couched these are currently: chttpd, mem3 and global_changes.

This is a special branch that pull the prepared branches (of the same name)
of chttpd, mem3 and global_changes, which have the config files.

Run 'make check' to test the handlers. They are implicitly tested by other
tests and there is a whitebox callback test chttpd_handler_callback_test,
which calls the dynamic functions directly and mocks the funs that they
return. This tests precisely the relationship between the *_handler function
clauses and the returned function.

There are more tests to come, both testing the endpoints via http, and the
configuration assembly.

BugzID: 27037

H. Diedrich added 4 commits November 28, 2014 18:05
chttpd hardcoded handlers are replaced with with dynamic url handlers,
which are functions in a dynamically created module, assembled from
priv/chttpd_handler.cfg files from all interested applications.

For couched these are currently: chttpd, mem3 and global_changes.

This is a special branch that pull the prepared branches (of the same name)
of chttpd, mem3 and global_changes, which have the config files.

Run 'make check' to test the handlers. They are implicitly tested by other
tests and there is a whitebox callback test chttpd_handler_callback_test,
which calls the dynamic functions directly and mocks the funs that they
return. This tests precisely the relationship between the *_handler function
clauses and the returned function.

There are more tests to come, both testing the endpoints via http, and the
configuration assembly.

BugzID: 27037
@hdiedrich
Copy link
Author

Note, I am adding less essential stuff, if unplanned for, in separate commits, as requested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't call ?assert from eunit tests generator: this makes debugging extremely hard:

  chttpd_handler_callback_test: all_test_.................................................. *failed*
::error:function_clause
  in function chttpd_db:handle_request/1
    called as handle_request(x)
  in call from chttpd_handler_callback_test:'-assertReturns/3-fun-1-'/2
  in call from chttpd_handler_callback_test:assertReturns/3

  chttpd_handler_callback_test: all_test_...favicon.ico.................................... [0.070 s] ok
  chttpd_handler_callback_test: all_test_..._utils......................................... [0.071 s] ok

since ?assert* macros checks expression in runtime while ?_assert* doing this when eunit really starts to run the tests + it provides better traceback. See how couchdb-couch tests are done.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now changed, thanks.

H. Diedrich added 2 commits December 1, 2014 13:22
As requested.

Added module comment justifying reload tests.

BugzID: 27037
@kxepal
Copy link
Member

kxepal commented Dec 1, 2014

All cool, but seems your logging is still there. Try this trick:

diff --git a/test/chttpd_handler_callback_test.erl b/test/chttpd_handler_callback_test.erl
index d1f340d..2050106 100644
--- a/test/chttpd_handler_callback_test.erl
+++ b/test/chttpd_handler_callback_test.erl
@@ -31,179 +31,179 @@

 -include_lib("eunit/include/eunit.hrl").

+
 all_test_() ->
-    io:format(user, "~nEndpoint handler callbacks:~n", []),
-    {setup,
+    {foreach,
     fun() -> chttpd_handler:build(test_cfg()) end,

     % url handlers
-    [fun test_empty_string/0,
-    fun test_favicon/0,
-    fun test_utils/0,
-    fun test_all_dbs/0,
-    fun test_active_tasks/0,
-    fun test_config/0,
-    fun test_reload_query_servers/0,
-    fun test_replicate/0,
-    fun test_uuids/0,
-    fun test_sleep/0,
-    fun test_session/0,
-    fun test_oauth/0,
-    fun test_up/0,
-    fun test_membership/0,
-    fun test_db_updates/0,
-    fun test_anything/0,
+    [fun test_empty_string/1,
+    fun test_favicon/1,
+    fun test_utils/1,
+    fun test_all_dbs/1,
+    fun test_active_tasks/1,
+    fun test_config/1,
+    fun test_reload_query_servers/1,
+    fun test_replicate/1,
+    fun test_uuids/1,
+    fun test_sleep/1,
+    fun test_session/1,
+    fun test_oauth/1,
+    fun test_up/1,
+    fun test_membership/1,
+    fun test_db_updates/1,
+    fun test_anything/1,

     % Test the tests: if the final target function is missing, the call must
     % fail, with any parameter. All parameters are valid.
-    fun  verify_unmocked_failing_empty_string/0,
-    fun verify_unmocked_failing_favicon/0,
-    fun verify_unmocked_failing_anything/0,
- 
+    fun  verify_unmocked_failing_empty_string/1,
+    fun verify_unmocked_failing_favicon/1,
+    fun verify_unmocked_failing_anything/1,
+
     % db url handler tests,
-    fun test_view_cleanup/0,
-    fun test_compact/0,
-    fun test_design/0,
-    fun test_temp_view/0,
-    fun test_changes/0,
-    fun test_shards/0,
-    
+    fun test_view_cleanup/1,
+    fun test_compact/1,
+    fun test_design/1,
+    fun test_temp_view/1,
+    fun test_changes/1,
+    fun test_shards/1,
+
     % Test the test: when the final target function is missing, the Fun call
     % must fail, with any argument, including valid ones.
-    fun  verify_unmocked_failing_view_cleanup/0,
-    fun verify_unmocked_db_failing_something/0,
+    fun  verify_unmocked_failing_view_cleanup/1,
+    fun verify_unmocked_db_failing_something/1,

     % design url handler tests
-    fun test_view/0,
-    fun test_show/0,
-    fun test_list/0,
-    fun test_update/0,
-    fun test_info/0,
-    fun test_rewrite/0,
+    fun test_view/1,
+    fun test_show/1,
+    fun test_list/1,
+    fun test_update/1,
+    fun test_info/1,
+    fun test_rewrite/1,

     % Test the test: when the final target function is missing, the Fun call
     % must fail with any argument, including valid ones.
-    fun verify_unmocked_failing_view/0,
-    fun verify_unmocked_design_failing_something/0]}.
+    fun verify_unmocked_failing_view/1,
+    fun verify_unmocked_design_failing_something/1]}.

-test_empty_string() ->
-    assertReturns("", chttpd_misc, handle_welcome_req).
+test_empty_string(_Cfg) ->
+    ?_test(assertReturns("", chttpd_misc, handle_welcome_req)).

-test_favicon() ->
-    assertReturns("favicon.ico", chttpd_misc, handle_favicon_req).
+test_favicon(_Cfg) ->
+    ?_test(assertReturns("favicon.ico", chttpd_misc, handle_favicon_req)).

-test_utils() ->
-    assertReturns("_utils", chttpd_misc, handle_utils_dir_req).
+test_utils(_Cfg) ->
+    ?_test(assertReturns("_utils", chttpd_misc, handle_utils_dir_req)).

-test_all_dbs() ->
-    assertReturns("_all_dbs", chttpd_misc, handle_all_dbs_req).
+test_all_dbs(_Cfg) ->
+    ?_test(assertReturns("_all_dbs", chttpd_misc, handle_all_dbs_req)).

-test_active_tasks() ->
-    assertReturns("_active_tasks", chttpd_misc, handle_task_status_req).
+test_active_tasks(_Cfg) ->
+    ?_test(assertReturns("_active_tasks", chttpd_misc, handle_task_status_req)).

-test_config() ->
-    assertReturns("_config", chttpd_misc, handle_config_req).
+test_config(_Cfg) ->
+    ?_test(assertReturns("_config", chttpd_misc, handle_config_req)).

-test_reload_query_servers() ->
-    assertReturns("_reload_query_servers", chttpd_misc,
-        handle_reload_query_servers_req).
+test_reload_query_servers(_Cfg) ->
+    ?_test(assertReturns("_reload_query_servers", chttpd_misc,
+        handle_reload_query_servers_req)).

-test_replicate() ->
-    assertReturns("_replicate", chttpd_misc, handle_replicate_req).
+test_replicate(_Cfg) ->
+    ?_test(assertReturns("_replicate", chttpd_misc, handle_replicate_req)).

-test_uuids() ->
-    assertReturns("_uuids", chttpd_misc, handle_uuids_req).
+test_uuids(_Cfg) ->
+    ?_test(assertReturns("_uuids", chttpd_misc, handle_uuids_req)).

-test_sleep() ->
-    assertReturns("_sleep", chttpd_misc, handle_sleep_req).
+test_sleep(_Cfg) ->
+    ?_test(assertReturns("_sleep", chttpd_misc, handle_sleep_req)).

-test_session() ->
-    assertReturns("_session", chttpd_auth, handle_session_req).
+test_session(_Cfg) ->
+    ?_test(assertReturns("_session", chttpd_auth, handle_session_req)).

-test_oauth() ->
-    assertReturns("_oauth", couch_httpd_oauth, handle_oauth_req).
+test_oauth(_Cfg) ->
+    ?_test(assertReturns("_oauth", couch_httpd_oauth, handle_oauth_req)).

-test_up() ->
-    assertReturns("_up", chttpd_misc, handle_up_req).
+test_up(_Cfg) ->
+    ?_test(assertReturns("_up", chttpd_misc, handle_up_req)).

-test_membership() ->
-    assertReturns("_membership", mem3_httpd, handle_membership_req).
+test_membership(_Cfg) ->
+    ?_test(assertReturns("_membership", mem3_httpd, handle_membership_req)).

-test_db_updates() ->
-    assertReturns("_db_updates", global_changes_httpd,
-        handle_global_changes_req).
+test_db_updates(_Cfg) ->
+    ?_test(assertReturns("_db_updates", global_changes_httpd,
+        handle_global_changes_req)).

-test_anything() ->
-    assertReturns("anything", chttpd_db, handle_request).
+test_anything(_Cfg) ->
+    ?_test(assertReturns("anything", chttpd_db, handle_request)).

-verify_unmocked_failing_empty_string() ->
-    assertUnmockedFails("", chttpd_misc).
+verify_unmocked_failing_empty_string(_Cfg) ->
+    ?_test(assertUnmockedFails("", chttpd_misc)).

-verify_unmocked_failing_favicon() ->
-    assertUnmockedFails("favicon.ico", chttpd_misc).
+verify_unmocked_failing_favicon(_Cfg) ->
+    ?_test(assertUnmockedFails("favicon.ico", chttpd_misc)).

-verify_unmocked_failing_anything() ->
-    assertUnmockedFails(anything, chttpd_db).
+verify_unmocked_failing_anything(_Cfg) ->
+    ?_test(assertUnmockedFails(anything, chttpd_db)).

-test_view_cleanup() ->
-    assertReturns(db_url_handlers, <<"_view_cleanup">>, chttpd_db,
-        handle_view_cleanup_req, 2).
+test_view_cleanup(_Cfg) ->
+    ?_test(assertReturns(db_url_handlers, <<"_view_cleanup">>, chttpd_db,
+        handle_view_cleanup_req, 2)).

-test_compact() ->
-    assertReturns(db_url_handlers, <<"_compact">>, chttpd_db,
-        handle_compact_req, 2).
+test_compact(_Cfg) ->
+    ?_test(assertReturns(db_url_handlers, <<"_compact">>, chttpd_db,
+        handle_compact_req, 2)).

-test_design() ->
-    assertReturns(db_url_handlers, <<"_design">>, chttpd_db,
-        handle_design_req, 2).
+test_design(_Cfg) ->
+    ?_test(assertReturns(db_url_handlers, <<"_design">>, chttpd_db,
+        handle_design_req, 2)).

-test_temp_view() ->
-    assertReturns(db_url_handlers, <<"_temp_view">>, chttpd_view,
-        handle_temp_view_req, 2).
+test_temp_view(_Cfg) ->
+    ?_test(assertReturns(db_url_handlers, <<"_temp_view">>, chttpd_view,
+        handle_temp_view_req, 2)).

-test_changes() ->
-    assertReturns(db_url_handlers, <<"_changes">>, chttpd_db,
-        handle_changes_req, 2).
+test_changes(_Cfg) ->
+    ?_test(assertReturns(db_url_handlers, <<"_changes">>, chttpd_db,
+        handle_changes_req, 2)).

-test_shards() ->
-    assertReturns(db_url_handlers, <<"_shards">>, mem3_httpd,
-        handle_shards_req, 2).
+test_shards(_Cfg) ->
+    ?_test(assertReturns(db_url_handlers, <<"_shards">>, mem3_httpd,
+        handle_shards_req, 2)).

-verify_unmocked_failing_view_cleanup() ->
-    assertUnmockedFails(db_url_handlers, <<"_view_cleanup">>, chttpd_db, 2).
+verify_unmocked_failing_view_cleanup(_Cfg) ->
+    ?_test(assertUnmockedFails(db_url_handlers, <<"_view_cleanup">>, chttpd_db, 2)).

-verify_unmocked_db_failing_something() ->
-    assertUnknownFails(db_url_handlers, <<"_something">>).
+verify_unmocked_db_failing_something(_Cfg) ->
+    ?_test(assertUnknownFails(db_url_handlers, <<"_something">>)).

-test_view() ->
-    assertReturns(design_url_handlers, <<"_view">>, chttpd_view,
-        handle_view_req, 3).
+test_view(_Cfg) ->
+    ?_test(assertReturns(design_url_handlers, <<"_view">>, chttpd_view,
+        handle_view_req, 3)).

-test_show() ->
-    assertReturns(design_url_handlers, <<"_show">>, chttpd_show,
-        handle_doc_show_req, 3).
+test_show(_Cfg) ->
+    ?_test(assertReturns(design_url_handlers, <<"_show">>, chttpd_show,
+        handle_doc_show_req, 3)).

-test_list() ->
-    assertReturns(design_url_handlers, <<"_list">>, chttpd_show,
-        handle_view_list_req, 3).
+test_list(_Cfg) ->
+    ?_test(assertReturns(design_url_handlers, <<"_list">>, chttpd_show,
+        handle_view_list_req, 3)).

-test_update() ->
-    assertReturns(design_url_handlers, <<"_update">>, chttpd_show,
-        handle_doc_update_req, 3).
+test_update(_Cfg) ->
+    ?_test(assertReturns(design_url_handlers, <<"_update">>, chttpd_show,
+        handle_doc_update_req, 3)).

-test_info() ->
-    assertReturns(design_url_handlers, <<"_info">>, chttpd_db,
-        handle_design_info_req, 3).
+test_info(_Cfg) ->
+    ?_test(assertReturns(design_url_handlers, <<"_info">>, chttpd_db,
+        handle_design_info_req, 3)).

-test_rewrite() ->
-    assertReturns(design_url_handlers, <<"_rewrite">>, chttpd_rewrite,
-        handle_rewrite_req, 3).
+test_rewrite(_Cfg) ->
+    ?_test(assertReturns(design_url_handlers, <<"_rewrite">>, chttpd_rewrite,
+        handle_rewrite_req, 3)).

-verify_unmocked_failing_view() ->
-    assertUnmockedFails(design_url_handlers, <<"_view">>, chttpd_view, 3).
+verify_unmocked_failing_view(_Cfg) ->
+    ?_test(assertUnmockedFails(design_url_handlers, <<"_view">>, chttpd_view, 3)).

-verify_unmocked_design_failing_something() ->
-    assertUnknownFails(design_url_handlers, <<"_something">>).
+verify_unmocked_design_failing_something(_Cfg) ->
+    ?_test(assertUnknownFails(design_url_handlers, <<"_something">>)).


 %% Call the dynamic function with a parameter known to trigger a specific
@@ -212,10 +212,9 @@ verify_unmocked_design_failing_something() ->
 assertReturns(Endpoint, M, F) ->
     meck:new(M, [passthrough, non_strict]),
     try
-        io:format(user, "~-47...s ", [Endpoint]),
         meck:expect(M, F, fun(X) -> {return, Endpoint, X} end),
         Fun = chttpd_handler:url_handler(Endpoint),
-        ?_assertEqual({return, Endpoint, x}, Fun(x))
+        ?assertEqual({return, Endpoint, x}, Fun(x))
     after
         meck:unload(M)
     end.
@@ -225,7 +224,7 @@ assertUnmockedFails(Endpoint, M) ->
     meck:new(M, [non_strict]),
     try
         Fun = chttpd_handler:url_handler(Endpoint),
-        ?_assertError(undef, Fun(x))
+        ?assertError(undef, Fun(x))
     after
         meck:unload(M)
     end.
@@ -234,7 +233,6 @@ assertUnmockedFails(Endpoint, M) ->
 assertReturns(HandlerLister, Endpoint, M, F, Arity) ->
     meck:new(M, [passthrough, non_strict]),
     try
-        io:format(user, "~-47...s ", [Endpoint]),
         case Arity of
         2 ->
             meck:expect(M, F, fun(X, Y) -> {return, Endpoint, X, Y} end),
@@ -243,7 +241,7 @@ assertReturns(HandlerLister, Endpoint, M, F, Arity) ->
         3 ->
             meck:expect(M, F, fun(X, Y, Z) -> {return, Endpoint, X, Y, Z} end),
             {_, Fun} = lists:keyfind(Endpoint, 1, chttpd_handler:HandlerLister()),
-            ?_assertEqual({return, Endpoint, x, y, z}, Fun(x, y, z))
+            ?assertEqual({return, Endpoint, x, y, z}, Fun(x, y, z))
         end
     after
         meck:unload(M)
@@ -255,8 +253,8 @@ assertUnmockedFails(HandlerLister, Endpoint, M, Arity) ->
     try
         {_, Fun} = lists:keyfind(Endpoint, 1, chttpd_handler:HandlerLister()),
         case Arity of
-        2 -> ?_assertError(undef, Fun(x, y));
-        3 -> ?_assertError(undef, Fun(x, y, z))
+        2 -> ?assertError(undef, Fun(x, y));
+        3 -> ?assertError(undef, Fun(x, y, z))
         end
     after
         meck:unload(M)
@@ -264,7 +262,7 @@ assertUnmockedFails(HandlerLister, Endpoint, M, Arity) ->

 %% Make sure that a wrong parameter also really fails.
 assertUnknownFails(HandlerLister, Endpoint) ->
-    false = lists:keyfind(Endpoint, 1, chttpd_handler:HandlerLister()).
+    ?assertEqual(false, lists:keyfind(Endpoint, 1, chttpd_handler:HandlerLister())).

 test_cfg() ->
 [{url_handler, clauses, [

And compare the output yours:

module 'chttpd_handler_callback_test'
  chttpd_handler_callback_test: all_test_.................................................. [0.142 s] ok
  chttpd_handler_callback_test: all_test_...favicon.ico.................................... [0.075 s] ok
  chttpd_handler_callback_test: all_test_..._utils......................................... [0.068 s] ok
  chttpd_handler_callback_test: all_test_..._all_dbs....................................... [0.069 s] ok
  chttpd_handler_callback_test: all_test_..._active_tasks.................................. [0.071 s] ok
  chttpd_handler_callback_test: all_test_..._config........................................ [0.070 s] ok
  chttpd_handler_callback_test: all_test_..._reload_query_servers.......................... [0.069 s] ok
  chttpd_handler_callback_test: all_test_..._replicate..................................... [0.068 s] ok
  chttpd_handler_callback_test: all_test_..._uuids......................................... [0.079 s] ok
  chttpd_handler_callback_test: all_test_..._sleep......................................... [0.092 s] ok
  chttpd_handler_callback_test: all_test_..._session....................................... [0.007 s] ok
  chttpd_handler_callback_test: all_test_..._oauth......................................... [0.075 s] ok
  chttpd_handler_callback_test: all_test_..._up............................................ [0.069 s] ok
  chttpd_handler_callback_test: all_test_..._membership.................................... [0.030 s] ok
  chttpd_handler_callback_test: all_test_..._db_updates.................................... [0.042 s] ok
  chttpd_handler_callback_test: all_test_...anything....................................... [0.284 s] ok
  chttpd_handler_callback_test: all_test_...[0.061 s] ok
  chttpd_handler_callback_test: all_test_...[0.064 s] ok
  chttpd_handler_callback_test: all_test_...[0.290 s] ok
  chttpd_handler_callback_test: all_test_..._view_cleanup.................................. [0.364 s] ok
  chttpd_handler_callback_test: all_test_..._compact....................................... [0.322 s] ok
  chttpd_handler_callback_test: all_test_..._design........................................ [0.320 s] ok
  chttpd_handler_callback_test: all_test_..._temp_view..................................... [0.026 s] ok
  chttpd_handler_callback_test: all_test_..._changes....................................... [0.296 s] ok
  chttpd_handler_callback_test: all_test_..._shards........................................ [0.020 s] ok
  chttpd_handler_callback_test: all_test_...[0.323 s] ok
  chttpd_handler_callback_test: all_test_...ok
  chttpd_handler_callback_test: all_test_..._view.......................................... [0.029 s] ok
  chttpd_handler_callback_test: all_test_..._show.......................................... [0.080 s] ok
  chttpd_handler_callback_test: all_test_..._list.......................................... [0.054 s] ok
  chttpd_handler_callback_test: all_test_..._update........................................ [0.052 s] ok
  chttpd_handler_callback_test: all_test_..._info.......................................... [0.351 s] ok
  chttpd_handler_callback_test: all_test_..._rewrite....................................... [0.062 s] ok
  chttpd_handler_callback_test: all_test_...[0.031 s] ok
  chttpd_handler_callback_test: all_test_...ok

And now:

module 'chttpd_handler_callback_test'
  chttpd_handler_callback_test:90: test_empty_string...[0.087 s] ok
  chttpd_handler_callback_test:93: test_favicon...[0.076 s] ok
  chttpd_handler_callback_test:96: test_utils...[0.076 s] ok
  chttpd_handler_callback_test:99: test_all_dbs...[0.075 s] ok
  chttpd_handler_callback_test:102: test_active_tasks...[0.077 s] ok
  chttpd_handler_callback_test:105: test_config...[0.076 s] ok
  chttpd_handler_callback_test:108: test_reload_query_servers...[0.077 s] ok
  chttpd_handler_callback_test:112: test_replicate...[0.075 s] ok
  chttpd_handler_callback_test:115: test_uuids...[0.076 s] ok
  chttpd_handler_callback_test:118: test_sleep...[0.099 s] ok
  chttpd_handler_callback_test:121: test_session...[0.007 s] ok
  chttpd_handler_callback_test:124: test_oauth...[0.054 s] ok
  chttpd_handler_callback_test:127: test_up...[0.076 s] ok
  chttpd_handler_callback_test:130: test_membership...[0.018 s] ok
  chttpd_handler_callback_test:133: test_db_updates...[0.045 s] ok
  chttpd_handler_callback_test:137: test_anything...[0.369 s] ok
  chttpd_handler_callback_test:140: verify_unmocked_failing_empty_string...[0.066 s] ok
  chttpd_handler_callback_test:143: verify_unmocked_failing_favicon...[0.065 s] ok
  chttpd_handler_callback_test:146: verify_unmocked_failing_anything...[0.362 s] ok
  chttpd_handler_callback_test:149: test_view_cleanup...[0.367 s] ok
  chttpd_handler_callback_test:153: test_compact...[0.372 s] ok
  chttpd_handler_callback_test:157: test_design...[0.370 s] ok
  chttpd_handler_callback_test:161: test_temp_view...[0.031 s] ok
  chttpd_handler_callback_test:165: test_changes...[0.406 s] ok
  chttpd_handler_callback_test:169: test_shards...[0.020 s] ok
  chttpd_handler_callback_test:173: verify_unmocked_failing_view_cleanup...[0.390 s] ok
  chttpd_handler_callback_test:176: verify_unmocked_db_failing_something...ok
  chttpd_handler_callback_test:179: test_view...[0.033 s] ok
  chttpd_handler_callback_test:183: test_show...[0.051 s] ok
  chttpd_handler_callback_test:187: test_list...[0.052 s] ok
  chttpd_handler_callback_test:191: test_update...[0.054 s] ok
  chttpd_handler_callback_test:195: test_info...[0.393 s] ok
  chttpd_handler_callback_test:199: test_rewrite...[0.060 s] ok
  chttpd_handler_callback_test:203: verify_unmocked_failing_view...[0.026 s] ok
  chttpd_handler_callback_test:206: verify_unmocked_design_failing_something...ok

Looks better right? I'd forgot a bit how to make eunit produce the right output: it doesn't works right if setup receives list of functions, so I eventually have to rollback ecd4f77 - sorry for the false tip. Now you see which function got executed and you'll easily know which one fails.

@hdiedrich
Copy link
Author

Thanks a lot for digging into it, I'll change accordingly, however, do we need to have "httpd_handler_callback_test:206:" before each output line? I don't know what apache/couchdb-chttpd does differently with the eunit setup but the same test source did not print these module:line hints before every line.

Also, I am using io:format to prevent even more prefix in each line and I will try out your setup but all I ever found was that ?debugFmt inevitably adds to the line. I did not invent using io:format(user, ... that is from the Eunit docs, the way to produce screen output.

I polished this output to be concise because I needed to find a race condition that only became apparent in the logs. From that I got to appreciate briefer, readable, cleaned up logs and modelled it after the etap output. I will try your proposal and go from there, then come back with what I found regarding ?debugFmt and leave it up to you.

@kxepal
Copy link
Member

kxepal commented Dec 1, 2014

however, do we need to have "httpd_handler_callback_test:206:" before each output line?

That will save a lot of time if something will go wrong since it directly points on the exact line in exact module where to start your search.

I don't know what apache/couchdb-chttpd does differently with the eunit setup but the same test source did not print these module:line hints before every line.

IIRC that's some eunit internal thing about using setup. I'd fight with the output year ago and might be forgot all the details, but one I know for sure: it's an easy to produce useless test report with eunit. Need to note, that I'm care here about further test suite support.

Also, I am using io:format to prevent even more prefix in each line and I will try out your setup but all I ever found was that ?debugFmt inevitably adds to the line. I did not invent using io:format(user, ... that is from the Eunit docs, the way to produce screen output.

Sorry if "reinvent" was sound a bit rude. The problem of io:format that it will always print things to stdout. As for ?debug, you can turn this output off after defining NODEBUG leaving whole report clean.

I polished this output to be concise because I needed to find a race condition that only became apparent in the logs.

Sounds like you'll have to add another case on that (; Good luck with chasing RC - that's not an easy.

From that I got to appreciate briefer, readable, cleaned up logs and modelled it after the etap output.

I see. Well, for eunit other tests are already uses the "default" output format, so if you think it could be improved, it need to be improved everywhere.

@hdiedrich
Copy link
Author

Ok, thanks! I can set NODEBUG at the top of the test module?

@kxepal
Copy link
Member

kxepal commented Dec 1, 2014

Yes, but better add {erl_opts, [{d, NODEBUG}]}. to rebar config (setup_eunit?). This better have global wide.

@hdiedrich
Copy link
Author

I guess the NODEBUG proposal was a misunderstanding. I was looking for a way to create readable test output, as created during the test. Not sure what you actually meant with using NODEBUG, will leave that out for now.

I'll otherwise rewrite as requested, to move forward. For my part I am unconvinced the test output needs line numbers added as it clutters the test source a bit, not making it more readable and adding a runtime indirection, if I understand that correctly, away from the intuitive assumption, for what it's worth. And adding the additional setup time using foreach reduces the test speed, for little gain, for all I can see.

@kxepal
Copy link
Member

kxepal commented Dec 2, 2014

@hdiedrich if you're looking for fixing eunit output take a look on how formatters are done for it. For instance: https://github.com/seancribbs/eunit_formatters . Doing the same work with io:format isn't right in anyway.

For my part I am unconvinced the test output needs line numbers added as it clutters the test source a bit.

Remove this info, break the tests, give someone to fix them and ask does this info could make his live simpler or not (: Chasing readability shouldn't hurt maintenance support.

@hdiedrich
Copy link
Author

It's peripheral, I believe, but the output of the test could be helpful to indicate, which endpoint breaks, rather than which test function breaks. That's why I think it may have been more helpful before.

It's not too important maybe, I changed it according to your preference. I certainly see your point.

Would it be welcome to propose eunit formatters?

@kxepal
Copy link
Member

kxepal commented Dec 2, 2014

It's peripheral, I believe, but the output of the test could be helpful to indicate, which endpoint breaks, rather than which test function breaks. That's why I think it may have been more helpful before.

If function name describes what exactly it tests (which endpoint for what behavior in your case), you'll hit two birds with single stone (;

Would it be welcome to propose eunit formatters?

I'm +1 on this. Dream on something colorful with slow tests highlight and nicer function name transforming into more readable form - that would be awesome!

@kxepal
Copy link
Member

kxepal commented Jan 9, 2015

I'm happy with merge this. @rnewson @davisp @chewbranca what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems I miss that moment. Why not to reuse config and have all the handlers defined there? We already keep httpd ones there and this gives us dynamic control over them with no server restart.

@iilyak
Copy link
Contributor

iilyak commented Apr 30, 2015

@hdiedrich: Any updates on this PR?

@hdiedrich
Copy link
Author

Hi, I need to review what the over all situation for this is at this point. Status is that there was a wish from Paul on how to better kick the handlers in, which I liked, but got stuck implementing it and kept going backwards finding out why until it became clear that I need to port my system tests over from the original implementation in dbcore that had met little love there. I then waited for integration tests from Russel and Ilya to be merged, so I don't double their effort but those got stuck, too IIRC. The way forward should be simple and fast and I'll be happy to finally get it merged.

The start up, as it is, has the weakness that there needs to be knowledge about the modules in play, which defeats the intended uncoupling. The solution would be to just re-compile every step of the way when a new app is added during start up. That makes it fool proof and self-sufficient. Config, as Alex suggests, should therefore not be needed.

There are merge conflicts in this PR now for rot but the core functionality was mergeable rather cleanly.

@kxepal
Copy link
Member

kxepal commented May 12, 2015

@hdiedrich Hey! Config support suddenly is needed by the following reasons:

  • It saved us many times when security issue was found in some HTTP handler. The recent example: http://docs.couchdb.org/en/latest/cve/2014-2668.html - users were able to handle that problem without upgrade procedure, but with a single config line change.
  • Some users are disables default handlers, or provide own overlay, in order to prevent or customize access to certain endpoints. Quite popular move is to disable /_all_dbs in order to prevent sharing database lists for everyone. Another option is to replace default handler with own from the plugin if you're going to change behaviour without patching the source code.
  • Somehow need to provide ability to register proxy and external handlers.

hdiedrich pushed a commit to hdiedrich/couchdb that referenced this pull request May 19, 2015
chttpd hardcoded handlers are replaced with with dynamic url handlers.

This is a special branch that pull the prepared branches (of the same name)
of chttpd, mem3, global_changes, setup_httpd, mango_httpd, which have the
relevant config files.

See chttpd/27037-5-dynamic-endpoint-handlers.

This is a re-do of PR 10 for bitrot:
apache/couchdb-chttpd#10

BugzID: 27037
@rnewson
Copy link
Member

rnewson commented Jun 25, 2015

The plan that the couchdb 2.0 sprint team agreed on is basically;

  1. every application can easily register its own endpoints simply by existing
  2. administrators can disable any endpoints they like
  3. the configuration file's proxy and external handlers section should be included in the set of endpoints (and added last)

As to how we can support 'overlay' of an application's endpoints, I'm less sure. I suggest we get the above steps done first and then reassess.

@kxepal
Copy link
Member

kxepal commented Jul 22, 2015

Dynamic handlers were landed based on @iilyak work. Could you close this PR please?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants