JianBo He 4 лет назад
Родитель
Сommit
fca5a3bc21

+ 15 - 1
apps/emqx_gateway/src/emqx_gateway_api_clients.erl

@@ -532,7 +532,21 @@ params_client_searching_in_qs() ->
     , {lte_connected_at,
        mk(binary(),
           M#{desc => <<"Match the client socket connected datatime less than "
-                       " a certain value">>})}
+                       "a certain value">>})}
+    , {endpoint_name,
+       mk(binary(),
+          M#{desc => <<"Match the lwm2m client's endpoint name">>})}
+    , {like_endpoint_name,
+       mk(binary(),
+          M#{desc => <<"Use sub-string to match lwm2m client's endpoint name">>})}
+    , {gte_lifetime,
+       mk(binary(),
+          M#{desc => <<"Match the lwm2m client registered lifetime greater "
+                        "than a certain value">>})}
+    , {lte_lifetime,
+       mk(binary(),
+          M#{desc => <<"Match the lwm2m client registered lifetime less than "
+                       "a certain value">>})}
     ].
 
 params_paging() ->

+ 30 - 24
apps/emqx_gateway/src/emqx_gateway_cli.erl

@@ -50,18 +50,24 @@ is_cmd(Fun) ->
 %% Cmds
 
 gateway(["list"]) ->
-    lists:foreach(fun(#{name := Name} = Gateway) ->
-        %% TODO: More infos: listeners?, connected?
-        Status = maps:get(status, Gateway, stopped),
-        print("Gateway(name=~ts, status=~ts)~n", [Name, Status])
-    end, emqx_gateway:list());
+    lists:foreach(
+      fun (#{name := Name, status := unloaded}) ->
+            print("Gateway(name=~ts, status=unloaded)\n", [Name]);
+          (#{name := Name, status := stopped, stopped_at := StoppedAt}) ->
+            print("Gateway(name=~ts, status=stopped, stopped_at=~ts)\n",
+                  [Name, StoppedAt]);
+          (#{name := Name, status := running, current_connections := ConnCnt,
+             started_at := StartedAt}) ->
+            print("Gateway(name=~ts, status=running, clients=~w, started_at=~ts)\n",
+                  [Name, ConnCnt, StartedAt])
+    end, emqx_gateway_http:gateways(all));
 
 gateway(["lookup", Name]) ->
     case emqx_gateway:lookup(atom(Name)) of
         undefined ->
-            print("undefined~n");
+            print("undefined\n");
         Info ->
-            print("~p~n", [Info])
+            print("~p\n", [Info])
     end;
 
 gateway(["load", Name, Conf]) ->
@@ -70,17 +76,17 @@ gateway(["load", Name, Conf]) ->
            emqx_json:decode(Conf, [return_maps])
           ) of
         {ok, _} ->
-            print("ok~n");
+            print("ok\n");
         {error, Reason} ->
-            print("Error: ~p~n", [Reason])
+            print("Error: ~p\n", [Reason])
     end;
 
 gateway(["unload", Name]) ->
     case emqx_gateway_conf:unload_gateway(bin(Name)) of
         ok ->
-            print("ok~n");
+            print("ok\n");
         {error, Reason} ->
-            print("Error: ~p~n", [Reason])
+            print("Error: ~p\n", [Reason])
     end;
 
 gateway(["stop", Name]) ->
@@ -89,9 +95,9 @@ gateway(["stop", Name]) ->
            #{<<"enable">> => <<"false">>}
           ) of
         {ok, _} ->
-            print("ok~n");
+            print("ok\n");
         {error, Reason} ->
-            print("Error: ~p~n", [Reason])
+            print("Error: ~p\n", [Reason])
     end;
 
 gateway(["start", Name]) ->
@@ -100,9 +106,9 @@ gateway(["start", Name]) ->
            #{<<"enable">> => <<"true">>}
           ) of
         {ok, _} ->
-            print("ok~n");
+            print("ok\n");
         {error, Reason} ->
-            print("Error: ~p~n", [Reason])
+            print("Error: ~p\n", [Reason])
     end;
 
 gateway(_) ->
@@ -123,7 +129,7 @@ gateway(_) ->
 'gateway-registry'(["list"]) ->
     lists:foreach(
       fun({Name, #{cbkmod := CbMod}}) ->
-        print("Registered Name: ~ts, Callback Module: ~ts~n", [Name, CbMod])
+        print("Registered Name: ~ts, Callback Module: ~ts\n", [Name, CbMod])
       end,
     emqx_gateway_registry:list());
 
@@ -137,15 +143,15 @@ gateway(_) ->
     InfoTab = emqx_gateway_cm:tabname(info, Name),
     case ets:info(InfoTab) of
         undefined ->
-            print("Bad Gateway Name.~n");
+            print("Bad Gateway Name.\n");
         _ ->
-        dump(InfoTab, client)
+            dump(InfoTab, client)
     end;
 
 'gateway-clients'(["lookup", Name, ClientId]) ->
     ChanTab = emqx_gateway_cm:tabname(chan, Name),
     case ets:lookup(ChanTab, bin(ClientId)) of
-        [] -> print("Not Found.~n");
+        [] -> print("Not Found.\n");
         [Chann] ->
             InfoTab = emqx_gateway_cm:tabname(info, Name),
             [ChannInfo] = ets:lookup(InfoTab, Chann),
@@ -154,8 +160,8 @@ gateway(_) ->
 
 'gateway-clients'(["kick", Name, ClientId]) ->
     case emqx_gateway_cm:kick_session(Name, bin(ClientId)) of
-        ok -> print("ok~n");
-        _ -> print("Not Found.~n")
+        ok -> print("ok\n");
+        _ -> print("Not Found.\n")
     end;
 
 'gateway-clients'(_) ->
@@ -171,11 +177,11 @@ gateway(_) ->
     Tab = emqx_gateway_metrics:tabname(Name),
     case ets:info(Tab) of
         undefined ->
-            print("Bad Gateway Name.~n");
+            print("Bad Gateway Name.\n");
         _ ->
             lists:foreach(
               fun({K, V}) ->
-                print("~-30s: ~w~n", [K, V])
+                print("~-30s: ~w\n", [K, V])
               end, lists:sort(ets:tab2list(Tab)))
     end;
 
@@ -232,7 +238,7 @@ print_record({client, {_, Infos, Stats}}) ->
     print("Client(~ts, username=~ts, peername=~ts, "
           "clean_start=~ts, keepalive=~w, "
           "subscriptions=~w, delivered_msgs=~w, "
-          "connected=~ts, created_at=~w, connected_at=~w)~n",
+          "connected=~ts, created_at=~w, connected_at=~w)\n",
           [format(K, maps:get(K, Info)) || K <- InfoKeys]).
 
 print(S) -> emqx_ctl:print(S).

+ 150 - 0
apps/emqx_gateway/test/emqx_gateway_cli_SUITE.erl

@@ -0,0 +1,150 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%%     http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%--------------------------------------------------------------------
+
+-module(emqx_gateway_cli_SUITE).
+
+-compile(export_all).
+-compile(nowarn_export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-define(GP(S), begin S, receive {fmt, P} -> P; O -> O end end).
+
+%% this parses to #{}, will not cause config cleanup
+%% so we will need call emqx_config:erase
+-define(CONF_DEFAULT, <<"
+gateway {}
+">>).
+
+%%--------------------------------------------------------------------
+%% Setup
+%%--------------------------------------------------------------------
+
+all() -> emqx_common_test_helpers:all(?MODULE).
+
+init_per_suite(Conf) ->
+    emqx_config:erase(gateway),
+    emqx_config:init_load(emqx_gateway_schema, ?CONF_DEFAULT),
+    emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_authn, emqx_gateway]),
+    Conf.
+
+end_per_suite(Conf) ->
+    emqx_mgmt_api_test_util:end_suite([emqx_gateway, emqx_authn, emqx_conf]),
+    Conf.
+
+init_per_testcase(_, Conf) ->
+    Self = self(),
+    ok = meck:new(emqx_ctl, [passthrough, no_history, no_link]),
+    ok = meck:expect(emqx_ctl, usage,
+                     fun(L) -> emqx_ctl:format_usage(L) end),
+    ok = meck:expect(emqx_ctl, print,
+                     fun(Fmt) ->
+                        Self ! {fmt, emqx_ctl:format(Fmt)}
+                     end),
+    ok = meck:expect(emqx_ctl, print,
+                     fun(Fmt, Args) ->
+                        Self ! {fmt, emqx_ctl:format(Fmt, Args)}
+                     end),
+    Conf.
+
+end_per_testcase(_, _) ->
+    meck:unload([emqx_ctl]),
+    ok.
+
+%%--------------------------------------------------------------------
+%% Cases
+%%--------------------------------------------------------------------
+
+%% TODO:
+
+t_load_unload(_) ->
+    ok.
+
+t_gateway_registry_usage(_) ->
+    ?assertEqual(
+       ["gateway-registry list # List all registered gateways\n"],
+       emqx_gateway_cli:'gateway-registry'(usage)).
+
+t_gateway_registry_list(_) ->
+    emqx_gateway_cli:'gateway-registry'(["list"]),
+    ?assertEqual(
+       "Registered Name: coap, Callback Module: emqx_coap_impl\n"
+       "Registered Name: exproto, Callback Module: emqx_exproto_impl\n"
+       "Registered Name: lwm2m, Callback Module: emqx_lwm2m_impl\n"
+       "Registered Name: mqttsn, Callback Module: emqx_sn_impl\n"
+       "Registered Name: stomp, Callback Module: emqx_stomp_impl\n"
+       , acc_print()).
+
+t_gateway_usage(_) ->
+    ?assertEqual(
+       ["gateway list                     # List all gateway\n",
+        "gateway lookup <Name>            # Lookup a gateway detailed informations\n",
+        "gateway load   <Name> <JsonConf> # Load a gateway with config\n",
+        "gateway unload <Name>            # Unload the gateway\n",
+        "gateway stop   <Name>            # Stop the gateway\n",
+        "gateway start  <Name>            # Start the gateway\n"],
+       emqx_gateway_cli:gateway(usage)
+     ).
+
+t_gateway_list(_) ->
+    emqx_gateway_cli:gateway(["list"]),
+    ?assertEqual(
+      "Gateway(name=coap, status=unloaded)\n"
+      "Gateway(name=exproto, status=unloaded)\n"
+      "Gateway(name=lwm2m, status=unloaded)\n"
+      "Gateway(name=mqttsn, status=unloaded)\n"
+      "Gateway(name=stomp, status=unloaded)\n"
+      , acc_print()).
+
+t_gateway_load(_) ->
+    ok.
+
+t_gateway_unload(_) ->
+    ok.
+
+t_gateway_start(_) ->
+    ok.
+
+t_gateway_stop(_) ->
+    ok.
+
+t_gateway_clients_usage(_) ->
+    ok.
+
+t_gateway_clients_list(_) ->
+    ok.
+
+t_gateway_clients_lookup(_) ->
+    ok.
+
+t_gateway_clients_kick(_) ->
+    ok.
+
+t_gateway_metrcis_usage(_) ->
+    ok.
+
+t_gateway_metrcis(_) ->
+    ok.
+
+acc_print() ->
+    lists:concat(lists:reverse(acc_print([]))).
+
+acc_print(Acc) ->
+    receive
+        {fmt, S} -> acc_print([S|Acc])
+    after 200 ->
+        Acc
+    end.