|
|
@@ -252,23 +252,26 @@ init_per_testcase(TestCase, Config) when
|
|
|
BridgeConfig
|
|
|
| Config
|
|
|
];
|
|
|
-init_per_testcase(_TestCase, Config) ->
|
|
|
+init_per_testcase(TestCase, Config) ->
|
|
|
case ?config(cluster_nodes, Config) of
|
|
|
undefined ->
|
|
|
init_mocks();
|
|
|
Nodes ->
|
|
|
[erpc:call(Node, ?MODULE, init_mocks, []) || Node <- Nodes]
|
|
|
end,
|
|
|
+ ShouldCreateConnector = not lists:member(TestCase, skip_connector_creation_test_cases()),
|
|
|
case ?config(bridge_kind, Config) of
|
|
|
- action ->
|
|
|
+ action when ShouldCreateConnector ->
|
|
|
{ok, 201, _} = request(post, uri(["connectors"]), ?ACTIONS_CONNECTOR, Config);
|
|
|
- source ->
|
|
|
+ source when ShouldCreateConnector ->
|
|
|
{ok, 201, _} = request(
|
|
|
post,
|
|
|
uri(["connectors"]),
|
|
|
source_connector_create_config(#{}),
|
|
|
Config
|
|
|
- )
|
|
|
+ );
|
|
|
+ _ ->
|
|
|
+ ok
|
|
|
end,
|
|
|
Config.
|
|
|
|
|
|
@@ -284,6 +287,12 @@ end_per_testcase(_TestCase, Config) ->
|
|
|
ok = emqx_common_test_helpers:call_janitor(),
|
|
|
ok.
|
|
|
|
|
|
+skip_connector_creation_test_cases() ->
|
|
|
+ [
|
|
|
+ t_connector_dependencies,
|
|
|
+ t_kind_dependencies
|
|
|
+ ].
|
|
|
+
|
|
|
%%------------------------------------------------------------------------------
|
|
|
%% Helper fns
|
|
|
%%------------------------------------------------------------------------------
|
|
|
@@ -500,6 +509,23 @@ source_config_base() ->
|
|
|
}
|
|
|
}.
|
|
|
|
|
|
+mqtt_action_config_base() ->
|
|
|
+ source_config_base().
|
|
|
+
|
|
|
+mqtt_action_create_config(Overrides0) ->
|
|
|
+ Overrides = emqx_utils_maps:binary_key_map(Overrides0),
|
|
|
+ Conf0 = maps:merge(
|
|
|
+ mqtt_action_config_base(),
|
|
|
+ #{
|
|
|
+ <<"enable">> => true,
|
|
|
+ <<"type">> => ?SOURCE_TYPE
|
|
|
+ }
|
|
|
+ ),
|
|
|
+ emqx_utils_maps:deep_merge(
|
|
|
+ Conf0,
|
|
|
+ Overrides
|
|
|
+ ).
|
|
|
+
|
|
|
source_create_config(Overrides0) ->
|
|
|
Overrides = emqx_utils_maps:binary_key_map(Overrides0),
|
|
|
Conf0 = maps:merge(
|
|
|
@@ -575,6 +601,77 @@ maybe_get_other_node(Config) ->
|
|
|
OtherNode
|
|
|
end.
|
|
|
|
|
|
+list_connectors_api() ->
|
|
|
+ Res = emqx_bridge_v2_testlib:list_connectors_http_api(),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+get_connector_api(Type, Name) ->
|
|
|
+ Res = emqx_bridge_v2_testlib:get_connector_api(Type, Name),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+get_source_api(Type, Name) ->
|
|
|
+ Res = emqx_bridge_v2_testlib:get_bridge_api(source, Type, Name),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+get_action_api(Type, Name) ->
|
|
|
+ Res = emqx_bridge_v2_testlib:get_bridge_api(action, Type, Name),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+create_source_api(Name, Type, Params) ->
|
|
|
+ Res = emqx_bridge_v2_testlib:create_kind_api([
|
|
|
+ {bridge_kind, source},
|
|
|
+ {source_type, Type},
|
|
|
+ {source_name, Name},
|
|
|
+ {source_config, Params}
|
|
|
+ ]),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+create_action_api(Name, Type, Params) ->
|
|
|
+ Res = emqx_bridge_v2_testlib:create_kind_api([
|
|
|
+ {bridge_kind, action},
|
|
|
+ {action_type, Type},
|
|
|
+ {action_name, Name},
|
|
|
+ {action_config, Params}
|
|
|
+ ]),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+list_sources_api() ->
|
|
|
+ Res = emqx_bridge_v2_testlib:list_sources_http_api(),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+list_actions_api() ->
|
|
|
+ Res = emqx_bridge_v2_testlib:list_actions_http_api(),
|
|
|
+ emqx_mgmt_api_test_util:simplify_result(Res).
|
|
|
+
|
|
|
+create_action_rule(ActionType, ActionName) ->
|
|
|
+ RuleTopic = <<"t/", ActionName/binary>>,
|
|
|
+ Config = [{action_name, ActionName}],
|
|
|
+ emqx_bridge_v2_testlib:create_rule_and_action_http(ActionType, RuleTopic, Config).
|
|
|
+
|
|
|
+create_source_rule1(SourceType, SourceName) ->
|
|
|
+ RuleTopic = <<"t/", SourceName/binary>>,
|
|
|
+ Config = [{action_name, <<"unused">>}],
|
|
|
+ Id = emqx_bridge_resource:bridge_id(SourceType, SourceName),
|
|
|
+ Opts = #{
|
|
|
+ overrides => #{
|
|
|
+ sql => <<"select * from \"$bridges/", Id/binary, "\"">>,
|
|
|
+ actions => []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ emqx_bridge_v2_testlib:create_rule_and_action_http(SourceType, RuleTopic, Config, Opts).
|
|
|
+
|
|
|
+create_source_rule2(SourceType, SourceName) ->
|
|
|
+ RuleTopic = <<"t/", SourceName/binary>>,
|
|
|
+ Config = [{action_name, <<"unused">>}],
|
|
|
+ Id = emqx_bridge_resource:bridge_id(SourceType, SourceName),
|
|
|
+ Opts = #{
|
|
|
+ overrides => #{
|
|
|
+ sql => <<"select * from \"$sources/", Id/binary, "\"">>,
|
|
|
+ actions => []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ emqx_bridge_v2_testlib:create_rule_and_action_http(SourceType, RuleTopic, Config, Opts).
|
|
|
+
|
|
|
%%------------------------------------------------------------------------------
|
|
|
%% Testcases
|
|
|
%%------------------------------------------------------------------------------
|
|
|
@@ -1598,3 +1695,215 @@ t_start_action_or_source_with_disabled_connector(matrix) ->
|
|
|
t_start_action_or_source_with_disabled_connector(Config) ->
|
|
|
ok = emqx_bridge_v2_testlib:t_start_action_or_source_with_disabled_connector(Config),
|
|
|
ok.
|
|
|
+
|
|
|
+%% Verifies that listing connectors return the actions and sources that depend on the
|
|
|
+%% connector
|
|
|
+t_connector_dependencies(matrix) ->
|
|
|
+ [
|
|
|
+ [single, actions],
|
|
|
+ [single, sources]
|
|
|
+ ];
|
|
|
+t_connector_dependencies(Config) when is_list(Config) ->
|
|
|
+ ?check_trace(
|
|
|
+ begin
|
|
|
+ %% This particular source type happens to serve both actions and sources, a
|
|
|
+ %% nice edge case for this test.
|
|
|
+ ActionType = ?SOURCE_TYPE,
|
|
|
+ ConnectorType = ?SOURCE_CONNECTOR_TYPE,
|
|
|
+ ConnectorName = <<"c">>,
|
|
|
+ {ok, {{_, 201, _}, _, _}} =
|
|
|
+ emqx_bridge_v2_testlib:create_connector_api([
|
|
|
+ {connector_config, source_connector_create_config(#{})},
|
|
|
+ {connector_name, ConnectorName},
|
|
|
+ {connector_type, ConnectorType}
|
|
|
+ ]),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [
|
|
|
+ #{
|
|
|
+ <<"actions">> := [],
|
|
|
+ <<"sources">> := []
|
|
|
+ }
|
|
|
+ ]},
|
|
|
+ list_connectors_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{
|
|
|
+ <<"actions">> := [],
|
|
|
+ <<"sources">> := []
|
|
|
+ }},
|
|
|
+ get_connector_api(ConnectorType, ConnectorName)
|
|
|
+ ),
|
|
|
+
|
|
|
+ SourceName1 = <<"s1">>,
|
|
|
+ {201, _} = create_source_api(
|
|
|
+ SourceName1,
|
|
|
+ ?SOURCE_TYPE,
|
|
|
+ source_create_config(#{
|
|
|
+ <<"connector">> => ConnectorName
|
|
|
+ })
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [
|
|
|
+ #{
|
|
|
+ <<"actions">> := [],
|
|
|
+ <<"sources">> := [SourceName1]
|
|
|
+ }
|
|
|
+ ]},
|
|
|
+ list_connectors_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{
|
|
|
+ <<"actions">> := [],
|
|
|
+ <<"sources">> := [SourceName1]
|
|
|
+ }},
|
|
|
+ get_connector_api(ConnectorType, ConnectorName)
|
|
|
+ ),
|
|
|
+
|
|
|
+ ActionName1 = <<"a1">>,
|
|
|
+ {201, _} = create_action_api(
|
|
|
+ ActionName1,
|
|
|
+ ActionType,
|
|
|
+ mqtt_action_create_config(#{
|
|
|
+ <<"connector">> => ConnectorName
|
|
|
+ })
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [
|
|
|
+ #{
|
|
|
+ <<"actions">> := [ActionName1],
|
|
|
+ <<"sources">> := [SourceName1]
|
|
|
+ }
|
|
|
+ ]},
|
|
|
+ list_connectors_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{
|
|
|
+ <<"actions">> := [ActionName1],
|
|
|
+ <<"sources">> := [SourceName1]
|
|
|
+ }},
|
|
|
+ get_connector_api(ConnectorType, ConnectorName)
|
|
|
+ ),
|
|
|
+
|
|
|
+ ok
|
|
|
+ end,
|
|
|
+ []
|
|
|
+ ),
|
|
|
+ ok.
|
|
|
+
|
|
|
+%% Verifies that listing actions/sources return the rules that depend on them.
|
|
|
+t_kind_dependencies(matrix) ->
|
|
|
+ [
|
|
|
+ [single, actions],
|
|
|
+ [single, sources]
|
|
|
+ ];
|
|
|
+t_kind_dependencies(Config) when is_list(Config) ->
|
|
|
+ ?check_trace(
|
|
|
+ begin
|
|
|
+ %% This particular source type happens to serve both actions and sources, a
|
|
|
+ %% nice edge case for this test.
|
|
|
+ ActionType = ?SOURCE_TYPE,
|
|
|
+ SourceType = ?SOURCE_TYPE,
|
|
|
+ ConnectorType = ?SOURCE_CONNECTOR_TYPE,
|
|
|
+ ConnectorName = <<"c">>,
|
|
|
+ {ok, {{_, 201, _}, _, _}} =
|
|
|
+ emqx_bridge_v2_testlib:create_connector_api([
|
|
|
+ {connector_config, source_connector_create_config(#{})},
|
|
|
+ {connector_name, ConnectorName},
|
|
|
+ {connector_type, ConnectorType}
|
|
|
+ ]),
|
|
|
+
|
|
|
+ ActionName1 = <<"a1">>,
|
|
|
+ {201, _} = create_action_api(
|
|
|
+ ActionName1,
|
|
|
+ ActionType,
|
|
|
+ mqtt_action_create_config(#{
|
|
|
+ <<"connector">> => ConnectorName
|
|
|
+ })
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := []}]},
|
|
|
+ list_actions_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{<<"rules">> := []}},
|
|
|
+ get_action_api(ActionType, ActionName1)
|
|
|
+ ),
|
|
|
+
|
|
|
+ {ok, #{<<"id">> := RuleId1}} = create_action_rule(ActionType, ActionName1),
|
|
|
+
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := [RuleId1]}]},
|
|
|
+ list_actions_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{<<"rules">> := [RuleId1]}},
|
|
|
+ get_action_api(ActionType, ActionName1)
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, []},
|
|
|
+ list_sources_api()
|
|
|
+ ),
|
|
|
+
|
|
|
+ SourceName1 = <<"s1">>,
|
|
|
+ {201, _} = create_source_api(
|
|
|
+ SourceName1,
|
|
|
+ ?SOURCE_TYPE,
|
|
|
+ source_create_config(#{
|
|
|
+ <<"connector">> => ConnectorName
|
|
|
+ })
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := []}]},
|
|
|
+ list_sources_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{<<"rules">> := []}},
|
|
|
+ get_source_api(SourceType, SourceName1)
|
|
|
+ ),
|
|
|
+ %% Action remains untouched
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := [RuleId1]}]},
|
|
|
+ list_actions_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{<<"rules">> := [RuleId1]}},
|
|
|
+ get_action_api(ActionType, ActionName1)
|
|
|
+ ),
|
|
|
+
|
|
|
+ %% using "$bridges/..." hookpoint
|
|
|
+ {ok, #{<<"id">> := RuleId2}} = create_source_rule1(SourceType, SourceName1),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := [RuleId2]}]},
|
|
|
+ list_sources_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{<<"rules">> := [RuleId2]}},
|
|
|
+ get_source_api(SourceType, SourceName1)
|
|
|
+ ),
|
|
|
+ %% Action remains untouched
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := [RuleId1]}]},
|
|
|
+ list_actions_api()
|
|
|
+ ),
|
|
|
+
|
|
|
+ %% using "$sources/..." hookpoint
|
|
|
+ {ok, #{<<"id">> := RuleId3}} = create_source_rule2(SourceType, SourceName1),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := [RuleId1]}]},
|
|
|
+ list_actions_api()
|
|
|
+ ),
|
|
|
+ Rules = lists:sort([RuleId2, RuleId3]),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, [#{<<"rules">> := Rules}]},
|
|
|
+ list_sources_api()
|
|
|
+ ),
|
|
|
+ ?assertMatch(
|
|
|
+ {200, #{<<"rules">> := Rules}},
|
|
|
+ get_source_api(SourceType, SourceName1)
|
|
|
+ ),
|
|
|
+
|
|
|
+ ok
|
|
|
+ end,
|
|
|
+ []
|
|
|
+ ),
|
|
|
+ ok.
|