2008-12-12 17:14:03 +00:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%%
|
|
|
|
%% bdberl: DB API Tests
|
|
|
|
%% Copyright (c) 2008 The Hive. All rights reserved.
|
|
|
|
%%
|
|
|
|
%% -------------------------------------------------------------------
|
2008-12-12 18:39:51 +00:00
|
|
|
-module(bdberl_SUITE).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
|
|
|
-compile(export_all).
|
|
|
|
|
|
|
|
-include_lib("ct.hrl").
|
|
|
|
|
2008-12-17 20:21:19 +00:00
|
|
|
all() ->
|
2008-12-12 17:14:03 +00:00
|
|
|
[open_should_create_database_if_none_exists,
|
2008-12-12 20:56:00 +00:00
|
|
|
open_should_allow_opening_multiple_databases,
|
|
|
|
close_should_fail_with_invalid_db_handle,
|
2008-12-12 17:14:03 +00:00
|
|
|
get_should_fail_when_getting_a_nonexistant_record,
|
|
|
|
get_should_return_a_value_when_getting_a_valid_record,
|
2008-12-12 20:56:00 +00:00
|
|
|
put_should_succeed_with_manual_transaction,
|
|
|
|
put_should_rollback_with_failed_manual_transaction,
|
2008-12-12 17:14:03 +00:00
|
|
|
transaction_should_commit_on_success,
|
|
|
|
transaction_should_abort_on_exception,
|
|
|
|
transaction_should_abort_on_user_abort,
|
2009-02-12 18:13:58 +00:00
|
|
|
transaction_error_should_return_error,
|
2008-12-12 20:56:00 +00:00
|
|
|
update_should_save_value_if_successful,
|
2008-12-12 21:50:44 +00:00
|
|
|
update_should_accept_args_for_fun,
|
2008-12-15 18:25:03 +00:00
|
|
|
port_should_tune_transaction_timeouts,
|
2008-12-15 18:47:38 +00:00
|
|
|
cursor_should_iterate, cursor_should_fail_if_not_open,
|
2008-12-17 20:07:36 +00:00
|
|
|
put_commit_should_end_txn,
|
|
|
|
data_dir_should_be_priv_dir,
|
|
|
|
delete_should_remove_file,
|
2009-02-02 21:51:47 +00:00
|
|
|
delete_should_fail_if_db_inuse,
|
2009-02-03 16:57:50 +00:00
|
|
|
truncate_should_empty_database,
|
|
|
|
truncate_all_should_empty_all_databases].
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2008-12-17 21:45:39 +00:00
|
|
|
|
2008-12-17 20:21:19 +00:00
|
|
|
dbconfig(Config) ->
|
|
|
|
Cfg = [{set_data_dir, ?config(priv_dir, Config)},
|
2008-12-17 21:45:39 +00:00
|
|
|
{set_flags, 'DB_TXN_NOSYNC'},
|
|
|
|
{set_log_config, 'DB_LOG_IN_MEMORY'}],
|
2008-12-17 20:21:19 +00:00
|
|
|
list_to_binary(lists:flatten([io_lib:format("~s ~s\n", [K,V]) || {K, V} <- Cfg])).
|
|
|
|
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2008-12-17 20:07:36 +00:00
|
|
|
init_per_suite(Config) ->
|
|
|
|
DbHome = ?config(priv_dir, Config),
|
|
|
|
os:putenv("DB_HOME", DbHome),
|
2008-12-17 20:21:19 +00:00
|
|
|
ok = file:write_file(DbHome ++ "DB_CONFIG", dbconfig(Config)),
|
2008-12-17 20:07:36 +00:00
|
|
|
Config.
|
|
|
|
|
|
|
|
end_per_suite(_Config) ->
|
|
|
|
ok.
|
|
|
|
|
2008-12-17 21:45:39 +00:00
|
|
|
init_per_testcase(TestCase, Config) ->
|
|
|
|
ct:print("~p", [TestCase]),
|
2008-12-12 18:39:51 +00:00
|
|
|
{ok, Db} = bdberl:open("api_test.db", btree, [create, exclusive]),
|
|
|
|
[{db, Db}|Config].
|
2008-12-12 17:14:03 +00:00
|
|
|
|
|
|
|
end_per_testcase(_TestCase, Config) ->
|
2008-12-12 18:39:51 +00:00
|
|
|
ok = bdberl:close(?config(db, Config)),
|
2009-02-11 19:04:37 +00:00
|
|
|
ok = bdberl:delete_database("api_test.db").
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2008-12-17 20:07:36 +00:00
|
|
|
open_should_create_database_if_none_exists(Config) ->
|
|
|
|
DbName = filename:join([?config(priv_dir, Config), "api_test.db"]),
|
|
|
|
true = filelib:is_file(DbName).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2008-12-12 20:56:00 +00:00
|
|
|
open_should_allow_opening_multiple_databases(_Config) ->
|
|
|
|
%% Open up another db -- should use dbref 1 as that's the first available
|
|
|
|
{ok, 1} = bdberl:open("api_test2.db", btree).
|
|
|
|
|
|
|
|
close_should_fail_with_invalid_db_handle(_Config) ->
|
|
|
|
{error, invalid_db} = bdberl:close(21000).
|
|
|
|
|
2008-12-12 17:14:03 +00:00
|
|
|
get_should_fail_when_getting_a_nonexistant_record(Config) ->
|
2008-12-12 18:39:51 +00:00
|
|
|
not_found = bdberl:get(?config(db, Config), bad_key).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
|
|
|
get_should_return_a_value_when_getting_a_valid_record(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
2008-12-12 18:39:51 +00:00
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
|
|
|
{ok, avalue} = bdberl:get(Db, mykey).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2008-12-12 20:56:00 +00:00
|
|
|
put_should_succeed_with_manual_transaction(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
ok = bdberl:txn_begin(),
|
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
|
|
|
ok = bdberl:txn_commit(),
|
|
|
|
{ok, avalue} = bdberl:get(Db, mykey).
|
|
|
|
|
|
|
|
put_should_rollback_with_failed_manual_transaction(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
ok = bdberl:txn_begin(),
|
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
|
|
|
ok = bdberl:txn_abort(),
|
|
|
|
not_found = bdberl:get(Db, mykey).
|
|
|
|
|
2008-12-12 17:14:03 +00:00
|
|
|
transaction_should_commit_on_success(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
2008-12-12 18:39:51 +00:00
|
|
|
F = fun() -> bdberl:put(Db, mykey, avalue) end,
|
|
|
|
{ok, ok} = bdberl:transaction(F),
|
|
|
|
{ok, avalue} = bdberl:get(Db, mykey).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
|
|
|
transaction_should_abort_on_exception(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
|
|
|
|
F = fun() ->
|
2008-12-12 18:39:51 +00:00
|
|
|
bdberl:put(Db, mykey, should_not_see_this),
|
2008-12-12 17:14:03 +00:00
|
|
|
throw(testing)
|
|
|
|
end,
|
|
|
|
|
2008-12-12 18:39:51 +00:00
|
|
|
{error, {transaction_failed, testing}} = bdberl:transaction(F),
|
|
|
|
not_found = bdberl:get(Db, mykey).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
|
|
|
transaction_should_abort_on_user_abort(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
|
|
|
|
F = fun() ->
|
2008-12-12 18:39:51 +00:00
|
|
|
bdberl:put(Db, mykey, should_not_see_this),
|
2008-12-12 17:14:03 +00:00
|
|
|
abort
|
|
|
|
end,
|
|
|
|
|
2008-12-12 18:39:51 +00:00
|
|
|
{error, transaction_aborted} = bdberl:transaction(F),
|
|
|
|
not_found = bdberl:get(Db, mykey).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2009-02-12 20:24:01 +00:00
|
|
|
transaction_error_should_return_error(_Config) ->
|
2009-02-12 18:13:58 +00:00
|
|
|
{skip, waiting_on_bug_818}.
|
2009-02-12 20:24:01 +00:00
|
|
|
%% Db = ?config(db, _Config),
|
2009-02-12 18:13:58 +00:00
|
|
|
%% F = fun() ->
|
|
|
|
%% bdberl:put(Db, mykey, should_not_see_this),
|
|
|
|
%% %% Explicitly kill the transaction so that when transaction/2
|
|
|
|
%% %% tries to commit it will fail
|
|
|
|
%% bdberl:txn_abort(),
|
|
|
|
%% %% Value to return
|
|
|
|
%% avalue
|
|
|
|
%% end,
|
|
|
|
%% %% This should fail as there is no transaction to commit
|
|
|
|
%% {error,{txn_commit,no_txn}} = bdberl:transaction(F).
|
|
|
|
|
2008-12-12 17:14:03 +00:00
|
|
|
update_should_save_value_if_successful(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
2008-12-12 18:39:51 +00:00
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
2008-12-12 17:14:03 +00:00
|
|
|
|
|
|
|
F = fun(Key, Value) ->
|
|
|
|
mykey = Key,
|
|
|
|
avalue = Value,
|
|
|
|
newvalue
|
|
|
|
end,
|
|
|
|
|
2008-12-12 18:39:51 +00:00
|
|
|
{ok, newvalue} = bdberl:update(Db, mykey, F),
|
|
|
|
{ok, newvalue} = bdberl:get(Db, mykey).
|
2008-12-12 17:14:03 +00:00
|
|
|
|
2008-12-12 21:50:44 +00:00
|
|
|
update_should_accept_args_for_fun(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
|
|
|
|
|
|
|
F = fun(_Key, _Value, Args) ->
|
|
|
|
look_at_me = Args, % This is all we are interested in
|
|
|
|
newvalue
|
|
|
|
end,
|
|
|
|
|
|
|
|
{ok, newvalue} = bdberl:update(Db, mykey, F, look_at_me).
|
|
|
|
|
2008-12-12 20:56:00 +00:00
|
|
|
port_should_tune_transaction_timeouts(_Config) ->
|
|
|
|
%% Test transaction timeouts
|
|
|
|
{ok, 500000} = bdberl:get_txn_timeout(),
|
|
|
|
ok = bdberl:set_txn_timeout(250000),
|
|
|
|
{ok, 250000} = bdberl:get_txn_timeout().
|
2008-12-15 18:25:03 +00:00
|
|
|
|
|
|
|
cursor_should_iterate(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
|
|
|
|
%% Store some sample values in the db
|
|
|
|
ok = bdberl:put(Db, key1, value1),
|
|
|
|
ok = bdberl:put(Db, key2, value2),
|
|
|
|
ok = bdberl:put(Db, key3, value3),
|
|
|
|
|
|
|
|
%% Validate that the cursor returns each value in order (ASSUME btree db)
|
|
|
|
ok = bdberl:cursor_open(Db),
|
|
|
|
{ok, key1, value1} = bdberl:cursor_next(),
|
|
|
|
{ok, key2, value2} = bdberl:cursor_next(),
|
|
|
|
{ok, key3, value3} = bdberl:cursor_next(),
|
|
|
|
not_found = bdberl:cursor_next(),
|
|
|
|
|
|
|
|
%% Validate that the "current" key is key3
|
|
|
|
{ok, key3, value3} = bdberl:cursor_current(),
|
|
|
|
|
|
|
|
%% Now move backwards (should jump to key2, since we are "on" key3)
|
|
|
|
{ok, key2, value2} = bdberl:cursor_prev(),
|
|
|
|
{ok, key1, value1} = bdberl:cursor_prev(),
|
|
|
|
not_found = bdberl:cursor_prev(),
|
|
|
|
|
|
|
|
ok = bdberl:cursor_close().
|
|
|
|
|
2009-02-03 15:37:21 +00:00
|
|
|
cursor_should_fail_if_not_open(_Config) ->
|
2008-12-15 18:25:03 +00:00
|
|
|
{error, no_cursor} = bdberl:cursor_next(),
|
|
|
|
{error, no_cursor} = bdberl:cursor_prev(),
|
|
|
|
{error, no_cursor} = bdberl:cursor_current(),
|
|
|
|
{error, no_cursor} = bdberl:cursor_close().
|
|
|
|
|
2008-12-15 18:47:38 +00:00
|
|
|
put_commit_should_end_txn(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
|
|
|
|
%% Start a transaction
|
|
|
|
ok = bdberl:txn_begin(),
|
|
|
|
ok = bdberl:put_commit(Db, key1, value1),
|
|
|
|
|
|
|
|
%% Commit should now fail since the txn is done
|
|
|
|
{error, {txn_commit, no_txn}} = bdberl:txn_commit(),
|
|
|
|
|
|
|
|
%% Verify data got committed
|
|
|
|
{ok, value1} = bdberl:get(Db, key1).
|
|
|
|
|
2008-12-17 20:07:36 +00:00
|
|
|
data_dir_should_be_priv_dir(Config) ->
|
|
|
|
PrivDir = ?config(priv_dir, Config),
|
|
|
|
[PrivDir] = bdberl:get_data_dirs().
|
|
|
|
|
|
|
|
delete_should_remove_file(Config) ->
|
|
|
|
{ok, Db} = bdberl:open("mytest.bdb", btree),
|
|
|
|
ok = bdberl:close(Db),
|
|
|
|
|
|
|
|
Fname = filename:join([?config(priv_dir, Config), "mytest.bdb"]),
|
|
|
|
true = filelib:is_file(Fname),
|
|
|
|
|
|
|
|
ok = bdberl:delete_database("mytest.bdb"),
|
|
|
|
|
|
|
|
false = filelib:is_file(Fname).
|
2008-12-15 18:25:03 +00:00
|
|
|
|
2008-12-17 20:07:36 +00:00
|
|
|
delete_should_fail_if_db_inuse(Config) ->
|
|
|
|
Fname = filename:join([?config(priv_dir, Config), "api_test.db"]),
|
|
|
|
true = filelib:is_file(Fname),
|
|
|
|
{error, _} = bdberl:delete_database(Fname),
|
|
|
|
true = filelib:is_file(Fname).
|
2009-02-02 21:51:47 +00:00
|
|
|
|
|
|
|
truncate_should_empty_database(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
|
|
|
ok = bdberl:truncate(Db),
|
|
|
|
not_found = bdberl:get(Db, mykey).
|
2009-02-03 16:57:50 +00:00
|
|
|
|
|
|
|
truncate_all_should_empty_all_databases(Config) ->
|
|
|
|
Db = ?config(db, Config),
|
|
|
|
ok = bdberl:put(Db, mykey, avalue),
|
|
|
|
ok = bdberl:truncate(),
|
|
|
|
not_found = bdberl:get(Db, mykey).
|