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 2014/02/05 00:44:39 UTC
[26/44] couchdb commit: updated
refs/heads/1843-feature-bigcouch-multi-repo to 2385a37
Remove src/ets_lru
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/ed8c2fb2
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/ed8c2fb2
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/ed8c2fb2
Branch: refs/heads/1843-feature-bigcouch-multi-repo
Commit: ed8c2fb2f50dda679aff79996667d8e2ffe8ad54
Parents: 191a9b4
Author: Paul J. Davis <pa...@gmail.com>
Authored: Tue Feb 4 17:40:55 2014 -0600
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Tue Feb 4 17:40:55 2014 -0600
----------------------------------------------------------------------
src/ets_lru/src/ets_lru.app.src | 24 --
src/ets_lru/src/ets_lru.erl | 311 --------------
src/ets_lru/test/01-basic-behavior.t | 91 ----
src/ets_lru/test/02-lru-options.t | 61 ---
src/ets_lru/test/03-limit-max-objects.t | 26 --
src/ets_lru/test/04-limit-max-size.t | 26 --
src/ets_lru/test/05-limit-lifetime.t | 23 -
src/ets_lru/test/etap.erl | 612 ---------------------------
src/ets_lru/test/tutil.erl | 29 --
9 files changed, 1203 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/src/ets_lru.app.src
----------------------------------------------------------------------
diff --git a/src/ets_lru/src/ets_lru.app.src b/src/ets_lru/src/ets_lru.app.src
deleted file mode 100644
index 2573a0f..0000000
--- a/src/ets_lru/src/ets_lru.app.src
+++ /dev/null
@@ -1,24 +0,0 @@
-% 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.
-
-{application, ets_lru, [
- {description, "ETS Base LRU Cache"},
- {vsn, git},
- {modules, [
- ets_lru
- ]},
- {registered, []},
- {applications, [
- kernel,
- stdlib
- ]}
-]}.
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/src/ets_lru.erl
----------------------------------------------------------------------
diff --git a/src/ets_lru/src/ets_lru.erl b/src/ets_lru/src/ets_lru.erl
deleted file mode 100644
index 5880bd5..0000000
--- a/src/ets_lru/src/ets_lru.erl
+++ /dev/null
@@ -1,311 +0,0 @@
-% 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.
-
--module(ets_lru).
--behavior(gen_server).
-
-
--export([
- start_link/2,
- stop/1,
-
- insert/3,
- lookup/2,
- remove/2,
- clear/1,
-
- % Dirty functions read straight from
- % the ETS tables which means there are
- % race conditions with concurrent access.
- lookup_d/2
-]).
-
--export([
- init/1,
- terminate/2,
-
- handle_call/3,
- handle_cast/2,
- handle_info/2,
-
- code_change/3
-]).
-
-
--record(entry, {
- key,
- val,
- atime,
- ctime
-}).
-
--record(st, {
- objects,
- atimes,
- ctimes,
-
- max_objs,
- max_size,
- max_lifetime
-}).
-
-
-start_link(Name, Options) when is_atom(Name) ->
- gen_server:start_link({local, Name}, ?MODULE, {Name, Options}, []).
-
-
-stop(LRU) ->
- gen_server:cast(LRU, stop).
-
-
-lookup(LRU, Key) ->
- gen_server:call(LRU, {lookup, Key}).
-
-
-insert(LRU, Key, Val) ->
- gen_server:call(LRU, {insert, Key, Val}).
-
-
-remove(LRU, Key) ->
- gen_server:call(LRU, {remove, Key}).
-
-
-clear(LRU) ->
- gen_server:call(LRU, clear).
-
-
-lookup_d(Name, Key) when is_atom(Name) ->
- case ets:lookup(obj_table(Name), Key) of
- [#entry{val=Val}] ->
- gen_server:cast(Name, {accessed, Key}),
- {ok, Val};
- [] ->
- not_found
- end.
-
-
-init({Name, Options}) ->
- St = set_options(#st{}, Options),
- ObjOpts = [set, named_table, protected, {keypos, #entry.key}],
- TimeOpts = [ordered_set, named_table, protected],
-
- {ok, St#st{
- objects = ets:new(obj_table(Name), ObjOpts),
- atimes = ets:new(at_table(Name), TimeOpts),
- ctimes = ets:new(ct_table(Name), TimeOpts)
- }}.
-
-
-terminate(_Reason, St) ->
- true = ets:delete(St#st.objects),
- true = ets:delete(St#st.atimes),
- true = ets:delete(St#st.ctimes),
- ok.
-
-
-handle_call({lookup, Key}, _From, St) ->
- Reply = case ets:lookup(St#st.objects, Key) of
- [#entry{val=Val}] ->
- accessed(St, Key),
- {ok, Val};
- [] ->
- not_found
- end,
- {reply, Reply, St, 0};
-
-handle_call({insert, Key, Val}, _From, St) ->
- NewATime = erlang:now(),
- Pattern = #entry{key=Key, atime='$1', _='_'},
- case ets:match(St#st.objects, Pattern) of
- [[ATime]] ->
- Update = {#entry.val, Val},
- true = ets:update_element(St#st.objects, Key, Update),
- true = ets:delete(St#st.atimes, ATime),
- true = ets:insert(St#st.atimes, {NewATime, Key});
- [] ->
- Entry = #entry{key=Key, val=Val, atime=NewATime, ctime=NewATime},
- true = ets:insert(St#st.objects, Entry),
- true = ets:insert(St#st.atimes, {NewATime, Key}),
- true = ets:insert(St#st.ctimes, {NewATime, Key})
- end,
- {reply, ok, St, 0};
-
-handle_call({remove, Key}, _From, St) ->
- Pattern = #entry{key=Key, atime='$1', ctime='$2', _='_'},
- Reply = case ets:match(St#st.objects, Pattern) of
- [[ATime, CTime]] ->
- true = ets:delete(St#st.objects, Key),
- true = ets:delete(St#st.atimes, ATime),
- true = ets:delete(St#st.ctimes, CTime),
- ok;
- [] ->
- not_found
- end,
- {reply, Reply, St, 0};
-
-handle_call(clear, _From, St) ->
- true = ets:delete_all_objects(St#st.objects),
- true = ets:delete_all_objects(St#st.atimes),
- true = ets:delete_all_objects(St#st.ctimes),
- % No need to timeout here and evict cache
- % entries because its now empty.
- {reply, ok, St};
-
-
-handle_call(Msg, _From, St) ->
- {stop, {invalid_call, Msg}, {invalid_call, Msg}, St}.
-
-
-handle_cast({accessed, Key}, St) ->
- accessed(Key, St),
- {noreply, St, 0};
-
-handle_cast(stop, St) ->
- {stop, normal, St};
-
-handle_cast(Msg, St) ->
- {stop, {invalid_cast, Msg}, St}.
-
-
-handle_info(timeout, St) ->
- trim(St),
- {noreply, St, next_timeout(St)};
-
-handle_info(Msg, St) ->
- {stop, {invalid_info, Msg}, St}.
-
-
-code_change(_OldVsn, St, _Extra) ->
- {ok, St}.
-
-
-accessed(Key, St) ->
- Pattern = #entry{key=Key, atime='$1', _='_'},
- case ets:match(St#st.objects, Pattern) of
- [[ATime]] ->
- NewATime = erlang:now(),
- Update = {#entry.atime, NewATime},
- true = ets:update_element(St#st.objects, Key, Update),
- true = ets:delete(St#st.atimes, ATime),
- true = ets:insert(St#st.atimes, {NewATime, Key}),
- ok;
- [] ->
- ok
- end.
-
-
-trim(St) ->
- trim_count(St),
- trim_size(St),
- trim_lifetime(St).
-
-
-trim_count(#st{max_objs=undefined}) ->
- ok;
-trim_count(#st{max_objs=Max}=St) ->
- case ets:info(St#st.objects, size) > Max of
- true ->
- drop_lru(St, fun trim_count/1);
- false ->
- ok
- end.
-
-
-trim_size(#st{max_size=undefined}) ->
- ok;
-trim_size(#st{max_size=Max}=St) ->
- case ets:info(St#st.objects, memory) > Max of
- true ->
- drop_lru(St, fun trim_size/1);
- false ->
- ok
- end.
-
-
-trim_lifetime(#st{max_lifetime=undefined}) ->
- ok;
-trim_lifetime(#st{max_lifetime=Max}=St) ->
- Now = os:timestamp(),
- case ets:first(St#st.ctimes) of
- '$end_of_table' ->
- ok;
- CTime ->
- DiffInMilli = timer:now_diff(Now, CTime) div 1000,
- case DiffInMilli > Max of
- true ->
- [{CTime, Key}] = ets:lookup(St#st.ctimes, CTime),
- Pattern = #entry{key=Key, atime='$1', _='_'},
- [[ATime]] = ets:match(St#st.objects, Pattern),
- true = ets:delete(St#st.objects, Key),
- true = ets:delete(St#st.atimes, ATime),
- true = ets:delete(St#st.ctimes, CTime),
- trim_lifetime(St);
- false ->
- ok
- end
- end.
-
-
-drop_lru(St, Continue) ->
- case ets:first(St#st.atimes) of
- '$end_of_table' ->
- empty;
- ATime ->
- [{ATime, Key}] = ets:lookup(St#st.atimes, ATime),
- Pattern = #entry{key=Key, ctime='$1', _='_'},
- [[CTime]] = ets:match(St#st.objects, Pattern),
- true = ets:delete(St#st.objects, Key),
- true = ets:delete(St#st.atimes, ATime),
- true = ets:delete(St#st.ctimes, CTime),
- Continue(St)
- end.
-
-
-next_timeout(#st{max_lifetime=undefined}) ->
- infinity;
-next_timeout(St) ->
- case ets:first(St#st.ctimes) of
- '$end_of_table' ->
- infinity;
- CTime ->
- Now = os:timestamp(),
- DiffInMilli = timer:now_diff(Now, CTime) div 1000,
- erlang:max(St#st.max_lifetime - DiffInMilli, 0)
- end.
-
-
-set_options(St, []) ->
- St;
-set_options(St, [{max_objects, N} | Rest]) when is_integer(N), N > 0 ->
- set_options(St#st{max_objs=N}, Rest);
-set_options(St, [{max_size, N} | Rest]) when is_integer(N), N > 0 ->
- set_options(St#st{max_size=N}, Rest);
-set_options(St, [{max_lifetime, N} | Rest]) when is_integer(N), N > 0 ->
- set_options(St#st{max_lifetime=N}, Rest);
-set_options(_, [Opt | _]) ->
- throw({invalid_option, Opt}).
-
-
-obj_table(Name) ->
- table_name(Name, "_objects").
-
-
-at_table(Name) ->
- table_name(Name, "_atimes").
-
-
-ct_table(Name) ->
- table_name(Name, "_ctimes").
-
-
-table_name(Name, Ext) ->
- list_to_atom(atom_to_list(Name) ++ Ext).
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/01-basic-behavior.t
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/01-basic-behavior.t b/src/ets_lru/test/01-basic-behavior.t
deleted file mode 100755
index 7e87a5d..0000000
--- a/src/ets_lru/test/01-basic-behavior.t
+++ /dev/null
@@ -1,91 +0,0 @@
-#! /usr/bin/env escript
-
--define(WITH_LRU(F), tutil:with_lru(fun(LRU) -> F(LRU) end)).
-
-main([]) ->
- code:add_pathz("test"),
- code:add_pathz("ebin"),
-
- tutil:run(16, fun() -> test() end).
-
-
-test() ->
- test_lifecycle(),
- test_table_names(),
- ?WITH_LRU(test_insert_lookup),
- ?WITH_LRU(test_insert_overwrite),
- ?WITH_LRU(test_insert_remove),
- ?WITH_LRU(test_clear),
-
- ok.
-
-
-test_lifecycle() ->
- Resp = ets_lru:start_link(?MODULE, []),
- etap:fun_is(
- fun({ok, LRU}) when is_pid(LRU) -> true; (_) -> false end,
- Resp,
- "ets_lru:start_link/2 returned an LRU"
- ),
- {ok, LRU} = Resp,
- etap:is(ok, ets_lru:stop(LRU), "Destroyed the LRU ok").
-
-
-test_table_names() ->
- {ok, LRU} = ets_lru:start_link(foo, []),
- Exists = fun(Name) -> ets:info(Name, size) == 0 end,
- NExists = fun(Name) -> ets:info(Name, size) == undefined end,
- etap:is(Exists(foo_objects), true, "foo_objects exists"),
- etap:is(Exists(foo_atimes), true, "foo_atimes exists"),
- etap:is(Exists(foo_ctimes), true, "foo_ctimes exists"),
-
- Ref = erlang:monitor(process, LRU),
- ets_lru:stop(LRU),
-
- receive {'DOWN', Ref, process, LRU, Reason} -> ok end,
- etap:is(Reason, normal, "LRU stopped normally"),
-
- etap:is(NExists(foo_objects), true, "foo_objects doesn't exist"),
- etap:is(NExists(foo_atimes), true, "foo_atimes doesn't exist"),
- etap:is(NExists(foo_ctimes), true, "foo_ctimes doesn't exist"),
-
- ok.
-
-
-test_insert_lookup(LRU) ->
- ok = ets_lru:insert(LRU, foo, bar),
- Resp = ets_lru:lookup(LRU, foo),
- etap:is(Resp, {ok, bar}, "Lookup returned the inserted value").
-
-
-test_insert_lookup_d(LRU) ->
- ok = ets_lru:insert(LRU, foo, bar),
- Resp = ets_lru:lookup_d(test_lru, foo),
- etap:is(Resp, {ok, bar}, "Dirty lookup returned the inserted value").
-
-
-test_insert_overwrite(LRU) ->
- ok = ets_lru:insert(LRU, foo, bar),
- Resp1 = ets_lru:lookup(LRU, foo),
- etap:is(Resp1, {ok, bar}, "Lookup returned the inserted value"),
- ok = ets_lru:insert(LRU, foo, bam),
- Resp2 = ets_lru:lookup(LRU, foo),
- etap:is(Resp2, {ok, bam}, "Lookup returned the newly inserted value").
-
-
-test_insert_remove(LRU) ->
- ok = ets_lru:insert(LRU, foo, bar),
- Resp1 = ets_lru:lookup(LRU, foo),
- etap:is(Resp1, {ok, bar}, "Lookup returned the inserted value"),
- ok = ets_lru:remove(LRU, foo),
- Resp2 = ets_lru:lookup(LRU, foo),
- etap:is(Resp2, not_found, "Lookup returned not_found for removed value").
-
-
-test_clear(LRU) ->
- ok = ets_lru:insert(LRU, foo, bar),
- Resp1 = ets_lru:lookup(LRU, foo),
- etap:is(Resp1, {ok, bar}, "Lookup returned the inserted value"),
- ok = ets_lru:clear(LRU),
- Resp2 = ets_lru:lookup(LRU, foo),
- etap:is(Resp2, not_found, "Lookup returned not_found after a clear").
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/02-lru-options.t
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/02-lru-options.t b/src/ets_lru/test/02-lru-options.t
deleted file mode 100755
index 59d0ba1..0000000
--- a/src/ets_lru/test/02-lru-options.t
+++ /dev/null
@@ -1,61 +0,0 @@
-#! /usr/bin/env escript
-
-main([]) ->
- code:add_pathz("test"),
- code:add_pathz("ebin"),
-
- tutil:run(9, fun() -> test() end).
-
-
-test() ->
- test_max_objects(),
- test_max_size(),
- test_lifetime(),
- test_bad_option(),
-
- ok.
-
-
-test_max_objects() ->
- % See also: 03-limit-max-objects.t
- test_good([{max_objects, 5}]),
- test_good([{max_objects, 1}]),
- test_good([{max_objects, 923928342098203942}]).
-
-
-test_max_size() ->
- % See also: 04-limit-max-size.t
- test_good([{max_size, 1}]),
- test_good([{max_size, 5}]),
- test_good([{max_size, 2342923423942309423094}]).
-
-
-test_lifetime() ->
- % See also: 05-limit-lifetime.t
- test_good([{max_lifetime, 1}]),
- test_good([{max_lifetime, 5}]),
- test_good([{max_lifetime, 1244209909180928348}]).
-
-
-test_bad_option() ->
- % Figure out a test for these.
- %test_bad([{bingo, bango}]),
- %test_bad([12]),
- %test_bad([true]).
- ok.
-
-
-test_good(Options) ->
- Msg = io_lib:format("LRU created ok with options: ~w", [Options]),
- etap:fun_is(fun
- ({ok, LRU}) when is_pid(LRU) -> ets_lru:stop(LRU), true;
- (_) -> false
- end, ets_lru:start_link(?MODULE, Options), lists:flatten(Msg)).
-
-
-% test_bad(Options) ->
-% etap:fun_is(fun
-% ({invalid_option, _}) -> true;
-% ({ok, LRU}) -> ets_lru:stop(LRU), false;
-% (_) -> false
-% end, catch ets_lru:start_link(?MODULE, Options), "LRU bad options").
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/03-limit-max-objects.t
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/03-limit-max-objects.t b/src/ets_lru/test/03-limit-max-objects.t
deleted file mode 100755
index bd4e793..0000000
--- a/src/ets_lru/test/03-limit-max-objects.t
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /usr/bin/env escript
-
-objs() -> 25.
-
-main([]) ->
- code:add_pathz("test"),
- code:add_pathz("ebin"),
-
- tutil:run(1, fun() -> test() end).
-
-
-test() ->
- {ok, LRU} = ets_lru:start_link(lru, [{max_objects, objs()}]),
- etap:is(insert_kvs(LRU, 100 * objs()), ok, "Max object count ok"),
- ok = ets_lru:stop(LRU).
-
-
-insert_kvs(LRU, 0) ->
- ok;
-insert_kvs(LRU, Count) ->
- ets_lru:insert(LRU, Count, bar),
- case ets:info(lru_objects, size) > objs() of
- true -> erlang:error(exceeded_max_objects);
- false -> ok
- end,
- insert_kvs(LRU, Count-1).
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/04-limit-max-size.t
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/04-limit-max-size.t b/src/ets_lru/test/04-limit-max-size.t
deleted file mode 100755
index 5cdf0ce..0000000
--- a/src/ets_lru/test/04-limit-max-size.t
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /usr/bin/env escript
-
-max_size() -> 1024.
-
-main([]) ->
- code:add_pathz("test"),
- code:add_pathz("ebin"),
-
- tutil:run(1, fun() -> test() end).
-
-
-test() ->
- {ok, LRU} = ets_lru:start_link(lru, [{max_size, max_size()}]),
- etap:is(insert_kvs(LRU, 10000), ok, "Max size ok"),
- ok = ets_lru:stop(LRU).
-
-
-insert_kvs(LRU, 0) ->
- ok;
-insert_kvs(LRU, Count) ->
- ets_lru:insert(LRU, Count, 1.5234),
- case ets:info(lru_objects, memory) > max_size() of
- true -> erlang:error(exceeded_max_size);
- false -> ok
- end,
- insert_kvs(LRU, Count-1).
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/05-limit-lifetime.t
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/05-limit-lifetime.t b/src/ets_lru/test/05-limit-lifetime.t
deleted file mode 100755
index 95effb2..0000000
--- a/src/ets_lru/test/05-limit-lifetime.t
+++ /dev/null
@@ -1,23 +0,0 @@
-#! /usr/bin/env escript
-
-lifetime() -> 100.
-
-main([]) ->
- code:add_pathz("test"),
- code:add_pathz("ebin"),
-
- tutil:run(2, fun() -> test() end).
-
-
-test() ->
- {ok, LRU} = ets_lru:start_link(lru, [{max_lifetime, lifetime()}]),
- ok = test_single_entry(LRU),
- ok = ets_lru:stop(LRU).
-
-
-test_single_entry(LRU) ->
- ets_lru:insert(LRU, foo, bar),
- etap:is(ets_lru:lookup(LRU, foo), {ok, bar}, "Expire leaves new entries"),
- timer:sleep(round(lifetime() * 1.5)),
- etap:is(ets_lru:lookup(LRU, foo), not_found, "Entry was expired"),
- ok.
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/etap.erl
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/etap.erl b/src/ets_lru/test/etap.erl
deleted file mode 100644
index 6924d09..0000000
--- a/src/ets_lru/test/etap.erl
+++ /dev/null
@@ -1,612 +0,0 @@
-%% Copyright (c) 2008-2009 Nick Gerakines <ni...@gerakines.net>
-%%
-%% Permission is hereby granted, free of charge, to any person
-%% obtaining a copy of this software and associated documentation
-%% files (the "Software"), to deal in the Software without
-%% restriction, including without limitation the rights to use,
-%% copy, modify, merge, publish, distribute, sublicense, and/or sell
-%% copies of the Software, and to permit persons to whom the
-%% Software is furnished to do so, subject to the following
-%% conditions:
-%%
-%% The above copyright notice and this permission notice shall be
-%% included in all copies or substantial portions of the Software.
-%%
-%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-%% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-%% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-%% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-%% OTHER DEALINGS IN THE SOFTWARE.
-%%
-%% @author Nick Gerakines <ni...@gerakines.net> [http://socklabs.com/]
-%% @author Jeremy Wall <je...@marzhillstudios.com>
-%% @version 0.3.4
-%% @copyright 2007-2008 Jeremy Wall, 2008-2009 Nick Gerakines
-%% @reference http://testanything.org/wiki/index.php/Main_Page
-%% @reference http://en.wikipedia.org/wiki/Test_Anything_Protocol
-%% @todo Finish implementing the skip directive.
-%% @todo Document the messages handled by this receive loop.
-%% @todo Explain in documentation why we use a process to handle test input.
-%% @doc etap is a TAP testing module for Erlang components and applications.
-%% This module allows developers to test their software using the TAP method.
-%%
-%% <blockquote cite="http://en.wikipedia.org/wiki/Test_Anything_Protocol"><p>
-%% TAP, the Test Anything Protocol, is a simple text-based interface between
-%% testing modules in a test harness. TAP started life as part of the test
-%% harness for Perl but now has implementations in C/C++, Python, PHP, Perl
-%% and probably others by the time you read this.
-%% </p></blockquote>
-%%
-%% The testing process begins by defining a plan using etap:plan/1, running
-%% a number of etap tests and then calling eta:end_tests/0. Please refer to
-%% the Erlang modules in the t directory of this project for example tests.
--module(etap).
--vsn("0.3.4").
-
--export([
- ensure_test_server/0,
- start_etap_server/0,
- test_server/1,
- msg/1, msg/2,
- diag/1, diag/2,
- expectation_mismatch_message/3,
- plan/1,
- end_tests/0,
- not_ok/2, ok/2, is_ok/2, is/3, isnt/3, any/3, none/3,
- fun_is/3, expect_fun/3, expect_fun/4,
- is_greater/3,
- skip/1, skip/2,
- datetime/1,
- skip/3,
- bail/0, bail/1,
- test_state/0, failure_count/0
-]).
-
--export([
- contains_ok/3,
- is_before/4
-]).
-
--export([
- is_pid/2,
- is_alive/2,
- is_mfa/3
-]).
-
--export([
- loaded_ok/2,
- can_ok/2, can_ok/3,
- has_attrib/2, is_attrib/3,
- is_behaviour/2
-]).
-
--export([
- dies_ok/2,
- lives_ok/2,
- throws_ok/3
-]).
-
-
--record(test_state, {
- planned = 0,
- count = 0,
- pass = 0,
- fail = 0,
- skip = 0,
- skip_reason = ""
-}).
-
-%% @spec plan(N) -> Result
-%% N = unknown | skip | {skip, string()} | integer()
-%% Result = ok
-%% @doc Create a test plan and boot strap the test server.
-plan(unknown) ->
- ensure_test_server(),
- etap_server ! {self(), plan, unknown},
- ok;
-plan(skip) ->
- io:format("1..0 # skip~n");
-plan({skip, Reason}) ->
- io:format("1..0 # skip ~s~n", [Reason]);
-plan(N) when is_integer(N), N > 0 ->
- ensure_test_server(),
- etap_server ! {self(), plan, N},
- ok.
-
-%% @spec end_tests() -> ok
-%% @doc End the current test plan and output test results.
-%% @todo This should probably be done in the test_server process.
-end_tests() ->
- case whereis(etap_server) of
- undefined -> self() ! true;
- _ -> etap_server ! {self(), state}
- end,
- State = receive X -> X end,
- if
- State#test_state.planned == -1 ->
- io:format("1..~p~n", [State#test_state.count]);
- true ->
- ok
- end,
- case whereis(etap_server) of
- undefined -> ok;
- _ -> etap_server ! done, ok
- end.
-
-bail() ->
- bail("").
-
-bail(Reason) ->
- etap_server ! {self(), diag, "Bail out! " ++ Reason},
- etap_server ! done, ok,
- ok.
-
-%% @spec test_state() -> Return
-%% Return = test_state_record() | {error, string()}
-%% @doc Return the current test state
-test_state() ->
- etap_server ! {self(), state},
- receive
- X when is_record(X, test_state) -> X
- after
- 1000 -> {error, "Timed out waiting for etap server reply.~n"}
- end.
-
-%% @spec failure_count() -> Return
-%% Return = integer() | {error, string()}
-%% @doc Return the current failure count
-failure_count() ->
- case test_state() of
- #test_state{fail=FailureCount} -> FailureCount;
- X -> X
- end.
-
-%% @spec msg(S) -> ok
-%% S = string()
-%% @doc Print a message in the test output.
-msg(S) -> etap_server ! {self(), diag, S}, ok.
-
-%% @spec msg(Format, Data) -> ok
-%% Format = atom() | string() | binary()
-%% Data = [term()]
-%% UnicodeList = [Unicode]
-%% Unicode = int()
-%% @doc Print a message in the test output.
-%% Function arguments are passed through io_lib:format/2.
-msg(Format, Data) -> msg(io_lib:format(Format, Data)).
-
-%% @spec diag(S) -> ok
-%% S = string()
-%% @doc Print a debug/status message related to the test suite.
-diag(S) -> msg("# " ++ S).
-
-%% @spec diag(Format, Data) -> ok
-%% Format = atom() | string() | binary()
-%% Data = [term()]
-%% UnicodeList = [Unicode]
-%% Unicode = int()
-%% @doc Print a debug/status message related to the test suite.
-%% Function arguments are passed through io_lib:format/2.
-diag(Format, Data) -> diag(io_lib:format(Format, Data)).
-
-%% @spec expectation_mismatch_message(Got, Expected, Desc) -> ok
-%% Got = any()
-%% Expected = any()
-%% Desc = string()
-%% @doc Print an expectation mismatch message in the test output.
-expectation_mismatch_message(Got, Expected, Desc) ->
- msg(" ---"),
- msg(" description: ~p", [Desc]),
- msg(" found: ~p", [Got]),
- msg(" wanted: ~p", [Expected]),
- msg(" ..."),
- ok.
-
-% @spec evaluate(Pass, Got, Expected, Desc) -> Result
-%% Pass = true | false
-%% Got = any()
-%% Expected = any()
-%% Desc = string()
-%% Result = true | false
-%% @doc Evaluate a test statement, printing an expectation mismatch message
-%% if the test failed.
-evaluate(Pass, Got, Expected, Desc) ->
- case mk_tap(Pass, Desc) of
- false ->
- expectation_mismatch_message(Got, Expected, Desc),
- false;
- true ->
- true
- end.
-
-%% @spec ok(Expr, Desc) -> Result
-%% Expr = true | false
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that a statement is true.
-ok(Expr, Desc) -> evaluate(Expr == true, Expr, true, Desc).
-
-%% @spec not_ok(Expr, Desc) -> Result
-%% Expr = true | false
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that a statement is false.
-not_ok(Expr, Desc) -> evaluate(Expr == false, Expr, false, Desc).
-
-%% @spec is_ok(Expr, Desc) -> Result
-%% Expr = any()
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that two values are the same.
-is_ok(Expr, Desc) -> evaluate(Expr == ok, Expr, ok, Desc).
-
-%% @spec is(Got, Expected, Desc) -> Result
-%% Got = any()
-%% Expected = any()
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that two values are the same.
-is(Got, Expected, Desc) -> evaluate(Got == Expected, Got, Expected, Desc).
-
-%% @spec isnt(Got, Expected, Desc) -> Result
-%% Got = any()
-%% Expected = any()
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that two values are not the same.
-isnt(Got, Expected, Desc) -> evaluate(Got /= Expected, Got, Expected, Desc).
-
-%% @spec is_greater(ValueA, ValueB, Desc) -> Result
-%% ValueA = number()
-%% ValueB = number()
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that an integer is greater than another.
-is_greater(ValueA, ValueB, Desc) when is_integer(ValueA), is_integer(ValueB) ->
- mk_tap(ValueA > ValueB, Desc).
-
-%% @spec any(Got, Items, Desc) -> Result
-%% Got = any()
-%% Items = [any()]
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that an item is in a list.
-any(Got, Items, Desc) when is_function(Got) ->
- is(lists:any(Got, Items), true, Desc);
-any(Got, Items, Desc) ->
- is(lists:member(Got, Items), true, Desc).
-
-%% @spec none(Got, Items, Desc) -> Result
-%% Got = any()
-%% Items = [any()]
-%% Desc = string()
-%% Result = true | false
-%% @doc Assert that an item is not in a list.
-none(Got, Items, Desc) when is_function(Got) ->
- is(lists:any(Got, Items), false, Desc);
-none(Got, Items, Desc) ->
- is(lists:member(Got, Items), false, Desc).
-
-%% @spec fun_is(Fun, Expected, Desc) -> Result
-%% Fun = function()
-%% Expected = any()
-%% Desc = string()
-%% Result = true | false
-%% @doc Use an anonymous function to assert a pattern match.
-fun_is(Fun, Expected, Desc) when is_function(Fun) ->
- is(Fun(Expected), true, Desc).
-
-%% @spec expect_fun(ExpectFun, Got, Desc) -> Result
-%% ExpectFun = function()
-%% Got = any()
-%% Desc = string()
-%% Result = true | false
-%% @doc Use an anonymous function to assert a pattern match, using actual
-%% value as the argument to the function.
-expect_fun(ExpectFun, Got, Desc) ->
- evaluate(ExpectFun(Got), Got, ExpectFun, Desc).
-
-%% @spec expect_fun(ExpectFun, Got, Desc, ExpectStr) -> Result
-%% ExpectFun = function()
-%% Got = any()
-%% Desc = string()
-%% ExpectStr = string()
-%% Result = true | false
-%% @doc Use an anonymous function to assert a pattern match, using actual
-%% value as the argument to the function.
-expect_fun(ExpectFun, Got, Desc, ExpectStr) ->
- evaluate(ExpectFun(Got), Got, ExpectStr, Desc).
-
-%% @equiv skip(TestFun, "")
-skip(TestFun) when is_function(TestFun) ->
- skip(TestFun, "").
-
-%% @spec skip(TestFun, Reason) -> ok
-%% TestFun = function()
-%% Reason = string()
-%% @doc Skip a test.
-skip(TestFun, Reason) when is_function(TestFun), is_list(Reason) ->
- begin_skip(Reason),
- catch TestFun(),
- end_skip(),
- ok.
-
-%% @spec skip(Q, TestFun, Reason) -> ok
-%% Q = true | false | function()
-%% TestFun = function()
-%% Reason = string()
-%% @doc Skips a test conditionally. The first argument to this function can
-%% either be the 'true' or 'false' atoms or a function that returns 'true' or
-%% 'false'.
-skip(QFun, TestFun, Reason) when is_function(QFun), is_function(TestFun), is_list(Reason) ->
- case QFun() of
- true -> begin_skip(Reason), TestFun(), end_skip();
- _ -> TestFun()
- end,
- ok;
-
-skip(Q, TestFun, Reason) when is_function(TestFun), is_list(Reason), Q == true ->
- begin_skip(Reason),
- TestFun(),
- end_skip(),
- ok;
-
-skip(_, TestFun, Reason) when is_function(TestFun), is_list(Reason) ->
- TestFun(),
- ok.
-
-%% @private
-begin_skip(Reason) ->
- etap_server ! {self(), begin_skip, Reason}.
-
-%% @private
-end_skip() ->
- etap_server ! {self(), end_skip}.
-
-%% @spec contains_ok(string(), string(), string()) -> true | false
-%% @doc Assert that a string is contained in another string.
-contains_ok(Source, String, Desc) ->
- etap:isnt(
- string:str(Source, String),
- 0,
- Desc
- ).
-
-%% @spec is_before(string(), string(), string(), string()) -> true | false
-%% @doc Assert that a string comes before another string within a larger body.
-is_before(Source, StringA, StringB, Desc) ->
- etap:is_greater(
- string:str(Source, StringB),
- string:str(Source, StringA),
- Desc
- ).
-
-%% @doc Assert that a given variable is a pid.
-is_pid(Pid, Desc) when is_pid(Pid) -> etap:ok(true, Desc);
-is_pid(_, Desc) -> etap:ok(false, Desc).
-
-%% @doc Assert that a given process/pid is alive.
-is_alive(Pid, Desc) ->
- etap:ok(erlang:is_process_alive(Pid), Desc).
-
-%% @doc Assert that the current function of a pid is a given {M, F, A} tuple.
-is_mfa(Pid, MFA, Desc) ->
- etap:is({current_function, MFA}, erlang:process_info(Pid, current_function), Desc).
-
-%% @spec loaded_ok(atom(), string()) -> true | false
-%% @doc Assert that a module has been loaded successfully.
-loaded_ok(M, Desc) when is_atom(M) ->
- etap:fun_is(fun({module, _}) -> true; (_) -> false end, code:load_file(M), Desc).
-
-%% @spec can_ok(atom(), atom()) -> true | false
-%% @doc Assert that a module exports a given function.
-can_ok(M, F) when is_atom(M), is_atom(F) ->
- Matches = [X || {X, _} <- M:module_info(exports), X == F],
- etap:ok(Matches > 0, lists:concat([M, " can ", F])).
-
-%% @spec can_ok(atom(), atom(), integer()) -> true | false
-%% @doc Assert that a module exports a given function with a given arity.
-can_ok(M, F, A) when is_atom(M); is_atom(F), is_number(A) ->
- Matches = [X || X <- M:module_info(exports), X == {F, A}],
- etap:ok(Matches > 0, lists:concat([M, " can ", F, "/", A])).
-
-%% @spec has_attrib(M, A) -> true | false
-%% M = atom()
-%% A = atom()
-%% @doc Asserts that a module has a given attribute.
-has_attrib(M, A) when is_atom(M), is_atom(A) ->
- etap:isnt(
- proplists:get_value(A, M:module_info(attributes), 'asdlkjasdlkads'),
- 'asdlkjasdlkads',
- lists:concat([M, " has attribute ", A])
- ).
-
-%% @spec has_attrib(M, A. V) -> true | false
-%% M = atom()
-%% A = atom()
-%% V = any()
-%% @doc Asserts that a module has a given attribute with a given value.
-is_attrib(M, A, V) when is_atom(M) andalso is_atom(A) ->
- etap:is(
- proplists:get_value(A, M:module_info(attributes)),
- [V],
- lists:concat([M, "'s ", A, " is ", V])
- ).
-
-%% @spec is_behavior(M, B) -> true | false
-%% M = atom()
-%% B = atom()
-%% @doc Asserts that a given module has a specific behavior.
-is_behaviour(M, B) when is_atom(M) andalso is_atom(B) ->
- is_attrib(M, behaviour, B).
-
-%% @doc Assert that an exception is raised when running a given function.
-dies_ok(F, Desc) ->
- case (catch F()) of
- {'EXIT', _} -> etap:ok(true, Desc);
- _ -> etap:ok(false, Desc)
- end.
-
-%% @doc Assert that an exception is not raised when running a given function.
-lives_ok(F, Desc) ->
- etap:is(try_this(F), success, Desc).
-
-%% @doc Assert that the exception thrown by a function matches the given exception.
-throws_ok(F, Exception, Desc) ->
- try F() of
- _ -> etap:ok(nok, Desc)
- catch
- _:E ->
- etap:is(E, Exception, Desc)
- end.
-
-%% @private
-%% @doc Run a function and catch any exceptions.
-try_this(F) when is_function(F, 0) ->
- try F() of
- _ -> success
- catch
- throw:E -> {throw, E};
- error:E -> {error, E};
- exit:E -> {exit, E}
- end.
-
-%% @private
-%% @doc Start the etap_server process if it is not running already.
-ensure_test_server() ->
- case whereis(etap_server) of
- undefined ->
- proc_lib:start(?MODULE, start_etap_server,[]);
- _ ->
- diag("The test server is already running.")
- end.
-
-%% @private
-%% @doc Start the etap_server loop and register itself as the etap_server
-%% process.
-start_etap_server() ->
- catch register(etap_server, self()),
- proc_lib:init_ack(ok),
- etap:test_server(#test_state{
- planned = 0,
- count = 0,
- pass = 0,
- fail = 0,
- skip = 0,
- skip_reason = ""
- }).
-
-
-%% @private
-%% @doc The main etap_server receive/run loop. The etap_server receive loop
-%% responds to seven messages apperatining to failure or passing of tests.
-%% It is also used to initiate the testing process with the {_, plan, _}
-%% message that clears the current test state.
-test_server(State) ->
- NewState = receive
- {_From, plan, unknown} ->
- io:format("# Current time local ~s~n", [datetime(erlang:localtime())]),
- io:format("# Using etap version ~p~n", [ proplists:get_value(vsn, proplists:get_value(attributes, etap:module_info())) ]),
- State#test_state{
- planned = -1,
- count = 0,
- pass = 0,
- fail = 0,
- skip = 0,
- skip_reason = ""
- };
- {_From, plan, N} ->
- io:format("# Current time local ~s~n", [datetime(erlang:localtime())]),
- io:format("# Using etap version ~p~n", [ proplists:get_value(vsn, proplists:get_value(attributes, etap:module_info())) ]),
- io:format("1..~p~n", [N]),
- State#test_state{
- planned = N,
- count = 0,
- pass = 0,
- fail = 0,
- skip = 0,
- skip_reason = ""
- };
- {_From, begin_skip, Reason} ->
- State#test_state{
- skip = 1,
- skip_reason = Reason
- };
- {_From, end_skip} ->
- State#test_state{
- skip = 0,
- skip_reason = ""
- };
- {_From, pass, Desc} ->
- FullMessage = skip_diag(
- " - " ++ Desc,
- State#test_state.skip,
- State#test_state.skip_reason
- ),
- io:format("ok ~p ~s~n", [State#test_state.count + 1, FullMessage]),
- State#test_state{
- count = State#test_state.count + 1,
- pass = State#test_state.pass + 1
- };
-
- {_From, fail, Desc} ->
- FullMessage = skip_diag(
- " - " ++ Desc,
- State#test_state.skip,
- State#test_state.skip_reason
- ),
- io:format("not ok ~p ~s~n", [State#test_state.count + 1, FullMessage]),
- State#test_state{
- count = State#test_state.count + 1,
- fail = State#test_state.fail + 1
- };
- {From, state} ->
- From ! State,
- State;
- {_From, diag, Message} ->
- io:format("~s~n", [Message]),
- State;
- {From, count} ->
- From ! State#test_state.count,
- State;
- {From, is_skip} ->
- From ! State#test_state.skip,
- State;
- done ->
- exit(normal)
- end,
- test_server(NewState).
-
-%% @private
-%% @doc Process the result of a test and send it to the etap_server process.
-mk_tap(Result, Desc) ->
- IsSkip = lib:sendw(etap_server, is_skip),
- case [IsSkip, Result] of
- [_, true] ->
- etap_server ! {self(), pass, Desc},
- true;
- [1, _] ->
- etap_server ! {self(), pass, Desc},
- true;
- _ ->
- etap_server ! {self(), fail, Desc},
- false
- end.
-
-%% @private
-%% @doc Format a date/time string.
-datetime(DateTime) ->
- {{Year, Month, Day}, {Hour, Min, Sec}} = DateTime,
- io_lib:format("~4.10.0B-~2.10.0B-~2.10.0B ~2.10.0B:~2.10.0B:~2.10.0B", [Year, Month, Day, Hour, Min, Sec]).
-
-%% @private
-%% @doc Craft an output message taking skip/todo into consideration.
-skip_diag(Message, 0, _) ->
- Message;
-skip_diag(_Message, 1, "") ->
- " # SKIP";
-skip_diag(_Message, 1, Reason) ->
- " # SKIP : " ++ Reason.
http://git-wip-us.apache.org/repos/asf/couchdb/blob/ed8c2fb2/src/ets_lru/test/tutil.erl
----------------------------------------------------------------------
diff --git a/src/ets_lru/test/tutil.erl b/src/ets_lru/test/tutil.erl
deleted file mode 100644
index 3e4bd68..0000000
--- a/src/ets_lru/test/tutil.erl
+++ /dev/null
@@ -1,29 +0,0 @@
--module(tutil).
-
--export([
- run/2,
- with_lru/1
-]).
-
-
-run(Plan, Fun) ->
- etap:plan(Plan),
- case (catch Fun()) of
- ok ->
- etap:end_tests();
- Error ->
- Msg = lists:flatten(io_lib:format("Error: ~p", [Error])),
- etap:bail(Msg)
- end.
-
-
-with_lru(Fun) ->
- {ok, LRU} = ets_lru:start_link(test_lru, []),
- Ref = erlang:monitor(process, LRU),
- try
- Fun(LRU)
- after
- ets_lru:stop(LRU),
- receive {'DOWN', Ref, process, LRU, _} -> ok end
- end.
-