diff --git a/apps/emqx/lib/mix/tasks/compile.copy_srcs.ex b/apps/emqx/lib/mix/tasks/compile.copy_srcs.ex new file mode 100644 index 000000000..68b86d072 --- /dev/null +++ b/apps/emqx/lib/mix/tasks/compile.copy_srcs.ex @@ -0,0 +1,37 @@ +defmodule Mix.Tasks.Compile.CopySrcs do + use Mix.Task.Compiler + + @recursive true + + @impl true + def run(_args) do + Mix.Project.get!() + config = Mix.Project.config() + extra_dirs = config[:extra_dirs] + + unless extra_dirs && is_list(extra_dirs) do + Mix.raise("application option :extra_dirs in #{Mix.Project.project_file()} must be a list of directories under the application") + end + + app_root = File.cwd!() + app_build_path = Mix.Project.app_path(config) + + for extra_dir <- extra_dirs do + src = Path.join([app_root, extra_dir]) + dest = Path.join([app_build_path, extra_dir]) + File.rm(dest) + case File.ln_s(src, dest) do + :ok -> + :ok + + {:error, :eexist} -> + Mix.shell().info(IO.ANSI.format([:yellow, "#{dest} still exists after attempted removal"])) + :ok + + {:error, error} -> + Mix.raise("error trying to link #{src} to #{dest}: #{error}") + end + end + {:noop, []} + end +end diff --git a/apps/emqx/mix.exs b/apps/emqx/mix.exs new file mode 100644 index 000000000..282380c09 --- /dev/null +++ b/apps/emqx/mix.exs @@ -0,0 +1,59 @@ +defmodule EMQX.MixProject do + use Mix.Project + + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx, + version: "0.1.0", + build_path: "../../_build", + erlc_paths: UMP.erlc_paths(), + erlc_options: [ + {:i, "src"} + | UMP.erlc_options() + ], + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [ + ## FIXME!!! go though emqx.app.src and add missing stuff... + extra_applications: [:public_key, :ssl, :os_mon, :logger, :mnesia] ++ UMP.extra_applications(), + mod: {:emqx_app, []} + ] + end + + def deps() do + ## FIXME!!! go though emqx.app.src and add missing stuff... + [ + {:emqx_utils, in_umbrella: true}, + {:emqx_ds_backends, in_umbrella: true}, + + {:ekka, github: "emqx/ekka", tag: "0.19.3", override: true}, + {:esockd, github: "emqx/esockd", tag: "5.11.2"}, + {:gproc, github: "emqx/gproc", tag: "0.9.0.1", override: true}, + {:hocon, github: "emqx/hocon", tag: "0.42.2", override: true}, + {:lc, github: "emqx/lc", tag: "0.3.2", override: true}, + {:ranch, github: "emqx/ranch", tag: "1.8.1-emqx", override: true}, + ] ++ UMP.quicer_dep() + end + + defp extra_dirs() do + dirs = ["src", "etc"] + if UMP.test_env?() do + ["test", "integration_test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx/test/emqx_bpapi_SUITE.erl b/apps/emqx/test/emqx_bpapi_SUITE.erl index 6b785d567..12591519e 100644 --- a/apps/emqx/test/emqx_bpapi_SUITE.erl +++ b/apps/emqx/test/emqx_bpapi_SUITE.erl @@ -21,7 +21,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). --include_lib("emqx/src/bpapi/emqx_bpapi.hrl"). +-include("../src/bpapi/emqx_bpapi.hrl"). all() -> emqx_common_test_helpers:all(?MODULE). diff --git a/apps/emqx/test/emqx_common_test_helpers.erl b/apps/emqx/test/emqx_common_test_helpers.erl index 7a25e925d..ce3c2543c 100644 --- a/apps/emqx/test/emqx_common_test_helpers.erl +++ b/apps/emqx/test/emqx_common_test_helpers.erl @@ -248,6 +248,7 @@ render_and_load_app_config(App, Opts) -> %% turn throw into error error({Conf, E, St}) end. + do_render_app_config(App, Schema, ConfigFile, Opts) -> %% copy acl_conf must run before read_schema_configs copy_acl_conf(), diff --git a/apps/emqx/test/emqx_cth_cluster.erl b/apps/emqx/test/emqx_cth_cluster.erl index f3c5d97f9..9f2997860 100644 --- a/apps/emqx/test/emqx_cth_cluster.erl +++ b/apps/emqx/test/emqx_cth_cluster.erl @@ -391,7 +391,14 @@ node_init(#{name := Node, work_dir := WorkDir}) -> _ = share_load_module(Node, cthr), %% Enable snabbkaffe trace forwarding ok = snabbkaffe:forward_trace(Node), - when_cover_enabled(fun() -> {ok, _} = cover:start([Node]) end), + when_cover_enabled(fun() -> + case cover:start([Node]) of + {ok, _} -> + ok; + {error, {already_started, _}} -> + ok + end + end), ok. %% Returns 'true' if this node should appear in running nodes list. @@ -456,7 +463,7 @@ stop(Nodes) -> stop_node(Name) -> Node = node_name(Name), - when_cover_enabled(fun() -> cover:flush([Node]) end), + when_cover_enabled(fun() -> ok = cover:flush([Node]) end), ok = emqx_cth_peer:stop(Node). %% Ports diff --git a/apps/emqx/test/emqx_cth_suite.erl b/apps/emqx/test/emqx_cth_suite.erl index ef83d7448..39e3ebc45 100644 --- a/apps/emqx/test/emqx_cth_suite.erl +++ b/apps/emqx/test/emqx_cth_suite.erl @@ -71,6 +71,7 @@ -export([start_app/3]). -export([stop_apps/1]). +-export([default_config/2]). -export([merge_appspec/2]). -export([merge_config/2]). @@ -243,6 +244,7 @@ log_appspec(App, #{}) -> spec_fmt(fc, config) -> "~n~ts"; spec_fmt(fc, _) -> "~p"; +spec_fmt(ffun, {config, false}) -> "false (don't inhibit config loader)"; spec_fmt(ffun, {config, C}) -> render_config(C); spec_fmt(ffun, {_, X}) -> X. @@ -349,6 +351,7 @@ default_appspec(emqx_conf, SuiteOpts) -> data_dir => unicode:characters_to_binary(maps:get(work_dir, SuiteOpts, "data")) } }, + SharedApps = maps:get(emqx_conf_shared_apps, SuiteOpts, [emqx, emqx_auth]), % NOTE % Since `emqx_conf_schema` manages config for a lot of applications, it's good to include % their defaults as well. @@ -357,10 +360,7 @@ default_appspec(emqx_conf, SuiteOpts) -> emqx_utils_maps:deep_merge(Acc, default_config(App, SuiteOpts)) end, Config, - [ - emqx, - emqx_auth - ] + SharedApps ), #{ config => SharedConfig, diff --git a/apps/emqx/test/emqx_persistent_session_ds_router_SUITE.erl b/apps/emqx/test/emqx_persistent_session_ds_router_SUITE.erl index 309876c63..65a43f38a 100644 --- a/apps/emqx/test/emqx_persistent_session_ds_router_SUITE.erl +++ b/apps/emqx/test/emqx_persistent_session_ds_router_SUITE.erl @@ -19,7 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx/src/emqx_persistent_session_ds/emqx_ps_ds_int.hrl"). +-include("../src/emqx_persistent_session_ds/emqx_ps_ds_int.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_audit/mix.exs b/apps/emqx_audit/mix.exs new file mode 100644 index 000000000..dcc4a8510 --- /dev/null +++ b/apps/emqx_audit/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXAudit.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_audit, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_audit_app, []}] + end + + def deps() do + [{:emqx, in_umbrella: true}, {:emqx_utils, in_umbrella: true}] + end +end diff --git a/apps/emqx_audit/test/emqx_audit_api_SUITE.erl b/apps/emqx_audit/test/emqx_audit_api_SUITE.erl index 1d4d29e7b..2597a8923 100644 --- a/apps/emqx_audit/test/emqx_audit_api_SUITE.erl +++ b/apps/emqx_audit/test/emqx_audit_api_SUITE.erl @@ -18,6 +18,7 @@ -compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). all() -> [ @@ -54,18 +55,27 @@ common_tests() -> }). init_per_suite(Config) -> - _ = application:load(emqx_conf), - emqx_config:erase_all(), - emqx_mgmt_api_test_util:init_suite([emqx_ctl, emqx_conf, emqx_audit]), - ok = emqx_common_test_helpers:load_config(emqx_enterprise_schema, ?CONF_DEFAULT), - emqx_config:save_schema_mod_and_names(emqx_enterprise_schema), - ok = emqx_config_logger:refresh_config(), - application:set_env(emqx, boot_modules, []), - emqx_conf_cli:load(), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_ctl, + emqx, + {emqx_conf, #{ + config => ?CONF_DEFAULT, + schema_mod => emqx_enterprise_schema + }}, + emqx_modules, + emqx_audit, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_) -> - emqx_mgmt_api_test_util:end_suite([emqx_audit, emqx_conf, emqx_ctl]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + ok = emqx_cth_suite:stop(Apps), + ok. t_http_api(_) -> process_flag(trap_exit, true), @@ -164,6 +174,7 @@ t_cli(_Config) -> ], Data ), + [ShowLogEntry] = Data, %% check create at is valid [#{<<"created_at">> := CreateAtRaw}] = Data, CreateAt = calendar:rfc3339_to_system_time(binary_to_list(CreateAtRaw), [{unit, microsecond}]), @@ -172,7 +183,10 @@ t_cli(_Config) -> %% check cli filter {ok, Res1} = emqx_mgmt_api_test_util:request_api(get, AuditPath, "from=cli", AuthHeader), #{<<"data">> := Data1} = emqx_utils_json:decode(Res1, [return_maps]), - ?assertEqual(Data, Data1), + ?assertMatch( + [ShowLogEntry, #{<<"operation_type">> := <<"emqx">>, <<"args">> := [<<"start">>]}], + Data1 + ), {ok, Res2} = emqx_mgmt_api_test_util:request_api( get, AuditPath, "from=erlang_console", AuthHeader ), diff --git a/apps/emqx_auth/mix.exs b/apps/emqx_auth/mix.exs new file mode 100644 index 000000000..aacc0bda6 --- /dev/null +++ b/apps/emqx_auth/mix.exs @@ -0,0 +1,44 @@ +defmodule EMQXAuth.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true} + ] + end + + defp extra_dirs() do + dirs = ["etc"] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_auth/src/emqx_authz/emqx_authz_app.erl b/apps/emqx_auth/src/emqx_authz/emqx_authz_app.erl index 7c399ba44..be30500d7 100644 --- a/apps/emqx_auth/src/emqx_authz/emqx_authz_app.erl +++ b/apps/emqx_auth/src/emqx_authz/emqx_authz_app.erl @@ -19,6 +19,8 @@ %% @end %%%------------------------------------------------------------------- +%% TODO: delete this module + -module(emqx_authz_app). -behaviour(application). diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_api_cache_SUITE.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_api_cache_SUITE.erl index fa1bd007b..a9a75ddb4 100644 --- a/apps/emqx_auth/test/emqx_authz/emqx_authz_api_cache_SUITE.erl +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_api_cache_SUITE.erl @@ -32,32 +32,30 @@ groups() -> []. init_per_suite(Config) -> - ok = emqx_mgmt_api_test_util:init_suite( - [emqx_conf, emqx_auth], - fun set_special_configs/1 + Apps = emqx_cth_suite:start( + [ + emqx_conf, + {emqx_auth, #{ + config => + #{ + authorization => + #{ + cache => #{enabled => true}, + no_match => deny, + sources => [] + } + } + }}, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - Config. + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - {ok, _} = emqx:update_config( - [authorization], - #{ - <<"no_match">> => <<"allow">>, - <<"cache">> => #{<<"enable">> => <<"true">>}, - <<"sources">> => [] - } - ), - emqx_mgmt_api_test_util:end_suite([emqx_auth, emqx_conf]), - ok. - -set_special_configs(emqx_dashboard) -> - emqx_dashboard_api_test_helpers:set_default_config(); -set_special_configs(emqx_auth) -> - {ok, _} = emqx:update_config([authorization, cache, enable], true), - {ok, _} = emqx:update_config([authorization, no_match], deny), - {ok, _} = emqx:update_config([authorization, sources], []), - ok; -set_special_configs(_App) -> +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. t_clean_cache(_) -> diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_api_settings_SUITE.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_api_settings_SUITE.erl index 90d6c076f..94acb2291 100644 --- a/apps/emqx_auth/test/emqx_authz/emqx_authz_api_settings_SUITE.erl +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_api_settings_SUITE.erl @@ -30,33 +30,30 @@ groups() -> []. init_per_suite(Config) -> - ok = emqx_mgmt_api_test_util:init_suite( - [emqx_conf, emqx_auth, emqx_dashboard], - fun set_special_configs/1 + Apps = emqx_cth_suite:start( + [ + emqx_conf, + {emqx_auth, #{ + config => + #{ + authorization => + #{ + cache => #{enabled => true}, + no_match => allow, + sources => [] + } + } + }}, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - Config. + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - {ok, _} = emqx:update_config( - [authorization], - #{ - <<"no_match">> => <<"allow">>, - <<"cache">> => #{<<"enable">> => <<"true">>}, - <<"sources">> => [] - } - ), - ok = stop_apps([emqx_resource]), - emqx_mgmt_api_test_util:end_suite([emqx_auth, emqx_conf]), - ok. - -set_special_configs(emqx_dashboard) -> - emqx_dashboard_api_test_helpers:set_default_config(); -set_special_configs(emqx_auth) -> - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), - {ok, _} = emqx:update_config([authorization, sources], []), - ok; -set_special_configs(_App) -> +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. %%------------------------------------------------------------------------------ diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_rule_SUITE.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_rule_SUITE.erl index d25b575e2..db0f95014 100644 --- a/apps/emqx_auth/test/emqx_authz/emqx_authz_rule_SUITE.erl +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_rule_SUITE.erl @@ -34,22 +34,30 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - ok = emqx_common_test_helpers:start_apps( - [emqx_conf, emqx_auth], - fun set_special_configs/1 + Apps = emqx_cth_suite:start( + [ + emqx_conf, + {emqx_auth, #{ + config => + #{ + authorization => + #{ + cache => #{enabled => false}, + no_match => deny, + sources => [] + } + } + }}, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - Config. + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - {ok, _} = emqx:update_config( - [authorization], - #{ - <<"no_match">> => <<"allow">>, - <<"cache">> => #{<<"enable">> => <<"true">>}, - <<"sources">> => [] - } - ), - emqx_common_test_helpers:stop_apps([emqx_auth, emqx_conf]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_testcase(_TestCase, Config) -> @@ -58,14 +66,6 @@ end_per_testcase(_TestCase, _Config) -> _ = emqx_authz:set_feature_available(rich_actions, true), ok. -set_special_configs(emqx_auth) -> - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), - {ok, _} = emqx:update_config([authorization, sources], []), - ok; -set_special_configs(_App) -> - ok. - t_compile(_) -> % NOTE % Some of the following testcase are relying on the internal representation of diff --git a/apps/emqx_auth_ext/mix.exs b/apps/emqx_auth_ext/mix.exs new file mode 100644 index 000000000..7b7e8534c --- /dev/null +++ b/apps/emqx_auth_ext/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXAuthExt.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_ext, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [{:emqx, in_umbrella: true}] + end +end diff --git a/apps/emqx_auth_http/mix.exs b/apps/emqx_auth_http/mix.exs new file mode 100644 index 000000000..615f6f34e --- /dev/null +++ b/apps/emqx_auth_http/mix.exs @@ -0,0 +1,35 @@ +defmodule EMQXAuthHTTP.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_http, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_http_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:emqx_connector, in_umbrella: true}, + {:hocon, github: "emqx/hocon", tag: "0.42.2", override: true} + ] + end +end diff --git a/apps/emqx_auth_jwt/mix.exs b/apps/emqx_auth_jwt/mix.exs new file mode 100644 index 000000000..dfbb13615 --- /dev/null +++ b/apps/emqx_auth_jwt/mix.exs @@ -0,0 +1,34 @@ +defmodule EMQXAuthJWT.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_jwt, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_jwt_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2"} + ] + end +end diff --git a/apps/emqx_auth_ldap/mix.exs b/apps/emqx_auth_ldap/mix.exs new file mode 100644 index 000000000..f97b1d8ef --- /dev/null +++ b/apps/emqx_auth_ldap/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXAuthLDAP.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_ldap, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: [:eldap], mod: {:emqx_auth_ldap_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_ldap, in_umbrella: true}, + ] + end +end diff --git a/apps/emqx_auth_ldap/test/emqx_authz_ldap_SUITE.erl b/apps/emqx_auth_ldap/test/emqx_authz_ldap_SUITE.erl index 904c6cd9d..09875a3fa 100644 --- a/apps/emqx_auth_ldap/test/emqx_authz_ldap_SUITE.erl +++ b/apps/emqx_auth_ldap/test/emqx_authz_ldap_SUITE.erl @@ -33,25 +33,27 @@ groups() -> emqx_authz_test_lib:table_groups(t_run_case, cases()). init_per_suite(Config) -> - ok = stop_apps([emqx_resource]), case emqx_common_test_helpers:is_tcp_server_available(?LDAP_HOST, ?LDAP_DEFAULT_PORT) of true -> - ok = emqx_common_test_helpers:start_apps( - [emqx_conf, emqx_auth, emqx_auth_ldap], - fun set_special_configs/1 + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_auth, + emqx_auth_ldap + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - ok = start_apps([emqx_resource]), ok = create_ldap_resource(), - Config; + [{apps, Apps} | Config]; false -> {skip, no_ldap} end. -end_per_suite(_Config) -> - ok = emqx_authz_test_lib:restore_authorizers(), - ok = emqx_resource:remove_local(?LDAP_RESOURCE), - ok = stop_apps([emqx_resource]), - ok = emqx_common_test_helpers:stop_apps([emqx_conf, emqx_auth, emqx_auth_ldap]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_group(Group, Config) -> [{test_case, emqx_authz_test_lib:get_case(Group, cases())} | Config]. diff --git a/apps/emqx_auth_mnesia/mix.exs b/apps/emqx_auth_mnesia/mix.exs new file mode 100644 index 000000000..e99bd5b47 --- /dev/null +++ b/apps/emqx_auth_mnesia/mix.exs @@ -0,0 +1,29 @@ +defmodule EMQXAuthMnesia.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_mnesia, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_mnesia_app, []}] + end + + def deps() do + [{:emqx, in_umbrella: true}, {:emqx_auth, in_umbrella: true}] + end +end diff --git a/apps/emqx_auth_mnesia/test/emqx_authn_api_mnesia_SUITE.erl b/apps/emqx_auth_mnesia/test/emqx_authn_api_mnesia_SUITE.erl index d7f04f562..71d4eea74 100644 --- a/apps/emqx_auth_mnesia/test/emqx_authn_api_mnesia_SUITE.erl +++ b/apps/emqx_auth_mnesia/test/emqx_authn_api_mnesia_SUITE.erl @@ -51,6 +51,7 @@ end_per_testcase(_, Config) -> init_per_suite(Config) -> Apps = emqx_cth_suite:start( [ + emqx_ctl, emqx, emqx_conf, emqx_auth, diff --git a/apps/emqx_auth_mnesia/test/emqx_authz_mnesia_SUITE.erl b/apps/emqx_auth_mnesia/test/emqx_authz_mnesia_SUITE.erl index 2fc67dad8..31b81ac36 100644 --- a/apps/emqx_auth_mnesia/test/emqx_authz_mnesia_SUITE.erl +++ b/apps/emqx_auth_mnesia/test/emqx_authz_mnesia_SUITE.erl @@ -18,7 +18,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_authz.hrl"). +-include_lib("emqx_auth/include/emqx_authz.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_mongodb/mix.exs b/apps/emqx_auth_mongodb/mix.exs new file mode 100644 index 000000000..80b43951b --- /dev/null +++ b/apps/emqx_auth_mongodb/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXAuthMongoDB.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_mongodb, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_mongodb_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_mongodb, in_umbrella: true}, + ] + end +end diff --git a/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_SUITE.erl b/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_SUITE.erl index 643b99d7b..df7d92311 100644 --- a/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_SUITE.erl +++ b/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_tls_SUITE.erl b/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_tls_SUITE.erl index 5a7271dba..90019bdc8 100644 --- a/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_tls_SUITE.erl +++ b/apps/emqx_auth_mongodb/test/emqx_authn_mongodb_tls_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_mongodb/test/emqx_authz_mongodb_SUITE.erl b/apps/emqx_auth_mongodb/test/emqx_authz_mongodb_SUITE.erl index e0d95e00c..a5ad17031 100644 --- a/apps/emqx_auth_mongodb/test/emqx_authz_mongodb_SUITE.erl +++ b/apps/emqx_auth_mongodb/test/emqx_authz_mongodb_SUITE.erl @@ -19,7 +19,7 @@ -compile(export_all). -include_lib("emqx_auth/include/emqx_authz.hrl"). --include_lib("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("emqx/include/emqx_placeholder.hrl"). diff --git a/apps/emqx_auth_mysql/mix.exs b/apps/emqx_auth_mysql/mix.exs new file mode 100644 index 000000000..258a2049c --- /dev/null +++ b/apps/emqx_auth_mysql/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXAuthMySQL.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_mysql, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_mysql_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_mysql, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_auth_mysql/test/emqx_authn_mysql_SUITE.erl b/apps/emqx_auth_mysql/test/emqx_authn_mysql_SUITE.erl index 8871098e7..8ab812fc0 100644 --- a/apps/emqx_auth_mysql/test/emqx_authn_mysql_SUITE.erl +++ b/apps/emqx_auth_mysql/test/emqx_authn_mysql_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_mysql/test/emqx_authn_mysql_tls_SUITE.erl b/apps/emqx_auth_mysql/test/emqx_authn_mysql_tls_SUITE.erl index 66dbe13ba..71edb0bac 100644 --- a/apps/emqx_auth_mysql/test/emqx_authn_mysql_tls_SUITE.erl +++ b/apps/emqx_auth_mysql/test/emqx_authn_mysql_tls_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_mysql/test/emqx_authz_mysql_SUITE.erl b/apps/emqx_auth_mysql/test/emqx_authz_mysql_SUITE.erl index ec24d9dd3..ce30e203e 100644 --- a/apps/emqx_auth_mysql/test/emqx_authz_mysql_SUITE.erl +++ b/apps/emqx_auth_mysql/test/emqx_authz_mysql_SUITE.erl @@ -18,7 +18,7 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authz.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_postgresql/mix.exs b/apps/emqx_auth_postgresql/mix.exs new file mode 100644 index 000000000..c570deefe --- /dev/null +++ b/apps/emqx_auth_postgresql/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXAuthPostgreSQL.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_postgresql, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_postgresql_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_postgresql, in_umbrella: true}, + ] + end +end diff --git a/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_SUITE.erl b/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_SUITE.erl index 570eb42ce..50bff634d 100644 --- a/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_SUITE.erl +++ b/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_postgresql/include/emqx_postgresql.hrl"). +-include_lib("../../emqx_postgresql/include/emqx_postgresql.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). @@ -196,7 +196,7 @@ test_user_auth(#{ ?GLOBAL ). -t_authenticate_disabled_prepared_statements(Config) -> +t_authenticate_disabled_prepared_statements(_Config) -> ResConfig = maps:merge(pgsql_config(), #{disable_prepared_statements => true}), {ok, _} = emqx_resource:recreate_local(?PGSQL_RESOURCE, emqx_postgresql, ResConfig), on_exit(fun() -> diff --git a/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_tls_SUITE.erl b/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_tls_SUITE.erl index 22a18b4b3..05022ca06 100644 --- a/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_tls_SUITE.erl +++ b/apps/emqx_auth_postgresql/test/emqx_authn_postgresql_tls_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_postgresql/include/emqx_postgresql.hrl"). +-include_lib("../../emqx_postgresql/include/emqx_postgresql.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_postgresql/test/emqx_authz_postgresql_SUITE.erl b/apps/emqx_auth_postgresql/test/emqx_authz_postgresql_SUITE.erl index 9365604fc..78b1e17a8 100644 --- a/apps/emqx_auth_postgresql/test/emqx_authz_postgresql_SUITE.erl +++ b/apps/emqx_auth_postgresql/test/emqx_authz_postgresql_SUITE.erl @@ -18,7 +18,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_postgresql/include/emqx_postgresql.hrl"). +-include_lib("../../emqx_postgresql/include/emqx_postgresql.hrl"). -include_lib("emqx_auth/include/emqx_authz.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_redis/mix.exs b/apps/emqx_auth_redis/mix.exs new file mode 100644 index 000000000..fcb96b3aa --- /dev/null +++ b/apps/emqx_auth_redis/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXAuthRedis.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auth_redis, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auth_redis_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_redis, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_auth_redis/test/emqx_authn_redis_SUITE.erl b/apps/emqx_auth_redis/test/emqx_authn_redis_SUITE.erl index 6329f4009..e8c8760de 100644 --- a/apps/emqx_auth_redis/test/emqx_authn_redis_SUITE.erl +++ b/apps/emqx_auth_redis/test/emqx_authn_redis_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auth_redis/test/emqx_authz_redis_SUITE.erl b/apps/emqx_auth_redis/test/emqx_authz_redis_SUITE.erl index 2ac3e0a44..5818eea07 100644 --- a/apps/emqx_auth_redis/test/emqx_authz_redis_SUITE.erl +++ b/apps/emqx_auth_redis/test/emqx_authz_redis_SUITE.erl @@ -19,7 +19,7 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_auth/include/emqx_authz.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_auto_subscribe/mix.exs b/apps/emqx_auto_subscribe/mix.exs new file mode 100644 index 000000000..54a6cef3e --- /dev/null +++ b/apps/emqx_auto_subscribe/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXAutoSubscribe.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_auto_subscribe, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_auto_subscribe_app, []}] + end + + def deps() do + [{:emqx, in_umbrella: true}, {:emqx_utils, in_umbrella: true}] + end +end diff --git a/apps/emqx_auto_subscribe/test/emqx_auto_subscribe_SUITE.erl b/apps/emqx_auto_subscribe/test/emqx_auto_subscribe_SUITE.erl index 6b16f2c25..33a1d0b25 100644 --- a/apps/emqx_auto_subscribe/test/emqx_auto_subscribe_SUITE.erl +++ b/apps/emqx_auto_subscribe/test/emqx_auto_subscribe_SUITE.erl @@ -19,8 +19,7 @@ -compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). - --define(APP, emqx_auto_subscribe). +-include_lib("common_test/include/ct.hrl"). -define(TOPIC_C, <<"/c/${clientid}">>). -define(TOPIC_U, <<"/u/${username}">>). @@ -44,8 +43,6 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - mria:start(), - application:stop(?APP), meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_schema, fields, fun ("auto_subscribe") -> @@ -60,43 +57,45 @@ init_per_suite(Config) -> meck:expect(emqx_resource, update, fun(_, _, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, remove, fun(_) -> ok end), - application:load(emqx_dashboard), - application:load(?APP), - ok = emqx_common_test_helpers:load_config( - emqx_auto_subscribe_schema, - << - "auto_subscribe {\n" - " topics = [\n" - " {\n" - " topic = \"/c/${clientid}\"\n" - " },\n" - " {\n" - " topic = \"/u/${username}\"\n" - " },\n" - " {\n" - " topic = \"/h/${host}\"\n" - " },\n" - " {\n" - " topic = \"/p/${port}\"\n" - " },\n" - " {\n" - " topic = \"/client/${clientid}/username/${username}/host/${host}/port/${port}\"\n" - " },\n" - " {\n" - " topic = \"/topic/simple\"\n" - " qos = 1\n" - " rh = 0\n" - " rap = 0\n" - " nl = 0\n" - " }\n" - " ]\n" - " }" - >> + ASCfg = << + "auto_subscribe {\n" + " topics = [\n" + " {\n" + " topic = \"/c/${clientid}\"\n" + " },\n" + " {\n" + " topic = \"/u/${username}\"\n" + " },\n" + " {\n" + " topic = \"/h/${host}\"\n" + " },\n" + " {\n" + " topic = \"/p/${port}\"\n" + " },\n" + " {\n" + " topic = \"/client/${clientid}/username/${username}/host/${host}/port/${port}\"\n" + " },\n" + " {\n" + " topic = \"/topic/simple\"\n" + " qos = 1\n" + " rh = 0\n" + " rap = 0\n" + " nl = 0\n" + " }\n" + " ]\n" + " }" + >>, + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + {emqx_auto_subscribe, ASCfg}, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - emqx_mgmt_api_test_util:init_suite( - [emqx_conf, ?APP] - ), - Config. + [{apps, Apps} | Config]. init_per_testcase(t_get_basic_usage_info, Config) -> {ok, _} = emqx_auto_subscribe:update([]), @@ -119,13 +118,10 @@ topic_config(T) -> nl => 0 }. -end_per_suite(_) -> - application:unload(emqx_management), - application:unload(emqx_conf), - application:unload(?APP), - meck:unload(emqx_resource), - meck:unload(emqx_schema), - emqx_mgmt_api_test_util:end_suite([emqx_conf, ?APP]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_auto_subscribe(_) -> emqx_auto_subscribe:update([#{<<"topic">> => Topic} || Topic <- ?TOPICS]), diff --git a/apps/emqx_bridge/mix.exs b/apps/emqx_bridge/mix.exs new file mode 100644 index 000000000..8322b5606 --- /dev/null +++ b/apps/emqx_bridge/mix.exs @@ -0,0 +1,45 @@ +defmodule EMQXBridge.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_bridge_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:emqx_connector, in_umbrella: true}, + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_bridge/src/emqx_bridge_api.erl b/apps/emqx_bridge/src/emqx_bridge_api.erl index 244326ee9..49e97c7f4 100644 --- a/apps/emqx_bridge/src/emqx_bridge_api.erl +++ b/apps/emqx_bridge/src/emqx_bridge_api.erl @@ -501,7 +501,18 @@ schema("/bridges_probe") -> end. '/bridges/:id'(get, #{bindings := #{id := Id}}) -> - ?TRY_PARSE_ID(Id, lookup_from_all_nodes(BridgeType, BridgeName, 200)); + ?TRY_PARSE_ID( + Id, + begin + CompatErrorMsg = non_compat_bridge_msg(), + case lookup_from_all_nodes(BridgeType, BridgeName, 200) of + {400, #{code := 'BAD_REQUEST', message := CompatErrorMsg}} -> + ?BRIDGE_NOT_FOUND(BridgeType, BridgeName); + Res -> + Res + end + end + ); '/bridges/:id'(put, #{bindings := #{id := Id}, body := Conf0}) -> Conf1 = filter_out_request_body(Conf0), ?TRY_PARSE_ID( @@ -634,7 +645,7 @@ lookup_from_all_nodes(BridgeType, BridgeName, SuccCode) -> {ok, [{error, not_found} | _]} -> ?BRIDGE_NOT_FOUND(BridgeType, BridgeName); {ok, [{error, not_bridge_v1_compatible} | _]} -> - ?NOT_FOUND(non_compat_bridge_msg()); + ?BAD_REQUEST(non_compat_bridge_msg()); {error, Reason} -> ?INTERNAL_ERROR(Reason) end. diff --git a/apps/emqx_bridge/test/emqx_bridge_v2_testlib.erl b/apps/emqx_bridge/test/emqx_bridge_v2_testlib.erl index 41c184af9..5421123ae 100644 --- a/apps/emqx_bridge/test/emqx_bridge_v2_testlib.erl +++ b/apps/emqx_bridge/test/emqx_bridge_v2_testlib.erl @@ -22,25 +22,22 @@ init_per_suite(Config, Apps) -> [{start_apps, Apps} | Config]. end_per_suite(Config) -> - delete_all_bridges_and_connectors(), - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps(lists:reverse(?config(start_apps, Config))), - _ = application:stop(emqx_connector), + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_group(TestGroup, BridgeType, Config) -> ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - application:load(emqx_bridge), - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps(?config(start_apps, Config)), - {ok, _} = application:ensure_all_started(emqx_connector), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + ?config(start_apps, Config), + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), UniqueNum = integer_to_binary(erlang:unique_integer([positive])), MQTTTopic = <<"mqtt/topic/abc", UniqueNum/binary>>, [ + {apps, Apps}, {proxy_host, ProxyHost}, {proxy_port, ProxyPort}, {mqtt_topic, MQTTTopic}, @@ -50,10 +47,11 @@ init_per_group(TestGroup, BridgeType, Config) -> ]. end_per_group(Config) -> + Apps = ?config(apps, Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - % delete_all_bridges(), + emqx_cth_suite:stop(Apps), ok. init_per_testcase(TestCase, Config0, BridgeConfigCb) -> diff --git a/apps/emqx_bridge_azure_event_hub/mix.exs b/apps/emqx_bridge_azure_event_hub/mix.exs new file mode 100644 index 000000000..42edddbbe --- /dev/null +++ b/apps/emqx_bridge_azure_event_hub/mix.exs @@ -0,0 +1,38 @@ +defmodule EMQXBridgeAzureEventHub.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_azure_event_hub, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:wolff, github: "kafka4beam/wolff", tag: "2.0.0"}, + {:kafka_protocol, github: "kafka4beam/kafka_protocol", tag: "4.1.5", override: true}, + {:brod_gssapi, github: "kafka4beam/brod_gssapi", tag: "v0.1.1"}, + {:brod, github: "kafka4beam/brod", tag: "3.18.0"}, + ## TODO: remove `mix.exs` from `wolff` and remove this override + ## TODO: remove `mix.exs` from `pulsar` and remove this override + {:snappyer, "1.2.9", override: true}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_cassandra/mix.exs b/apps/emqx_bridge_cassandra/mix.exs new file mode 100644 index 000000000..52e0ec840 --- /dev/null +++ b/apps/emqx_bridge_cassandra/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeCassandra.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_cassandra, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:ecql, github: "emqx/ecql", tag: "v0.7.0"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_SUITE.erl b/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_SUITE.erl index 449d1fa51..8c9e954aa 100644 --- a/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_SUITE.erl +++ b/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_SUITE.erl @@ -148,8 +148,6 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([emqx_bridge, emqx_conf]), ok. init_per_testcase(_Testcase, Config) -> @@ -191,11 +189,10 @@ common_init(Config0) -> emqx_bridge, emqx_rule_engine, emqx_management, - {emqx_dashboard, "dashboard.listeners.http { enable = true, bind = 18083 }"} + emqx_mgmt_api_test_util:emqx_dashboard() ], #{work_dir => emqx_cth_suite:work_dir(Config0)} ), - {ok, _Api} = emqx_common_test_http:create_default_app(), % Connect to cassnadra directly and create the table catch connect_and_drop_table(Config0), connect_and_create_table(Config0), diff --git a/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_connector_SUITE.erl b/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_connector_SUITE.erl index 1300bd8c8..b784d36c0 100644 --- a/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_connector_SUITE.erl +++ b/apps/emqx_bridge_cassandra/test/emqx_bridge_cassandra_connector_SUITE.erl @@ -9,7 +9,7 @@ -include_lib("common_test/include/ct.hrl"). -include("emqx_bridge_cassandra.hrl"). --include("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("emqx/include/emqx.hrl"). -include_lib("stdlib/include/assert.hrl"). @@ -53,10 +53,24 @@ cassandra_servers(CassandraHost, CassandraPort) -> ). init_per_suite(Config) -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - Config. + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_bridge_cassandra, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. + +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_group(Group, Config) -> {CassandraHost, CassandraPort, AuthOpts} = @@ -98,11 +112,6 @@ init_per_group(Group, Config) -> end_per_group(_Group, _Config) -> ok. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector). - init_per_testcase(_, Config) -> Config. diff --git a/apps/emqx_bridge_clickhouse/mix.exs b/apps/emqx_bridge_clickhouse/mix.exs new file mode 100644 index 000000000..02c85296d --- /dev/null +++ b/apps/emqx_bridge_clickhouse/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeClickhouse.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_clickhouse, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:clickhouse, github: "emqx/clickhouse-client-erl", tag: "0.3.1"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_SUITE.erl b/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_SUITE.erl index 1720cea43..8bb03aaff 100644 --- a/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_SUITE.erl +++ b/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_SUITE.erl @@ -7,9 +7,9 @@ -compile(nowarn_export_all). -compile(export_all). --define(APP, emqx_bridge_clickhouse). -define(CLICKHOUSE_HOST, "clickhouse"). -define(CLICKHOUSE_PORT, "8123"). +-include_lib("common_test/include/ct.hrl"). -include_lib("emqx_connector/include/emqx_connector.hrl"). %% See comment in @@ -25,17 +25,26 @@ init_per_suite(Config) -> Port = list_to_integer(clickhouse_port()), case emqx_common_test_helpers:is_tcp_server_available(Host, Port) of true -> - emqx_common_test_helpers:render_and_load_app_config(emqx_conf), - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_bridge]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource, ?APP]), - snabbkaffe:fix_ct_logging(), + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_bridge_clickhouse, + emqx_connector, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), %% Create the db table Conn = start_clickhouse_connection(), % erlang:monitor,sb {ok, _, _} = clickhouse:query(Conn, sql_create_database(), #{}), {ok, _, _} = clickhouse:query(Conn, sql_create_table(), []), clickhouse:query(Conn, sql_find_key(42), []), - [{clickhouse_connection, Conn} | Config]; + [{apps, Apps}, {clickhouse_connection, Conn} | Config]; false -> case os:getenv("IS_CI") of "yes" -> @@ -74,8 +83,9 @@ start_clickhouse_connection() -> end_per_suite(Config) -> ClickhouseConnection = proplists:get_value(clickhouse_connection, Config), clickhouse:stop(ClickhouseConnection), - ok = emqx_connector_test_helpers:stop_apps([?APP, emqx_resource]), - ok = emqx_common_test_helpers:stop_apps([emqx_bridge, emqx_conf]). + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> reset_table(Config), diff --git a/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_connector_SUITE.erl b/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_connector_SUITE.erl index 0307981da..1c83961a5 100644 --- a/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_connector_SUITE.erl +++ b/apps/emqx_bridge_clickhouse/test/emqx_bridge_clickhouse_connector_SUITE.erl @@ -7,7 +7,7 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("stdlib/include/assert.hrl"). -include_lib("common_test/include/ct.hrl"). @@ -43,8 +43,19 @@ init_per_suite(Config) -> Port = list_to_integer(emqx_bridge_clickhouse_SUITE:clickhouse_port()), case emqx_common_test_helpers:is_tcp_server_available(Host, Port) of true -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource, ?APP]), + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_bridge_clickhouse, + emqx_connector, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), %% Create the db table {ok, Conn} = clickhouse:start_link([ @@ -55,7 +66,7 @@ init_per_suite(Config) -> ]), {ok, _, _} = clickhouse:query(Conn, <<"CREATE DATABASE IF NOT EXISTS mqtt">>, #{}), clickhouse:stop(Conn), - Config; + [{apps, Apps} | Config]; false -> case os:getenv("IS_CI") of "yes" -> @@ -65,9 +76,10 @@ init_per_suite(Config) -> end end. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([?APP, emqx_resource]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> Config. diff --git a/apps/emqx_bridge_confluent/mix.exs b/apps/emqx_bridge_confluent/mix.exs new file mode 100644 index 000000000..46cbe9a02 --- /dev/null +++ b/apps/emqx_bridge_confluent/mix.exs @@ -0,0 +1,38 @@ +defmodule EMQXBridgeConfluent.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_confluent, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:wolff, github: "kafka4beam/wolff", tag: "2.0.0"}, + {:kafka_protocol, github: "kafka4beam/kafka_protocol", tag: "4.1.5", override: true}, + {:brod_gssapi, github: "kafka4beam/brod_gssapi", tag: "v0.1.1"}, + {:brod, github: "kafka4beam/brod", tag: "3.18.0"}, + ## TODO: remove `mix.exs` from `wolff` and remove this override + ## TODO: remove `mix.exs` from `pulsar` and remove this override + {:snappyer, "1.2.9", override: true}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_dynamo/mix.exs b/apps/emqx_bridge_dynamo/mix.exs new file mode 100644 index 000000000..dab4df583 --- /dev/null +++ b/apps/emqx_bridge_dynamo/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeDynamo.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_dynamo, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:erlcloud, github: "emqx/erlcloud", tag: "3.7.0.3"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl b/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl index ff3d5824e..a21c171fb 100644 --- a/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl +++ b/apps/emqx_bridge_dynamo/test/emqx_bridge_dynamo_SUITE.erl @@ -69,14 +69,18 @@ init_per_group(_Group, Config) -> Config. end_per_group(Group, Config) when Group =:= with_batch; Group =:= without_batch -> + Apps = ?config(apps, Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + emqx_cth_suite:stop(Apps), ok; end_per_group(Group, Config) when Group =:= flaky -> + Apps = ?config(apps, Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + emqx_cth_suite:stop(Apps), timer:sleep(1000), ok; end_per_group(_Group, _Config) -> @@ -135,18 +139,23 @@ common_init(ConfigT) -> ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - % Ensure enterprise bridge module is loaded - ok = emqx_common_test_helpers:start_apps([ - emqx_conf, emqx_resource, emqx_bridge, emqx_rule_engine - ]), - _ = application:ensure_all_started(erlcloud), - _ = emqx_bridge_enterprise:module_info(), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_bridge_dynamo, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config0)} + ), % setup dynamo setup_dynamo(Config0), {Name, TDConf} = dynamo_config(BridgeType, Config0), Config = [ + {apps, Apps}, {dynamo_config, TDConf}, {dynamo_bridge_type, BridgeType}, {dynamo_name, Name}, diff --git a/apps/emqx_bridge_es/mix.exs b/apps/emqx_bridge_es/mix.exs new file mode 100644 index 000000000..c049c0ac8 --- /dev/null +++ b/apps/emqx_bridge_es/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXBridgeEs.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_es, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_bridge_http, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_gcp_pubsub/mix.exs b/apps/emqx_bridge_gcp_pubsub/mix.exs new file mode 100644 index 000000000..3a9fae0a1 --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeGcpPubsub.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_gcp_pubsub, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_bridge_http, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_greptimedb/mix.exs b/apps/emqx_bridge_greptimedb/mix.exs new file mode 100644 index 000000000..7164444d2 --- /dev/null +++ b/apps/emqx_bridge_greptimedb/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeGreptimedb.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_greptimedb, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:greptimedb, github: "GreptimeTeam/greptimedb-ingester-erl", tag: "v0.1.8"} + ] + end +end diff --git a/apps/emqx_bridge_greptimedb/test/emqx_bridge_greptimedb_connector_SUITE.erl b/apps/emqx_bridge_greptimedb/test/emqx_bridge_greptimedb_connector_SUITE.erl index 3c209fe1b..be36cb167 100644 --- a/apps/emqx_bridge_greptimedb/test/emqx_bridge_greptimedb_connector_SUITE.erl +++ b/apps/emqx_bridge_greptimedb/test/emqx_bridge_greptimedb_connector_SUITE.erl @@ -25,11 +25,17 @@ init_per_suite(Config) -> Servers = [{GreptimedbTCPHost, GreptimedbTCPPort}], case emqx_common_test_helpers:is_all_tcp_servers_available(Servers) of true -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - {ok, _} = application:ensure_all_started(greptimedb), + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_bridge_greptimedb, + emqx_bridge + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), [ + {apps, Apps}, {greptimedb_tcp_host, GreptimedbTCPHost}, {greptimedb_tcp_port, GreptimedbTCPPort} | Config @@ -43,11 +49,9 @@ init_per_suite(Config) -> end end. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector), - _ = application:stop(greptimedb), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_testcase(_, Config) -> diff --git a/apps/emqx_bridge_hstreamdb/mix.exs b/apps/emqx_bridge_hstreamdb/mix.exs new file mode 100644 index 000000000..87f8b80c2 --- /dev/null +++ b/apps/emqx_bridge_hstreamdb/mix.exs @@ -0,0 +1,34 @@ +defmodule EMQXBridgeHstreamdb.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_hstreamdb, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:hstreamdb_erl, + github: "hstreamdb/hstreamdb_erl", tag: "0.5.18+v0.18.1+ezstd-v1.0.5-emqx1"}, + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_hstreamdb/test/emqx_bridge_hstreamdb_SUITE.erl b/apps/emqx_bridge_hstreamdb/test/emqx_bridge_hstreamdb_SUITE.erl index 02f3477b9..6762e4e50 100644 --- a/apps/emqx_bridge_hstreamdb/test/emqx_bridge_hstreamdb_SUITE.erl +++ b/apps/emqx_bridge_hstreamdb/test/emqx_bridge_hstreamdb_SUITE.erl @@ -100,10 +100,12 @@ init_per_group(_Group, Config) -> Config. end_per_group(Group, Config) when Group =:= with_batch; Group =:= without_batch -> + Apps = ?config(apps, Config), connect_and_delete_stream(Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + emqx_cth_suite:stop(Apps), ok; end_per_group(_Group, _Config) -> ok. @@ -408,11 +410,16 @@ common_init(ConfigT) -> ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - % Ensure EE bridge module is loaded - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_resource, emqx_bridge]), - _ = application:ensure_all_started(hstreamdb_erl), - _ = emqx_bridge_enterprise:module_info(), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_bridge_hstreamdb, + emqx_bridge, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config0)} + ), % Connect to hstreamdb directly % drop old stream and then create new one connect_and_delete_stream(Config0), @@ -420,6 +427,7 @@ common_init(ConfigT) -> {Name, HStreamDBConf} = hstreamdb_config(BridgeType, Config0), Config = [ + {apps, Apps}, {hstreamdb_config, HStreamDBConf}, {hstreamdb_bridge_type, BridgeType}, {hstreamdb_name, Name}, diff --git a/apps/emqx_bridge_http/mix.exs b/apps/emqx_bridge_http/mix.exs new file mode 100644 index 000000000..acaffd578 --- /dev/null +++ b/apps/emqx_bridge_http/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXBridgeHTTP.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_http, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:ehttpc, github: "emqx/ehttpc", tag: "0.4.13"} + ] + end +end diff --git a/apps/emqx_bridge_influxdb/mix.exs b/apps/emqx_bridge_influxdb/mix.exs new file mode 100644 index 000000000..cbcf76f5c --- /dev/null +++ b/apps/emqx_bridge_influxdb/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeInfluxdb.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_influxdb, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:influxdb, github: "emqx/influxdb-client-erl", tag: "1.1.13"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_SUITE.erl b/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_SUITE.erl index 3d50282ab..730622be5 100644 --- a/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_SUITE.erl +++ b/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_SUITE.erl @@ -53,12 +53,6 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - delete_all_bridges(), - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_connector_test_helpers:stop_apps([ - emqx_conf, emqx_bridge, emqx_resource, emqx_rule_engine - ]), - _ = application:stop(emqx_connector), ok. init_per_group(InfluxDBType, Config0) when @@ -92,10 +86,18 @@ init_per_group(InfluxDBType, Config0) when ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - ok = start_apps(), - {ok, _} = application:ensure_all_started(emqx_connector), - emqx_mgmt_api_test_util:init_suite(), - Config = [{use_tls, UseTLS} | Config0], + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_bridge_influxdb, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config0)} + ), + Config = [{apps, Apps}, {use_tls, UseTLS} | Config0], {Name, ConfigString, InfluxDBConfig} = influxdb_config( apiv1, InfluxDBHost, InfluxDBPort, Config ), @@ -164,10 +166,18 @@ init_per_group(InfluxDBType, Config0) when ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - ok = start_apps(), - {ok, _} = application:ensure_all_started(emqx_connector), - emqx_mgmt_api_test_util:init_suite(), - Config = [{use_tls, UseTLS} | Config0], + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_bridge_influxdb, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config0)} + ), + Config = [{apps, Apps}, {use_tls, UseTLS} | Config0], {Name, ConfigString, InfluxDBConfig} = influxdb_config( apiv2, InfluxDBHost, InfluxDBPort, Config ), @@ -222,12 +232,13 @@ end_per_group(Group, Config) when Group =:= apiv2_tcp; Group =:= apiv2_tls -> + Apps = ?config(apps, Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), EHttpcPoolName = ?config(ehttpc_pool_name, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), ehttpc_sup:stop_pool(EHttpcPoolName), - delete_bridge(Config), + emqx_cth_suite:stop(Apps), ok; end_per_group(_Group, _Config) -> ok. @@ -250,14 +261,6 @@ end_per_testcase(_Testcase, Config) -> %% Helper fns %%------------------------------------------------------------------------------ -start_apps() -> - %% some configs in emqx_conf app are mandatory - %% we want to make sure they are loaded before - %% ekka start in emqx_common_test_helpers:start_apps/1 - emqx_common_test_helpers:render_and_load_app_config(emqx_conf), - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource, emqx_bridge, emqx_rule_engine]). - example_write_syntax() -> %% N.B.: this single space character is relevant <<"${topic},clientid=${clientid}", " ", "payload=${payload},", diff --git a/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_connector_SUITE.erl b/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_connector_SUITE.erl index df98dd541..0ca693171 100644 --- a/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_connector_SUITE.erl +++ b/apps/emqx_bridge_influxdb/test/emqx_bridge_influxdb_connector_SUITE.erl @@ -27,10 +27,16 @@ init_per_suite(Config) -> Servers = [{InfluxDBTCPHost, InfluxDBTCPPort}, {InfluxDBTLSHost, InfluxDBTLSPort}], case emqx_common_test_helpers:is_all_tcp_servers_available(Servers) of true -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_bridge_influxdb, + emqx_bridge + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), [ + {apps, Apps}, {influxdb_tcp_host, InfluxDBTCPHost}, {influxdb_tcp_port, InfluxDBTCPPort}, {influxdb_tls_host, InfluxDBTLSHost}, @@ -46,10 +52,10 @@ init_per_suite(Config) -> end end. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> Config. diff --git a/apps/emqx_bridge_iotdb/mix.exs b/apps/emqx_bridge_iotdb/mix.exs new file mode 100644 index 000000000..5f1bcde31 --- /dev/null +++ b/apps/emqx_bridge_iotdb/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXBridgeIotdb.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_iotdb, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_bridge_http, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_iotdb/test/emqx_bridge_iotdb_impl_SUITE.erl b/apps/emqx_bridge_iotdb/test/emqx_bridge_iotdb_impl_SUITE.erl index d5661e2fe..c02e68887 100644 --- a/apps/emqx_bridge_iotdb/test/emqx_bridge_iotdb_impl_SUITE.erl +++ b/apps/emqx_bridge_iotdb/test/emqx_bridge_iotdb_impl_SUITE.erl @@ -12,7 +12,6 @@ -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -define(BRIDGE_TYPE_BIN, <<"iotdb">>). --define(APPS, [emqx_bridge, emqx_resource, emqx_rule_engine, emqx_bridge_iotdb]). %%------------------------------------------------------------------------------ %% CT boilerplate @@ -34,7 +33,19 @@ groups() -> ]. init_per_suite(Config) -> - emqx_bridge_v2_testlib:init_per_suite(Config, ?APPS). + emqx_bridge_v2_testlib:init_per_suite( + Config, + [ + emqx, + emqx_conf, + emqx_bridge_iotdb, + emqx_connector, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ] + ). end_per_suite(Config) -> emqx_bridge_v2_testlib:end_per_suite(Config). diff --git a/apps/emqx_bridge_kafka/mix.exs b/apps/emqx_bridge_kafka/mix.exs new file mode 100644 index 000000000..b74b1fdd0 --- /dev/null +++ b/apps/emqx_bridge_kafka/mix.exs @@ -0,0 +1,38 @@ +defmodule EMQXBridgeKafka.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_kafka, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:wolff, github: "kafka4beam/wolff", tag: "2.0.0"}, + {:kafka_protocol, github: "kafka4beam/kafka_protocol", tag: "4.1.5", override: true}, + {:brod_gssapi, github: "kafka4beam/brod_gssapi", tag: "v0.1.1"}, + {:brod, github: "kafka4beam/brod", tag: "3.18.0"}, + ## TODO: remove `mix.exs` from `wolff` and remove this override + ## TODO: remove `mix.exs` from `pulsar` and remove this override + {:snappyer, "1.2.9", override: true}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_kafka/test/emqx_bridge_v2_kafka_producer_SUITE.erl b/apps/emqx_bridge_kafka/test/emqx_bridge_v2_kafka_producer_SUITE.erl index a7918610e..c26f5e94e 100644 --- a/apps/emqx_bridge_kafka/test/emqx_bridge_v2_kafka_producer_SUITE.erl +++ b/apps/emqx_bridge_kafka/test/emqx_bridge_v2_kafka_producer_SUITE.erl @@ -94,7 +94,7 @@ end_per_testcase(TestCase, Config) when TestCase =:= t_ancient_v1_config_migration_without_local_topic -> Cluster = ?config(cluster, Config), - emqx_cth_cluster:stop(Cluster), + ok = emqx_cth_cluster:stop(Cluster), ok; end_per_testcase(_TestCase, Config) -> ProxyHost = ?config(proxy_host, Config), diff --git a/apps/emqx_bridge_kinesis/mix.exs b/apps/emqx_bridge_kinesis/mix.exs new file mode 100644 index 000000000..89942e34b --- /dev/null +++ b/apps/emqx_bridge_kinesis/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeKinesis.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_kinesis, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:erlcloud, github: "emqx/erlcloud", tag: "3.7.0.3"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_kinesis/test/emqx_bridge_kinesis_impl_producer_SUITE.erl b/apps/emqx_bridge_kinesis/test/emqx_bridge_kinesis_impl_producer_SUITE.erl index bca8c10ec..d5d56fed8 100644 --- a/apps/emqx_bridge_kinesis/test/emqx_bridge_kinesis_impl_producer_SUITE.erl +++ b/apps/emqx_bridge_kinesis/test/emqx_bridge_kinesis_impl_producer_SUITE.erl @@ -42,11 +42,21 @@ init_per_suite(Config) -> ProxyName = "kinesis", SecretFile = filename:join(?config(priv_dir, Config), "secret"), ok = file:write_file(SecretFile, <>), - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource, emqx_bridge, emqx_rule_engine]), - {ok, _} = application:ensure_all_started(emqx_connector), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_bridge_kinesis, + emqx_connector, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), [ + {apps, Apps}, {proxy_host, ProxyHost}, {proxy_port, ProxyPort}, {kinesis_port, list_to_integer(os:getenv("KINESIS_PORT", integer_to_list(?KINESIS_PORT)))}, @@ -55,11 +65,9 @@ init_per_suite(Config) -> | Config ]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_bridge, emqx_resource, emqx_rule_engine]), - _ = application:stop(emqx_connector), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_group(with_batch, Config) -> diff --git a/apps/emqx_bridge_matrix/mix.exs b/apps/emqx_bridge_matrix/mix.exs new file mode 100644 index 000000000..b63ab8873 --- /dev/null +++ b/apps/emqx_bridge_matrix/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXBridgeMatrix.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_matrix, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_mongodb/mix.exs b/apps/emqx_bridge_mongodb/mix.exs new file mode 100644 index 000000000..8d31dba0c --- /dev/null +++ b/apps/emqx_bridge_mongodb/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeMongodb.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_mongodb, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_mongodb, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_mqtt/mix.exs b/apps/emqx_bridge_mqtt/mix.exs new file mode 100644 index 000000000..8278554eb --- /dev/null +++ b/apps/emqx_bridge_mqtt/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXBridgeMQTT.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_mqtt, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:emqtt, github: "emqx/emqtt", tag: "1.10.1", system_env: UMP.maybe_no_quic_env()} + ] + end +end diff --git a/apps/emqx_bridge_mqtt/test/emqx_bridge_mqtt_SUITE.erl b/apps/emqx_bridge_mqtt/test/emqx_bridge_mqtt_SUITE.erl index 5d4c82ca6..a220eb9f7 100644 --- a/apps/emqx_bridge_mqtt/test/emqx_bridge_mqtt_SUITE.erl +++ b/apps/emqx_bridge_mqtt/test/emqx_bridge_mqtt_SUITE.erl @@ -20,9 +20,9 @@ -import(emqx_dashboard_api_test_helpers, [request/4, uri/1]). --include("emqx/include/emqx.hrl"). --include("emqx/include/emqx_hooks.hrl"). --include("emqx/include/asserts.hrl"). +-include_lib("emqx/include/emqx.hrl"). +-include_lib("emqx/include/emqx_hooks.hrl"). +-include_lib("emqx/include/asserts.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). @@ -214,6 +214,7 @@ t_conf_bridge_authn_password(_) -> ). t_conf_bridge_authn_passfile(Config) -> + %% test_server_ctrl:run_test_cases_loop DataDir = ?config(data_dir, Config), Username2 = <<"user2">>, PasswordFilename = filename:join(DataDir, "password"), diff --git a/apps/emqx_bridge_mysql/mix.exs b/apps/emqx_bridge_mysql/mix.exs new file mode 100644 index 000000000..2999ee66a --- /dev/null +++ b/apps/emqx_bridge_mysql/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeMysql.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_mysql, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_mysql, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_mysql/test/emqx_bridge_mysql_SUITE.erl b/apps/emqx_bridge_mysql/test/emqx_bridge_mysql_SUITE.erl index 9ad2fbc5a..528d55e9b 100644 --- a/apps/emqx_bridge_mysql/test/emqx_bridge_mysql_SUITE.erl +++ b/apps/emqx_bridge_mysql/test/emqx_bridge_mysql_SUITE.erl @@ -105,10 +105,12 @@ init_per_group(_Group, Config) -> Config. end_per_group(Group, Config) when Group =:= with_batch; Group =:= without_batch -> + Apps = ?config(apps, Config), connect_and_drop_table(Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + emqx_cth_suite:stop(Apps), ok; end_per_group(_Group, _Config) -> ok. @@ -150,15 +152,25 @@ common_init(Config0) -> ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - % Ensure enterprise bridge module is loaded - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_bridge, emqx_rule_engine]), - _ = emqx_bridge_enterprise:module_info(), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_connector, + emqx_bridge, + emqx_bridge_mysql, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config0)} + ), % Connect to mysql directly and create the table connect_and_create_table(Config0), {Name, MysqlConfig} = mysql_config(BridgeType, Config0), Config = [ + {apps, Apps}, {mysql_config, MysqlConfig}, {mysql_bridge_type, BridgeType}, {mysql_name, Name}, @@ -171,7 +183,12 @@ common_init(Config0) -> ], Config; false -> - {skip, no_mysql} + case os:getenv("IS_CI") of + "yes" -> + throw(no_mysql); + _ -> + {skip, no_mysql} + end end. mysql_config(BridgeType, Config) -> diff --git a/apps/emqx_bridge_opents/mix.exs b/apps/emqx_bridge_opents/mix.exs new file mode 100644 index 000000000..aa6e3c42b --- /dev/null +++ b/apps/emqx_bridge_opents/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeOpents.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_opents, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:opentsdb, github: "emqx/opentsdb-client-erl", tag: "v0.5.1"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_opents/test/emqx_bridge_opents_SUITE.erl b/apps/emqx_bridge_opents/test/emqx_bridge_opents_SUITE.erl index 23d5ee077..49a2c6451 100644 --- a/apps/emqx_bridge_opents/test/emqx_bridge_opents_SUITE.erl +++ b/apps/emqx_bridge_opents/test/emqx_bridge_opents_SUITE.erl @@ -13,7 +13,6 @@ % DB defaults -define(BRIDGE_TYPE_BIN, <<"opents">>). --define(APPS, [opentsdb, emqx_bridge, emqx_resource, emqx_rule_engine, emqx_bridge_opents_SUITE]). %%------------------------------------------------------------------------------ %% CT boilerplate @@ -31,7 +30,16 @@ groups() -> ]. init_per_suite(Config) -> - emqx_bridge_v2_testlib:init_per_suite(Config, ?APPS). + emqx_bridge_v2_testlib:init_per_suite(Config, [ + emqx, + emqx_conf, + emqx_bridge_opents, + emqx_connector, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ]). end_per_suite(Config) -> emqx_bridge_v2_testlib:end_per_suite(Config). diff --git a/apps/emqx_bridge_oracle/mix.exs b/apps/emqx_bridge_oracle/mix.exs new file mode 100644 index 000000000..b1f007c31 --- /dev/null +++ b/apps/emqx_bridge_oracle/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXBridgeOracle.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_oracle, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_oracle, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_oracle/test/emqx_bridge_oracle_SUITE.erl b/apps/emqx_bridge_oracle/test/emqx_bridge_oracle_SUITE.erl index 30cddcd3d..15720b226 100644 --- a/apps/emqx_bridge_oracle/test/emqx_bridge_oracle_SUITE.erl +++ b/apps/emqx_bridge_oracle/test/emqx_bridge_oracle_SUITE.erl @@ -13,7 +13,6 @@ -import(emqx_common_test_helpers, [on_exit/1]). -define(BRIDGE_TYPE_BIN, <<"oracle">>). --define(APPS, [emqx_bridge, emqx_resource, emqx_rule_engine, emqx_oracle, emqx_bridge_oracle]). -define(SID, "XE"). -define(RULE_TOPIC, "mqtt/rule"). @@ -36,10 +35,6 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps(lists:reverse(?APPS)), - _ = application:stop(emqx_connector), ok. init_per_group(plain = Type, Config) -> @@ -48,7 +43,7 @@ init_per_group(plain = Type, Config) -> ProxyName = "oracle", case emqx_common_test_helpers:is_tcp_server_available(OracleHost, OraclePort) of true -> - Config1 = common_init_per_group(), + Config1 = common_init_per_group(Config), [ {proxy_name, ProxyName}, {oracle_host, OracleHost}, @@ -71,23 +66,33 @@ end_per_group(Group, Config) when Group =:= plain -> common_end_per_group(Config), + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok; end_per_group(_Group, _Config) -> ok. -common_init_per_group() -> +common_init_per_group(Config) -> ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), %% Ensure enterprise bridge module is loaded - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_bridge]), - _ = emqx_bridge_enterprise:module_info(), - ok = emqx_connector_test_helpers:start_apps(?APPS), - {ok, _} = application:ensure_all_started(emqx_connector), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_oracle, + emqx_bridge_oracle, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), UniqueNum = integer_to_binary(erlang:unique_integer()), MQTTTopic = <<"mqtt/topic/", UniqueNum/binary>>, [ + {apps, Apps}, {proxy_host, ProxyHost}, {proxy_port, ProxyPort}, {mqtt_topic, MQTTTopic} diff --git a/apps/emqx_bridge_pgsql/mix.exs b/apps/emqx_bridge_pgsql/mix.exs new file mode 100644 index 000000000..eeb9292e3 --- /dev/null +++ b/apps/emqx_bridge_pgsql/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgePgsql.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_pgsql, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_postgresql, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl b/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl index faa470bc6..f671c90df 100644 --- a/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl +++ b/apps/emqx_bridge_pgsql/test/emqx_bridge_pgsql_SUITE.erl @@ -10,7 +10,7 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). --include("emqx_resource_errors.hrl"). +-include("../../emqx_resource/include/emqx_resource_errors.hrl"). % SQL definitions -define(SQL_BRIDGE, diff --git a/apps/emqx_bridge_pgsql/test/emqx_bridge_v2_pgsql_SUITE.erl b/apps/emqx_bridge_pgsql/test/emqx_bridge_v2_pgsql_SUITE.erl index 82efd609e..4d39a3629 100644 --- a/apps/emqx_bridge_pgsql/test/emqx_bridge_v2_pgsql_SUITE.erl +++ b/apps/emqx_bridge_pgsql/test/emqx_bridge_v2_pgsql_SUITE.erl @@ -61,14 +61,12 @@ init_per_suite(Config) -> emqx_bridge_pgsql, emqx_rule_engine, emqx_management, - {emqx_dashboard, "dashboard.listeners.http { enable = true, bind = 18083 }"} + emqx_mgmt_api_test_util:emqx_dashboard() ], #{work_dir => emqx_cth_suite:work_dir(Config)} ), - {ok, Api} = emqx_common_test_http:create_default_app(), NConfig = [ {apps, Apps}, - {api, Api}, {pgsql_host, PostgresHost}, {pgsql_port, PostgresPort}, {enable_tls, false}, diff --git a/apps/emqx_bridge_pulsar/mix.exs b/apps/emqx_bridge_pulsar/mix.exs new file mode 100644 index 000000000..417d9192e --- /dev/null +++ b/apps/emqx_bridge_pulsar/mix.exs @@ -0,0 +1,36 @@ +defmodule EMQXBridgePulsar.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_pulsar, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:crc32cer, git: "https://github.com/zmstone/crc32cer", tag: "0.1.8", override: true}, + ## TODO: remove `mix.exs` from `pulsar` and remove this override + ## TODO: remove `mix.exs` from `pulsar` and remove this override + {:snappyer, "1.2.9", override: true}, + {:pulsar, github: "emqx/pulsar-client-erl", tag: "0.8.3"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_rabbitmq/mix.exs b/apps/emqx_bridge_rabbitmq/mix.exs new file mode 100644 index 000000000..b5efbbc1f --- /dev/null +++ b/apps/emqx_bridge_rabbitmq/mix.exs @@ -0,0 +1,41 @@ +defmodule EMQXBridgeRabbitmq.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_rabbitmq, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_bridge_rabbitmq_app, []}] + end + + def deps() do + [ + {:thoas, github: "emqx/thoas", tag: "v1.0.0", override: true}, + {:credentials_obfuscation, + github: "emqx/credentials-obfuscation", tag: "v3.2.0", override: true}, + {:rabbit_common, + github: "emqx/rabbitmq-server", + tag: "v3.11.13.2", + sparse: "deps/rabbit_common", + override: true}, + {:amqp_client, + github: "emqx/rabbitmq-server", tag: "v3.11.13.2", sparse: "deps/amqp_client"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_connector_SUITE.erl b/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_connector_SUITE.erl index 56cdc8b0d..77482ae0f 100644 --- a/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_connector_SUITE.erl +++ b/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_connector_SUITE.erl @@ -7,7 +7,7 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("stdlib/include/assert.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_test_utils.erl b/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_test_utils.erl index 2110a0520..249b911d6 100644 --- a/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_test_utils.erl +++ b/apps/emqx_bridge_rabbitmq/test/emqx_bridge_rabbitmq_test_utils.erl @@ -9,16 +9,21 @@ -include_lib("emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). -init_per_group(tcp, Config) -> +init_per_group(tcp = Group, Config) -> RabbitMQHost = os:getenv("RABBITMQ_PLAIN_HOST", "rabbitmq"), RabbitMQPort = list_to_integer(os:getenv("RABBITMQ_PLAIN_PORT", "5672")), case emqx_common_test_helpers:is_tcp_server_available(RabbitMQHost, RabbitMQPort) of true -> Config1 = common_init_per_group(#{ - host => RabbitMQHost, port => RabbitMQPort, tls => false + group => Group, + tc_config => Config, + host => RabbitMQHost, + port => RabbitMQPort, + tls => false }), Config1 ++ Config; false -> @@ -29,13 +34,17 @@ init_per_group(tcp, Config) -> {skip, no_rabbitmq} end end; -init_per_group(tls, Config) -> +init_per_group(tls = Group, Config) -> RabbitMQHost = os:getenv("RABBITMQ_TLS_HOST", "rabbitmq"), RabbitMQPort = list_to_integer(os:getenv("RABBITMQ_TLS_PORT", "5671")), case emqx_common_test_helpers:is_tcp_server_available(RabbitMQHost, RabbitMQPort) of true -> Config1 = common_init_per_group(#{ - host => RabbitMQHost, port => RabbitMQPort, tls => true + group => Group, + tc_config => Config, + host => RabbitMQHost, + port => RabbitMQPort, + tls => true }), Config1 ++ Config; false -> @@ -50,17 +59,24 @@ init_per_group(_Group, Config) -> Config. common_init_per_group(Opts) -> - emqx_common_test_helpers:render_and_load_app_config(emqx_conf), - ok = emqx_common_test_helpers:start_apps([ - emqx_conf, emqx_bridge, emqx_bridge_rabbitmq, emqx_rule_engine, emqx_modules - ]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - {ok, _} = application:ensure_all_started(amqp_client), - emqx_mgmt_api_test_util:init_suite(), + #{group := Group, tc_config := Config} = Opts, + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_connector, + emqx_bridge_rabbitmq, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Group, Config)} + ), #{host := Host, port := Port, tls := UseTLS} = Opts, ChannelConnection = setup_rabbit_mq_exchange_and_queue(Host, Port, UseTLS), [ + {apps, Apps}, {channel_connection, ChannelConnection}, {rabbitmq, #{server => Host, port => Port, tls => UseTLS}} ]. @@ -115,13 +131,8 @@ end_per_group(_Group, Config) -> channel := Channel } = get_channel_connection(Config), amqp_channel:call(Channel, #'queue.purge'{queue = rabbit_mq_queue()}), - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([ - emqx_conf, emqx_bridge_rabbitmq, emqx_rule_engine, emqx_modules - ]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector), - _ = application:stop(emqx_bridge), + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), %% Close the channel ok = amqp_channel:close(Channel), %% Close the connection diff --git a/apps/emqx_bridge_redis/mix.exs b/apps/emqx_bridge_redis/mix.exs new file mode 100644 index 000000000..0f9c473c8 --- /dev/null +++ b/apps/emqx_bridge_redis/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeRedis.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_redis, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false}, + {:emqx_redis, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_rocketmq/mix.exs b/apps/emqx_bridge_rocketmq/mix.exs new file mode 100644 index 000000000..dbcbda12d --- /dev/null +++ b/apps/emqx_bridge_rocketmq/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeRocketmq.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_rocketmq, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:rocketmq, github: "emqx/rocketmq-client-erl", tag: "v0.6.1"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_rocketmq/test/emqx_bridge_rocketmq_SUITE.erl b/apps/emqx_bridge_rocketmq/test/emqx_bridge_rocketmq_SUITE.erl index 554a3eac8..a09911d34 100644 --- a/apps/emqx_bridge_rocketmq/test/emqx_bridge_rocketmq_SUITE.erl +++ b/apps/emqx_bridge_rocketmq/test/emqx_bridge_rocketmq_SUITE.erl @@ -73,8 +73,6 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([emqx_bridge, emqx_conf]), ok. init_per_testcase(_Testcase, Config) -> diff --git a/apps/emqx_bridge_s3/mix.exs b/apps/emqx_bridge_s3/mix.exs new file mode 100644 index 000000000..db4530b7a --- /dev/null +++ b/apps/emqx_bridge_s3/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXBridgeS3.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_s3, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_bridge_s3_app, []}] + end + + def deps() do + [ + {:emqx_resource, in_umbrella: true}, + {:emqx_connector_aggregator, in_umbrella: true}, + {:emqx_s3, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_bridge_sqlserver/mix.exs b/apps/emqx_bridge_sqlserver/mix.exs new file mode 100644 index 000000000..8c10d07b6 --- /dev/null +++ b/apps/emqx_bridge_sqlserver/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXBridgeSqlserver.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_sqlserver, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: [:odbc] ++ UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_sqlserver/test/emqx_bridge_sqlserver_SUITE.erl b/apps/emqx_bridge_sqlserver/test/emqx_bridge_sqlserver_SUITE.erl index 4d292254c..4dc1e5d0d 100644 --- a/apps/emqx_bridge_sqlserver/test/emqx_bridge_sqlserver_SUITE.erl +++ b/apps/emqx_bridge_sqlserver/test/emqx_bridge_sqlserver_SUITE.erl @@ -7,7 +7,7 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_bridge_sqlserver/include/emqx_bridge_sqlserver.hrl"). +-include("../include/emqx_bridge_sqlserver.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). @@ -122,9 +122,11 @@ init_per_group(_Group, Config) -> end_per_group(Group, Config) when Group =:= with_batch; Group =:= without_batch -> connect_and_drop_table(Config), connect_and_drop_db(Config), + Apps = ?config(apps, Config), ProxyHost = ?config(proxy_host, Config), ProxyPort = ?config(proxy_port, Config), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + emqx_cth_suite:stop(Apps), ok; end_per_group(_Group, _Config) -> ok. @@ -135,8 +137,6 @@ init_per_suite(Config) -> [{sqlserver_passfile, Passfile} | Config]. end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(), - ok = emqx_common_test_helpers:stop_apps([emqx_bridge, emqx_conf]), ok. init_per_testcase(_Testcase, Config) -> @@ -422,16 +422,23 @@ common_init(ConfigT) -> ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), - % Ensure enterprise bridge module is loaded - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_bridge, odbc]), - _ = emqx_bridge_enterprise:module_info(), - emqx_mgmt_api_test_util:init_suite(), + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_bridge_sqlserver, + emqx_bridge, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config0)} + ), % Connect to sqlserver directly % drop old db and table, and then create new ones connect_and_create_db_and_table(Config0), {Name, SQLServerConf} = sqlserver_config(BridgeType, Config0), Config = [ + {apps, Apps}, {sqlserver_config, SQLServerConf}, {sqlserver_bridge_type, BridgeType}, {sqlserver_name, Name}, diff --git a/apps/emqx_bridge_syskeeper/mix.exs b/apps/emqx_bridge_syskeeper/mix.exs new file mode 100644 index 000000000..f88007f4f --- /dev/null +++ b/apps/emqx_bridge_syskeeper/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXBridgeSyskeeper.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_syskeeper, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_tdengine/mix.exs b/apps/emqx_bridge_tdengine/mix.exs new file mode 100644 index 000000000..3a7b17179 --- /dev/null +++ b/apps/emqx_bridge_tdengine/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXBridgeTdengine.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_tdengine, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:tdengine, github: "emqx/tdengine-client-erl", tag: "0.1.7"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_bridge_tdengine/test/emqx_bridge_tdengine_SUITE.erl b/apps/emqx_bridge_tdengine/test/emqx_bridge_tdengine_SUITE.erl index 4b796984e..60830b7be 100644 --- a/apps/emqx_bridge_tdengine/test/emqx_bridge_tdengine_SUITE.erl +++ b/apps/emqx_bridge_tdengine/test/emqx_bridge_tdengine_SUITE.erl @@ -55,9 +55,6 @@ ). -define(BRIDGE_TYPE_BIN, <<"tdengine">>). --define(APPS, [ - hackney, tdengine, emqx_bridge, emqx_resource, emqx_rule_engine, emqx_bridge_tdengine -]). %%------------------------------------------------------------------------------ %% CT boilerplate @@ -81,7 +78,19 @@ groups() -> ]. init_per_suite(Config) -> - emqx_bridge_v2_testlib:init_per_suite(Config, ?APPS). + emqx_bridge_v2_testlib:init_per_suite( + Config, + [ + emqx, + emqx_conf, + emqx_bridge_tdengine, + emqx_connector, + emqx_bridge, + emqx_rule_engine, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ] + ). end_per_suite(Config) -> emqx_bridge_v2_testlib:end_per_suite(Config). @@ -99,7 +108,10 @@ init_per_group(without_batch, Config0) -> init_per_group(_Group, Config) -> Config. -end_per_group(default, Config) -> +end_per_group(Group, Config) when + Group =:= with_batch; + Group =:= without_batch +-> emqx_bridge_v2_testlib:end_per_group(Config), ok; end_per_group(_Group, _Config) -> diff --git a/apps/emqx_bridge_timescale/mix.exs b/apps/emqx_bridge_timescale/mix.exs new file mode 100644 index 000000000..3fd0983e5 --- /dev/null +++ b/apps/emqx_bridge_timescale/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXBridgeTimescale.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_bridge_timescale, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_conf/mix.exs b/apps/emqx_conf/mix.exs new file mode 100644 index 000000000..c7137504c --- /dev/null +++ b/apps/emqx_conf/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXConf.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_conf, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_conf_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true, runtime: false}, + {:emqx_auth, in_umbrella: true, runtime: false} + ] + end +end diff --git a/apps/emqx_conf/test/emqx_conf_app_SUITE.erl b/apps/emqx_conf/test/emqx_conf_app_SUITE.erl index 4b872abdf..5ba3f0b49 100644 --- a/apps/emqx_conf/test/emqx_conf_app_SUITE.erl +++ b/apps/emqx_conf/test/emqx_conf_app_SUITE.erl @@ -57,7 +57,6 @@ t_copy_conf_override_on_restarts(Config) -> t_copy_new_data_dir(Config) -> ct:timetrap({seconds, 120}), - snabbkaffe:fix_ct_logging(), Cluster = cluster( ?FUNCTION_NAME, [cluster_spec({core, 4}), cluster_spec({core, 5}), cluster_spec({core, 6})], diff --git a/apps/emqx_conf/test/emqx_conf_cli_SUITE.erl b/apps/emqx_conf/test/emqx_conf_cli_SUITE.erl index 78a5fb5d6..63f6821b8 100644 --- a/apps/emqx_conf/test/emqx_conf_cli_SUITE.erl +++ b/apps/emqx_conf/test/emqx_conf_cli_SUITE.erl @@ -19,6 +19,7 @@ -compile(export_all). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include("emqx_conf.hrl"). -import(emqx_config_SUITE, [prepare_conf_file/3]). @@ -27,15 +28,34 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_auth, emqx_auth_redis]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_auth_redis, + emqx_auth, + emqx_management + ], + #{ + %% N.B.: This is needed to avoid `emqx_cth_suite' default behavior of setting + %% `authorization.sources = []'. + emqx_conf_shared_apps => [emqx], + work_dir => emqx_cth_suite:work_dir(Config) + } + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf, emqx_auth, emqx_auth_redis]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_load_config(Config) -> Authz = authorization, Conf = emqx_conf:get_raw([Authz]), + ?assertEqual( + [emqx_authz_schema:default_authz()], + maps:get(<<"sources">>, Conf) + ), %% set sources to [] ConfBin = hocon_pp:do(#{<<"authorization">> => #{<<"sources">> => []}}, #{}), ConfFile = prepare_conf_file(?FUNCTION_NAME, ConfBin, Config), diff --git a/apps/emqx_connector/mix.exs b/apps/emqx_connector/mix.exs new file mode 100644 index 000000000..e7d18d0e3 --- /dev/null +++ b/apps/emqx_connector/mix.exs @@ -0,0 +1,43 @@ +defmodule EMQXConnector.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_connector, + version: "0.1.0", + build_path: "../../_build", + # erlc_options: [ + # # config_path: "../../config/config.exs", + # # We need this because we can't make `:emqx_connector` application depend on + # # `:emqx_bridge`, otherwise a dependency cycle would be created, but at the same + # # time `:emqx_connector` need some includes from `:emqx_bridge` to compile... + # {:i, "../emqx_bridge/include"} | UMP.erlc_options() + # ], + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: [:eredis], mod: {:emqx_connector_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2"}, + {:ecpool, github: "emqx/ecpool", tag: "0.5.7"}, + {:eredis_cluster, github: "emqx/eredis_cluster", tag: "0.8.4"}, + {:ehttpc, github: "emqx/ehttpc", tag: "0.4.13"}, + {:emqtt, github: "emqx/emqtt", tag: "1.10.1", system_env: UMP.maybe_no_quic_env()} + ] + end +end diff --git a/apps/emqx_connector/src/emqx_connector_resource.erl b/apps/emqx_connector/src/emqx_connector_resource.erl index c71afca60..be8d3a32d 100644 --- a/apps/emqx_connector/src/emqx_connector_resource.erl +++ b/apps/emqx_connector/src/emqx_connector_resource.erl @@ -15,7 +15,7 @@ %%-------------------------------------------------------------------- -module(emqx_connector_resource). --include_lib("emqx_bridge/include/emqx_bridge_resource.hrl"). +-include("../../emqx_bridge/include/emqx_bridge_resource.hrl"). -include_lib("emqx/include/logger.hrl"). -include_lib("emqx_resource/include/emqx_resource.hrl"). diff --git a/apps/emqx_connector/test/emqx_connector_SUITE.erl b/apps/emqx_connector/test/emqx_connector_SUITE.erl index 7df49bd82..1b210e7fb 100644 --- a/apps/emqx_connector/test/emqx_connector_SUITE.erl +++ b/apps/emqx_connector/test/emqx_connector_SUITE.erl @@ -21,19 +21,22 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(START_APPS, [emqx, emqx_conf, emqx_connector]). -define(CONNECTOR, emqx_connector_dummy_impl). all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - _ = application:load(emqx_conf), - ok = emqx_common_test_helpers:start_apps(?START_APPS), - Config. + Apps = emqx_cth_suite:start( + [emqx, emqx_conf, emqx_connector], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps(?START_APPS). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(TestCase, Config) -> ?MODULE:TestCase({init, Config}). diff --git a/apps/emqx_connector_aggregator/mix.exs b/apps/emqx_connector_aggregator/mix.exs new file mode 100644 index 000000000..62e42c4fa --- /dev/null +++ b/apps/emqx_connector_aggregator/mix.exs @@ -0,0 +1,30 @@ +defmodule EMQXConnectorAggregator.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_connector_aggregator, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:erl_csv, "0.2.0"} + ] + end +end diff --git a/apps/emqx_ctl/mix.exs b/apps/emqx_ctl/mix.exs new file mode 100644 index 000000000..435bb96ec --- /dev/null +++ b/apps/emqx_ctl/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXCtl.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_ctl, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_ctl_app, []}] + end + + def deps() do + [] + end +end diff --git a/apps/emqx_dashboard/mix.exs b/apps/emqx_dashboard/mix.exs new file mode 100644 index 000000000..2f6c89c32 --- /dev/null +++ b/apps/emqx_dashboard/mix.exs @@ -0,0 +1,33 @@ +defmodule EMQXDashboard.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_dashboard, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_dashboard_app, []}] + end + + def deps() do + [ + {:emqx_ctl, in_umbrella: true}, + {:emqx, in_umbrella: true}, + {:minirest, github: "emqx/minirest", tag: "1.4.1"} + ] + end +end diff --git a/apps/emqx_dashboard/test/emqx_dashboard_admin_SUITE.erl b/apps/emqx_dashboard/test/emqx_dashboard_admin_SUITE.erl index 08beae685..4e0f0baaa 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_admin_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_admin_SUITE.erl @@ -20,16 +20,26 @@ -include("emqx_dashboard.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. end_per_testcase(_, _Config) -> All = emqx_dashboard_admin:all_users(), diff --git a/apps/emqx_dashboard/test/emqx_dashboard_error_code_SUITE.erl b/apps/emqx_dashboard/test/emqx_dashboard_error_code_SUITE.erl index 02de3e7ed..e925af4bb 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_error_code_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_error_code_SUITE.erl @@ -22,6 +22,7 @@ -include_lib("emqx/include/http_api.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(SERVER, "http://127.0.0.1:18083/api/v5"). @@ -29,11 +30,20 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_all_code(_) -> HrlDef = ?ERROR_CODES, diff --git a/apps/emqx_dashboard/test/emqx_dashboard_listener_SUITE.erl b/apps/emqx_dashboard/test/emqx_dashboard_listener_SUITE.erl index 219663d15..b921e7bee 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_listener_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_listener_SUITE.erl @@ -20,18 +20,26 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). +-include_lib("common_test/include/ct.hrl"). all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - ok = change_i18n_lang(en), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - ok = change_i18n_lang(en), - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_change_i18n_lang(_Config) -> ?check_trace( diff --git a/apps/emqx_dashboard/test/emqx_dashboard_not_found_SUITE.erl b/apps/emqx_dashboard/test/emqx_dashboard_not_found_SUITE.erl index 656d2fbe6..e0c4fb8ed 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_not_found_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_not_found_SUITE.erl @@ -22,6 +22,7 @@ -include_lib("emqx/include/http_api.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(SERVER, "http://127.0.0.1:18083/"). @@ -31,11 +32,20 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_bad_api_path(_) -> Url = ?SERVER ++ "/for/test/some/path/not/exist", diff --git a/apps/emqx_dashboard/test/emqx_dashboard_schema_api_SUITE.erl b/apps/emqx_dashboard/test/emqx_dashboard_schema_api_SUITE.erl index 3cb5a9249..43d6f1651 100644 --- a/apps/emqx_dashboard/test/emqx_dashboard_schema_api_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_dashboard_schema_api_SUITE.erl @@ -22,6 +22,7 @@ -include_lib("emqx/include/http_api.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(SERVER, "http://127.0.0.1:18083/api/v5"). @@ -31,11 +32,20 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_hotconf(_) -> Url = ?SERVER ++ "/schemas/hotconf", diff --git a/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl index 5e482e5e7..a5703b303 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl @@ -28,6 +28,7 @@ -export([all/0, suite/0, groups/0]). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl"). -import(hoconsc, [mk/2]). @@ -63,11 +64,20 @@ groups() -> ]. init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_in_path(_Config) -> Expect = diff --git a/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl index 0f2448480..600c94b16 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_requestBody_SUITE.erl @@ -23,6 +23,7 @@ -compile(export_all). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl"). -import(hoconsc, [mk/2]). @@ -30,11 +31,19 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - _ = emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. t_object(_Config) -> diff --git a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl index e9397f643..0708914cb 100644 --- a/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl +++ b/apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl @@ -20,8 +20,7 @@ -behaviour(hocon_schema). -include_lib("eunit/include/eunit.hrl"). - --include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl"). -import(hoconsc, [mk/2]). @@ -36,16 +35,20 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. end_per_suite(Config) -> - end_suite(), - Config. - -end_suite() -> - application:unload(emqx_management), - emqx_mgmt_api_test_util:end_suite([emqx_conf]). + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. t_simple_binary(_config) -> Path = "/simple/bin", diff --git a/apps/emqx_dashboard_rbac/mix.exs b/apps/emqx_dashboard_rbac/mix.exs new file mode 100644 index 000000000..cabcbbd77 --- /dev/null +++ b/apps/emqx_dashboard_rbac/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXDashboardRbac.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_dashboard_rbac, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [{:emqx_dashboard, in_umbrella: true}] + end +end diff --git a/apps/emqx_dashboard_rbac/test/emqx_dashboard_rbac_SUITE.erl b/apps/emqx_dashboard_rbac/test/emqx_dashboard_rbac_SUITE.erl index 3d42432bf..b9c585606 100644 --- a/apps/emqx_dashboard_rbac/test/emqx_dashboard_rbac_SUITE.erl +++ b/apps/emqx_dashboard_rbac/test/emqx_dashboard_rbac_SUITE.erl @@ -7,8 +7,9 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_dashboard.hrl"). +-include("../../emqx_dashboard/include/emqx_dashboard.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -import(emqx_dashboard_api_test_helpers, [request/4, uri/1]). @@ -20,11 +21,22 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_mgmt_api_test_util:init_suite([emqx_conf]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard(), + emqx_dashboard_rbac + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. end_per_testcase(_, _Config) -> All = emqx_dashboard_admin:all_users(), diff --git a/apps/emqx_dashboard_sso/mix.exs b/apps/emqx_dashboard_sso/mix.exs new file mode 100644 index 000000000..13a44f61f --- /dev/null +++ b/apps/emqx_dashboard_sso/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXDashboardSso.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_dashboard_sso, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_dashboard_sso_app, []}] + end + + def deps() do + [ + {:emqx_ctl, in_umbrella: true}, + {:emqx_ldap, in_umbrella: true}, + {:emqx_dashboard, in_umbrella: true}, + {:esaml, github: "emqx/esaml", tag: "v1.1.3"} + ] + end +end diff --git a/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_cli_SUITE.erl b/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_cli_SUITE.erl index e52f252e6..26677f8fa 100644 --- a/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_cli_SUITE.erl +++ b/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_cli_SUITE.erl @@ -7,7 +7,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx_dashboard/include/emqx_dashboard.hrl"). +-include("../../emqx_dashboard/include/emqx_dashboard.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). diff --git a/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl b/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl index e71386f29..51524f0fd 100644 --- a/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl +++ b/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl @@ -7,7 +7,7 @@ -compile(nowarn_export_all). -compile(export_all). --include_lib("emqx_dashboard/include/emqx_dashboard.hrl"). +-include("../../emqx_dashboard/include/emqx_dashboard.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). diff --git a/apps/emqx_durable_storage/mix.exs b/apps/emqx_durable_storage/mix.exs new file mode 100644 index 000000000..1bbaeff22 --- /dev/null +++ b/apps/emqx_durable_storage/mix.exs @@ -0,0 +1,37 @@ +defmodule EMQXDurableStorage.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_durable_storage, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [ + extra_applications: [:mria] ++ UMP.extra_applications(), + mod: {:emqx_ds_app, []} + ] + end + + def deps() do + [ + {:emqx_utils, in_umbrella: true}, + {:gproc, github: "emqx/gproc", tag: "0.9.0.1"}, + {:rocksdb, github: "emqx/erlang-rocksdb", tag: "1.8.0-emqx-5"}, + {:ra, "2.7.3"}, + ] + end +end diff --git a/apps/emqx_durable_storage/test/emqx_ds_SUITE.erl b/apps/emqx_durable_storage/test/emqx_ds_SUITE.erl index eb14456cb..34bdd0a6a 100644 --- a/apps/emqx_durable_storage/test/emqx_ds_SUITE.erl +++ b/apps/emqx_durable_storage/test/emqx_ds_SUITE.erl @@ -18,10 +18,10 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx/include/emqx.hrl"). +-include("../../emqx/include/emqx.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). --include_lib("emqx/include/asserts.hrl"). +-include("../../emqx/include/asserts.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -define(N_SHARDS, 1). diff --git a/apps/emqx_durable_storage/test/emqx_ds_replication_SUITE.erl b/apps/emqx_durable_storage/test/emqx_ds_replication_SUITE.erl index 1b2a21105..b5a0738b2 100644 --- a/apps/emqx_durable_storage/test/emqx_ds_replication_SUITE.erl +++ b/apps/emqx_durable_storage/test/emqx_ds_replication_SUITE.erl @@ -18,7 +18,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx/include/emqx.hrl"). +-include("../../emqx/include/emqx.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). diff --git a/apps/emqx_durable_storage/test/emqx_ds_storage_SUITE.erl b/apps/emqx_durable_storage/test/emqx_ds_storage_SUITE.erl index dad18f89e..1d15ffa98 100644 --- a/apps/emqx_durable_storage/test/emqx_ds_storage_SUITE.erl +++ b/apps/emqx_durable_storage/test/emqx_ds_storage_SUITE.erl @@ -18,7 +18,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx/include/emqx.hrl"). +-include("../../emqx/include/emqx.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). diff --git a/apps/emqx_durable_storage/test/emqx_ds_storage_bitfield_lts_SUITE.erl b/apps/emqx_durable_storage/test/emqx_ds_storage_bitfield_lts_SUITE.erl index 004096431..a3aefdba9 100644 --- a/apps/emqx_durable_storage/test/emqx_ds_storage_bitfield_lts_SUITE.erl +++ b/apps/emqx_durable_storage/test/emqx_ds_storage_bitfield_lts_SUITE.erl @@ -18,7 +18,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx/include/emqx.hrl"). +-include("../../emqx/include/emqx.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include_lib("stdlib/include/assert.hrl"). diff --git a/apps/emqx_durable_storage/test/props/emqx_ds_message_storage_bitmask_shim.erl b/apps/emqx_durable_storage/test/props/emqx_ds_message_storage_bitmask_shim.erl index 97b90fcb7..faa0bdf06 100644 --- a/apps/emqx_durable_storage/test/props/emqx_ds_message_storage_bitmask_shim.erl +++ b/apps/emqx_durable_storage/test/props/emqx_ds_message_storage_bitmask_shim.erl @@ -16,7 +16,7 @@ -module(emqx_ds_message_storage_bitmask_shim). --include_lib("emqx/include/emqx.hrl"). +-include("../../../emqx/include/emqx.hrl"). -export([open/0]). -export([close/1]). diff --git a/apps/emqx_enterprise/mix.exs b/apps/emqx_enterprise/mix.exs new file mode 100644 index 000000000..1cf3320ca --- /dev/null +++ b/apps/emqx_enterprise/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXEnterprise.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_enterprise, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:snabbkaffe, github: "kafka4beam/snabbkaffe", tag: "1.0.10"}, + {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1"}, + {:hocon, github: "emqx/hocon", tag: "0.42.2"} + ] + end +end diff --git a/apps/emqx_eviction_agent/mix.exs b/apps/emqx_eviction_agent/mix.exs new file mode 100644 index 000000000..eb7f5eb38 --- /dev/null +++ b/apps/emqx_eviction_agent/mix.exs @@ -0,0 +1,30 @@ +defmodule EMQXEvictionAgent.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_eviction_agent, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_eviction_agent_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_exhook/lib/emqx/grpc/template/client.eex b/apps/emqx_exhook/lib/emqx/grpc/template/client.eex new file mode 100644 index 000000000..ef246711b --- /dev/null +++ b/apps/emqx_exhook/lib/emqx/grpc/template/client.eex @@ -0,0 +1,85 @@ +%%%------------------------------------------------------------------- +%% @doc Client module for grpc service <%= unmodified_service_name %>. +%% @end +%%%------------------------------------------------------------------- + +%% this module was generated and should not be modified manually + +-module(<%= module_name %>_client). + +-compile(export_all). +-compile(nowarn_export_all). + +-include_lib("grpc/include/grpc.hrl"). + +-define(SERVICE, '<%= unmodified_service_name %>'). +-define(PROTO_MODULE, '<%= pb_module %>'). +-define(MARSHAL(T), fun(I) -> ?PROTO_MODULE:encode_msg(I, T) end). +-define(UNMARSHAL(T), fun(I) -> ?PROTO_MODULE:decode_msg(I, T) end). +-define(DEF(Path, Req, Resp, MessageType), + #{path => Path, + service =>?SERVICE, + message_type => MessageType, + marshal => ?MARSHAL(Req), + unmarshal => ?UNMARSHAL(Resp)}). + +<%= for method <- methods do %> +<%!-- IF1 --%> +<%= if (not method.input_stream) and (not method.output_stream) do %> +-spec <%= method.snake_case %>(<%= method.pb_module %>:<%= method.input %>()) + -> {ok, <%= method.pb_module %>:<%= method.output %>(), grpc:metadata()} + | {error, term()}. +<%= method.snake_case %>(Req) -> + <%= method.snake_case %>(Req, #{}, #{}). + +-spec <%= method.snake_case %>(<%= method.pb_module %>:<%= method.input %>(), grpc:options()) + -> {ok, <%= method.pb_module %>:<%= method.output %>(), grpc:metadata()} + | {error, term()}. +<%= method.snake_case %>(Req, Options) -> + <%= method.snake_case %>(Req, #{}, Options). + +-spec <%= method.snake_case %>(<%= method.pb_module %>:<%= method.input %>(), grpc:metadata(), grpc_client:options()) + -> {ok, <%= method.pb_module %>:<%= method.output %>(), grpc:metadata()} + | {error, term()}. +<%= method.snake_case %>(Req, Metadata, Options) -> + grpc_client:unary(?DEF(<<"/<%= unmodified_service_name %>/<%= method.unmodified_method %>">>, + <%= method.input %>, <%= method.output %>, <<"<%= method.message_type %>">>), + Req, Metadata, Options). +<%!-- END IF1 --%> +<% end %> +<%!-- IF2 --%> +<%= if (not method.input_stream) and method.output_stream do %> +-spec <%= method.snake_case %>(grpc_client:options()) + -> {ok, grpc_client:grpcstream()} + | {error, term()}. +<%= method.snake_case %>(Options) -> + <%= method.snake_case %>(#{}, Options). + +-spec <%= method.snake_case %>(grpc:metadata(), grpc_client:options()) + -> {ok, grpc_client:grpcstream()} + | {error, term()}. +<%= method.snake_case %>(Metadata, Options) -> + grpc_client:open(?DEF(<<"/<%= unmodified_service_name %>/<%= method.unmodified_method %>">>, + <%= method.input %>, <%= method.output %>, <<"<%= method.message_type %>">>), + Metadata, Options). +<%!-- END IF2 --%> +<% end %> +<%!-- IF3 --%> +<%= if method.input_stream do %> +-spec <%= method.snake_case %>(grpc_client:options()) + -> {ok, grpc_client:grpcstream()} + | {error, term()}. +<%= method.snake_case %>(Options) -> + <%= method.snake_case %>(#{}, Options). + +-spec <%= method.snake_case %>(grpc:metadata(), grpc_client:options()) + -> {ok, grpc_client:grpcstream()} + | {error, term()}. +<%= method.snake_case %>(Metadata, Options) -> + grpc_client:open(?DEF(<<"/<%= unmodified_service_name %>/<%= method.unmodified_method %>">>, + <%= method.input %>, <%= method.output %>, <<"<%= method.message_type %>">>), + Metadata, Options). +<% end %> +<%!-- END IF3 --%> +<% end %> +<%!-- END for method <- methods --%> diff --git a/apps/emqx_exhook/lib/emqx/grpc/template/service.eex b/apps/emqx_exhook/lib/emqx/grpc/template/service.eex new file mode 100644 index 000000000..9c7964d8c --- /dev/null +++ b/apps/emqx_exhook/lib/emqx/grpc/template/service.eex @@ -0,0 +1,29 @@ +%%%------------------------------------------------------------------- +%% @doc Behaviour to implement for grpc service <%= unmodified_service_name %>. +%% @end +%%%------------------------------------------------------------------- + +%% this module was generated and should not be modified manually + +-module(<%= module_name %>_bhvr). + +<%= for method <- methods do %> + +<%= if (not method.input_stream) and (not method.output_stream) do %> +-callback <%= method.snake_case %>(<%= method.pb_module %>:<%= method.input %>(), grpc:metadata()) + -> {ok, <%= method.pb_module %>:<%= method.output %>(), grpc:metadata()} + | {error, grpc_stream:error_response()}. +<% end %> + +<%= if method.input_stream and (not method.output_stream) do %> +-callback <%= method.snake_case %>(grpc_stream:stream(), grpc:metadata()) + -> {ok, grpc_stream:stream()}. +<% end %> + +<%= if method.output_stream do %> +-callback <%= method.snake_case %>(grpc_stream:stream(), grpc:metadata()) + -> {ok, grpc_stream:stream()}. +<% end %> + +<%!-- END for method <- methods --%> +<% end %> diff --git a/apps/emqx_exhook/lib/mix/tasks/compile.grpc.ex b/apps/emqx_exhook/lib/mix/tasks/compile.grpc.ex new file mode 100644 index 000000000..615f98c29 --- /dev/null +++ b/apps/emqx_exhook/lib/mix/tasks/compile.grpc.ex @@ -0,0 +1,225 @@ +defmodule Mix.Tasks.Compile.Grpc do + use Mix.Task.Compiler + + @recursive true + @manifest_vsn 1 + @manifest "compile.grpc" + # TODO: use manifest to track generated files? + + @impl true + def manifests(), do: [manifest()] + defp manifest(), do: Path.join(Mix.Project.manifest_path(), @manifest) + + @impl true + def run(_args) do + Mix.Project.get!() + config = Mix.Project.config() + %{ + gpb_opts: gpb_opts, + proto_dirs: proto_dirs, + out_dir: out_dir + } = config[:grpc_opts] + + add_to_path_and_cache(:syntax_tools) + :ok = Application.ensure_loaded(:syntax_tools) + :ok = Application.ensure_loaded(:gpb) + + app_root = File.cwd!() + app_build_path = Mix.Project.app_path(config) + + proto_srcs = + proto_dirs + |> Enum.map(& Path.join([app_root, &1])) + |> Mix.Utils.extract_files([:proto]) + + manifest_data = read_manifest(manifest()) + context = %{ + manifest_data: manifest_data, + app_root: app_root, + app_build_path: app_build_path, + out_dir: out_dir, + gpb_opts: gpb_opts, + } + + Enum.each(proto_srcs, & compile_pb(&1, context)) + + write_manifest(manifest(), manifest_data) + + {:noop, []} + end + + defp compile_pb(proto_src, context) do + %{ + app_root: app_root, + app_build_path: app_build_path, + out_dir: out_dir, + gpb_opts: gpb_opts, + } = context + manifest_modified_time = Mix.Utils.last_modified(manifest()) + ebin_path = Path.join([app_build_path, "ebin"]) + basename = proto_src |> Path.basename(".proto") |> to_charlist() + prefix = Keyword.get(gpb_opts, :module_name_prefix, '') + suffix = Keyword.get(gpb_opts, :module_name_suffix, '') + mod_name = '#{prefix}#{basename}#{suffix}' + opts = [ + :use_packages, + :maps, + :strings_as_binaries, + i: '.', + o: out_dir, + report_errors: false, + rename: {:msg_name, :snake_case}, + rename: {:msg_fqname, :base_name}, + ] + + if stale?(proto_src, manifest_modified_time) do + Mix.shell().info("compiling proto file: #{proto_src}") + File.mkdir_p!(out_dir) + # TODO: better error logging... + :ok = :gpb_compile.file( + to_charlist(proto_src), + opts ++ gpb_opts + ) + else + Mix.shell().info("proto file up to date, not compiling: #{proto_src}") + end + + generated_src = Path.join([app_root, out_dir, "#{mod_name}.erl"]) + gpb_include_dir = :code.lib_dir(:gpb, :include) + + if stale?(generated_src, manifest_modified_time) do + Mix.shell().info("compiling proto module: #{generated_src}") + compile_res = :compile.file( + to_charlist(generated_src), + [ + :return_errors, + i: to_charlist(gpb_include_dir), + outdir: to_charlist(ebin_path) + ] + ) + # todo: error handling & logging + case compile_res do + {:ok, _} -> + :ok + + {:ok, _, _warnings} -> + :ok + end + else + Mix.shell().info("file up to date, not compiling: #{generated_src}") + end + + mod_name + |> List.to_atom() + |> :code.purge() + + {:module, _mod} = + ebin_path + |> Path.join(mod_name) + |> to_charlist() + |> :code.load_abs() + + mod_name = List.to_atom(mod_name) + service_quoted = + [__DIR__, "../../", "emqx/grpc/template/service.eex"] + |> Path.join() + |> Path.expand() + |> EEx.compile_file() + client_quoted = + [__DIR__, "../../", "emqx/grpc/template/client.eex"] + |> Path.join() + |> Path.expand() + |> EEx.compile_file() + + mod_name.get_service_names() + |> Enum.each(fn service -> + service + |> mod_name.get_service_def() + |> then(fn {{:service, service_name}, methods} -> + methods = Enum.map(methods, fn method -> + snake_case = method.name |> to_string() |> Macro.underscore() + message_type = mod_name.msg_name_to_fqbin(method.input) + method + |> Map.put(:message_type, message_type) + |> Map.put(:snake_case, snake_case) + |> Map.put(:pb_module, mod_name) + |> Map.put(:unmodified_method, method.name) + end) + + snake_service = + service_name + |> to_string() + |> Macro.underscore() + |> String.replace("/", "_") + |> String.replace(~r/(.)([0-9]+)/, "\\1_\\2") + + bindings = [ + methods: methods, + pb_module: mod_name, + module_name: snake_service, + unmodified_service_name: service_name + ] + + bhvr_output_src = Path.join([app_root, out_dir, "#{snake_service}_bhvr.erl"]) + if stale?(bhvr_output_src, manifest_modified_time) do + render_and_write(service_quoted, bhvr_output_src, bindings) + else + Mix.shell().info("file up to date, not compiling: #{bhvr_output_src}") + end + + client_output_src = Path.join([app_root, out_dir, "#{snake_service}_client.erl"]) + if stale?(client_output_src, manifest_modified_time) do + render_and_write(client_quoted, client_output_src, bindings) + else + Mix.shell().info("file up to date, not compiling: #{client_output_src}") + end + + :ok + end) + end) + + :ok + end + + defp stale?(file, manifest_modified_time) do + with true <- File.exists?(file), + false <- Mix.Utils.stale?([file], [manifest_modified_time]) do + false + else + _ -> true + end + end + + defp read_manifest(file) do + try do + file |> File.read!() |> :erlang.binary_to_term() + rescue + _ -> %{} + else + {@manifest_vsn, data} when is_map(data) -> data + _ -> %{} + end + end + + defp write_manifest(file, data) do + Mix.shell().info("writing manifest #{file}") + File.mkdir_p!(Path.dirname(file)) + File.write!(file, :erlang.term_to_binary({@manifest_vsn, data})) + end + + defp render_and_write(quoted_file, output_src, bindings) do + {result, _bindings} = Code.eval_quoted(quoted_file, bindings) + result = String.replace(result, ~r/\n\n\n+/, "\n\n\n") + File.write!(output_src, result) + end + + def add_to_path_and_cache(lib_name) do + :code.lib_dir() + |> Path.join("#{lib_name}-*") + |> Path.wildcard() + |> hd() + |> Path.join("ebin") + |> to_charlist() + |> :code.add_path(:cache) + end +end diff --git a/apps/emqx_exhook/mix.exs b/apps/emqx_exhook/mix.exs new file mode 100644 index 000000000..581694096 --- /dev/null +++ b/apps/emqx_exhook/mix.exs @@ -0,0 +1,53 @@ +defmodule EMQXExhook.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_exhook, + version: "0.1.0", + build_path: "../../_build", + compilers: [:elixir, :grpc, :erlang, :app, :copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + # used by our `Mix.Tasks.Compile.Grpc` compiler + grpc_opts: %{ + gpb_opts: [ + module_name_prefix: 'emqx_', + module_name_suffix: '_pb', + o: 'src/pb', + ], + proto_dirs: ["priv/protos"], + out_dir: "src/pb" + }, + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_exhook_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:grpc, github: "emqx/grpc-erl", tag: "0.6.12", override: true} + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_ft/mix.exs b/apps/emqx_ft/mix.exs new file mode 100644 index 000000000..bc7cc9fac --- /dev/null +++ b/apps/emqx_ft/mix.exs @@ -0,0 +1,30 @@ +defmodule EMQXFt.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_ft, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_ft_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_s3, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_gateway/mix.exs b/apps/emqx_gateway/mix.exs new file mode 100644 index 000000000..7c4daeb46 --- /dev/null +++ b/apps/emqx_gateway/mix.exs @@ -0,0 +1,44 @@ +defmodule EMQXGateway.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_gateway_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true}, + {:emqx_auth, in_umbrella: true} + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_gateway/test/emqx_gateway_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_SUITE.erl index ac351cdee..661f5e384 100644 --- a/apps/emqx_gateway/test/emqx_gateway_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_SUITE.erl @@ -36,7 +36,12 @@ init_per_suite(Config) -> Apps = emqx_cth_suite:start( [ {emqx_conf, ?CONF_DEFAULT}, - emqx_gateway + emqx_resource, + emqx_gateway_lwm2m, + emqx_gateway, + emqx_auth, + emqx_auth_redis, + emqx_auth_mnesia ], #{work_dir => emqx_cth_suite:work_dir(Config)} ), @@ -47,6 +52,21 @@ end_per_suite(Config) -> emqx_config:delete_override_conf_files(), ok. +init_per_testcase(t_get_basic_usage_info_2, Config) -> + DataDir = ?config(data_dir, Config), + ok = setup_fake_usage_data(DataDir), + Config; +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(t_get_basic_usage_info_2, _Config) -> + emqx_gateway_cm:unregister_channel(lwm2m, <<"client_id">>), + ok = emqx_gateway:unload(lwm2m), + {ok, _} = emqx_conf:update([gateway], #{}, #{override_to => cluster}), + ok; +end_per_testcase(_TestCase, _Config) -> + ok. + %%-------------------------------------------------------------------- %% cases %%-------------------------------------------------------------------- @@ -128,18 +148,41 @@ t_get_basic_usage_info_empty(_Config) -> t_get_basic_usage_info_1(_Config) -> {ok, _} = emqx_gateway:load(?GWNAME, #{idle_timeout => 1000}), - ?assertEqual( + try + ?assertEqual( + #{ + mqttsn => + #{ + authn => <<"undefined">>, + listeners => [], + num_clients => 0 + } + }, + emqx_gateway:get_basic_usage_info() + ) + after + ok = emqx_gateway:unload(?GWNAME) + end. + +t_get_basic_usage_info_2(_Config) -> + ?assertMatch( #{ - mqttsn => + lwm2m := #{ - authn => <<"undefined">>, - listeners => [], - num_clients => 0 + authn := <<"password_based:redis">>, + listeners := + [ + #{ + authn := + <<"password_based:built_in_database">>, + type := udp + } + ], + num_clients := 1 } }, emqx_gateway:get_basic_usage_info() - ), - ok = emqx_gateway:unload(?GWNAME). + ). %%-------------------------------------------------------------------- %% helper functions @@ -162,7 +205,7 @@ setup_fake_usage_data(Lwm2mDataDir) -> Lwm2mConf = read_lwm2m_conf(Lwm2mDataDir), ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, Lwm2mConf), emqx_config:put([gateway, lwm2m, xml_dir], XmlDir), - {ok, _} = application:ensure_all_started(emqx_gateway), + {ok, _} = emqx_gateway:load(lwm2m, emqx_config:get([gateway, lwm2m])), %% to simulate a connection FakeConnInfo = #{conn_mod => fake_conn_mod}, FakeChanPid = self(), diff --git a/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl index e74b25a06..11271b329 100644 --- a/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl @@ -59,9 +59,7 @@ init_per_suite(Conf) -> [{suite_apps, Apps} | Conf]. end_per_suite(Conf) -> - _ = emqx_common_test_http:delete_default_app(), - ok = emqx_cth_suite:stop(proplists:get_value(suite_apps, Conf)), - emqx_config:delete_override_conf_files(). + ok = emqx_cth_suite:stop(proplists:get_value(suite_apps, Conf)). init_per_testcase(t_gateway_fail, Config) -> meck:expect( diff --git a/apps/emqx_gateway/test/emqx_gateway_cli_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_cli_SUITE.erl index 5ec956f31..77dc6842f 100644 --- a/apps/emqx_gateway/test/emqx_gateway_cli_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_cli_SUITE.erl @@ -56,21 +56,17 @@ end). all() -> emqx_common_test_helpers:all(?MODULE). -init_per_suite(Conf) -> - emqx_config:erase(gateway), - emqx_gateway_test_utils:load_all_gateway_apps(), +init_per_suite(Config) -> Apps = emqx_cth_suite:start( - [ - {emqx_conf, <<"gateway {}">>}, - emqx_gateway - ], - #{work_dir => emqx_cth_suite:work_dir(Conf)} + [emqx, emqx_conf, emqx_gateway], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - [{suite_apps, Apps} | Conf]. + [{apps, Apps} | Config]. -end_per_suite(Conf) -> - emqx_cth_suite:stop(?config(suite_apps, Conf)), - emqx_config:delete_override_conf_files(). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Conf) -> Self = self(), diff --git a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl index e084214bf..f326a8deb 100644 --- a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl @@ -37,20 +37,17 @@ all() -> emqx_common_test_helpers:all(?MODULE). -init_per_suite(Conf) -> - emqx_gateway_test_utils:load_all_gateway_apps(), +init_per_suite(Config) -> Apps = emqx_cth_suite:start( - [ - {emqx_conf, <<"gateway {}">>}, - emqx_gateway - ], - #{work_dir => emqx_cth_suite:work_dir(Conf)} + [emqx, emqx_conf, emqx_auth, emqx_auth_mnesia, emqx_gateway], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - [{suite_apps, Apps} | Conf]. + [{apps, Apps} | Config]. -end_per_suite(Conf) -> - emqx_cth_suite:stop(?config(suite_apps, Conf)), - emqx_config:delete_override_conf_files(). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_CaseName, Conf) -> _ = emqx_gateway_conf:unload_gateway(stomp), diff --git a/apps/emqx_gateway_coap/mix.exs b/apps/emqx_gateway_coap/mix.exs new file mode 100644 index 000000000..7fb4c8750 --- /dev/null +++ b/apps/emqx_gateway_coap/mix.exs @@ -0,0 +1,41 @@ +defmodule EMQXGatewayCoap.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_coap, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true} + ] ++ test_deps() + end + + defp test_deps() do + if UMP.test_env?() do + [ + {:er_coap_client, github: "emqx/er_coap_client", tag: "v1.0.5"}, + ] + else + [] + end + end +end diff --git a/apps/emqx_gateway_exproto/mix.exs b/apps/emqx_gateway_exproto/mix.exs new file mode 100644 index 000000000..72d9bd785 --- /dev/null +++ b/apps/emqx_gateway_exproto/mix.exs @@ -0,0 +1,43 @@ +defmodule EMQXGatewayExproto.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_exproto, + version: "0.1.0", + build_path: "../../_build", + compilers: [:elixir, :grpc, :erlang, :app], + # used by our `Mix.Tasks.Compile.Grpc` compiler + grpc_opts: %{ + gpb_opts: [ + module_name_prefix: 'emqx_', + module_name_suffix: '_pb', + ], + proto_dirs: ["priv/protos"], + out_dir: "src" + }, + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + test_deps = if UMP.test_env?(), do: [{:emqx_exhook, in_umbrella: true, runtime: false}], else: [] + test_deps ++ [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true}, + {:grpc, github: "emqx/grpc-erl", tag: "0.6.12", override: true} + ] + end +end diff --git a/apps/emqx_gateway_gbt32960/mix.exs b/apps/emqx_gateway_gbt32960/mix.exs new file mode 100644 index 000000000..8288b375f --- /dev/null +++ b/apps/emqx_gateway_gbt32960/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXGatewayGbt32960.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_gbt32960, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_gateway_jt808/mix.exs b/apps/emqx_gateway_jt808/mix.exs new file mode 100644 index 000000000..6a8714cbf --- /dev/null +++ b/apps/emqx_gateway_jt808/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXGatewayJt808.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_jt808, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_gateway_lwm2m/mix.exs b/apps/emqx_gateway_lwm2m/mix.exs new file mode 100644 index 000000000..3255b04c0 --- /dev/null +++ b/apps/emqx_gateway_lwm2m/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXGatewayLwm2m.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_lwm2m, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true}, + {:emqx_gateway_coap, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_SUITE.erl b/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_SUITE.erl index c302c5cd3..8277e2c44 100644 --- a/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_SUITE.erl +++ b/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_SUITE.erl @@ -134,17 +134,22 @@ groups() -> ]. init_per_suite(Config) -> - %% load application first for minirest api searching - application:load(emqx_gateway), - application:load(emqx_gateway_lwm2m), - emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_auth]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_gateway_lwm2m, + emqx_gateway, + emqx_auth, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{suite_apps, Apps} | Config]. end_per_suite(Config) -> - timer:sleep(300), - {ok, _} = emqx_conf:remove([<<"gateway">>, <<"lwm2m">>], #{}), - emqx_mgmt_api_test_util:end_suite([emqx_conf, emqx_auth]), - Config. + emqx_cth_suite:stop(?config(suite_apps, Config)), + ok. init_per_testcase(TestCase, Config) -> snabbkaffe:start_trace(), @@ -155,9 +160,8 @@ init_per_testcase(TestCase, Config) -> _ -> default_config() end, - ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, GatewayConfig), + ok = emqx_conf_cli:load_config(GatewayConfig, #{mode => replace}), - {ok, _} = application:ensure_all_started(emqx_gateway), {ok, ClientUdpSock} = gen_udp:open(0, [binary, {active, false}]), {ok, C} = emqtt:start_link([ @@ -175,7 +179,7 @@ end_per_testcase(_AllTestCase, Config) -> gen_udp:close(?config(sock, Config)), emqtt:disconnect(?config(emqx_c, Config)), snabbkaffe:stop(), - ok = application:stop(emqx_gateway). + ok. default_config() -> default_config(#{}). diff --git a/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_api_SUITE.erl b/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_api_SUITE.erl index 03c7a3269..07955bca0 100644 --- a/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_api_SUITE.erl +++ b/apps/emqx_gateway_lwm2m/test/emqx_lwm2m_api_SUITE.erl @@ -24,7 +24,7 @@ -define(LOGT(Format, Args), ct:pal("TEST_SUITE: " ++ Format, Args)). -include("emqx_lwm2m.hrl"). --include("emqx_gateway_coap/include/emqx_coap.hrl"). +-include("../../emqx_gateway_coap/include/emqx_coap.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). @@ -58,23 +58,26 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - application:load(emqx_gateway), - application:load(emqx_gateway_lwm2m), - DefaultConfig = emqx_lwm2m_SUITE:default_config(), - ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, DefaultConfig), - emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_auth]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_gateway_lwm2m, + emqx_gateway, + emqx_auth, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + ok = emqx_conf_cli:load_config(emqx_lwm2m_SUITE:default_config(), #{mode => replace}), + [{suite_apps, Apps} | Config]. end_per_suite(Config) -> - timer:sleep(300), - {ok, _} = emqx_conf:remove([<<"gateway">>, <<"lwm2m">>], #{}), - emqx_mgmt_api_test_util:end_suite([emqx_auth, emqx_conf]), - Config. + emqx_cth_suite:stop(?config(suite_apps, Config)), + ok. init_per_testcase(_AllTestCase, Config) -> - DefaultConfig = emqx_lwm2m_SUITE:default_config(), - ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, DefaultConfig), - {ok, _} = application:ensure_all_started(emqx_gateway), + ok = emqx_conf_cli:load_config(emqx_lwm2m_SUITE:default_config(), #{mode => replace}), {ok, ClientUdpSock} = gen_udp:open(0, [binary, {active, false}]), {ok, C} = emqtt:start_link([{host, "localhost"}, {port, 1883}, {clientid, <<"c1">>}]), @@ -86,7 +89,6 @@ init_per_testcase(_AllTestCase, Config) -> end_per_testcase(_AllTestCase, Config) -> gen_udp:close(?config(sock, Config)), emqtt:disconnect(?config(emqx_c, Config)), - ok = application:stop(emqx_gateway), timer:sleep(300). %%-------------------------------------------------------------------- diff --git a/apps/emqx_gateway_lwm2m/test/emqx_tlv_SUITE.erl b/apps/emqx_gateway_lwm2m/test/emqx_tlv_SUITE.erl index d63b188fd..b1a2d378a 100644 --- a/apps/emqx_gateway_lwm2m/test/emqx_tlv_SUITE.erl +++ b/apps/emqx_gateway_lwm2m/test/emqx_tlv_SUITE.erl @@ -22,7 +22,7 @@ -define(LOGT(Format, Args), logger:debug("TEST_SUITE: " ++ Format, Args)). -include("emqx_lwm2m.hrl"). --include("emqx_gateway_coap/include/emqx_coap.hrl"). +-include("../../emqx_gateway_coap/include/emqx_coap.hrl"). -include_lib("eunit/include/eunit.hrl"). %%-------------------------------------------------------------------- diff --git a/apps/emqx_gateway_mqttsn/mix.exs b/apps/emqx_gateway_mqttsn/mix.exs new file mode 100644 index 000000000..a53eaeac6 --- /dev/null +++ b/apps/emqx_gateway_mqttsn/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXGatewayMqttsn.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_mqttsn, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [{:emqx, in_umbrella: true}, {:emqx_gateway, in_umbrella: true}] + end +end diff --git a/apps/emqx_gateway_ocpp/mix.exs b/apps/emqx_gateway_ocpp/mix.exs new file mode 100644 index 000000000..75ec2f975 --- /dev/null +++ b/apps/emqx_gateway_ocpp/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXGatewayOcpp.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_ocpp, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:jesse, github: "emqx/jesse", tag: "1.8.0"}, + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_gateway_stomp/mix.exs b/apps/emqx_gateway_stomp/mix.exs new file mode 100644 index 000000000..04a506be0 --- /dev/null +++ b/apps/emqx_gateway_stomp/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXGatewayStomp.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gateway_stomp, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_gateway, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_gcp_device/mix.exs b/apps/emqx_gcp_device/mix.exs new file mode 100644 index 000000000..ceb0083d0 --- /dev/null +++ b/apps/emqx_gcp_device/mix.exs @@ -0,0 +1,44 @@ +defmodule EMQXGCPDevice.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_gcp_device, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_gcp_device_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2"} + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_ldap/mix.exs b/apps/emqx_ldap/mix.exs new file mode 100644 index 000000000..fea16592f --- /dev/null +++ b/apps/emqx_ldap/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXLdap.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_ldap, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: [:eldap]] + end + + def deps() do + [{:emqx_connector, in_umbrella: true}, {:emqx_resource, in_umbrella: true}] + end +end diff --git a/apps/emqx_ldap/test/emqx_ldap_SUITE.erl b/apps/emqx_ldap/test/emqx_ldap_SUITE.erl index 3c11f9d58..a15ff2775 100644 --- a/apps/emqx_ldap/test/emqx_ldap_SUITE.erl +++ b/apps/emqx_ldap/test/emqx_ldap_SUITE.erl @@ -21,6 +21,7 @@ -include_lib("emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). -include_lib("eldap/include/eldap.hrl"). @@ -52,18 +53,23 @@ init_per_suite(Config) -> Port = port(tcp), case emqx_common_test_helpers:is_tcp_server_available(?LDAP_HOST, Port) of true -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - Config; + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_ldap + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]; false -> {skip, no_ldap} end. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> emqx_common_test_helpers:reset_proxy(?PROXY_HOST, ?PROXY_PORT), diff --git a/apps/emqx_license/mix.exs b/apps/emqx_license/mix.exs new file mode 100644 index 000000000..e0d2937de --- /dev/null +++ b/apps/emqx_license/mix.exs @@ -0,0 +1,43 @@ +defmodule EMQXLicense.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_license, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_license_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true}, + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_machine/mix.exs b/apps/emqx_machine/mix.exs new file mode 100644 index 000000000..dee7ef915 --- /dev/null +++ b/apps/emqx_machine/mix.exs @@ -0,0 +1,35 @@ +defmodule EMQXMachine.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_machine, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_machine_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true, runtime: false}, + {:emqx_conf, in_umbrella: true, runtime: false}, + {:emqx_dashboard, in_umbrella: true, runtime: false}, + {:emqx_management, in_umbrella: true, runtime: false}, + {:covertool, github: "zmstone/covertool", tag: "2.0.4.1"} + ] + end +end diff --git a/apps/emqx_machine/test/emqx_machine_SUITE.erl b/apps/emqx_machine/test/emqx_machine_SUITE.erl index c28ffa313..001c8bf20 100644 --- a/apps/emqx_machine/test/emqx_machine_SUITE.erl +++ b/apps/emqx_machine/test/emqx_machine_SUITE.erl @@ -43,12 +43,34 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_common_test_helpers:start_apps([emqx_conf, emqx_opentelemetry]), - application:load(emqx_dashboard), - Config. + Apps = emqx_cth_suite:start( + app_specs(), + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_opentelemetry, emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. + +app_specs() -> + [ + emqx_conf, + emqx_prometheus, + emqx_modules, + emqx_dashboard, + emqx_gateway, + emqx_resource, + emqx_rule_engine, + emqx_bridge, + emqx_management, + emqx_retainer, + emqx_exhook, + emqx_auth, + emqx_plugins, + emqx_opentelemetry + ]. init_per_testcase(t_custom_shard_transports, Config) -> OldConfig = application:get_env(emqx_machine, custom_shard_transports), @@ -86,13 +108,29 @@ end_per_testcase(t_open_ports_check, Config) -> end_per_testcase(_TestCase, _Config) -> ok. -t_shutdown_reboot(_Config) -> - emqx_machine_boot:stop_apps(), - false = emqx:is_running(node()), - emqx_machine_boot:ensure_apps_started(), - true = emqx:is_running(node()), - ok = emqx_machine_boot:stop_apps(), - false = emqx:is_running(node()). +t_shutdown_reboot(Config) -> + [Node] = emqx_cth_cluster:start( + [{machine_reboot_SUITE1, #{role => core, apps => app_specs()}}], + #{work_dir => emqx_cth_suite:work_dir(?FUNCTION_NAME, Config)} + ), + try + erpc:call(Node, fun() -> + true = emqx:is_running(node()), + emqx_machine_boot:stop_apps(), + false = emqx:is_running(node()), + %% This is to emulate the presence of `emqx.conf' or `cluster.hocon' files, + %% which are not present in the peer. + %% This is done by `emqx_cth_suite' initially. + ok = emqx_app:set_config_loader(emqx_cth_suite), + emqx_machine_boot:ensure_apps_started(), + true = emqx:is_running(node()), + ok = emqx_machine_boot:stop_apps(), + false = emqx:is_running(node()), + ok + end) + after + catch emqx_cth_cluster:stop([Node]) + end. t_sorted_reboot_apps(_Config) -> Apps = emqx_machine_boot:sorted_reboot_apps(), diff --git a/apps/emqx_management/mix.exs b/apps/emqx_management/mix.exs new file mode 100644 index 000000000..097ffe1e8 --- /dev/null +++ b/apps/emqx_management/mix.exs @@ -0,0 +1,34 @@ +defmodule EMQXManagement.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_management, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_mgmt_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_bridge_http, in_umbrella: true}, + {:emqx_dashboard, in_umbrella: true, runtime: false}, + {:emqx_plugins, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_management/test/emqx_mgmt_api_SUITE.erl b/apps/emqx_management/test/emqx_mgmt_api_SUITE.erl index ec2f7b382..6e62ac2ab 100644 --- a/apps/emqx_management/test/emqx_mgmt_api_SUITE.erl +++ b/apps/emqx_management/test/emqx_mgmt_api_SUITE.erl @@ -40,7 +40,6 @@ end_per_suite(_) -> t_cluster_query(Config) -> net_kernel:start(['master@127.0.0.1', longnames]), ct:timetrap({seconds, 120}), - snabbkaffe:fix_ct_logging(), ListenerConf = fun(Port) -> io_lib:format( "\n listeners.tcp.default.bind = ~p" diff --git a/apps/emqx_management/test/emqx_mgmt_api_nodes_SUITE.erl b/apps/emqx_management/test/emqx_mgmt_api_nodes_SUITE.erl index 1a0ea8903..07a776c2d 100644 --- a/apps/emqx_management/test/emqx_mgmt_api_nodes_SUITE.erl +++ b/apps/emqx_management/test/emqx_mgmt_api_nodes_SUITE.erl @@ -131,7 +131,6 @@ t_node_metrics_api(_) -> t_multiple_nodes_api(Config) -> ct:timetrap({seconds, 120}), - snabbkaffe:fix_ct_logging(), Nodes = [Node1, Node2] = emqx_cth_cluster:start( [ diff --git a/apps/emqx_message_transformation/mix.exs b/apps/emqx_message_transformation/mix.exs new file mode 100644 index 000000000..2437639df --- /dev/null +++ b/apps/emqx_message_transformation/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXMessageTransformation.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_message_transformation, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_message_transformation_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_schema_registry, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_modules/mix.exs b/apps/emqx_modules/mix.exs new file mode 100644 index 000000000..f271d7729 --- /dev/null +++ b/apps/emqx_modules/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXModules.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_modules, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_modules_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_conf, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_modules/test/emqx_delayed_SUITE.erl b/apps/emqx_modules/test/emqx_delayed_SUITE.erl index e8d10e4e7..70e896645 100644 --- a/apps/emqx_modules/test/emqx_delayed_SUITE.erl +++ b/apps/emqx_modules/test/emqx_delayed_SUITE.erl @@ -40,12 +40,19 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, ?BASE_CONF), - emqx_common_test_helpers:start_apps([emqx_conf, emqx_modules]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + {emqx_modules, #{config => ?BASE_CONF}} + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_) -> - emqx_common_test_helpers:stop_apps([emqx_modules, emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(t_load_case, Config) -> Config; diff --git a/apps/emqx_modules/test/emqx_delayed_api_SUITE.erl b/apps/emqx_modules/test/emqx_delayed_api_SUITE.erl index 8c66bbfab..7ce19243c 100644 --- a/apps/emqx_modules/test/emqx_delayed_api_SUITE.erl +++ b/apps/emqx_modules/test/emqx_delayed_api_SUITE.erl @@ -32,17 +32,21 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, ?BASE_CONF), - ok = emqx_mgmt_api_test_util:init_suite( - [emqx_conf, emqx_modules] + Apps = emqx_cth_suite:start( + [ + emqx_conf, + {emqx_modules, #{config => ?BASE_CONF}}, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - emqx_delayed:load(), - Config. + [{apps, Apps} | Config]. end_per_suite(Config) -> - ok = emqx_delayed:unload(), - emqx_mgmt_api_test_util:end_suite([emqx_conf, emqx_modules]), - Config. + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> {ok, _} = emqx_cluster_rpc:start_link(), diff --git a/apps/emqx_modules/test/emqx_modules_conf_SUITE.erl b/apps/emqx_modules/test/emqx_modules_conf_SUITE.erl index fae6f08c2..68924a8b2 100644 --- a/apps/emqx_modules/test/emqx_modules_conf_SUITE.erl +++ b/apps/emqx_modules/test/emqx_modules_conf_SUITE.erl @@ -20,6 +20,7 @@ -compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). %%-------------------------------------------------------------------- %% Setups @@ -28,13 +29,20 @@ all() -> emqx_common_test_helpers:all(?MODULE). -init_per_suite(Conf) -> - emqx_common_test_helpers:load_config(emqx_modules_schema, <<"gateway {}">>), - emqx_common_test_helpers:start_apps([emqx_conf, emqx_modules]), - Conf. +init_per_suite(Config) -> + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_modules + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Conf) -> - emqx_common_test_helpers:stop_apps([emqx_modules, emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_CaseName, Conf) -> Conf. diff --git a/apps/emqx_modules/test/emqx_rewrite_SUITE.erl b/apps/emqx_modules/test/emqx_rewrite_SUITE.erl index 73cf7f02e..2a3cef91a 100644 --- a/apps/emqx_modules/test/emqx_rewrite_SUITE.erl +++ b/apps/emqx_modules/test/emqx_rewrite_SUITE.erl @@ -21,6 +21,7 @@ -include_lib("emqx/include/emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(REWRITE, #{ <<"rewrite">> => [ @@ -72,13 +73,19 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_common_test_helpers:boot_modules(all), - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, #{}), - emqx_common_test_helpers:start_apps([emqx_conf, emqx_modules]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_modules + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_conf, emqx_modules]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(t_get_basic_usage_info, Config) -> ok = emqx_rewrite:update([]), diff --git a/apps/emqx_modules/test/emqx_rewrite_api_SUITE.erl b/apps/emqx_modules/test/emqx_rewrite_api_SUITE.erl index 7bf8fefc6..9c095618d 100644 --- a/apps/emqx_modules/test/emqx_rewrite_api_SUITE.erl +++ b/apps/emqx_modules/test/emqx_rewrite_api_SUITE.erl @@ -33,15 +33,20 @@ init_per_testcase(_, Config) -> Config. init_per_suite(Config) -> - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, ?BASE_CONF), - ok = emqx_mgmt_api_test_util:init_suite( - [emqx_conf, emqx_modules] + Apps = emqx_cth_suite:start( + [ + emqx_conf, + {emqx_modules, #{config => ?BASE_CONF}}, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), + [{apps, Apps} | Config]. - Config. - -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf, emqx_modules]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. %%------------------------------------------------------------------------------ diff --git a/apps/emqx_modules/test/emqx_topic_metrics_SUITE.erl b/apps/emqx_modules/test/emqx_topic_metrics_SUITE.erl index 142beb5f2..b797301b7 100644 --- a/apps/emqx_modules/test/emqx_topic_metrics_SUITE.erl +++ b/apps/emqx_modules/test/emqx_topic_metrics_SUITE.erl @@ -19,21 +19,26 @@ -compile(export_all). -compile(nowarn_export_all). --define(TOPIC, #{<<"topic_metrics">> => []}). - -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_common_test_helpers:boot_modules(all), - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, ?TOPIC), - emqx_common_test_helpers:start_apps([emqx_conf, emqx_modules]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_modules + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_modules, emqx_conf]). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_Case, Config) -> emqx_topic_metrics:enable(), diff --git a/apps/emqx_modules/test/emqx_topic_metrics_api_SUITE.erl b/apps/emqx_modules/test/emqx_topic_metrics_api_SUITE.erl index 370ae0ffe..8e4ceb758 100644 --- a/apps/emqx_modules/test/emqx_topic_metrics_api_SUITE.erl +++ b/apps/emqx_modules/test/emqx_topic_metrics_api_SUITE.erl @@ -23,10 +23,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(BASE_CONF, #{ - <<"topic_metrics">> => [] -}). - suite() -> [{timetrap, {seconds, 30}}]. all() -> @@ -40,23 +36,25 @@ init_per_testcase(_, Config) -> Config. init_per_suite(Config) -> - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, ?BASE_CONF), - ok = emqx_mgmt_api_test_util:init_suite( - [emqx_conf, emqx_modules] - ), - - %% When many tests run in an obscure order, it may occur that - %% `gen_rpc` started with its default settings before `emqx_conf`. + %% For some unknown reason, this test suite depends on + %% `gen_rpc` not starting with its default settings before `emqx_conf`. %% `gen_rpc` and `emqx_conf` have different default `port_discovery` modes, %% so we reinitialize `gen_rpc` explicitly. - ok = application:stop(gen_rpc), - ok = application:start(gen_rpc), + Apps = emqx_cth_suite:start( + [ + {gen_rpc, #{override_env => [{port_discovery, stateless}]}}, + {emqx_conf, "rpc.port_discovery = stateless"}, + emqx_modules, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. - Config. - -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite([emqx_conf, emqx_modules]), - application:stop(gen_rpc), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. %%------------------------------------------------------------------------------ diff --git a/apps/emqx_mongodb/mix.exs b/apps/emqx_mongodb/mix.exs new file mode 100644 index 000000000..2d31e0f85 --- /dev/null +++ b/apps/emqx_mongodb/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXMongodb.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_mongodb, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:mongodb, github: "emqx/mongodb-erlang", tag: "v3.0.23"} + ] + end +end diff --git a/apps/emqx_mongodb/test/emqx_mongodb_SUITE.erl b/apps/emqx_mongodb/test/emqx_mongodb_SUITE.erl index 90f569dde..8af05e0d3 100644 --- a/apps/emqx_mongodb/test/emqx_mongodb_SUITE.erl +++ b/apps/emqx_mongodb/test/emqx_mongodb_SUITE.erl @@ -18,7 +18,7 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("emqx/include/emqx.hrl"). @@ -36,19 +36,23 @@ groups() -> init_per_suite(Config) -> case emqx_common_test_helpers:is_tcp_server_available(?MONGO_HOST, ?MONGO_DEFAULT_PORT) of true -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - {ok, _} = application:ensure_all_started(emqx_mongodb), - Config; + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_connector, + emqx_mongodb + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]; false -> {skip, no_mongo} end. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> Config. diff --git a/apps/emqx_mysql/mix.exs b/apps/emqx_mysql/mix.exs new file mode 100644 index 000000000..d745aac29 --- /dev/null +++ b/apps/emqx_mysql/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXMysql.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_mysql, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:mysql, github: "emqx/mysql-otp", tag: "1.7.4.1"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_node_rebalance/mix.exs b/apps/emqx_node_rebalance/mix.exs new file mode 100644 index 000000000..76049afef --- /dev/null +++ b/apps/emqx_node_rebalance/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXNodeRebalance.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_node_rebalance, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_node_rebalance_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true}, + {:emqx_eviction_agent, in_umbrella: true}, + ] + end +end diff --git a/apps/emqx_node_rebalance/test/emqx_node_rebalance_purge_SUITE.erl b/apps/emqx_node_rebalance/test/emqx_node_rebalance_purge_SUITE.erl index 0daeac106..9b3f90ee6 100644 --- a/apps/emqx_node_rebalance/test/emqx_node_rebalance_purge_SUITE.erl +++ b/apps/emqx_node_rebalance/test/emqx_node_rebalance_purge_SUITE.erl @@ -106,6 +106,7 @@ app_specs() -> end, override_env => [{boot_modules, [broker, listeners]}] }}, + emqx_conf, {emqx_retainer, #{ config => #{ diff --git a/apps/emqx_opentelemetry/mix.exs b/apps/emqx_opentelemetry/mix.exs new file mode 100644 index 000000000..6400a01ec --- /dev/null +++ b/apps/emqx_opentelemetry/mix.exs @@ -0,0 +1,54 @@ +defmodule EMQXOpentelemetry.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_opentelemetry, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_otel_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:opentelemetry_api, + github: "emqx/opentelemetry-erlang", + tag: "v1.4.7-emqx", + sparse: "apps/opentelemetry_api", + override: true}, + {:opentelemetry, + github: "emqx/opentelemetry-erlang", + tag: "v1.4.7-emqx", + sparse: "apps/opentelemetry", + override: true}, + {:opentelemetry_experimental, + github: "emqx/opentelemetry-erlang", + tag: "v1.4.7-emqx", + sparse: "apps/opentelemetry_experimental", + override: true}, + {:opentelemetry_api_experimental, + github: "emqx/opentelemetry-erlang", + tag: "v1.4.7-emqx", + sparse: "apps/opentelemetry_api_experimental", + override: true}, + {:opentelemetry_exporter, + github: "emqx/opentelemetry-erlang", + tag: "v1.4.7-emqx", + sparse: "apps/opentelemetry_exporter", + override: true} + ] + end +end diff --git a/apps/emqx_oracle/mix.exs b/apps/emqx_oracle/mix.exs new file mode 100644 index 000000000..0a72a2e43 --- /dev/null +++ b/apps/emqx_oracle/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXOracle.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_oracle, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:jamdb_oracle, github: "emqx/jamdb_oracle", tag: "0.4.9.5"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_plugins/mix.exs b/apps/emqx_plugins/mix.exs new file mode 100644 index 000000000..3df6025d4 --- /dev/null +++ b/apps/emqx_plugins/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXPlugins.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_plugins, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_plugins_app, []}] + end + + def deps() do + [{:emqx, in_umbrella: true}, {:erlavro, github: "emqx/erlavro", tag: "2.10.0"}] + end +end diff --git a/apps/emqx_postgresql/mix.exs b/apps/emqx_postgresql/mix.exs new file mode 100644 index 000000000..ea40699ba --- /dev/null +++ b/apps/emqx_postgresql/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXPostgresql.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_postgresql, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:epgsql, github: "emqx/epgsql", tag: "4.7.1.2"}, + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_postgresql/test/emqx_postgresql_SUITE.erl b/apps/emqx_postgresql/test/emqx_postgresql_SUITE.erl index c932981db..d771d80d8 100644 --- a/apps/emqx_postgresql/test/emqx_postgresql_SUITE.erl +++ b/apps/emqx_postgresql/test/emqx_postgresql_SUITE.erl @@ -18,9 +18,10 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector/include/emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_postgresql/include/emqx_postgresql.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("emqx/include/emqx.hrl"). -include_lib("stdlib/include/assert.hrl"). @@ -36,18 +37,19 @@ groups() -> init_per_suite(Config) -> case emqx_common_test_helpers:is_tcp_server_available(?PGSQL_HOST, ?PGSQL_DEFAULT_PORT) of true -> - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - Config; + Apps = emqx_cth_suite:start( + [emqx_conf, emqx_connector], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]; false -> {skip, no_pgsql} end. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_conf]), - ok = emqx_connector_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> Config. diff --git a/apps/emqx_prometheus/mix.exs b/apps/emqx_prometheus/mix.exs new file mode 100644 index 000000000..f9488bf52 --- /dev/null +++ b/apps/emqx_prometheus/mix.exs @@ -0,0 +1,34 @@ +defmodule EMQXPrometheus.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_prometheus, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_prometheus_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_auth, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:emqx_durable_storage, in_umbrella: true}, + {:prometheus, git: "https://github.com/emqx/prometheus.erl", tag: "v4.10.0.2"} + ] + end +end diff --git a/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl b/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl index a2c2b96c2..c97913ec2 100644 --- a/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl +++ b/apps/emqx_prometheus/test/emqx_prometheus_SUITE.erl @@ -87,22 +87,30 @@ common_tests() -> init_per_group(new_config, Config) -> Apps = emqx_cth_suite:start( - [ + lists:flatten([ %% coverage olp metrics {emqx, "overload_protection.enable = true"}, - {emqx_license, "license.key = default"}, - {emqx_prometheus, #{config => config(default)}} - ], + [ + {emqx_license, "license.key = default"} + || emqx_release:edition() == ee + ], + {emqx_prometheus, #{config => config(default)}}, + emqx_management + ]), #{work_dir => emqx_cth_suite:work_dir(Config)} ), [{suite_apps, Apps} | Config]; init_per_group(legacy_config, Config) -> Apps = emqx_cth_suite:start( - [ + lists:flatten([ {emqx, "overload_protection.enable = false"}, - {emqx_license, "license.key = default"}, - {emqx_prometheus, #{config => config(legacy)}} - ], + [ + {emqx_license, "license.key = default"} + || emqx_release:edition() == ee + ], + {emqx_prometheus, #{config => config(legacy)}}, + emqx_management + ]), #{work_dir => emqx_cth_suite:work_dir(Config)} ), [{suite_apps, Apps} | Config]. @@ -204,7 +212,9 @@ t_push_gateway(_) -> ok. start_mock_pushgateway(Port) -> - application:ensure_all_started(cowboy), + ensure_loaded(cowboy), + ensure_loaded(ranch), + {ok, _} = application:ensure_all_started(cowboy), Dispatch = cowboy_router:compile([{'_', [{'_', ?MODULE, []}]}]), {ok, _} = cowboy:start_clear( mock_pushgateway_listener, @@ -212,8 +222,16 @@ start_mock_pushgateway(Port) -> #{env => #{dispatch => Dispatch}} ). +ensure_loaded(App) -> + case application:load(App) of + ok -> ok; + {error, {already_loaded, _}} -> ok + end. + stop_mock_pushgateway() -> - cowboy:stop_listener(mock_pushgateway_listener). + cowboy:stop_listener(mock_pushgateway_listener), + ok = application:stop(cowboy), + ok = application:stop(ranch). init(Req0, Opts) -> Method = cowboy_req:method(Req0), diff --git a/apps/emqx_prometheus/test/emqx_prometheus_api_SUITE.erl b/apps/emqx_prometheus/test/emqx_prometheus_api_SUITE.erl index ae95c8246..a3a78b431 100644 --- a/apps/emqx_prometheus/test/emqx_prometheus_api_SUITE.erl +++ b/apps/emqx_prometheus/test/emqx_prometheus_api_SUITE.erl @@ -39,14 +39,17 @@ groups() -> init_per_suite(Config) -> Apps = emqx_cth_suite:start( - [ + lists:flatten([ emqx, emqx_conf, emqx_management, {emqx_prometheus, #{start => false}}, {emqx_dashboard, "dashboard.listeners.http { enable = true, bind = 18083 }"}, - {emqx_license, "license.key = default"} - ], + [ + {emqx_license, "license.key = default"} + || emqx_release:edition() == ee + ] + ]), #{work_dir => emqx_cth_suite:work_dir(Config)} ), {ok, _} = emqx_common_test_http:create_default_app(), diff --git a/apps/emqx_prometheus/test/emqx_prometheus_data_SUITE.erl b/apps/emqx_prometheus/test/emqx_prometheus_data_SUITE.erl index ce6eeb71d..2b7cd2f1e 100644 --- a/apps/emqx_prometheus/test/emqx_prometheus_data_SUITE.erl +++ b/apps/emqx_prometheus/test/emqx_prometheus_data_SUITE.erl @@ -111,7 +111,6 @@ groups() -> ]. init_per_suite(Config) -> - emqx_common_test_helpers:clear_screen(), meck:new(emqx_retainer, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_retainer, retained_count, fun() -> 0 end), meck:expect( @@ -124,7 +123,6 @@ init_per_suite(Config) -> ok = emqx_prometheus_SUITE:maybe_meck_license(), emqx_prometheus_SUITE:start_mock_pushgateway(9091), - application:load(emqx_auth), Apps = emqx_cth_suite:start( lists:flatten([ emqx, @@ -142,7 +140,8 @@ init_per_suite(Config) -> {emqx_message_transformation, #{config => message_transformation_config()}} || emqx_release:edition() == ee ], - {emqx_prometheus, emqx_prometheus_SUITE:legacy_conf_default()} + {emqx_prometheus, emqx_prometheus_SUITE:legacy_conf_default()}, + emqx_management ]), #{ work_dir => filename:join(?config(priv_dir, Config), ?MODULE) @@ -155,14 +154,6 @@ end_per_suite(Config) -> meck:unload([emqx_retainer]), emqx_prometheus_SUITE:maybe_unmeck_license(), emqx_prometheus_SUITE:stop_mock_pushgateway(), - {ok, _} = emqx:update_config( - [authorization], - #{ - <<"no_match">> => <<"allow">>, - <<"cache">> => #{<<"enable">> => <<"true">>}, - <<"sources">> => [] - } - ), emqx_cth_suite:stop(?config(apps, Config)), ok. diff --git a/apps/emqx_psk/mix.exs b/apps/emqx_psk/mix.exs new file mode 100644 index 000000000..2b190bc9d --- /dev/null +++ b/apps/emqx_psk/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXPsk.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_psk, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_psk_app, []}] + end + + def deps() do + [{:emqx, in_umbrella: true}] + end +end diff --git a/apps/emqx_redis/mix.exs b/apps/emqx_redis/mix.exs new file mode 100644 index 000000000..9a1fc2f64 --- /dev/null +++ b/apps/emqx_redis/mix.exs @@ -0,0 +1,31 @@ +defmodule EMQXRedis.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_redis, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications()] + end + + def deps() do + [ + {:emqx_connector, in_umbrella: true, runtime: false}, + {:emqx_resource, in_umbrella: true}, + {:eredis_cluster, github: "emqx/eredis_cluster", tag: "0.8.4"} + ] + end +end diff --git a/apps/emqx_redis/rebar.config b/apps/emqx_redis/rebar.config index e495a4eb6..524155c1d 100644 --- a/apps/emqx_redis/rebar.config +++ b/apps/emqx_redis/rebar.config @@ -3,7 +3,7 @@ {erl_opts, [debug_info]}. {deps, [ %% NOTE: mind ecpool version when updating eredis_cluster version - {eredis_cluster, {git, "https://github.com/emqx/eredis_cluster", {tag, "0.8.3"}}}, + {eredis_cluster, {git, "https://github.com/emqx/eredis_cluster", {tag, "0.8.4"}}}, {emqx_connector, {path, "../../apps/emqx_connector"}}, {emqx_resource, {path, "../../apps/emqx_resource"}} ]}. diff --git a/apps/emqx_redis/test/emqx_redis_SUITE.erl b/apps/emqx_redis/test/emqx_redis_SUITE.erl index accfb8f34..a9064f184 100644 --- a/apps/emqx_redis/test/emqx_redis_SUITE.erl +++ b/apps/emqx_redis/test/emqx_redis_SUITE.erl @@ -18,8 +18,9 @@ -compile(nowarn_export_all). -compile(export_all). --include("emqx_connector.hrl"). +-include("../../emqx_connector/include/emqx_connector.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("emqx/include/emqx.hrl"). -include_lib("stdlib/include/assert.hrl"). @@ -44,14 +45,19 @@ init_per_suite(Config) -> _ -> 1 end, ok = wait_for_redis(Checks), - ok = emqx_common_test_helpers:start_apps([emqx_conf]), - ok = emqx_connector_test_helpers:start_apps([emqx_resource]), - {ok, _} = application:ensure_all_started(emqx_connector), - Config. + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_connector + ], + #{work_dir => ?config(priv_dir, Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - ok = emqx_common_test_helpers:stop_apps([emqx_resource]), - _ = application:stop(emqx_connector). +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), + ok. init_per_testcase(_, Config) -> Config. diff --git a/apps/emqx_resource/mix.exs b/apps/emqx_resource/mix.exs new file mode 100644 index 000000000..94607a6f7 --- /dev/null +++ b/apps/emqx_resource/mix.exs @@ -0,0 +1,35 @@ +defmodule EMQXResource.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_resource, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_resource_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:ecpool, github: "emqx/ecpool", tag: "0.5.7"}, + {:gproc, github: "emqx/gproc", tag: "0.9.0.1"}, + {:jsx, github: "talentdeficit/jsx", tag: "v3.1.0"}, + {:telemetry, "1.1.0"} + ] + end +end diff --git a/apps/emqx_retainer/mix.exs b/apps/emqx_retainer/mix.exs new file mode 100644 index 000000000..c9467d2b3 --- /dev/null +++ b/apps/emqx_retainer/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXRetainer.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_retainer, + version: "0.1.0", + build_path: "../../_build", + # config_path: "../../config/config.exs", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_retainer_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true}, + ] + end +end diff --git a/apps/emqx_rule_engine/mix.exs b/apps/emqx_rule_engine/mix.exs new file mode 100644 index 000000000..d270607f3 --- /dev/null +++ b/apps/emqx_rule_engine/mix.exs @@ -0,0 +1,40 @@ +defmodule EMQXRuleEngine.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_rule_engine, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_rule_engine_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_ctl, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_modules, in_umbrella: true}, + {:emqx_resource, in_umbrella: true}, + {:emqx_bridge, in_umbrella: true}, + {:emqtt, + github: "emqx/emqtt", tag: "1.10.1", override: true, system_env: maybe_no_quic_env()} + ] + end + + defp maybe_no_quic_env() do + UMP.maybe_no_quic_env() + end +end diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl index da1df58ea..4dca243d1 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl @@ -159,17 +159,21 @@ groups() -> %%------------------------------------------------------------------------------ init_per_suite(Config) -> - %% ensure module loaded - emqx_rule_funcs_demo:module_info(), - application:load(emqx_conf), - ok = emqx_common_test_helpers:start_apps( - [emqx_conf, emqx_rule_engine, emqx_auth, emqx_bridge], - fun set_special_configs/1 + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_rule_engine, + emqx_auth, + emqx_bridge + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), - Config. + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_conf, emqx_rule_engine, emqx_auth, emqx_bridge]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. set_special_configs(emqx_auth) -> diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl index bd31a1450..e5e5eec31 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_api_SUITE.erl @@ -22,7 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"rule_engine {rules {}}">>). -define(SIMPLE_RULE(NAME_SUFFIX), #{ <<"description">> => <<"A simple rule">>, <<"enable">> => true, @@ -36,13 +35,19 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - application:load(emqx_conf), - ok = emqx_common_test_helpers:load_config(emqx_rule_engine_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_rule_engine]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_rule_engine + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_conf, emqx_rule_engine]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_testcase(t_crud_rule_api, Config) -> diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_api_rule_test_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_api_rule_test_SUITE.erl index 46563d71a..481247e2a 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_api_rule_test_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_api_rule_test_SUITE.erl @@ -22,19 +22,24 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"rule_engine {rules {}}">>). - all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - application:load(emqx_conf), - ok = emqx_common_test_helpers:load_config(emqx_rule_engine_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_conf, emqx_rule_engine, emqx_modules]), - Config. + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_rule_engine, + emqx_modules + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_conf, emqx_rule_engine, emqx_modules]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. t_ctx_pub(_) -> diff --git a/apps/emqx_s3/mix.exs b/apps/emqx_s3/mix.exs new file mode 100644 index 000000000..75d9406be --- /dev/null +++ b/apps/emqx_s3/mix.exs @@ -0,0 +1,45 @@ +defmodule EMQXS3.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_s3, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_s3_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:gproc, github: "emqx/gproc", tag: "0.9.0.1"}, + {:ehttpc, github: "emqx/ehttpc", tag: "0.4.13"}, + {:erlcloud, github: "emqx/erlcloud", tag: "3.7.0.3"}, + {:emqx_bridge_http, in_umbrella: true, runtime: false} + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_schema_registry/mix.exs b/apps/emqx_schema_registry/mix.exs new file mode 100644 index 000000000..e0da9c4bf --- /dev/null +++ b/apps/emqx_schema_registry/mix.exs @@ -0,0 +1,34 @@ +defmodule EMQXSchemaRegistry.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_schema_registry, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_schema_registry_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_rule_engine, in_umbrella: true}, + {:erlavro, github: "emqx/erlavro", tag: "2.10.0"}, + {:jesse, github: "emqx/jesse", tag: "1.8.0"}, + {:gpb, "4.19.9"} + ] + end +end diff --git a/apps/emqx_schema_registry/test/emqx_schema_registry_SUITE.erl b/apps/emqx_schema_registry/test/emqx_schema_registry_SUITE.erl index d9286f266..a403c3976 100644 --- a/apps/emqx_schema_registry/test/emqx_schema_registry_SUITE.erl +++ b/apps/emqx_schema_registry/test/emqx_schema_registry_SUITE.erl @@ -14,8 +14,6 @@ -import(emqx_common_test_helpers, [on_exit/1]). --define(APPS, [emqx_conf, emqx_rule_engine, emqx_schema_registry]). - %%------------------------------------------------------------------------------ %% CT boilerplate %%------------------------------------------------------------------------------ @@ -49,12 +47,22 @@ sparkplug_tests() -> ]. init_per_suite(Config) -> - emqx_config:save_schema_mod_and_names(emqx_schema_registry_schema), - emqx_mgmt_api_test_util:init_suite(?APPS), - Config. + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_rule_engine, + emqx_schema_registry, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(lists:reverse(?APPS)), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_group(avro, Config) -> @@ -369,7 +377,11 @@ cluster(Config) -> Cluster = emqx_common_test_helpers:emqx_cluster( [core, core], [ - {apps, ?APPS}, + {apps, [ + emqx_conf, + emqx_rule_engine, + emqx_schema_registry + ]}, {listener_ports, []}, {priv_data_dir, PrivDataDir}, {load_schema, true}, diff --git a/apps/emqx_schema_registry/test/emqx_schema_registry_http_api_SUITE.erl b/apps/emqx_schema_registry/test/emqx_schema_registry_http_api_SUITE.erl index 21c93b276..dfba3d1cd 100644 --- a/apps/emqx_schema_registry/test/emqx_schema_registry_http_api_SUITE.erl +++ b/apps/emqx_schema_registry/test/emqx_schema_registry_http_api_SUITE.erl @@ -36,12 +36,22 @@ groups() -> ]. init_per_suite(Config) -> - emqx_config:save_schema_mod_and_names(emqx_schema_registry_schema), - emqx_mgmt_api_test_util:init_suite(?APPS), - Config. + Apps = emqx_cth_suite:start( + [ + emqx, + emqx_conf, + emqx_rule_engine, + emqx_schema_registry, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} + ), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_mgmt_api_test_util:end_suite(lists:reverse(?APPS)), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_group(avro, Config) -> diff --git a/apps/emqx_schema_validation/mix.exs b/apps/emqx_schema_validation/mix.exs new file mode 100644 index 000000000..bc17e5f95 --- /dev/null +++ b/apps/emqx_schema_validation/mix.exs @@ -0,0 +1,32 @@ +defmodule EMQXSchemaValidation.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_schema_validation, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_schema_validation_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_rule_engine, in_umbrella: true}, + {:emqx_schema_registry, in_umbrella: true} + ] + end +end diff --git a/apps/emqx_slow_subs/mix.exs b/apps/emqx_slow_subs/mix.exs new file mode 100644 index 000000000..aa1549da7 --- /dev/null +++ b/apps/emqx_slow_subs/mix.exs @@ -0,0 +1,27 @@ +defmodule EMQXSlowSubs.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_slow_subs, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_slow_subs_app, []}] + end + + def deps() do + [{:emqx, in_umbrella: true}, {:emqx_utils, in_umbrella: true}] + end +end diff --git a/apps/emqx_telemetry/mix.exs b/apps/emqx_telemetry/mix.exs new file mode 100644 index 000000000..224296d2f --- /dev/null +++ b/apps/emqx_telemetry/mix.exs @@ -0,0 +1,43 @@ +defmodule EMQXTelemetry.MixProject do + use Mix.Project + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_telemetry, + version: "0.1.0", + build_path: "../../_build", + compilers: Mix.compilers() ++ [:copy_srcs], + # used by our `Mix.Tasks.Compile.CopySrcs` compiler + extra_dirs: extra_dirs(), + erlc_options: UMP.erlc_options(), + erlc_paths: UMP.erlc_paths(), + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [extra_applications: UMP.extra_applications(), mod: {:emqx_telemetry_app, []}] + end + + def deps() do + [ + {:emqx, in_umbrella: true}, + {:emqx_utils, in_umbrella: true}, + {:emqx_conf, in_umbrella: true} + ] + end + + defp extra_dirs() do + dirs = [] + if UMP.test_env?() do + ["test" | dirs] + else + dirs + end + end +end diff --git a/apps/emqx_telemetry/test/emqx_telemetry_SUITE.erl b/apps/emqx_telemetry/test/emqx_telemetry_SUITE.erl index f7916265d..e9eddc60b 100644 --- a/apps/emqx_telemetry/test/emqx_telemetry_SUITE.erl +++ b/apps/emqx_telemetry/test/emqx_telemetry_SUITE.erl @@ -52,20 +52,21 @@ apps() -> emqx_bridge_http, emqx_bridge, emqx_rule_engine, - emqx_management + emqx_gateway, + emqx_exhook, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard() ]. init_per_suite(Config) -> WorkDir = ?config(priv_dir, Config), Apps = emqx_cth_suite:start(apps(), #{work_dir => WorkDir}), - emqx_mgmt_api_test_util:init_suite(), [{apps, Apps}, {work_dir, WorkDir} | Config]. end_per_suite(Config) -> mnesia:clear_table(cluster_rpc_commit), mnesia:clear_table(cluster_rpc_mfa), Apps = ?config(apps, Config), - emqx_mgmt_api_test_util:end_suite(), ok = emqx_cth_suite:stop(Apps), ok. @@ -103,7 +104,6 @@ init_per_testcase(t_get_telemetry, Config) -> "test/emqx_gateway_SUITE_data" ), ok = emqx_gateway_SUITE:setup_fake_usage_data(Lwm2mDataDir), - emqx_common_test_helpers:start_apps([emqx_gateway]), Config; init_per_testcase(t_advanced_mqtt_features, Config) -> {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), @@ -134,24 +134,14 @@ init_per_testcase(t_rule_engine_and_data_bridge_info, Config) -> Config; init_per_testcase(t_exhook_info, Config) -> {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), - ExhookConf = - #{ - <<"exhook">> => - #{ - <<"servers">> => - [ - #{ - <<"name">> => "myhook", - <<"url">> => "http://127.0.0.1:9000" - } - ] - } - }, {ok, _} = emqx_exhook_demo_svr:start(), + ExhookConf = #{ + <<"name">> => "myhook", + <<"url">> => "http://127.0.0.1:9000" + }, + {ok, _} = emqx_exhook_mgr:update_config([exhook, servers], {add, ExhookConf}), {ok, Sock} = gen_tcp:connect("localhost", 9000, [], 3000), _ = gen_tcp:close(Sock), - ok = emqx_common_test_helpers:load_config(emqx_exhook_schema, ExhookConf), - emqx_common_test_helpers:start_apps([emqx_exhook]), Config; init_per_testcase(t_cluster_uuid, Config) -> Node = start_peer(n1), diff --git a/apps/emqx_telemetry/test/emqx_telemetry_api_SUITE.erl b/apps/emqx_telemetry/test/emqx_telemetry_api_SUITE.erl index ba3b1ebc7..1fb274163 100644 --- a/apps/emqx_telemetry/test/emqx_telemetry_api_SUITE.erl +++ b/apps/emqx_telemetry/test/emqx_telemetry_api_SUITE.erl @@ -29,27 +29,22 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - ok = emqx_common_test_helpers:load_config(emqx_modules_schema, ?BASE_CONF), - ok = emqx_common_test_helpers:load_config(emqx_telemetry_schema, ?BASE_CONF), - ok = emqx_mgmt_api_test_util:init_suite( - [emqx_conf, emqx_auth, emqx_management, emqx_telemetry], - fun set_special_configs/1 + Apps = emqx_cth_suite:start( + [ + emqx_conf, + emqx_auth, + emqx_management, + emqx_mgmt_api_test_util:emqx_dashboard(), + emqx_modules, + emqx_telemetry + ], + #{work_dir => emqx_cth_suite:work_dir(Config)} ), + [{apps, Apps} | Config]. - Config. - -end_per_suite(_Config) -> - {ok, _} = emqx:update_config( - [authorization], - #{ - <<"no_match">> => <<"allow">>, - <<"cache">> => #{<<"enable">> => <<"true">>}, - <<"sources">> => [] - } - ), - emqx_mgmt_api_test_util:end_suite([ - emqx_conf, emqx_auth, emqx_management, emqx_telemetry - ]), +end_per_suite(Config) -> + Apps = ?config(apps, Config), + emqx_cth_suite:stop(Apps), ok. init_per_testcase(t_status_non_official, Config) -> diff --git a/apps/emqx_utils/mix.exs b/apps/emqx_utils/mix.exs new file mode 100644 index 000000000..ed7c30b53 --- /dev/null +++ b/apps/emqx_utils/mix.exs @@ -0,0 +1,34 @@ +defmodule EMQXUtils.MixProject do + use Mix.Project + + alias EMQXUmbrella.MixProject, as: UMP + + def project do + [ + app: :emqx_utils, + version: "0.1.0", + build_path: "../../_build", + erlc_options: UMP.erlc_options(), + erlc_paths: ["etc" | UMP.erlc_paths()], + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.14", + start_permanent: Mix.env() == :prod, + deps: UMP.common_deps() ++ deps() + ] + end + + def application do + [ + extra_applications: UMP.extra_applications() + ] + end + + def deps() do + [ + {:jiffy, github: "emqx/jiffy", tag: "1.0.6"}, + {:emqx_http_lib, github: "emqx/emqx_http_lib", tag: "0.5.3"}, + {:snabbkaffe, github: "kafka4beam/snabbkaffe", tag: "1.0.10", override: true}, + ] + end +end diff --git a/apps/emqx_utils/test/emqx_template_SUITE.erl b/apps/emqx_utils/test/emqx_template_SUITE.erl index a049ebfbc..1cbc86fae 100644 --- a/apps/emqx_utils/test/emqx_template_SUITE.erl +++ b/apps/emqx_utils/test/emqx_template_SUITE.erl @@ -19,7 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("emqx/include/emqx_placeholder.hrl"). +-include("../../emqx/include/emqx_placeholder.hrl"). -include_lib("eunit/include/eunit.hrl"). all() -> emqx_common_test_helpers:all(?MODULE). diff --git a/apps/emqx_utils/test/emqx_utils_SUITE.erl b/apps/emqx_utils/test/emqx_utils_SUITE.erl index acb2623de..c124f5384 100644 --- a/apps/emqx_utils/test/emqx_utils_SUITE.erl +++ b/apps/emqx_utils/test/emqx_utils_SUITE.erl @@ -20,7 +20,7 @@ -compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). --include_lib("emqx/include/asserts.hrl"). +-include("../../emqx/include/asserts.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -define(SOCKOPTS, [ diff --git a/apps/emqx_utils/test/emqx_utils_api_SUITE.erl b/apps/emqx_utils/test/emqx_utils_api_SUITE.erl index e6cc03b7b..7029e466a 100644 --- a/apps/emqx_utils/test/emqx_utils_api_SUITE.erl +++ b/apps/emqx_utils/test/emqx_utils_api_SUITE.erl @@ -19,7 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). --include("emqx_utils_api.hrl"). +-include_lib("emqx_utils/include/emqx_utils_api.hrl"). -include_lib("eunit/include/eunit.hrl"). -define(DUMMY, dummy_module). @@ -27,12 +27,11 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - emqx_common_test_helpers:boot_modules(all), - emqx_common_test_helpers:start_apps([]), - Config. + Apps = emqx_cth_suite:start([emqx], #{work_dir => emqx_cth_suite:work_dir(Config)}), + [{apps, Apps} | Config]. -end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([]). +end_per_suite(Config) -> + emqx_cth_suite:stop(proplists:get_value(apps, Config)). init_per_testcase(_Case, Config) -> meck:new(?DUMMY, [non_strict]), diff --git a/lib/mix/tasks/emqx.ct.ex b/lib/mix/tasks/emqx.ct.ex new file mode 100644 index 000000000..ed75f3adc --- /dev/null +++ b/lib/mix/tasks/emqx.ct.ex @@ -0,0 +1,260 @@ +defmodule Mix.Tasks.Emqx.Ct do + use Mix.Task + + # todo: invoke the equivalent of `make merge-config` as a requirement... + @requirements ["compile", "loadpaths"] + + @impl true + def run(args) do + Mix.debug(true) + + opts = parse_args!(args) + + Enum.each([:common_test, :eunit, :mnesia], &add_to_path_and_cache/1) + + # app_to_debug = :emqx_conf + # Mix.Dep.Umbrella.cached() + # |> Enum.find(& &1.app == app_to_debug) + # |> Mix.Dep.in_dependency(fn _dep_mix_project_mod -> + # config = Mix.Project.config() + # |> IO.inspect(label: app_to_debug) + # end) + + ensure_whole_emqx_project_is_loaded!() + unload_emqx_applications!() + load_common_helpers!() + hack_test_data_dirs!(opts.suites) + + # ensure_suites_are_loaded!(opts.suites) + + {_, 0} = System.cmd("epmd", ["-daemon"]) + node_name = :"test@127.0.0.1" + :net_kernel.start([node_name, :longnames]) + logdir = Path.join([Mix.Project.build_path(), "logs"]) + File.mkdir_p!(logdir) + {:ok, _} = Application.ensure_all_started(:cth_readable) + + # unmangle PROFILE env because some places (`:emqx_conf.resolve_schema_module`) expect + # the version without the `-test` suffix. + System.fetch_env!("PROFILE") + |> String.replace_suffix("-test", "") + |> then(& System.put_env("PROFILE", &1)) + + # {_, _, _} = ["test_server:do_init_tc_call -> return"] |> Enum.map(&to_charlist/1) |> :redbug.start() + + maybe_start_cover() + + results = :ct.run_test( + abort_if_missing_suites: true, + auto_compile: false, + suite: opts |> Map.fetch!(:suites) |> Enum.map(&to_charlist/1), + testcase: opts |> Map.fetch!(:cases) |> Enum.map(&to_charlist/1), + readable: 'true', + name: node_name, + ct_hooks: [:cth_readable_shell], + logdir: to_charlist(logdir) + ) + + symlink_to_last_run(logdir) + + case results do + {_success, failed, {_user_skipped, auto_skipped}} when failed > 0 or auto_skipped > 0 -> + Mix.raise("failures running tests: #{failed} failed, #{auto_skipped} auto skipped") + + {success, _failed = 0, {user_skipped, _auto_skipped = 0}} -> + Mix.shell().info("Test suites ran successfully. #{success} succeeded, #{user_skipped} skipped by the user") + end + end + + @doc """ + Here we ensure the _modules_ are loaded, not the applications. + + Specially useful for suites that use utilities such as `emqx_common_test_helpers` and + similar. + + This needs to run before we unload the applications, otherwise we lose their `:modules` + attribute. + """ + def ensure_whole_emqx_project_is_loaded!() do + apps_path = + Mix.Project.project_file() + |> Path.dirname() + |> Path.join("apps") + + apps_path + |> File.ls!() + |> Stream.filter(fn app_name -> + apps_path + |> Path.join(app_name) + |> File.dir?() + end) + |> Stream.map(&String.to_atom/1) + |> Enum.flat_map(fn app -> + case :application.get_key(app, :modules) do + {:ok, mods} -> + mods + + other -> + # IO.inspect({app, other}, label: :bad_mods) + [] + end + end) + |> Code.ensure_all_loaded!() + end + + @doc """ + We do this because some callbacks rely on the side-effect of the application being + loaded. We leave starting them to `:emqx_cth_suite:start`. + + For example, `:emqx_dashboard:apps/0` uses that to decide which specs to load. + """ + def unload_emqx_applications!() do + for {app, _, _} <- Application.loaded_applications(), + to_string(app) =~ ~r/^emqx/ do + :ok = Application.unload(app) + end + end + + defp load_common_helpers!() do + Code.ensure_all_loaded!([ + :emqx_common_test_helpers, + :emqx_bridge_testlib, + :emqx_bridge_v2_testlib, + :emqx_authn_http_test_server, + ]) + end + + defp hack_test_data_dirs!(suites) do + project_root = Path.dirname(Mix.Project.project_file()) + + suites + |> Stream.map(fn suite_path -> + src_data_dir = + project_root + |> Path.join(Path.rootname(suite_path) <> "_data") + data_dir_exists? = File.dir?(src_data_dir) + IO.inspect(binding()) + if data_dir_exists? do + suite_mod = + suite_path + |> Path.basename(".erl") + |> String.to_atom() + ebin_path = get_mod_ebin_path(suite_mod) + data_dir = Path.basename(src_data_dir) + dest_data_path = + [ebin_path, "..", data_dir] + |> Path.join() + |> Path.expand() + File.rm(dest_data_path) + case File.ln_s(src_data_dir, dest_data_path) do + :ok -> + :ok + + {:error, :eexist} -> + :ok + end + IO.inspect(binding()) + end + end) + |> Stream.run() + end + + defp get_mod_ebin_path(mod) do + case :code.which(mod) do + :cover_compiled -> + Mix.raise("todo (see test_server_ctrl:get_data_dir/2)") + + full_path when is_list(full_path) -> + full_path + end + end + + defp ensure_suites_are_loaded!(suites) do + suites + |> Enum.map(fn suite_path -> + ["apps", app_name | _] = Path.split(suite_path) + String.to_atom(app_name) + end) + |> Enum.uniq() + |> Enum.flat_map(fn app -> + {:ok, mods} = :application.get_key(app, :modules) + mods + end) + |> Code.ensure_all_loaded!() + end + + def add_to_path_and_cache(lib_name) do + :code.lib_dir() + |> Path.join("#{lib_name}-*") + |> Path.wildcard() + |> hd() + |> Path.join("ebin") + |> to_charlist() + |> :code.add_path(:cache) + end + + defp parse_args!(args) do + {opts, _rest} = OptionParser.parse!( + args, + strict: [ + suites: :string, + groups: :string, + cases: :string]) + |> IO.inspect(label: :opts) + suites = get_name_list(opts, :suites) + groups = get_name_list(opts, :groups) + cases = get_name_list(opts, :cases) + + if suites == [] do + Mix.raise("must define at least one suite using --suites path/to/suite1.erl,path/to/suite2.erl") + end + + %{ + suites: suites, + groups: groups, + cases: cases + } + end + + defp get_name_list(opts, key) do + opts + |> Keyword.get(key, "") + |> String.split(",", trim: true) + end + + def cover_enabled?() do + case System.get_env("ENABLE_COVER_COMPILE") do + "1" -> true + "true" -> true + _ -> false + end + end + + defp maybe_start_cover() do + if cover_enabled?() do + {:ok, _} = start_cover() + end + end + + defp start_cover() do + case :cover.start() do + {:ok, pid} -> {:ok, pid} + {:error, {:already_started, pid}} -> {:ok, pid} + end + end + + defp symlink_to_last_run(log_dir) do + last_dir = + log_dir + |> File.ls!() + |> Stream.filter(& &1 =~ ~r/^ct_run/) + |> Enum.sort() + |> List.last() + + if last_dir do + dest = Path.join(log_dir, "last") + File.rm(dest) + File.ln_s!(last_dir, dest) + end + end +end diff --git a/lib/mix/tasks/emqx.eunit.ex b/lib/mix/tasks/emqx.eunit.ex new file mode 100644 index 000000000..a2c0dfe39 --- /dev/null +++ b/lib/mix/tasks/emqx.eunit.ex @@ -0,0 +1,58 @@ +defmodule Mix.Tasks.Emqx.Eunit do + use Mix.Task + + # Code.require_file("emqx.ct.ex", __DIR__) + + alias Mix.Tasks.Emqx.Ct, as: ECt + + # todo: invoke the equivalent of `make merge-config` as a requirement... + @requirements ["compile", "loadpaths"] + + @impl true + def run(args) do + Mix.debug(true) + IO.inspect(args) + + + Enum.each([:common_test, :eunit, :mnesia], &ECt.add_to_path_and_cache/1) + + ECt.ensure_whole_emqx_project_is_loaded!() + ECt.unload_emqx_applications!() + + {_, 0} = System.cmd("epmd", ["-daemon"]) + node_name = :"test@127.0.0.1" + :net_kernel.start([node_name, :longnames]) + + # unmangle PROFILE env because some places (`:emqx_conf.resolve_schema_module`) expect + # the version without the `-test` suffix. + System.fetch_env!("PROFILE") + |> String.replace_suffix("-test", "") + |> then(& System.put_env("PROFILE", &1)) + + discover_tests() + |> :eunit.test( + verbose: true, + print_depth: 100 + ) + |> case do + :ok -> :ok + :error -> Mix.raise("errors found in tests") + end + end + + defp add_to_path_and_cache(lib_name) do + :code.lib_dir() + |> Path.join("#{lib_name}-*") + |> Path.wildcard() + |> hd() + |> Path.join("ebin") + |> to_charlist() + |> :code.add_path(:cache) + end + + ## TODO: allow filtering modules and test names + defp discover_tests() do + Mix.Dep.Umbrella.cached() + |> Enum.map(& {:application, &1.app}) + end +end diff --git a/lib/mix/tasks/emqx.proper.ex b/lib/mix/tasks/emqx.proper.ex new file mode 100644 index 000000000..55dbbe23c --- /dev/null +++ b/lib/mix/tasks/emqx.proper.ex @@ -0,0 +1,77 @@ +defmodule Mix.Tasks.Emqx.Proper do + use Mix.Task + + # Code.require_file("emqx.ct.ex", __DIR__) + + alias Mix.Tasks.Emqx.Ct, as: ECt + + # todo: invoke the equivalent of `make merge-config` as a requirement... + @requirements ["compile", "loadpaths"] + + @impl true + def run(args) do + Mix.debug(true) + IO.inspect(args) + + + Enum.each([:common_test, :eunit, :mnesia], &ECt.add_to_path_and_cache/1) + + ECt.ensure_whole_emqx_project_is_loaded!() + ECt.unload_emqx_applications!() + + {_, 0} = System.cmd("epmd", ["-daemon"]) + node_name = :"test@127.0.0.1" + :net_kernel.start([node_name, :longnames]) + + # unmangle PROFILE env because some places (`:emqx_conf.resolve_schema_module`) expect + # the version without the `-test` suffix. + System.fetch_env!("PROFILE") + |> String.replace_suffix("-test", "") + |> then(& System.put_env("PROFILE", &1)) + + for {mod, fun} <- discover_props() do + Mix.shell().info("testing #{mod}:#{fun}") + opts = fetch_opts(mod, fun) + :proper.quickcheck(apply(mod, fun, []), opts) + end + |> IO.inspect() + end + + defp add_to_path_and_cache(lib_name) do + :code.lib_dir() + |> Path.join("#{lib_name}-*") + |> Path.wildcard() + |> hd() + |> Path.join("ebin") + |> to_charlist() + |> :code.add_path(:cache) + end + + ## TODO: allow filtering modules and test names + defp discover_props() do + Mix.Dep.Umbrella.cached() + |> Enum.map(fn dep -> + dep.opts[:path] + |> Path.join("test") + end) + |> Mix.Utils.extract_files("prop_*.erl") + |> Enum.flat_map(fn suite_path -> + suite_path + |> Path.basename(".erl") + |> String.to_atom() + |> then(fn suite_mod -> + suite_mod.module_info(:exports) + |> Enum.filter(fn {name, _arity} -> to_string(name) =~ ~r/^prop_/ end) + |> Enum.map(fn {name, _arity} -> {suite_mod, name} end) + end) + end) + end + + defp fetch_opts(mod, fun) do + try do + mod.fun(:opts) + rescue + e in [FunctionClauseError, UndefinedFunctionError] -> [] + end + end +end diff --git a/mix.exs b/mix.exs index fabb446cf..8a27f0ba1 100644 --- a/mix.exs +++ b/mix.exs @@ -34,80 +34,107 @@ defmodule EMQXUmbrella.MixProject do version = pkg_vsn() [ + # TODO: these lines will be uncommented when we switch to using mix as the manager + # for all umbrella apps. + # apps_path: "apps", + # apps: applications(profile_info.release_type, profile_info.edition_type) |> Keyword.keys(), + app: :emqx_mix, + erlc_options: erlc_options(profile_info, version), version: version, deps: deps(profile_info, version), - releases: releases() + releases: releases(), + aliases: aliases() ] end defp deps(profile_info, version) do # we need several overrides here because dependencies specify # other exact versions, and not ranges. - [ - {:lc, github: "emqx/lc", tag: "0.3.2", override: true}, - {:redbug, github: "emqx/redbug", tag: "2.0.10"}, - {:covertool, github: "zmstone/covertool", tag: "2.0.4.1", override: true}, - {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true}, - {:ehttpc, github: "emqx/ehttpc", tag: "0.4.14", override: true}, - {:gproc, github: "emqx/gproc", tag: "0.9.0.1", override: true}, - {:jiffy, github: "emqx/jiffy", tag: "1.0.6", override: true}, - {:cowboy, github: "emqx/cowboy", tag: "2.9.2", override: true}, - {:esockd, github: "emqx/esockd", tag: "5.11.2", override: true}, - {:rocksdb, github: "emqx/erlang-rocksdb", tag: "1.8.0-emqx-5", override: true}, - {:ekka, github: "emqx/ekka", tag: "0.19.5", override: true}, - {:gen_rpc, github: "emqx/gen_rpc", tag: "3.3.1", override: true}, - {:grpc, github: "emqx/grpc-erl", tag: "0.6.12", override: true}, - {:minirest, github: "emqx/minirest", tag: "1.4.3", override: true}, - {:ecpool, github: "emqx/ecpool", tag: "0.5.7", override: true}, - {:replayq, github: "emqx/replayq", tag: "0.3.8", override: true}, - {:pbkdf2, github: "emqx/erlang-pbkdf2", tag: "2.0.4", override: true}, - # maybe forbid to fetch quicer - {:emqtt, - github: "emqx/emqtt", tag: "1.10.1", override: true, system_env: maybe_no_quic_env()}, - {:rulesql, github: "emqx/rulesql", tag: "0.2.1"}, - {:observer_cli, "1.7.1"}, - {:system_monitor, github: "ieQu1/system_monitor", tag: "3.0.5"}, - {:telemetry, "1.1.0", override: true}, - # in conflict by emqtt and hocon - {:getopt, "1.0.2", override: true}, - {:snabbkaffe, github: "kafka4beam/snabbkaffe", tag: "1.0.10", override: true}, - {:hocon, github: "emqx/hocon", tag: "0.42.2", override: true}, - {:emqx_http_lib, github: "emqx/emqx_http_lib", tag: "0.5.3", override: true}, - {:esasl, github: "emqx/esasl", tag: "0.2.1"}, - {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2", override: true}, - # in conflict by ehttpc and emqtt - {:gun, github: "emqx/gun", tag: "1.3.11", override: true}, - # in conflict by emqx_connector and system_monitor - {:epgsql, github: "emqx/epgsql", tag: "4.7.1.2", override: true}, - # in conflict by emqx and observer_cli - {:recon, github: "ferd/recon", tag: "2.5.1", override: true}, - {:jsx, github: "talentdeficit/jsx", tag: "v3.1.0", override: true}, - # in conflict by erlavro and rocketmq - {:jsone, github: "emqx/jsone", tag: "1.7.1", override: true}, - # dependencies of dependencies; we choose specific refs to match - # what rebar3 chooses. - # in conflict by gun and emqtt - {:cowlib, - github: "ninenines/cowlib", ref: "c6553f8308a2ca5dcd69d845f0a7d098c40c3363", override: true}, - # in conflict by cowboy_swagger and cowboy - {:ranch, github: "emqx/ranch", tag: "1.8.1-emqx", override: true}, - # in conflict by grpc and eetcd - {:gpb, "4.19.9", override: true, runtime: false}, - {:hackney, github: "emqx/hackney", tag: "1.18.1-1", override: true}, - # set by hackney (dependency) - {:ssl_verify_fun, "1.1.7", override: true}, - {:rfc3339, github: "emqx/rfc3339", tag: "0.2.3", override: true}, - {:bcrypt, github: "emqx/erlang-bcrypt", tag: "0.6.2", override: true}, - {:uuid, github: "okeuday/uuid", tag: "v2.0.6", override: true}, - {:quickrand, github: "okeuday/quickrand", tag: "v2.0.6", override: true}, - {:ra, "2.7.3", override: true}, - {:mimerl, "1.2.0", override: true} - ] ++ - emqx_apps(profile_info, version) ++ - enterprise_deps(profile_info) ++ jq_dep() ++ quicer_dep() + + ## TODO: this should be removed once we migrate the release build to mix + rebar3_umbrella_apps = emqx_apps(profile_info, version) ++ enterprise_deps(profile_info) + + common_deps() ++ + [ + {:lc, github: "emqx/lc", tag: "0.3.2", override: true}, + {:redbug, github: "emqx/redbug", tag: "2.0.10"}, + {:covertool, github: "zmstone/covertool", tag: "2.0.4.1", override: true}, + {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true}, + {:ehttpc, github: "emqx/ehttpc", tag: "0.4.14", override: true}, + {:gproc, github: "emqx/gproc", tag: "0.9.0.1", override: true}, + {:jiffy, github: "emqx/jiffy", tag: "1.0.6", override: true}, + {:cowboy, github: "emqx/cowboy", tag: "2.9.2", override: true}, + {:esockd, github: "emqx/esockd", tag: "5.11.2", override: true}, + {:rocksdb, github: "emqx/erlang-rocksdb", tag: "1.8.0-emqx-5", override: true}, + {:ekka, github: "emqx/ekka", tag: "0.19.5", override: true}, + {:gen_rpc, github: "emqx/gen_rpc", tag: "3.3.1", override: true}, + {:grpc, github: "emqx/grpc-erl", tag: "0.6.12", override: true}, + {:minirest, github: "emqx/minirest", tag: "1.4.3", override: true}, + {:ecpool, github: "emqx/ecpool", tag: "0.5.7", override: true}, + {:replayq, github: "emqx/replayq", tag: "0.3.8", override: true}, + {:pbkdf2, github: "emqx/erlang-pbkdf2", tag: "2.0.4", override: true}, + # maybe forbid to fetch quicer + {:emqtt, + github: "emqx/emqtt", tag: "1.10.1", override: true, system_env: maybe_no_quic_env()}, + {:rulesql, github: "emqx/rulesql", tag: "0.2.1"}, + {:observer_cli, "1.7.1"}, + {:system_monitor, github: "ieQu1/system_monitor", tag: "3.0.5"}, + {:telemetry, "1.1.0", override: true}, + # in conflict by emqtt and hocon + {:getopt, "1.0.2", override: true}, + { + :snabbkaffe, + ## without this, snabbkaffe is compiled with `-define(snk_kind, '$kind')`, which + ## will basically make events in tests never match any predicates. + github: "kafka4beam/snabbkaffe", + tag: "1.0.10", + override: true, + system_env: emqx_app_system_env(profile_info, version) + }, + {:hocon, github: "emqx/hocon", tag: "0.42.2", override: true}, + {:emqx_http_lib, github: "emqx/emqx_http_lib", tag: "0.5.3", override: true}, + {:esasl, github: "emqx/esasl", tag: "0.2.1"}, + {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2", override: true}, + # in conflict by ehttpc and emqtt + {:gun, github: "emqx/gun", tag: "1.3.11", override: true}, + # in conflict by emqx_connector and system_monitor + {:epgsql, github: "emqx/epgsql", tag: "4.7.1.2", override: true}, + # in conflict by emqx and observer_cli + {:recon, github: "ferd/recon", tag: "2.5.1", override: true}, + {:jsx, github: "talentdeficit/jsx", tag: "v3.1.0", override: true}, + # in conflict by erlavro and rocketmq + {:jsone, github: "emqx/jsone", tag: "1.7.1", override: true}, + # dependencies of dependencies; we choose specific refs to match + # what rebar3 chooses. + # in conflict by gun and emqtt + {:cowlib, + github: "ninenines/cowlib", + ref: "c6553f8308a2ca5dcd69d845f0a7d098c40c3363", + override: true}, + # in conflict by cowboy_swagger and cowboy + {:ranch, github: "emqx/ranch", tag: "1.8.1-emqx", override: true}, + # in conflict by grpc and eetcd + {:gpb, "4.19.9", override: true, runtime: false}, + {:hackney, github: "emqx/hackney", tag: "1.18.1-1", override: true}, + # set by hackney (dependency) + {:ssl_verify_fun, "1.1.7", override: true}, + {:rfc3339, github: "emqx/rfc3339", tag: "0.2.3", override: true}, + {:bcrypt, github: "emqx/erlang-bcrypt", tag: "0.6.2", override: true}, + {:uuid, github: "okeuday/uuid", tag: "v2.0.6", override: true}, + {:quickrand, github: "okeuday/quickrand", tag: "v2.0.6", override: true}, + {:ra, "2.7.3", override: true}, + {:mimerl, "1.2.0", override: true} + ] ++ + jq_dep() ++ + quicer_dep() ++ rebar3_umbrella_apps end + ############################################################################################### + # BEGIN DEPRECATED FOR MIX BLOCK + # These should be removed once we fully migrate to mix + ############################################################################################### + defp emqx_apps(profile_info, version) do apps = umbrella_apps(profile_info) ++ enterprise_apps(profile_info) set_emqx_app_system_env(apps, profile_info, version) @@ -259,6 +286,10 @@ defmodule EMQXUmbrella.MixProject do ) end + ############################################################################################### + # END DEPRECATED FOR MIX BLOCK + ############################################################################################### + def emqx_app_system_env(profile_info, version) do erlc_options(profile_info, version) |> dump_as_erl() @@ -272,7 +303,95 @@ defmodule EMQXUmbrella.MixProject do {:d, :EMQX_RELEASE_EDITION, erlang_edition(edition_type)}, {:d, :EMQX_ELIXIR}, {:d, :snk_kind, :msg} - ] + ] ++ + singleton(test_env?(), {:d, :TEST}) ++ + singleton(not enable_quicer?(), {:d, :BUILD_WITHOUT_QUIC}) + end + + defp singleton(false, _value), do: [] + defp singleton(true, value), do: [value] + + def profile_info() do + k = {__MODULE__, :profile_info} + get_memoized(k, &check_profile!/0) + end + + def pkg_vsn() do + k = {__MODULE__, :pkg_vsn} + get_memoized(k, &do_pkg_vsn/0) + end + + def common_deps() do + if test_env?() do + [ + {:bbmustache, "1.10.0"}, + {:cth_readable, "1.5.1"}, + {:proper, "1.4.0"}, + {:meck, "0.9.2"} + ] + else + [] + end + end + + def extra_applications() do + k = {__MODULE__, :extra_applications} + + get_memoized(k, fn -> + if test_env?() do + [:eunit, :common_test, :dialyzer, :mnesia] + else + [] + end + end) + end + + def erlc_paths() do + k = {__MODULE__, :erlc_paths} + + get_memoized(k, fn -> + if test_env?() do + ["src", "test"] + else + ["src"] + end + end) + end + + def erlc_options() do + k = {__MODULE__, :erlc_options} + + get_memoized(k, fn -> + profile_info = profile_info() + version = pkg_vsn() + erlc_options(profile_info, version) + end) + end + + def test_env?() do + k = {__MODULE__, :test_env?} + + get_memoized(k, fn -> + env = to_string(Mix.env()) + System.get_env("TEST") == "1" || env =~ ~r/-test$/ + end) + end + + defp set_test_env!(test_env?) do + k = {__MODULE__, :test_env?} + :persistent_term.put(k, test_env?) + end + + defp get_memoized(k, compute_fn) do + case :persistent_term.get(k, :undefined) do + :undefined -> + res = compute_fn.() + :persistent_term.put(k, res) + res + + res -> + res + end end def maybe_no_quic_env() do @@ -293,7 +412,7 @@ defmodule EMQXUmbrella.MixProject do } = check_profile!() base_steps = [ - &make_docs(&1), + &make_docs/1, :assemble, &create_RELEASES/1, ©_files(&1, release_type, package_type, edition_type), @@ -312,6 +431,7 @@ defmodule EMQXUmbrella.MixProject do applications: applications(release_type, edition_type), skip_mode_validation_for: [ :emqx_mix, + :emqx_machine, :emqx_gateway, :emqx_gateway_stomp, :emqx_gateway_mqttsn, @@ -380,9 +500,12 @@ defmodule EMQXUmbrella.MixProject do db_apps = Enum.map(db_apps, &{&1, :load}) business_apps = Enum.map(business_apps, &{&1, :load}) - [system_apps, db_apps, [emqx_machine: :permanent], business_apps] + [system_apps, db_apps, [emqx_ctl: :permanent, emqx_machine: :permanent], business_apps] |> List.flatten() - |> Keyword.reject(fn {app, _type} -> app in excluded_apps end) + |> Keyword.reject(fn {app, _type} -> + app in excluded_apps || + (edition_type == :enterprise && app == :emqx_telemetry) + end) end defp excluded_apps(_release_type) do @@ -412,8 +535,10 @@ defmodule EMQXUmbrella.MixProject do def check_profile!() do valid_envs = [ :emqx, + :"emqx-test", :"emqx-pkg", :"emqx-enterprise", + :"emqx-enterprise-test", :"emqx-enterprise-pkg" ] @@ -426,12 +551,10 @@ defmodule EMQXUmbrella.MixProject do |> String.to_atom() |> Mix.env() else - IO.puts( - IO.ANSI.format([ - :yellow, - "Warning: env var PROFILE is unset; defaulting to emqx" - ]) - ) + Mix.shell().info([ + :yellow, + "Warning: env var PROFILE is unset; defaulting to emqx" + ]) Mix.env(:emqx) end @@ -449,21 +572,29 @@ defmodule EMQXUmbrella.MixProject do """) end + mix_env = Mix.env() + { release_type, package_type, edition_type } = - case Mix.env() do + case mix_env do :dev -> {:standard, :bin, :community} :emqx -> {:standard, :bin, :community} + :"emqx-test" -> + {:standard, :bin, :community} + :"emqx-enterprise" -> {:standard, :bin, :enterprise} + :"emqx-enterprise-test" -> + {:standard, :bin, :enterprise} + :"emqx-pkg" -> {:standard, :pkg, :community} @@ -471,12 +602,45 @@ defmodule EMQXUmbrella.MixProject do {:standard, :pkg, :enterprise} end - normalize_env!() + test? = to_string(mix_env) =~ ~r/-test$/ || test_env?() + + normalize_env!(test?) + + # Mix.debug(true) + + if Mix.debug?() do + Mix.shell().info([ + :blue, + "mix_env: #{Mix.env()}", + "; release type: #{release_type}", + "; package type: #{package_type}", + "; edition type: #{edition_type}", + "; test env?: #{test?}" + ]) + end + + test? = to_string(mix_env) =~ ~r/-test$/ || test_env?() + + normalize_env!(test?) + + # Mix.debug(true) + + if Mix.debug?() do + Mix.shell().info([ + :blue, + "mix_env: #{Mix.env()}", + "; release type: #{release_type}", + "; package type: #{package_type}", + "; edition type: #{edition_type}", + "; test env?: #{test?}" + ]) + end %{ release_type: release_type, package_type: package_type, - edition_type: edition_type + edition_type: edition_type, + test?: test? } end @@ -814,7 +978,7 @@ defmodule EMQXUmbrella.MixProject do else: [] end - defp quicer_dep() do + def quicer_dep() do if enable_quicer?(), # in conflict with emqx and emqtt do: [{:quicer, github: "emqx/quic", tag: "0.0.313", override: true}], @@ -827,7 +991,7 @@ defmodule EMQXUmbrella.MixProject do ]) end - defp enable_quicer?() do + def enable_quicer?() do "1" == System.get_env("BUILD_WITH_QUIC") or not Enum.any?([ macos?(), @@ -842,7 +1006,7 @@ defmodule EMQXUmbrella.MixProject do ]) end - defp pkg_vsn() do + defp do_pkg_vsn() do %{edition_type: edition_type} = check_profile!() basedir = Path.dirname(__ENV__.file) script = Path.join(basedir, "pkg-vsn.sh") @@ -854,7 +1018,7 @@ defmodule EMQXUmbrella.MixProject do String.trim(str) end - defp macos?() do + def macos?() do {:unix, :darwin} == :os.type() end @@ -868,7 +1032,7 @@ defmodule EMQXUmbrella.MixProject do String.downcase(opt) != "false" end - defp build_without_quic?() do + def build_without_quic?() do opt = System.get_env("BUILD_WITHOUT_QUIC", "false") String.downcase(opt) != "false" @@ -915,7 +1079,7 @@ defmodule EMQXUmbrella.MixProject do to_string(8 * size) end - defp normalize_env!() do + defp normalize_env!(test_env?) do env = case Mix.env() do :dev -> @@ -925,6 +1089,10 @@ defmodule EMQXUmbrella.MixProject do env end + if test_env? do + ensure_test_mix_env!() + end + Mix.env(env) end @@ -960,4 +1128,51 @@ defmodule EMQXUmbrella.MixProject do defp erlang_edition(:community), do: :ce defp erlang_edition(:enterprise), do: :ee + + defp aliases() do + [ + ct: &do_ct/1, + eunit: &do_eunit/1, + proper: &do_proper/1 + ] + end + + defp do_ct(args) do + IO.inspect(args) + Mix.shell().info("testing") + + ensure_test_mix_env!() + set_test_env!(true) + + Code.require_file("lib/mix/tasks/emqx.ct.ex") + Mix.Task.run("emqx.ct", args) + end + + defp do_eunit(args) do + ensure_test_mix_env!() + set_test_env!(true) + Code.require_file("lib/mix/tasks/emqx.eunit.ex") + Mix.Task.run("emqx.eunit", args) + end + + defp do_proper(args) do + ensure_test_mix_env!() + set_test_env!(true) + Code.require_file("lib/mix/tasks/emqx.proper.ex") + Mix.Task.run("emqx.proper", args) + end + + defp ensure_test_mix_env!() do + Mix.env() + |> to_string() + |> then(fn env -> + if String.ends_with?(env, "-test") do + env + else + env <> "-test" + end + end) + |> String.to_atom() + |> Mix.env() + end end diff --git a/scripts/check-nl-at-eof.sh b/scripts/check-nl-at-eof.sh index 8ca110c81..546ed7937 100755 --- a/scripts/check-nl-at-eof.sh +++ b/scripts/check-nl-at-eof.sh @@ -32,6 +32,8 @@ n=0 while read -r file; do if ! nl_at_eof "$file"; then echo "nl_at_eof: $file" + # shellcheck disable=SC1003 + sed -i -e '$a\' "$file" n=$(( n + 1 )) fi done < <(git ls-files)