1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2006-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(observer_SUITE). 22-include_lib("common_test/include/ct.hrl"). 23-include_lib("wx/include/wx.hrl"). 24-include_lib("observer/src/observer_tv.hrl"). 25 26-define(ID_LOGVIEW, 5). 27 28%% Test server specific exports 29-export([all/0, suite/0,groups/0]). 30-export([init_per_testcase/2, end_per_testcase/2, 31 init_per_group/2, end_per_group/2, 32 init_per_suite/1, end_per_suite/1 33 ]). 34 35%% Test cases 36-export([app_file/1, appup_file/1, 37 basic/1, process_win/1, table_win/1, 38 port_win_when_tab_not_initiated/1 39 ]). 40 41%% Default timetrap timeout (set in init_per_testcase) 42-define(default_timeout, ?t:minutes(2)). 43 44suite() -> [{timetrap, {minutes, 5}}, 45 {ct_hooks,[ts_install_cth]}]. 46 47all() -> 48 [app_file, appup_file, {group, gui}]. 49 50groups() -> 51 [{gui, [], 52 [basic, 53 process_win, 54 table_win, 55 port_win_when_tab_not_initiated 56 ] 57 }]. 58 59init_per_suite(Config) -> 60 Config. 61 62end_per_suite(_Config) -> 63 ok. 64 65init_per_testcase(_Case, Config) -> 66 Dog = ?t:timetrap(?default_timeout), 67 [{watchdog, Dog} | Config]. 68 69end_per_testcase(_Case, Config) -> 70 Dog = ?config(watchdog, Config), 71 ?t:timetrap_cancel(Dog), 72 ok. 73 74init_per_group(gui, Config) -> 75 try 76 case os:type() of 77 {unix,darwin} -> 78 exit("Can not test on MacOSX"); 79 {unix, _} -> 80 io:format("DISPLAY ~s~n", [os:getenv("DISPLAY")]), 81 case ct:get_config(xserver, none) of 82 none -> ignore; 83 Server -> os:putenv("DISPLAY", Server) 84 end; 85 _ -> ignore 86 end, 87 wx:new(), 88 wx:destroy(), 89 Config 90 catch 91 _:undef -> 92 {skipped, "No wx compiled for this platform"}; 93 _:Reason -> 94 SkipReason = io_lib:format("Start wx failed: ~p", [Reason]), 95 {skipped, lists:flatten(SkipReason)} 96 end. 97end_per_group(_, _) -> 98 ok. 99 100app_file(suite) -> 101 []; 102app_file(doc) -> 103 ["Testing .app file"]; 104app_file(Config) when is_list(Config) -> 105 ?line ok = ?t:app_test(observer), 106 ok. 107 108%% Testing .appup file 109appup_file(Config) when is_list(Config) -> 110 ok = ?t:appup_test(observer). 111 112-define(DBG(Foo), io:format("~p: ~p~n",[?LINE, catch Foo])). 113 114basic(suite) -> []; 115basic(doc) -> [""]; 116basic(Config) when is_list(Config) -> 117 %% Start these before 118 wx:new(), 119 wx:destroy(), 120 timer:send_after(100, "foobar"), 121 {foo, node@machine} ! dummy_msg, %% start distribution stuff 122 %% Otherwise ever lasting servers gets added to procs 123 ProcsBefore = processes(), 124 ProcInfoBefore = [{P,process_info(P)} || P <- ProcsBefore], 125 NumProcsBefore = length(ProcsBefore), 126 127 ok = observer:start(), 128 Notebook = setup_whitebox_testing(), 129 130 io:format("Notebook ~p~n",[Notebook]), 131 Count = wxNotebook:getPageCount(Notebook), 132 true = Count >= 6, 133 0 = wxNotebook:getSelection(Notebook), 134 timer:sleep(500), 135 Check = fun(N, TestMore) -> 136 TestMore andalso 137 test_page(wxNotebook:getPageText(Notebook, N), 138 wxNotebook:getCurrentPage(Notebook)), 139 timer:sleep(200), 140 ok = wxNotebook:advanceSelection(Notebook) 141 end, 142 %% Just verify that we can toggle through all pages 143 [_|_] = [Check(N, false) || N <- lists:seq(1, Count)], 144 %% Cause it to resize 145 Frame = get_top_level_parent(Notebook), 146 {W,H} = wxWindow:getSize(Frame), 147 wxWindow:setSize(Frame, W+10, H+10), 148 [_|_] = [Check(N, true) || N <- lists:seq(0, Count-1)], 149 150 ok = observer:stop(), 151 timer:sleep(2000), %% stop is async 152 ProcsAfter = processes(), 153 NumProcsAfter = length(ProcsAfter), 154 if NumProcsAfter=/=NumProcsBefore -> 155 BeforeNotAfter = ProcsBefore -- ProcsAfter, 156 ct:log("Before but not after:~n~p~n", 157 [[{P,I} || {P,I} <- ProcInfoBefore, 158 lists:member(P,BeforeNotAfter)]]), 159 ct:log("After but not before:~n~p~n", 160 [[{P,process_info(P)} || P <- ProcsAfter -- ProcsBefore]]), 161 ct:fail("leaking processes"); 162 true -> 163 ok 164 end, 165 ok. 166 167test_page("Load Charts" ++ _, _Window) -> 168 %% Just let it display some info and hopefully it doesn't crash 169 timer:sleep(2000), 170 ok; 171test_page("Applications" ++ _, _Window) -> 172 ok = application:start(mnesia), 173 timer:sleep(1000), %% Give it time to refresh 174 Active = get_active(), 175 FakeEv = #wx{event=#wxCommand{type=command_listbox_selected, cmdString="mnesia"}}, 176 Active ! FakeEv, 177 timer:sleep(1000), %% Give it time to refresh 178 ok = application:stop(mnesia), 179 timer:sleep(1000), %% Give it time to refresh 180 ok; 181 182test_page("Processes" ++ _, _Window) -> 183 timer:sleep(500), %% Give it time to refresh 184 Active = get_active(), 185 Active ! refresh_interval, 186 ChangeSort = fun(N) -> 187 FakeEv = #wx{event=#wxList{type=command_list_col_click, col=N}}, 188 Active ! FakeEv, 189 timer:sleep(200) 190 end, 191 [ChangeSort(N) || N <- lists:seq(1,5) ++ [0]], 192 Focus = #wx{event=#wxList{type=command_list_item_focused, itemIndex=2}}, 193 Active ! Focus, 194 Activate = #wx{event=#wxList{type=command_list_item_activated}}, 195 Active ! Activate, 196 timer:sleep(1000), %% Give it time to refresh 197 ok; 198 199test_page("Ports" ++ _, _Window) -> 200 timer:sleep(500), %% Give it time to refresh 201 Active = get_active(), 202 Active ! refresh_interval, 203 ChangeSort = fun(N) -> 204 FakeEv = #wx{event=#wxList{type=command_list_col_click, col=N}}, 205 Active ! FakeEv, 206 timer:sleep(200) 207 end, 208 [ChangeSort(N) || N <- lists:seq(1,4) ++ [0]], 209 Activate = #wx{event=#wxList{type=command_list_item_activated, 210 itemIndex=2}}, 211 Active ! Activate, 212 timer:sleep(1000), %% Give it time to refresh 213 ok; 214 215test_page("Table" ++ _, _Window) -> 216 Tables = [ets:new(list_to_atom("Test-" ++ [C]), [public]) || C <- lists:seq($A, $Z)], 217 Table = lists:nth(3, Tables), 218 ets:insert(Table, [{N,100-N} || N <- lists:seq(1,100)]), 219 220 Active = get_active(), 221 Active ! refresh_interval, 222 ChangeSort = fun(N) -> 223 FakeEv = #wx{event=#wxList{type=command_list_col_click, col=N}}, 224 Active ! FakeEv, 225 timer:sleep(200) 226 end, 227 [ChangeSort(N) || N <- lists:seq(1,5) ++ [0]], 228 timer:sleep(1000), 229 Focus = #wx{event=#wxList{type=command_list_item_selected, itemIndex=2}}, 230 Active ! Focus, 231 Activate = #wx{event=#wxList{type=command_list_item_activated, itemIndex=2}}, 232 Active ! Activate, 233 234 Info = 407, %% whitebox... 235 Active ! #wx{id=Info}, 236 timer:sleep(1000), 237 ok; 238 239test_page("Trace Overview" ++ _, _Window) -> 240 timer:sleep(500), %% Give it time to refresh 241 Active = get_active(), 242 Active ! refresh_interval, 243 timer:sleep(1000), %% Give it time to refresh 244 ok; 245 246test_page(Title, Window) -> 247 io:format("Page ~p: ~p~n", [Title, Window]), 248 %% Just let it display some info and hopefully it doesn't crash 249 timer:sleep(1000), 250 ok. 251 252 253process_win(suite) -> []; 254process_win(doc) -> [""]; 255process_win(Config) when is_list(Config) -> 256 % Stop SASL if already started 257 SaslStart = case whereis(sasl_sup) of 258 undefined -> false; 259 _ -> application:stop(sasl), 260 true 261 end, 262 % Define custom sasl and log_mf_h app vars 263 Privdir=?config(priv_dir,Config), 264 application:set_env(sasl, sasl_error_logger, tty), 265 application:set_env(sasl, error_logger_mf_dir, Privdir), 266 application:set_env(sasl, error_logger_mf_maxbytes, 1000), 267 application:set_env(sasl, error_logger_mf_maxfiles, 5), 268 application:start(sasl), 269 ok = observer:start(), 270 ObserverNB = setup_whitebox_testing(), 271 Parent = get_top_level_parent(ObserverNB), 272 % Activate log view 273 whereis(observer) ! #wx{id = ?ID_LOGVIEW, event = #wxCommand{type = command_menu_selected}}, 274 timer:sleep(1000), 275 % Process window tests (use sasl_sup for a non empty Log tab) 276 Frame = observer_procinfo:start(whereis(sasl_sup), Parent, self()), 277 PIPid = wx_object:get_pid(Frame), 278 PIPid ! {get_debug_info, self()}, 279 Notebook = receive {procinfo_debug, NB} -> NB end, 280 Count = wxNotebook:getPageCount(Notebook), 281 Check = fun(_N) -> 282 ok = wxNotebook:advanceSelection(Notebook), 283 timer:sleep(400) 284 end, 285 [_|_] = [Check(N) || N <- lists:seq(1, Count)], 286 PIPid ! #wx{event=#wxClose{type=close_window}}, 287 observer:stop(), 288 application:stop(sasl), 289 case SaslStart of 290 true -> application:start(sasl); 291 false -> ok 292 end, 293 ok. 294 295table_win(suite) -> []; 296table_win(doc) -> [""]; 297table_win(Config) when is_list(Config) -> 298 Tables = [ets:new(list_to_atom("Test-" ++ [C]), [public]) || C <- lists:seq($A, $Z)], 299 Table = lists:nth(3, Tables), 300 ets:insert(Table, [{N,100-N} || N <- lists:seq(1,100)]), 301 ok = observer:start(), 302 Notebook = setup_whitebox_testing(), 303 Parent = get_top_level_parent(Notebook), 304 TObj = observer_tv_table:start_link(Parent, [{node,node()}, {type,ets}, {table,#tab{name=foo, id=Table}}]), 305 %% Modal cannot test edit.. 306 %% TPid = wx_object:get_pid(TObj), 307 %% TPid ! #wx{event=#wxList{type=command_list_item_activated, itemIndex=12}}, 308 timer:sleep(3000), 309 wx_object:get_pid(TObj) ! #wx{event=#wxClose{type=close_window}}, 310 observer:stop(), 311 ok. 312 313%% Test PR-1296/OTP-14151 314%% Clicking a link to a port before the port tab has been activated the 315%% first time crashes observer. 316port_win_when_tab_not_initiated(_Config) -> 317 {ok,Port} = gen_tcp:listen(0,[]), 318 ok = observer:start(), 319 _Notebook = setup_whitebox_testing(), 320 observer ! {open_link,erlang:port_to_list(Port)}, 321 timer:sleep(1000), 322 observer:stop(), 323 ok. 324 325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 326 327get_top_level_parent(Window) -> 328 Parent = wxWindow:getParent(Window), 329 case wx:is_null(Parent) of 330 true -> Window; 331 false -> get_top_level_parent(Parent) 332 end. 333 334setup_whitebox_testing() -> 335 %% So that if we die observer exists 336 link(whereis(observer)), 337 {Env, Notebook, _Active} = get_observer_debug(), 338 wx:set_env(Env), 339 Notebook. 340 341get_active() -> 342 {_, _, Active} = get_observer_debug(), 343 Active. 344 345get_observer_debug() -> 346 observer ! {get_debug_info, self()}, 347 receive 348 {observer_debug, Env, Notebook, Active} -> 349 {Env, Notebook, Active} 350 end. 351