339 lines
10 KiB
Erlang
339 lines
10 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2021-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
|
%%
|
|
%% 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(emqx_resource_SUITE).
|
|
|
|
-compile(nowarn_export_all).
|
|
-compile(export_all).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
-include_lib("common_test/include/ct.hrl").
|
|
-include("emqx_resource.hrl").
|
|
|
|
-define(TEST_RESOURCE, emqx_test_resource).
|
|
-define(ID, <<"id">>).
|
|
-define(DEFAULT_RESOURCE_GROUP, <<"default">>).
|
|
|
|
all() ->
|
|
emqx_common_test_helpers:all(?MODULE).
|
|
|
|
groups() ->
|
|
[].
|
|
|
|
init_per_testcase(_, Config) ->
|
|
Config.
|
|
|
|
init_per_suite(Config) ->
|
|
code:ensure_loaded(?TEST_RESOURCE),
|
|
ok = emqx_common_test_helpers:start_apps([emqx_conf]),
|
|
{ok, _} = application:ensure_all_started(emqx_resource),
|
|
Config.
|
|
|
|
end_per_suite(_Config) ->
|
|
ok = emqx_common_test_helpers:stop_apps([emqx_resource, emqx_conf]).
|
|
|
|
%%------------------------------------------------------------------------------
|
|
%% Tests
|
|
%%------------------------------------------------------------------------------
|
|
|
|
t_list_types(_) ->
|
|
?assert(lists:member(?TEST_RESOURCE, emqx_resource:list_types())).
|
|
|
|
t_check_config(_) ->
|
|
{ok, #{}} = emqx_resource:check_config(?TEST_RESOURCE, bin_config()),
|
|
{ok, #{}} = emqx_resource:check_config(?TEST_RESOURCE, config()),
|
|
|
|
{error, _} = emqx_resource:check_config(?TEST_RESOURCE, <<"not a config">>),
|
|
{error, _} = emqx_resource:check_config(?TEST_RESOURCE, #{invalid => config}).
|
|
|
|
t_create_remove(_) ->
|
|
{error, _} = emqx_resource:check_and_create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{unknown => test_resource}),
|
|
|
|
{ok, _} = emqx_resource:create(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource}),
|
|
|
|
emqx_resource:recreate(
|
|
?ID,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource},
|
|
#{}),
|
|
#{pid := Pid} = emqx_resource:query(?ID, get_state),
|
|
|
|
?assert(is_process_alive(Pid)),
|
|
|
|
ok = emqx_resource:remove(?ID),
|
|
{error, _} = emqx_resource:remove(?ID),
|
|
|
|
?assertNot(is_process_alive(Pid)).
|
|
|
|
t_create_remove_local(_) ->
|
|
{error, _} = emqx_resource:check_and_create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{unknown => test_resource}),
|
|
|
|
{ok, _} = emqx_resource:create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource}),
|
|
|
|
emqx_resource:recreate_local(
|
|
?ID,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource},
|
|
#{}),
|
|
#{pid := Pid} = emqx_resource:query(?ID, get_state),
|
|
|
|
?assert(is_process_alive(Pid)),
|
|
|
|
emqx_resource:set_resource_status_connecting(?ID),
|
|
|
|
emqx_resource:recreate_local(
|
|
?ID,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource},
|
|
#{}),
|
|
|
|
ok = emqx_resource:remove_local(?ID),
|
|
{error, _} = emqx_resource:remove_local(?ID),
|
|
|
|
?assertNot(is_process_alive(Pid)).
|
|
|
|
t_query(_) ->
|
|
{ok, _} = emqx_resource:create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource}),
|
|
|
|
Pid = self(),
|
|
Success = fun() -> Pid ! success end,
|
|
Failure = fun() -> Pid ! failure end,
|
|
|
|
#{pid := _} = emqx_resource:query(?ID, get_state),
|
|
#{pid := _} = emqx_resource:query(?ID, get_state, {[{Success, []}], [{Failure, []}]}),
|
|
#{pid := _} = emqx_resource:query(?ID, get_state, undefined),
|
|
#{pid := _} = emqx_resource:query(?ID, get_state_failed, undefined),
|
|
|
|
receive
|
|
Message -> ?assertEqual(success, Message)
|
|
after 100 ->
|
|
?assert(false)
|
|
end,
|
|
|
|
?assertMatch({error, {emqx_resource, #{reason := not_found}}},
|
|
emqx_resource:query(<<"unknown">>, get_state)),
|
|
|
|
ok = emqx_resource:remove_local(?ID).
|
|
|
|
t_healthy_timeout(_) ->
|
|
{ok, _} = emqx_resource:create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{name => <<"test_resource">>},
|
|
#{health_check_timeout => 200}),
|
|
timer:sleep(500),
|
|
|
|
ok = emqx_resource:remove_local(?ID).
|
|
|
|
t_healthy(_) ->
|
|
{ok, _} = emqx_resource:create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{name => <<"test_resource">>}),
|
|
timer:sleep(400),
|
|
|
|
emqx_resource_health_check:create_checker(?ID, 15000, 10000),
|
|
#{pid := Pid} = emqx_resource:query(?ID, get_state),
|
|
timer:sleep(300),
|
|
emqx_resource:set_resource_status_connecting(?ID),
|
|
|
|
ok = emqx_resource:health_check(?ID),
|
|
|
|
?assertMatch(
|
|
[#{status := connected}],
|
|
emqx_resource:list_instances_verbose()),
|
|
|
|
erlang:exit(Pid, shutdown),
|
|
|
|
?assertEqual(
|
|
{error, dead},
|
|
emqx_resource:health_check(?ID)),
|
|
|
|
?assertMatch(
|
|
[#{status := connecting}],
|
|
emqx_resource:list_instances_verbose()),
|
|
|
|
ok = emqx_resource:remove_local(?ID).
|
|
|
|
t_stop_start(_) ->
|
|
{error, _} = emqx_resource:check_and_create(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{unknown => test_resource}),
|
|
|
|
{ok, _} = emqx_resource:check_and_create(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{<<"name">> => <<"test_resource">>}),
|
|
|
|
{ok, _} = emqx_resource:check_and_recreate(
|
|
?ID,
|
|
?TEST_RESOURCE,
|
|
#{<<"name">> => <<"test_resource">>},
|
|
#{}),
|
|
|
|
#{pid := Pid0} = emqx_resource:query(?ID, get_state),
|
|
|
|
?assert(is_process_alive(Pid0)),
|
|
|
|
ok = emqx_resource:stop(?ID),
|
|
|
|
?assertNot(is_process_alive(Pid0)),
|
|
|
|
?assertMatch({error, {emqx_resource, #{reason := disconnected}}},
|
|
emqx_resource:query(?ID, get_state)),
|
|
|
|
ok = emqx_resource:restart(?ID),
|
|
|
|
timer:sleep(300),
|
|
|
|
#{pid := Pid1} = emqx_resource:query(?ID, get_state),
|
|
|
|
?assert(is_process_alive(Pid1)).
|
|
|
|
t_stop_start_local(_) ->
|
|
{error, _} = emqx_resource:check_and_create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{unknown => test_resource}),
|
|
|
|
{ok, _} = emqx_resource:check_and_create_local(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{<<"name">> => <<"test_resource">>}),
|
|
|
|
{ok, _} = emqx_resource:check_and_recreate_local(
|
|
?ID,
|
|
?TEST_RESOURCE,
|
|
#{<<"name">> => <<"test_resource">>},
|
|
#{}),
|
|
|
|
#{pid := Pid0} = emqx_resource:query(?ID, get_state),
|
|
|
|
?assert(is_process_alive(Pid0)),
|
|
|
|
ok = emqx_resource:stop(?ID),
|
|
|
|
?assertNot(is_process_alive(Pid0)),
|
|
|
|
?assertMatch({error, {emqx_resource, #{reason := disconnected}}},
|
|
emqx_resource:query(?ID, get_state)),
|
|
|
|
ok = emqx_resource:restart(?ID),
|
|
|
|
#{pid := Pid1} = emqx_resource:query(?ID, get_state),
|
|
|
|
?assert(is_process_alive(Pid1)).
|
|
|
|
t_list_filter(_) ->
|
|
{ok, _} = emqx_resource:create_local(
|
|
emqx_resource:generate_id(<<"a">>),
|
|
<<"group1">>,
|
|
?TEST_RESOURCE,
|
|
#{name => a}),
|
|
{ok, _} = emqx_resource:create_local(
|
|
emqx_resource:generate_id(<<"a">>),
|
|
<<"group2">>,
|
|
?TEST_RESOURCE,
|
|
#{name => grouped_a}),
|
|
|
|
[Id1] = emqx_resource:list_group_instances(<<"group1">>),
|
|
?assertMatch(
|
|
{ok, <<"group1">>, #{config := #{name := a}}},
|
|
emqx_resource:get_instance(Id1)),
|
|
|
|
[Id2] = emqx_resource:list_group_instances(<<"group2">>),
|
|
?assertMatch(
|
|
{ok, <<"group2">>, #{config := #{name := grouped_a}}},
|
|
emqx_resource:get_instance(Id2)).
|
|
|
|
t_create_dry_run_local(_) ->
|
|
?assertEqual(
|
|
ok,
|
|
emqx_resource:create_dry_run_local(
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource, register => true})),
|
|
|
|
?assertEqual(undefined, whereis(test_resource)).
|
|
|
|
t_create_dry_run_local_failed(_) ->
|
|
{Res, _} = emqx_resource:create_dry_run_local(?TEST_RESOURCE,
|
|
#{cteate_error => true}),
|
|
?assertEqual(error, Res),
|
|
|
|
{Res, _} = emqx_resource:create_dry_run_local(?TEST_RESOURCE,
|
|
#{name => test_resource, health_check_error => true}),
|
|
?assertEqual(error, Res),
|
|
|
|
{Res, _} = emqx_resource:create_dry_run_local(?TEST_RESOURCE,
|
|
#{name => test_resource, stop_error => true}),
|
|
?assertEqual(error, Res).
|
|
|
|
t_test_func(_) ->
|
|
?assertEqual(ok, erlang:apply(emqx_resource_validator:not_empty("not_empty"), [<<"someval">>])),
|
|
?assertEqual(ok, erlang:apply(emqx_resource_validator:min(int, 3), [4])),
|
|
?assertEqual(ok, erlang:apply(emqx_resource_validator:max(array, 10), [[a,b,c,d]])),
|
|
?assertEqual(ok, erlang:apply(emqx_resource_validator:max(string, 10), ["less10"])).
|
|
|
|
t_reset_metrics(_) ->
|
|
{ok, _} = emqx_resource:create(
|
|
?ID,
|
|
?DEFAULT_RESOURCE_GROUP,
|
|
?TEST_RESOURCE,
|
|
#{name => test_resource}),
|
|
|
|
#{pid := Pid} = emqx_resource:query(?ID, get_state),
|
|
emqx_resource:reset_metrics(?ID),
|
|
?assert(is_process_alive(Pid)),
|
|
ok = emqx_resource:remove(?ID),
|
|
?assertNot(is_process_alive(Pid)).
|
|
|
|
%%------------------------------------------------------------------------------
|
|
%% Helpers
|
|
%%------------------------------------------------------------------------------
|
|
|
|
bin_config() ->
|
|
<<"\"name\": \"test_resource\"">>.
|
|
|
|
config() ->
|
|
{ok, Config} = hocon:binary(bin_config()),
|
|
Config.
|