mirror of
https://github.com/valitydev/riak_test.git
synced 2024-11-06 16:45:29 +00:00
Further Time Series Tests
Please see the ts.README for details of the test structure Some of these tests will fail: * because they are bugs Some of these tests will fail: because we are currently awaiting query fixes and merges
This commit is contained in:
parent
c225a6107f
commit
84dde26a5a
@ -25,16 +25,14 @@
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-define(MAXVARCHARLEN, 16).
|
||||
-define(MAXTIMESTAMP, trunc(math:pow(2, 63))).
|
||||
-define(MAXFLOAT, math:pow(2, 63)).
|
||||
-define(MAXVARCHARLEN, 16).
|
||||
-define(MAXTIMESTAMP, trunc(math:pow(2, 63))).
|
||||
-define(MAXFLOAT, math:pow(2, 63)).
|
||||
-define(MULTIPLECLUSTERSIZE, 3).
|
||||
|
||||
confirm_create(single, DDL, Expected) ->
|
||||
confirm_create(ClusterType, DDL, Expected) ->
|
||||
|
||||
ClusterSize = 1,
|
||||
lager:info("Building cluster of 1"),
|
||||
|
||||
[Node] =build_cluster(ClusterSize),
|
||||
[Node | _] =build_cluster(ClusterType),
|
||||
|
||||
Props = io_lib:format("{\\\"props\\\": {\\\"n_val\\\": 3, \\\"table_def\\\": \\\"~s\\\"}}", [DDL]),
|
||||
Got = rt:admin(Node, ["bucket-type", "create", get_bucket(), lists:flatten(Props)]),
|
||||
@ -42,47 +40,50 @@ confirm_create(single, DDL, Expected) ->
|
||||
|
||||
pass.
|
||||
|
||||
confirm_activate(single, DDL, Expected) ->
|
||||
confirm_activate(ClusterType, DDL, Expected) ->
|
||||
|
||||
[Node] = build_cluster(1),
|
||||
[Node | Rest] = build_cluster(ClusterType),
|
||||
ok = maybe_stop_a_node(ClusterType, Rest),
|
||||
{ok, _} = create_bucket(Node, DDL),
|
||||
Got = activate_bucket(Node, DDL),
|
||||
?assertEqual(Expected, Got),
|
||||
|
||||
pass.
|
||||
|
||||
confirm_put(single, normal, DDL, Obj, Expected) ->
|
||||
|
||||
[Node] = build_cluster(1),
|
||||
{ok, _} = create_bucket(Node, DDL),
|
||||
{ok, _} = activate_bucket(Node, DDL),
|
||||
confirm_put(ClusterType, TestType, DDL, Obj, Expected) ->
|
||||
|
||||
[Node | _] = build_cluster(ClusterType),
|
||||
|
||||
case TestType of
|
||||
normal ->
|
||||
io:format("1 - Creating and activating bucket~n"),
|
||||
{ok, _} = create_bucket(Node, DDL),
|
||||
{ok, _} = activate_bucket(Node, DDL);
|
||||
no_ddl ->
|
||||
io:format("1 - NOT Creating or activating bucket - failure test~n"),
|
||||
ok
|
||||
end,
|
||||
Bucket = list_to_binary(get_bucket()),
|
||||
io:format("writing to bucket ~p with:~n- ~p~n", [Bucket, Obj]),
|
||||
io:format("2 - writing to bucket ~p with:~n- ~p~n", [Bucket, Obj]),
|
||||
C = rt:pbc(Node),
|
||||
Get = riakc_ts:put(C, Bucket, Obj),
|
||||
?assertEqual(Expected, Get),
|
||||
|
||||
pass;
|
||||
confirm_put(single, no_ddl, _DDL, Obj, Expected) ->
|
||||
[Node] = build_cluster(1),
|
||||
Bucket = list_to_binary(get_bucket()),
|
||||
io:format("writing to bucket ~p with:~n- ~p~n", [Bucket, Obj]),
|
||||
C = rt:pbc(Node),
|
||||
Get = riakc_ts:put(C, Bucket, Obj),
|
||||
?assertEqual(Expected, Get),
|
||||
pass.
|
||||
|
||||
pass.
|
||||
|
||||
confirm_select(single, DDL, Data, Qry, Expected) ->
|
||||
confirm_select(ClusterType, TestType, DDL, Data, Qry, Expected) ->
|
||||
|
||||
io:format("in confirm_select DDL is ~p~n- Data is ~p~n- Qry is ~p~n- Expected is ~p~n",
|
||||
[DDL, Data, Qry, Expected]),
|
||||
[Node] = build_cluster(1),
|
||||
[Node | _] = build_cluster(ClusterType),
|
||||
|
||||
io:format("1 - Create and activate the bucket~n"),
|
||||
{ok, _} = create_bucket(Node, DDL),
|
||||
{ok, _} = activate_bucket(Node, DDL),
|
||||
case TestType of
|
||||
normal ->
|
||||
io:format("1 - Create and activate the bucket~n"),
|
||||
{ok, _} = create_bucket(Node, DDL),
|
||||
{ok, _} = activate_bucket(Node, DDL);
|
||||
no_ddl ->
|
||||
io:format("1 - NOT Creating or activating bucket - failure test~n"),
|
||||
ok
|
||||
end,
|
||||
|
||||
Bucket = list_to_binary(get_bucket()),
|
||||
io:format("2 - writing to bucket ~p with:~n- ~p~n", [Bucket, Data]),
|
||||
@ -90,10 +91,9 @@ confirm_select(single, DDL, Data, Qry, Expected) ->
|
||||
ok = riakc_ts:put(C, Bucket, Data),
|
||||
|
||||
io:format("3 - Now run the query ~p~n", [Qry]),
|
||||
{Columns, Rows} = riakc_ts:query(C, Qry),
|
||||
io:format("Columms is ~p Rows is ~p~n", [Columns, Rows]),
|
||||
|
||||
?assertEqual(fish, fash),
|
||||
Got = riakc_ts:query(C, Qry),
|
||||
io:format("Got is ~p~n", [Got]),
|
||||
?assertEqual(Expected, Got),
|
||||
pass.
|
||||
|
||||
%%
|
||||
@ -110,13 +110,21 @@ create_bucket(Node, DDL) ->
|
||||
lists:flatten(Props)]).
|
||||
|
||||
%% @ignore
|
||||
%% copied from ensemble_util.erl
|
||||
-spec build_cluster(non_neg_integer()) -> [node()].
|
||||
build_cluster(Size) ->
|
||||
maybe_stop_a_node(one_down, [H | _T]) ->
|
||||
ok = rt:stop(H);
|
||||
maybe_stop_a_node(_, _) ->
|
||||
ok.
|
||||
|
||||
build_cluster(single) -> build_c2(1);
|
||||
build_cluster(multiple) -> build_c2(?MULTIPLECLUSTERSIZE);
|
||||
build_cluster(one_down) -> build_c2(?MULTIPLECLUSTERSIZE).
|
||||
|
||||
-spec build_c2(non_neg_integer()) -> [node()].
|
||||
build_c2(Size) ->
|
||||
lager:info("Building cluster of ~p~n", [Size]),
|
||||
build_cluster(Size, []).
|
||||
-spec build_cluster(non_neg_integer(), list()) -> [node()].
|
||||
build_cluster(Size, Config) ->
|
||||
build_c2(Size, []).
|
||||
-spec build_c2(non_neg_integer(), list()) -> [node()].
|
||||
build_c2(Size, Config) ->
|
||||
[_Node1|_] = Nodes = rt:deploy_nodes(Size, Config),
|
||||
rt:join_cluster(Nodes),
|
||||
Nodes.
|
||||
@ -125,7 +133,18 @@ get_bucket() ->
|
||||
"GeoCheckin".
|
||||
|
||||
get_valid_qry() ->
|
||||
"select * from GeoCheckin Where time > 1 and time < 10".
|
||||
"select * from GeoCheckin Where time > 1 and time < 10 and family = 'myfamily' and series ='myseries'".
|
||||
|
||||
get_invalid_qry(borked_syntax) ->
|
||||
"selectah * from GeoCheckin Where time > 1 and time < 10";
|
||||
get_invalid_qry(key_not_covered) ->
|
||||
"select * from GeoCheckin Where time > 1 and time < 10";
|
||||
get_invalid_qry(invalid_operator) ->
|
||||
"select * from GeoCheckin Where time > 1 and time < 10 and family = 'myfamily' and series ='myseries' and weather > 'bob'";
|
||||
get_invalid_qry(field_comparison) ->
|
||||
"select * from GeoCheckin Where time > 1 and time < 10 and family = 'myfamily' and series ='myseries' and weather = myfamily";
|
||||
get_invalid_qry(type_error) ->
|
||||
"select * from GeoCheckin Where time > 1 and time < 10 and family = 'myfamily' and series ='myseries' and weather = true".
|
||||
|
||||
get_valid_select_data() ->
|
||||
Family = <<"myfamily">>,
|
||||
|
15
tests/ts.README
Normal file
15
tests/ts.README
Normal file
@ -0,0 +1,15 @@
|
||||
Time Series tests are organised in sets
|
||||
ts_A
|
||||
ts_B
|
||||
ts_C
|
||||
etc, etc
|
||||
|
||||
Basically, if a ts_A type test fails then there SHOULD also be failures
|
||||
in ts_B, ts_C series tests as well
|
||||
|
||||
Basically fix the ts_A tests first, and that 'should' fix a lot of
|
||||
ts_B, ts_C etc tests
|
||||
|
||||
If you have a failure in say a ts_B test, but no failures in ts_C that
|
||||
indicates you might not have enough ts_C, ts_D tests written, consider
|
||||
extending the test suite
|
@ -1,4 +1,4 @@
|
||||
-module(ts_activate_table_pass_1).
|
||||
-module(ts_A_activate_table_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
@ -1,4 +1,4 @@
|
||||
-module(ts_create_table_fail_1).
|
||||
-module(ts_A_create_table_fail_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
18
tests/ts_A_create_table_fail_2.erl
Normal file
18
tests/ts_A_create_table_fail_2.erl
Normal file
@ -0,0 +1,18 @@
|
||||
-module(ts_A_create_table_fail_2).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
confirm_create/3
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
ClusterType = single,
|
||||
DDL = get_ddl(shortkey_fail),
|
||||
Expected = {ok,"some error message, yeah?"},
|
||||
confirm_create(ClusterType, DDL, Expected).
|
24
tests/ts_A_create_table_fail_3.erl
Normal file
24
tests/ts_A_create_table_fail_3.erl
Normal file
@ -0,0 +1,24 @@
|
||||
-module(ts_A_create_table_fail_3).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
confirm_create/3
|
||||
]).
|
||||
|
||||
%%
|
||||
%% should error if you try and create a table twice
|
||||
%%
|
||||
|
||||
confirm() ->
|
||||
ClusterType = single,
|
||||
DDL = get_ddl(docs),
|
||||
Expected1 = {ok, "GeoCheckin created\n\nWARNING: After activating GeoCheckin, nodes in this cluster\ncan no longer be downgraded to a version of Riak prior to 2.0\n"},
|
||||
pass = confirm_create(ClusterType, DDL, Expected1),
|
||||
Expected2 = {ok,"some error message, yeah?"},
|
||||
confirm_create(ClusterType, DDL, Expected2).
|
27
tests/ts_A_create_table_fail_4.erl
Normal file
27
tests/ts_A_create_table_fail_4.erl
Normal file
@ -0,0 +1,27 @@
|
||||
-module(ts_A_create_table_fail_4).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
confirm_create/3,
|
||||
confirm_activate/3
|
||||
]).
|
||||
|
||||
%%
|
||||
%% should error if you try and create a table twice
|
||||
%%
|
||||
|
||||
confirm() ->
|
||||
ClusterType = single,
|
||||
DDL = get_ddl(docs),
|
||||
Expected1 = {ok, "GeoCheckin created\n\nWARNING: After activating GeoCheckin, nodes in this cluster\ncan no longer be downgraded to a version of Riak prior to 2.0\n"},
|
||||
pass = confirm_create(ClusterType, DDL, Expected1),
|
||||
Expected2 = {ok,"GeoCheckin has been activated\n\nWARNING: Nodes in this cluster can no longer be\ndowngraded to a version of Riak prior to 2.0\n"},
|
||||
pass = confirm_activate(ClusterType, DDL, Expected2),
|
||||
Expected3 = {ok,"Error creating bucket type GeoCheckin:\nalready_active\n"},
|
||||
confirm_create(ClusterType, DDL, Expected3).
|
@ -1,4 +1,4 @@
|
||||
-module(ts_create_table_pass_1).
|
||||
-module(ts_A_create_table_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
@ -1,4 +1,4 @@
|
||||
-module(ts_put_fail_1).
|
||||
-module(ts_A_put_fail_1).
|
||||
|
||||
%%
|
||||
%% this test tries to write to a non-existant bucket
|
@ -1,4 +1,4 @@
|
||||
-module(ts_put_fail_2).
|
||||
-module(ts_A_put_fail_2).
|
||||
|
||||
%%
|
||||
%% this test tries to write well structured data that doesn't
|
@ -1,4 +1,4 @@
|
||||
-module(ts_put_fail_3).
|
||||
-module(ts_A_put_fail_3).
|
||||
|
||||
%%
|
||||
%% this test tries to write total gibberish data to a bucket
|
@ -1,4 +1,4 @@
|
||||
-module(ts_put_pass_1).
|
||||
-module(ts_A_put_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
21
tests/ts_A_select_fail_1.erl
Normal file
21
tests/ts_A_select_fail_1.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_A_select_fail_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_invalid_qry/1,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = "",
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_invalid_qry(borked_syntax),
|
||||
Expected = "some error message, fix me",
|
||||
confirm_select(single, no_ddl, DDL, Data, Qry, Expected).
|
21
tests/ts_A_select_fail_2.erl
Normal file
21
tests/ts_A_select_fail_2.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_A_select_fail_2).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_invalid_qry/1,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_invalid_qry(borked_syntax),
|
||||
Expected = "some error message, fix me",
|
||||
confirm_select(single, normal, DDL, Data, Qry, Expected).
|
21
tests/ts_A_select_fail_3.erl
Normal file
21
tests/ts_A_select_fail_3.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_A_select_fail_3).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_invalid_qry/1,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_invalid_qry(key_not_covered),
|
||||
Expected = "some error message, fix me",
|
||||
confirm_select(single, normal, DDL, Data, Qry, Expected).
|
21
tests/ts_A_select_fail_4.erl
Normal file
21
tests/ts_A_select_fail_4.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_A_select_fail_4).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_invalid_qry/1,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_invalid_qry(invalid_operator),
|
||||
Expected = "some error message, fix me",
|
||||
confirm_select(single, normal, DDL, Data, Qry, Expected).
|
21
tests/ts_A_select_fail_5.erl
Normal file
21
tests/ts_A_select_fail_5.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_A_select_fail_5).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_invalid_qry/1,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_invalid_qry(field_comparison),
|
||||
Expected = "some error message, fix me",
|
||||
confirm_select(single, normal, DDL, Data, Qry, Expected).
|
21
tests/ts_A_select_fail_6.erl
Normal file
21
tests/ts_A_select_fail_6.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_A_select_fail_6).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_invalid_qry/1,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_invalid_qry(type_error),
|
||||
Expected = "some error message, fix me",
|
||||
confirm_select(single, normal, DDL, Data, Qry, Expected).
|
@ -1,4 +1,4 @@
|
||||
-module(ts_select_pass_1).
|
||||
-module(ts_A_select_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
@ -10,13 +10,12 @@
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_valid_qry/0,
|
||||
confirm_select/5
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
Cluster = single,
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_valid_qry(),
|
||||
Expected = ok,
|
||||
confirm_select(Cluster, DDL, Data, Qry, Expected).
|
||||
confirm_select(single, normal, DDL, Data, Qry, Expected).
|
18
tests/ts_B_activate_table_pass_1.erl
Normal file
18
tests/ts_B_activate_table_pass_1.erl
Normal file
@ -0,0 +1,18 @@
|
||||
-module(ts_B_activate_table_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
confirm_activate/3
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
ClusterType = multiple,
|
||||
DDL = get_ddl(docs),
|
||||
Expected = {ok,"GeoCheckin has been activated\n\nWARNING: Nodes in this cluster can no longer be\ndowngraded to a version of Riak prior to 2.0\n"},
|
||||
confirm_activate(ClusterType, DDL, Expected).
|
18
tests/ts_B_create_table_pass_1.erl
Normal file
18
tests/ts_B_create_table_pass_1.erl
Normal file
@ -0,0 +1,18 @@
|
||||
-module(ts_B_create_table_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
confirm_create/3
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
ClusterType = multiple,
|
||||
DDL = get_ddl(docs),
|
||||
Expected = {ok, "GeoCheckin created\n\nWARNING: After activating GeoCheckin, nodes in this cluster\ncan no longer be downgraded to a version of Riak prior to 2.0\n"},
|
||||
confirm_create(ClusterType, DDL, Expected).
|
20
tests/ts_B_put_pass_1.erl
Normal file
20
tests/ts_B_put_pass_1.erl
Normal file
@ -0,0 +1,20 @@
|
||||
-module(ts_B_put_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_obj/0,
|
||||
confirm_put/5
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
Cluster = multiple,
|
||||
DDL = get_ddl(docs),
|
||||
Obj = [get_valid_obj()],
|
||||
Expected = ok,
|
||||
confirm_put(Cluster, normal, DDL, Obj, Expected).
|
21
tests/ts_B_select_pass_1.erl
Normal file
21
tests/ts_B_select_pass_1.erl
Normal file
@ -0,0 +1,21 @@
|
||||
-module(ts_B_select_pass_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
get_valid_select_data/0,
|
||||
get_valid_qry/0,
|
||||
confirm_select/6
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
DDL = get_ddl(docs),
|
||||
Data = get_valid_select_data(),
|
||||
Qry = get_valid_qry(),
|
||||
Expected = ok,
|
||||
confirm_select(multiple, normal, DDL, Data, Qry, Expected).
|
18
tests/ts_C_activate_table_fail_1.erl
Normal file
18
tests/ts_C_activate_table_fail_1.erl
Normal file
@ -0,0 +1,18 @@
|
||||
-module(ts_C_activate_table_fail_1).
|
||||
|
||||
-behavior(riak_test).
|
||||
|
||||
-export([
|
||||
confirm/0
|
||||
]).
|
||||
|
||||
-import(timeseries_util, [
|
||||
get_ddl/1,
|
||||
confirm_activate/3
|
||||
]).
|
||||
|
||||
confirm() ->
|
||||
ClusterType = one_down,
|
||||
DDL = get_ddl(docs),
|
||||
Expected = {ok,"GeoCheckin has been created but cannot be activated yet\n"},
|
||||
confirm_activate(ClusterType, DDL, Expected).
|
Loading…
Reference in New Issue
Block a user