2015-12-09 23:17:31 +00:00
|
|
|
% -------------------------------------------------------------------
|
2015-09-15 21:37:57 +00:00
|
|
|
%%
|
|
|
|
%% Copyright (c) 2015 Basho Technologies, Inc.
|
|
|
|
%%
|
|
|
|
%% This file is provided to you 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.
|
|
|
|
%%
|
|
|
|
%% -------------------------------------------------------------------
|
2015-12-07 23:10:13 +00:00
|
|
|
%% @doc A module to test riak_ts basic create bucket/put/select cycle,
|
|
|
|
%% including testing native Erlang term_to_binary encoding.
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2016-01-11 17:40:38 +00:00
|
|
|
-module(ts_cluster_comprehensive).
|
2015-09-15 21:37:57 +00:00
|
|
|
-behavior(riak_test).
|
2015-11-06 02:02:33 +00:00
|
|
|
-export([confirm/0, run_tests/2]).
|
2015-09-15 21:37:57 +00:00
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
|
2015-09-16 12:33:34 +00:00
|
|
|
-define(BUCKET, <<"ts_test_bucket_one">>).
|
2015-11-12 05:00:15 +00:00
|
|
|
-define(PKEY_P1, <<"pooter1">>).
|
|
|
|
-define(PKEY_P2, <<"pooter2">>).
|
2015-11-06 02:02:33 +00:00
|
|
|
-define(PKEY_P3, <<"time">>).
|
2015-09-20 23:25:14 +00:00
|
|
|
-define(PVAL_P1, <<"ZXC11">>).
|
2015-11-06 02:02:33 +00:00
|
|
|
-define(PVAL_P2, <<"PDP-11">>).
|
2015-09-20 23:25:14 +00:00
|
|
|
-define(TIMEBASE, (10*1000*1000)).
|
2015-11-17 11:43:14 +00:00
|
|
|
-define(BADKEY, [<<"b">>,<<"a">>, ?TIMEBASE-1]).
|
2015-12-06 13:26:32 +00:00
|
|
|
-define(LIFESPAN, 300). %% > 100, which is the default chunk size for list_keys
|
2015-09-15 21:37:57 +00:00
|
|
|
|
|
|
|
confirm() ->
|
2015-11-06 02:02:33 +00:00
|
|
|
run_tests(?PVAL_P1, ?PVAL_P2).
|
|
|
|
|
2015-11-12 05:00:15 +00:00
|
|
|
run_tests(PvalP1, PvalP2) ->
|
|
|
|
Data = make_data(PvalP1, PvalP2),
|
|
|
|
io:format("Data to be written:\n~p\n...\n~p\n", [hd(Data), lists:last(Data)]),
|
2015-09-16 12:33:34 +00:00
|
|
|
|
2015-12-02 23:02:00 +00:00
|
|
|
Cluster = ts_util:build_cluster(multiple),
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2015-11-12 05:00:15 +00:00
|
|
|
%% use riak-admin to create a bucket
|
2015-09-15 21:37:57 +00:00
|
|
|
TableDef = io_lib:format(
|
|
|
|
"CREATE TABLE ~s "
|
|
|
|
"(~s varchar not null, "
|
2015-11-06 02:02:33 +00:00
|
|
|
" ~s varchar not null, "
|
2015-09-15 21:37:57 +00:00
|
|
|
" ~s timestamp not null, "
|
2015-11-06 02:02:33 +00:00
|
|
|
" score double not null, "
|
2015-11-12 05:00:15 +00:00
|
|
|
" PRIMARY KEY ((~s, ~s, quantum(~s, 10, s)), ~s, ~s, ~s))",
|
|
|
|
[?BUCKET,
|
|
|
|
?PKEY_P1, ?PKEY_P2, ?PKEY_P3,
|
|
|
|
?PKEY_P1, ?PKEY_P2, ?PKEY_P3,
|
|
|
|
?PKEY_P1, ?PKEY_P2, ?PKEY_P3]),
|
2016-04-18 18:50:43 +00:00
|
|
|
?assertEqual({ok, {[], []}}, riakc_ts:query(rt:pbc(hd(Cluster)), TableDef)),
|
2015-11-12 05:02:25 +00:00
|
|
|
|
2015-12-02 23:02:00 +00:00
|
|
|
%% Make sure data is written to each node
|
|
|
|
lists:foreach(fun(Node) -> confirm_all_from_node(Node, Data, PvalP1, PvalP2) end, Cluster),
|
2015-11-12 05:02:25 +00:00
|
|
|
pass.
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2015-11-12 05:02:25 +00:00
|
|
|
|
|
|
|
confirm_all_from_node(Node, Data, PvalP1, PvalP2) ->
|
|
|
|
%% set up a client
|
|
|
|
C = rt:pbc(Node),
|
2015-11-12 05:00:15 +00:00
|
|
|
|
|
|
|
%% 1. put some data
|
2016-06-14 17:46:23 +00:00
|
|
|
ok = confirm_put(C, Data),
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2015-12-09 23:17:31 +00:00
|
|
|
%% 2. get a single key
|
2015-12-06 13:26:32 +00:00
|
|
|
ok = confirm_get(C, lists:nth(12, Data)),
|
|
|
|
ok = confirm_nx_get(C),
|
|
|
|
|
2015-12-09 23:17:31 +00:00
|
|
|
%% 3. list keys and delete one
|
2015-12-06 13:26:32 +00:00
|
|
|
ok = confirm_nx_list_keys(C),
|
2015-12-09 23:17:31 +00:00
|
|
|
{ok, First} = confirm_list_keys(C, ?LIFESPAN),
|
|
|
|
io:format("Before delete = ~p", [length(First)]),
|
2015-12-06 13:26:32 +00:00
|
|
|
|
|
|
|
ok = confirm_delete(C, lists:nth(14, Data)),
|
2015-11-12 05:00:15 +00:00
|
|
|
ok = confirm_nx_delete(C),
|
2015-10-14 02:51:21 +00:00
|
|
|
|
2015-12-08 01:00:07 +00:00
|
|
|
%% Pause briefly. Deletions have a default 3 second
|
|
|
|
%% reaping interval, and our list keys test may run
|
|
|
|
%% afoul of that.
|
|
|
|
timer:sleep(3500),
|
2015-12-09 23:17:31 +00:00
|
|
|
{ok, RemainingKeys} = confirm_list_keys(C, ?LIFESPAN - 1),
|
2015-12-08 01:00:07 +00:00
|
|
|
|
2015-10-14 02:51:21 +00:00
|
|
|
%% 5. select
|
2015-11-12 05:00:15 +00:00
|
|
|
ok = confirm_select(C, PvalP1, PvalP2),
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2015-10-18 00:49:33 +00:00
|
|
|
%% 6. single-key get some data
|
2015-11-12 05:00:15 +00:00
|
|
|
ok = confirm_get(C, lists:nth(12, Data)),
|
|
|
|
ok = confirm_nx_get(C),
|
2015-10-18 00:49:33 +00:00
|
|
|
|
2016-04-13 07:19:39 +00:00
|
|
|
%% Switch to protocol buffer mode and repeat a few tests
|
2015-12-07 23:10:13 +00:00
|
|
|
|
|
|
|
%% 5 (redux). select
|
2016-04-13 23:21:51 +00:00
|
|
|
ok = confirm_select(C, PvalP1, PvalP2, [{use_ttb, false}]),
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2015-12-07 23:10:13 +00:00
|
|
|
%% 6 (redux). single-key get some data
|
2016-04-13 23:21:51 +00:00
|
|
|
ok = confirm_get(C, lists:nth(12, Data), [{use_ttb, false}]),
|
|
|
|
ok = confirm_nx_get(C, [{use_ttb, false}]),
|
2015-12-07 23:10:13 +00:00
|
|
|
|
2015-12-06 13:26:32 +00:00
|
|
|
ok = confirm_delete_all(C, RemainingKeys),
|
|
|
|
{ok, []} = confirm_list_keys(C, 0).
|
2015-10-18 00:49:33 +00:00
|
|
|
|
2015-09-15 21:37:57 +00:00
|
|
|
|
2015-11-12 05:02:25 +00:00
|
|
|
make_data(PvalP1, PvalP2) ->
|
|
|
|
lists:reverse(
|
|
|
|
lists:foldl(
|
|
|
|
fun(T, Q) ->
|
2016-04-13 07:19:39 +00:00
|
|
|
[{PvalP1,
|
2015-11-12 05:02:25 +00:00
|
|
|
PvalP2,
|
|
|
|
?TIMEBASE + ?LIFESPAN - T + 1,
|
2016-04-13 07:19:39 +00:00
|
|
|
math:sin(float(T) / 100 * math:pi())} | Q]
|
2015-11-12 05:02:25 +00:00
|
|
|
end,
|
2015-12-09 23:17:31 +00:00
|
|
|
[], lists:seq(?LIFESPAN, 1, -1))).
|
2015-11-12 05:00:15 +00:00
|
|
|
|
|
|
|
confirm_put(C, Data) ->
|
2015-11-19 18:57:29 +00:00
|
|
|
ResFail = riakc_ts:put(C, <<"no-bucket-like-this">>, Data),
|
2015-12-02 23:02:00 +00:00
|
|
|
io:format("Nothing put in a non-existent bucket: ~p\n", [ResFail]),
|
2015-11-17 11:43:14 +00:00
|
|
|
?assertMatch({error, _}, ResFail),
|
|
|
|
|
2015-11-12 05:00:15 +00:00
|
|
|
%% Res = lists:map(fun(Datum) -> riakc_ts:put(C, ?BUCKET, [Datum]), timer:sleep(300) end, Data0),
|
|
|
|
%% (for future tests of batch put writing order)
|
|
|
|
Res = riakc_ts:put(C, ?BUCKET, Data),
|
|
|
|
io:format("Put ~b records: ~p\n", [length(Data), Res]),
|
|
|
|
?assertEqual(ok, Res),
|
|
|
|
ok.
|
|
|
|
|
2016-04-13 07:19:39 +00:00
|
|
|
confirm_delete(C, {Pooter1, Pooter2, Timepoint, _} = Record) ->
|
2015-11-17 11:43:14 +00:00
|
|
|
ResFail = riakc_ts:delete(C, <<"no-bucket-like-this">>, ?BADKEY, []),
|
2015-12-02 23:02:00 +00:00
|
|
|
io:format("Nothing deleted from a non-existent bucket: ~p\n", [ResFail]),
|
2015-11-17 11:43:14 +00:00
|
|
|
?assertMatch({error, _}, ResFail),
|
|
|
|
|
2015-11-12 05:00:15 +00:00
|
|
|
Key = [Pooter1, Pooter2, Timepoint],
|
|
|
|
|
|
|
|
BadKey1 = [Pooter1],
|
|
|
|
BadRes1 = riakc_ts:delete(C, ?BUCKET, BadKey1, []),
|
|
|
|
io:format("Not deleted because short key: ~p\n", [BadRes1]),
|
|
|
|
?assertMatch({error, _}, BadRes1),
|
|
|
|
|
|
|
|
BadKey2 = Key ++ [43],
|
|
|
|
BadRes2 = riakc_ts:delete(C, ?BUCKET, BadKey2, []),
|
|
|
|
io:format("Not deleted because long key: ~p\n", [BadRes2]),
|
|
|
|
?assertMatch({error, _}, BadRes2),
|
|
|
|
|
|
|
|
Res = riakc_ts:delete(C, ?BUCKET, Key, []),
|
|
|
|
io:format("Deleted record ~p: ~p\n", [Record, Res]),
|
|
|
|
?assertEqual(ok, Res),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
confirm_nx_delete(C) ->
|
2016-02-04 17:30:24 +00:00
|
|
|
?assertEqual(
|
|
|
|
{error, {1021, <<"notfound">>}},
|
|
|
|
riakc_ts:delete(C, ?BUCKET, ?BADKEY, [])
|
|
|
|
),
|
2015-11-12 05:00:15 +00:00
|
|
|
ok.
|
|
|
|
|
|
|
|
confirm_select(C, PvalP1, PvalP2) ->
|
2016-04-13 23:21:51 +00:00
|
|
|
confirm_select(C, PvalP1, PvalP2, []).
|
|
|
|
confirm_select(C, PvalP1, PvalP2, Options) ->
|
2015-11-12 05:00:15 +00:00
|
|
|
Query =
|
|
|
|
lists:flatten(
|
|
|
|
io_lib:format(
|
|
|
|
"select score, pooter2 from ~s where"
|
2016-08-02 15:56:46 +00:00
|
|
|
" ~s = '~ts'"
|
|
|
|
" and ~s = '~ts'"
|
2015-11-12 05:00:15 +00:00
|
|
|
" and ~s > ~b and ~s < ~b",
|
|
|
|
[?BUCKET,
|
|
|
|
?PKEY_P1, PvalP1,
|
|
|
|
?PKEY_P2, PvalP2,
|
|
|
|
?PKEY_P3, ?TIMEBASE + 10, ?PKEY_P3, ?TIMEBASE + 20])),
|
2016-08-02 15:56:46 +00:00
|
|
|
io:format("Running query: ~ts\n", [Query]),
|
2016-04-15 19:41:25 +00:00
|
|
|
{ok, {_Columns, Rows}} = riakc_ts:query(C, Query, Options),
|
2015-11-12 05:00:15 +00:00
|
|
|
io:format("Got ~b rows back\n~p\n", [length(Rows), Rows]),
|
2015-12-06 13:26:32 +00:00
|
|
|
?assertEqual(10 - 1 - 1, length(Rows)),
|
2016-04-15 19:41:25 +00:00
|
|
|
{ok, {_Columns, Rows}} = riakc_ts:query(C, Query, Options),
|
2015-11-12 05:00:15 +00:00
|
|
|
io:format("Got ~b rows back again\n", [length(Rows)]),
|
|
|
|
?assertEqual(10 - 1 - 1, length(Rows)),
|
|
|
|
ok.
|
|
|
|
|
2016-04-13 23:21:51 +00:00
|
|
|
confirm_get(C, Record) ->
|
|
|
|
confirm_get(C, Record, []).
|
|
|
|
confirm_get(C, Record = {Pooter1, Pooter2, Timepoint, _}, Options) ->
|
2015-11-17 11:43:14 +00:00
|
|
|
ResFail = riakc_ts:get(C, <<"no-bucket-like-this">>, ?BADKEY, []),
|
2015-12-02 23:02:00 +00:00
|
|
|
io:format("Got nothing from a non-existent bucket: ~p\n", [ResFail]),
|
2015-11-17 11:43:14 +00:00
|
|
|
?assertMatch({error, _}, ResFail),
|
|
|
|
|
2015-11-12 05:00:15 +00:00
|
|
|
Key = [Pooter1, Pooter2, Timepoint],
|
2016-04-13 23:21:51 +00:00
|
|
|
Res = riakc_ts:get(C, ?BUCKET, Key, Options),
|
2015-11-12 05:00:15 +00:00
|
|
|
io:format("Get a single record: ~p\n", [Res]),
|
2015-11-17 11:43:14 +00:00
|
|
|
?assertMatch({ok, {_, [Record]}}, Res),
|
2015-11-12 05:00:15 +00:00
|
|
|
ok.
|
|
|
|
|
|
|
|
confirm_nx_get(C) ->
|
2016-04-13 23:21:51 +00:00
|
|
|
confirm_nx_get(C, []).
|
|
|
|
confirm_nx_get(C, Options) ->
|
|
|
|
Res = riakc_ts:get(C, ?BUCKET, ?BADKEY, Options),
|
2015-11-12 05:00:15 +00:00
|
|
|
io:format("Not got a nonexistent single record: ~p\n", [Res]),
|
2015-11-17 11:43:14 +00:00
|
|
|
?assertMatch({ok, {[], []}}, Res),
|
2015-11-12 05:00:15 +00:00
|
|
|
ok.
|
2015-11-12 05:02:25 +00:00
|
|
|
|
2015-12-06 13:26:32 +00:00
|
|
|
confirm_nx_list_keys(C) ->
|
|
|
|
{Status, Reason} = list_keys(C, <<"no-bucket-like-this">>),
|
2015-12-06 03:53:46 +00:00
|
|
|
io:format("Nothing listed from a non-existent bucket: ~p\n", [Reason]),
|
2015-12-06 13:26:32 +00:00
|
|
|
?assertMatch(error, Status),
|
2015-11-12 05:02:25 +00:00
|
|
|
ok.
|
|
|
|
|
2015-12-06 13:26:32 +00:00
|
|
|
confirm_list_keys(C, N) ->
|
|
|
|
confirm_list_keys(C, N, 15).
|
|
|
|
confirm_list_keys(_C, _N, 0) ->
|
|
|
|
io:format("stream_list_keys is lying\n", []),
|
|
|
|
fail;
|
|
|
|
confirm_list_keys(C, N, TriesToGo) ->
|
|
|
|
{Status, Keys} = list_keys(C, ?BUCKET),
|
|
|
|
case length(Keys) of
|
|
|
|
N ->
|
|
|
|
{ok, Keys};
|
|
|
|
_NotN ->
|
|
|
|
io:format("Listed ~b (expected ~b) keys streaming (~p). Retrying.\n", [length(Keys), N, Status]),
|
|
|
|
confirm_list_keys(C, N, TriesToGo - 1)
|
|
|
|
end.
|
|
|
|
|
|
|
|
confirm_delete_all(C, AllKeys) ->
|
|
|
|
io:format("Deleting ~b keys\n", [length(AllKeys)]),
|
2015-11-12 05:02:25 +00:00
|
|
|
lists:foreach(
|
|
|
|
fun(K) -> ok = riakc_ts:delete(C, ?BUCKET, tuple_to_list(K), []) end,
|
2015-12-06 13:26:32 +00:00
|
|
|
AllKeys),
|
2015-12-08 01:14:06 +00:00
|
|
|
timer:sleep(3500),
|
2015-12-09 23:17:31 +00:00
|
|
|
{ok, Res} = list_keys(C, ?BUCKET),
|
2015-11-12 05:02:25 +00:00
|
|
|
io:format("Deleted all: ~p\n", [Res]),
|
|
|
|
?assertMatch([], Res),
|
|
|
|
ok.
|
2015-12-06 03:53:46 +00:00
|
|
|
|
|
|
|
list_keys(C, Bucket) ->
|
|
|
|
{ok, ReqId1} = riakc_ts:stream_list_keys(C, Bucket, []),
|
|
|
|
receive_keys(ReqId1, []).
|
|
|
|
|
|
|
|
receive_keys(ReqId, Acc) ->
|
|
|
|
receive
|
|
|
|
{ReqId, {keys, Keys}} ->
|
2015-12-06 13:26:32 +00:00
|
|
|
io:format("received batch of ~b\n", [length(Keys)]),
|
2015-12-06 03:53:46 +00:00
|
|
|
receive_keys(ReqId, lists:append(Keys, Acc));
|
|
|
|
{ReqId, {error, Reason}} ->
|
|
|
|
io:format("list_keys(~p) at ~b got an error: ~p\n", [ReqId, length(Acc), Reason]),
|
|
|
|
{error, Reason};
|
|
|
|
{ReqId, done} ->
|
2015-12-06 13:26:32 +00:00
|
|
|
io:format("done receiving from one quantum\n", []),
|
|
|
|
receive_keys(ReqId, Acc);
|
2015-12-06 03:53:46 +00:00
|
|
|
Else ->
|
|
|
|
io:format("What's that? ~p\n", [Else]),
|
|
|
|
receive_keys(ReqId, Acc)
|
2015-12-06 13:26:32 +00:00
|
|
|
after 3000 ->
|
|
|
|
io:format("Consider streaming done\n", []),
|
|
|
|
{ok, Acc}
|
2015-12-06 03:53:46 +00:00
|
|
|
end.
|