Merge lp:~mhr3/libunity/test-tool into lp:libunity
- test-tool
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Didier Roche-Tolomelli |
Approved revision: | 118 |
Merged at revision: | 116 |
Proposed branch: | lp:~mhr3/libunity/test-tool |
Merge into: | lp:libunity |
Diff against target: |
580 lines (+548/-0) 4 files modified
Makefile.am (+1/-0) configure.ac (+1/-0) tools/Makefile.am (+54/-0) tools/unity-tool.vala (+492/-0) |
To merge this branch: | bzr merge lp:~mhr3/libunity/test-tool |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Didier Roche-Tolomelli | Approve | ||
Mikkel Kamstrup Erlandsen (community) | Needs Fixing | ||
Review via email: mp+91027@code.launchpad.net |
Commit message
Description of the change
Added unity-lens-
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
More bits:
314 + catch (Error err)
315 + {
316 + warning ("%s", err.message);
317 + return 1;
318 + }
Can this just do print ("unity-tool: %s", er.message); instead of warning()? The G logging systems appends some odd debugging info (like filename and line) that seems out of place for these messages.
And, the --test-server-mode; can we have a more descriptive string somehow? Maybe ala "Run a collection of test scripts"
Michal Hruby (mhr3) wrote : | # |
Pushed fixes.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Perfect! (almost :-))
191 + "Run a collection of test sceripts", null
Michal Hruby (mhr3) wrote : | # |
And... fixed!
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
On the one!
Unity Merger (unity-merger) wrote : | # |
The Jenkins job https:/
Not merging it.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
The bot reports:
dh_install: usr/bin/unity-tool exists in debian/tmp but is not installed to anywhere
dh_install: missing files, aborting
We should ping Didier to have unity-tool handled.
Didier Roche-Tolomelli (didrocks) wrote : | # |
You wanted it? You got it! (It's installed in libunity-dev package now)
Preview Diff
1 | === modified file 'Makefile.am' |
2 | --- Makefile.am 2011-11-28 09:28:37 +0000 |
3 | +++ Makefile.am 2012-02-02 08:34:18 +0000 |
4 | @@ -2,6 +2,7 @@ |
5 | data \ |
6 | src \ |
7 | bindings \ |
8 | + tools \ |
9 | doc \ |
10 | examples \ |
11 | test \ |
12 | |
13 | === modified file 'configure.ac' |
14 | --- configure.ac 2012-01-12 15:13:36 +0000 |
15 | +++ configure.ac 2012-02-02 08:34:18 +0000 |
16 | @@ -164,6 +164,7 @@ |
17 | doc/reference/Makefile |
18 | examples/Makefile |
19 | src/Makefile |
20 | +tools/Makefile |
21 | test/Makefile |
22 | test/C/Makefile |
23 | test/vala/Makefile |
24 | |
25 | === added directory 'tools' |
26 | === added file 'tools/Makefile.am' |
27 | --- tools/Makefile.am 1970-01-01 00:00:00 +0000 |
28 | +++ tools/Makefile.am 2012-02-02 08:34:18 +0000 |
29 | @@ -0,0 +1,54 @@ |
30 | +NULL = |
31 | +BUILT_SOURCES = |
32 | +CLEANFILES = |
33 | +EXTRA_DIST = |
34 | + |
35 | +bin_PROGRAMS = \ |
36 | + unity-tool |
37 | + |
38 | +unity_tool_CPPFLAGS = \ |
39 | + -DG_LOG_DOMAIN=\"unity-tool\" \ |
40 | + -I$(srcdir) \ |
41 | + $(LIBUNITY_CFLAGS) |
42 | + |
43 | +if !ENABLE_C_WARNINGS |
44 | + unity_tool_CPPFLAGS += -w |
45 | +endif |
46 | + |
47 | +if ENABLE_TRACE_LOG |
48 | + unity_tool_CPPFLAGS += -DENABLE_UNITY_TRACE_LOG |
49 | +endif |
50 | + |
51 | +unity_tool_LDADD = \ |
52 | + $(LIBUNITY_LIBS) |
53 | + |
54 | +unity_tool_VALAFLAGS = \ |
55 | + -C \ |
56 | + --vapidir $(top_srcdir)/vapi \ |
57 | + --pkg config \ |
58 | + $(LIBUNITY_PACKAGES) |
59 | + $(MAINTAINER_VALAFLAGS) |
60 | + |
61 | +unity_tool_VALASOURCES = \ |
62 | + unity-tool.vala \ |
63 | + $(NULL) |
64 | + |
65 | +unity_tool_SOURCES = \ |
66 | + $(unity_tool_VALASOURCES:.vala=.c) \ |
67 | + $(NULL) |
68 | + |
69 | +BUILT_SOURCES += unity_tool_vala.stamp |
70 | +EXTRA_DIST += \ |
71 | + $(BUILT_SOURCES) \ |
72 | + $(unity_tool_VALASOURCES) \ |
73 | + $(NULL) |
74 | + |
75 | +unity_tool_vala.stamp: $(unity_tool_VALASOURCES) |
76 | + $(AM_V_GEN) $(VALAC) $(unity_tool_VALAFLAGS) $^ |
77 | + @touch $@ |
78 | + |
79 | +CLEANFILES += \ |
80 | + *.stamp \ |
81 | + $(unity_tool_VALASOURCES:.vala=.c) \ |
82 | + $(NULL) |
83 | + |
84 | |
85 | === added file 'tools/unity-tool.vala' |
86 | --- tools/unity-tool.vala 1970-01-01 00:00:00 +0000 |
87 | +++ tools/unity-tool.vala 2012-02-02 08:34:18 +0000 |
88 | @@ -0,0 +1,492 @@ |
89 | +/* |
90 | + * Copyright (C) 2012 Canonical Ltd |
91 | + * |
92 | + * This program is free software: you can redistribute it and/or modify |
93 | + * it under the terms of the GNU General Public License version 3 as |
94 | + * published by the Free Software Foundation. |
95 | + * |
96 | + * This program is distributed in the hope that it will be useful, |
97 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
98 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
99 | + * GNU General Public License for more details. |
100 | + * |
101 | + * You should have received a copy of the GNU General Public License |
102 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
103 | + * |
104 | + * Authored by Michal Hruby <michal.hruby@canonical.com> |
105 | + * |
106 | + */ |
107 | + |
108 | +namespace Unity.Tester |
109 | +{ |
110 | + namespace Options |
111 | + { |
112 | + public static string lens_dbus_name; |
113 | + public static string lens_dbus_path; |
114 | + public static string lens_file; |
115 | + public static string search_string; |
116 | + public static int search_type; |
117 | + public static bool common_tests; |
118 | + public static bool no_search_reply; |
119 | + public static bool dump_results; |
120 | + public static bool dump_filters; |
121 | + |
122 | + public static bool test_server_mode; |
123 | + public static string[] test_cases; |
124 | + } |
125 | + |
126 | + namespace TestRunner |
127 | + { |
128 | + public static string[] test_cases; |
129 | + public static int test_index; |
130 | + } |
131 | + |
132 | + public errordomain TesterError |
133 | + { |
134 | + INVALID_ARGS |
135 | + } |
136 | + |
137 | + public struct LensInfo |
138 | + { |
139 | + public string dbus_path; |
140 | + public bool search_in_global; |
141 | + public bool visible; |
142 | + public string search_hint; |
143 | + public string private_connection_name; |
144 | + public string results_model_name; |
145 | + public string global_results_model_name; |
146 | + public string categories_model_name; |
147 | + public string filters_model_name; |
148 | + public HashTable<string, Variant> hints; |
149 | + } |
150 | + |
151 | + const OptionEntry[] options = |
152 | + { |
153 | + { |
154 | + "dbus-name", 'n', 0, OptionArg.STRING, out Options.lens_dbus_name, |
155 | + "Unique dbus name of the tested lens", null |
156 | + }, |
157 | + { |
158 | + "dbus-path", 'p', 0, OptionArg.STRING, out Options.lens_dbus_path, |
159 | + "Object path of the lens", null |
160 | + }, |
161 | + { |
162 | + "lens-file", 'l', 0, OptionArg.STRING, out Options.lens_file, |
163 | + "Path to the lens file (to read out dbus name and path)", null |
164 | + }, |
165 | + { |
166 | + "common-tests", 'c', 0, OptionArg.NONE, out Options.common_tests, |
167 | + "Perform common tests each lens should conform to", null |
168 | + }, |
169 | + { |
170 | + "search", 's', 0, OptionArg.STRING, out Options.search_string, |
171 | + "Search string to send to the lens", null |
172 | + }, |
173 | + { |
174 | + "search-type", 't', 0, OptionArg.INT, out Options.search_type, |
175 | + "Type of the search (value from Unity.SearchType enum)", null |
176 | + }, |
177 | + { |
178 | + "dump-results", 'r', 0, OptionArg.NONE, out Options.dump_results, |
179 | + "Output the results model on stdout", null |
180 | + }, |
181 | + { |
182 | + "dump-filters", 'f', 0, OptionArg.NONE, out Options.dump_filters, |
183 | + "Output the filter model on stdout", null |
184 | + }, |
185 | + { |
186 | + "no-search-reply", 0, 0, OptionArg.NONE, out Options.no_search_reply, |
187 | + "Don't output reply of the search call", null |
188 | + }, |
189 | + { |
190 | + "test-server-mode", 0, 0, OptionArg.NONE, out Options.test_server_mode, |
191 | + "Run a collection of test scripts", null |
192 | + }, |
193 | + { |
194 | + "", 0, 0, OptionArg.FILENAME_ARRAY, out Options.test_cases, |
195 | + "Invididual test cases", "<test-scripts>" |
196 | + }, |
197 | + { |
198 | + null |
199 | + } |
200 | + }; |
201 | + |
202 | + public static void warn (string format, ...) |
203 | + { |
204 | + var args = va_list (); |
205 | + logv ("unity-tool", LogLevelFlags.LEVEL_WARNING, format, args); |
206 | + } |
207 | + |
208 | + public static int main (string[] args) |
209 | + { |
210 | + Environment.set_prgname ("unity-tool"); |
211 | + var opt_context = new OptionContext (" - Unity tool"); |
212 | + opt_context.add_main_entries (options, null); |
213 | + |
214 | + try |
215 | + { |
216 | + if (args.length <= 1) |
217 | + { |
218 | + print ("%s\n", opt_context.get_help (true, null)); |
219 | + return 0; |
220 | + } |
221 | + |
222 | + opt_context.parse (ref args); |
223 | + if (Options.test_server_mode) |
224 | + { |
225 | + if (Options.test_cases == null || |
226 | + (Options.test_cases.length=(int)strv_length(Options.test_cases)) == 0) |
227 | + { |
228 | + throw new TesterError.INVALID_ARGS ("No test cases specified"); |
229 | + } |
230 | + |
231 | + // special mode where we just run test scripts inside a directory |
232 | + string[] test_scripts = get_test_cases (); |
233 | + TestRunner.test_cases = test_scripts; |
234 | + |
235 | + Test.init (ref args); |
236 | + foreach (unowned string test_case in test_scripts) |
237 | + { |
238 | + Test.add_data_func ("/Integration/LensTest/" + |
239 | + Path.get_basename (test_case), |
240 | + () => |
241 | + { |
242 | + string test = TestRunner.test_cases[TestRunner.test_index++]; |
243 | + int status; |
244 | + try |
245 | + { |
246 | + Process.spawn_command_line_sync (test, |
247 | + null, |
248 | + null, |
249 | + out status); |
250 | + } |
251 | + catch (Error e) |
252 | + { |
253 | + warn ("%s", e.message); |
254 | + status = -1; |
255 | + } |
256 | + assert (status == 0); |
257 | + }); |
258 | + } |
259 | + return Test.run (); |
260 | + } |
261 | + else |
262 | + { |
263 | + // read dbus name and path from the lens file |
264 | + if (Options.lens_file != null) |
265 | + { |
266 | + var keyfile = new KeyFile (); |
267 | + keyfile.load_from_file (Options.lens_file, 0); |
268 | + |
269 | + Options.lens_dbus_name = keyfile.get_string ("Lens", "DBusName"); |
270 | + Options.lens_dbus_path = keyfile.get_string ("Lens", "DBusPath"); |
271 | + } |
272 | + |
273 | + // check that we have dbus names |
274 | + if (Options.lens_dbus_name == null || Options.lens_dbus_path == null) |
275 | + { |
276 | + throw new TesterError.INVALID_ARGS ("Lens DBus name and path not specified!"); |
277 | + } |
278 | + |
279 | + if (Options.common_tests) |
280 | + { |
281 | + int status = run_common_tests (); |
282 | + assert (status == 0); |
283 | + } |
284 | + |
285 | + // Performing search |
286 | + if (Options.search_string != null) |
287 | + { |
288 | + var ml = new MainLoop (); |
289 | + |
290 | + call_lens_search (Options.search_string, |
291 | + Options.search_type, |
292 | + (result) => |
293 | + { |
294 | + if (!Options.no_search_reply) |
295 | + print ("%s\n", result.print (true)); |
296 | + ml.quit (); |
297 | + }); |
298 | + |
299 | + assert (run_with_timeout (ml, 15000)); |
300 | + } |
301 | + |
302 | + // Dumping models |
303 | + if (Options.dump_results || Options.dump_filters) |
304 | + { |
305 | + LensInfo li = get_lens_info (); |
306 | + |
307 | + if (Options.dump_results) |
308 | + { |
309 | + var model_name = Options.search_type == 0 ? |
310 | + li.results_model_name : li.global_results_model_name; |
311 | + var model = new Dee.SharedModel (model_name); |
312 | + sync_model (model); |
313 | + |
314 | + dump_results_model (model); |
315 | + } |
316 | + |
317 | + if (Options.dump_filters) |
318 | + { |
319 | + var model = new Dee.SharedModel (li.filters_model_name); |
320 | + sync_model (model); |
321 | + |
322 | + dump_filters_model (model); |
323 | + } |
324 | + } |
325 | + } |
326 | + } |
327 | + catch (Error err) |
328 | + { |
329 | + warn ("%s", err.message); |
330 | + return 1; |
331 | + } |
332 | + |
333 | + |
334 | + return 0; |
335 | + } |
336 | + |
337 | + public static string[] get_test_cases () |
338 | + { |
339 | + string[] results = {}; |
340 | + foreach (string path in Options.test_cases) |
341 | + { |
342 | + if (FileUtils.test (path, FileTest.IS_REGULAR) && |
343 | + FileUtils.test (path, FileTest.IS_EXECUTABLE)) |
344 | + { |
345 | + results += path; |
346 | + } |
347 | + else if (FileUtils.test (path, FileTest.IS_DIR)) |
348 | + { |
349 | + try |
350 | + { |
351 | + var dir = Dir.open (path); |
352 | + unowned string name = dir.read_name (); |
353 | + while (name != null) |
354 | + { |
355 | + var child_path = Path.build_filename (path, name, null); |
356 | + if (FileUtils.test (child_path, FileTest.IS_REGULAR) && |
357 | + FileUtils.test (child_path, FileTest.IS_EXECUTABLE)) |
358 | + { |
359 | + results += child_path; |
360 | + } |
361 | + |
362 | + name = dir.read_name (); |
363 | + } |
364 | + } catch (Error e) { warn ("%s", e.message); } |
365 | + } |
366 | + } |
367 | + |
368 | + return results; |
369 | + } |
370 | + |
371 | + public static bool run_with_timeout (MainLoop ml, uint timeout_ms) |
372 | + { |
373 | + bool timeout_reached = false; |
374 | + var t_id = Timeout.add (timeout_ms, () => |
375 | + { |
376 | + timeout_reached = true; |
377 | + debug ("Timeout reached"); |
378 | + ml.quit (); |
379 | + return false; |
380 | + }); |
381 | + |
382 | + ml.run (); |
383 | + |
384 | + if (!timeout_reached) Source.remove (t_id); |
385 | + |
386 | + return !timeout_reached; |
387 | + } |
388 | + |
389 | + private static int run_common_tests () |
390 | + { |
391 | + string[] args = { "./unity-tool" }; |
392 | + unowned string[] dummy = args; |
393 | + |
394 | + Test.init (ref dummy); |
395 | + |
396 | + // checks that lens emits finished signal for every search type |
397 | + // (and both empty and non-empty searches) |
398 | + Test.add_data_func ("/Integration/LensTest/DefaultSearch/Empty", () => |
399 | + { |
400 | + var ml = new MainLoop (); |
401 | + call_lens_search ("", 0, () => { ml.quit (); }); |
402 | + if (!run_with_timeout (ml, 20000)) warn ("Lens didn't respond"); |
403 | + }); |
404 | + |
405 | + Test.add_data_func ("/Integration/LensTest/DefaultSearch/NonEmpty", () => |
406 | + { |
407 | + var ml = new MainLoop (); |
408 | + call_lens_search ("a", 0, () => { ml.quit (); }); |
409 | + if (!run_with_timeout (ml, 20000)) warn ("Lens didn't respond"); |
410 | + }); |
411 | + |
412 | + // check also non-empty -> empty search |
413 | + Test.add_data_func ("/Integration/LensTest/DefaultSearch/Empty2", () => |
414 | + { |
415 | + var ml = new MainLoop (); |
416 | + call_lens_search ("", 0, () => { ml.quit (); }); |
417 | + if (!run_with_timeout (ml, 20000)) warn ("Lens didn't respond"); |
418 | + }); |
419 | + |
420 | + Test.add_data_func ("/Integration/LensTest/GlobalSearch/Empty", () => |
421 | + { |
422 | + var ml = new MainLoop (); |
423 | + call_lens_search ("", 1, () => { ml.quit (); }); |
424 | + if (!run_with_timeout (ml, 20000)) warn ("Lens didn't respond"); |
425 | + }); |
426 | + |
427 | + Test.add_data_func ("/Integration/LensTest/GlobalSearch/NonEmpty", () => |
428 | + { |
429 | + var ml = new MainLoop (); |
430 | + call_lens_search ("a", 1, () => { ml.quit (); }); |
431 | + if (!run_with_timeout (ml, 20000)) warn ("Lens didn't respond"); |
432 | + }); |
433 | + |
434 | + // check also non-empty -> empty search |
435 | + Test.add_data_func ("/Integration/LensTest/GlobalSearch/Empty2", () => |
436 | + { |
437 | + var ml = new MainLoop (); |
438 | + call_lens_search ("", 1, () => { ml.quit (); }); |
439 | + if (!run_with_timeout (ml, 20000)) warn ("Lens didn't respond"); |
440 | + }); |
441 | + |
442 | + return Test.run (); |
443 | + } |
444 | + |
445 | + private static void call_lens_search (string search_string, |
446 | + int search_type, |
447 | + Func<Variant?>? cb = null) |
448 | + { |
449 | + var vb = new VariantBuilder (new VariantType ("(sa{sv})")); |
450 | + vb.add ("s", search_string); |
451 | + vb.open (new VariantType ("a{sv}")); |
452 | + vb.close (); |
453 | + |
454 | + try |
455 | + { |
456 | + var bus = Bus.get_sync (BusType.SESSION); |
457 | + |
458 | + bus.call.begin (Options.lens_dbus_name, |
459 | + Options.lens_dbus_path, |
460 | + "com.canonical.Unity.Lens", |
461 | + search_type == 0 ? "Search" : "GlobalSearch", |
462 | + vb.end (), |
463 | + null, |
464 | + 0, |
465 | + -1, |
466 | + null, |
467 | + (obj, res) => |
468 | + { |
469 | + try |
470 | + { |
471 | + var reply = bus.call.end (res); |
472 | + if (cb != null) cb (reply); |
473 | + } |
474 | + catch (Error e) |
475 | + { |
476 | + warn ("%s", e.message); |
477 | + } |
478 | + }); |
479 | + } |
480 | + catch (Error e) { warn ("%s", e.message); } |
481 | + } |
482 | + |
483 | + private static LensInfo get_lens_info () |
484 | + { |
485 | + |
486 | + var ml = new MainLoop (); |
487 | + LensInfo info = LensInfo (); |
488 | + |
489 | + try |
490 | + { |
491 | + var bus = Bus.get_sync (BusType.SESSION); |
492 | + var sig_id = bus.signal_subscribe (null, |
493 | + "com.canonical.Unity.Lens", |
494 | + "Changed", |
495 | + Options.lens_dbus_path, |
496 | + null, |
497 | + 0, |
498 | + (conn, sender, obj_path, ifc_name, sig_name, parameters) => |
499 | + { |
500 | + info = (LensInfo) parameters.get_child_value (0); |
501 | + ml.quit (); |
502 | + }); |
503 | + bus.call.begin (Options.lens_dbus_name, |
504 | + Options.lens_dbus_path, |
505 | + "com.canonical.Unity.Lens", |
506 | + "InfoRequest", |
507 | + null, |
508 | + null, |
509 | + 0, |
510 | + -1, |
511 | + null, |
512 | + null); |
513 | + |
514 | + if (!run_with_timeout (ml, 5000)) warn ("Unable to get LensInfo!"); |
515 | + |
516 | + bus.signal_unsubscribe (sig_id); |
517 | + } |
518 | + catch (Error e) { warn ("%s", e.message); } |
519 | + |
520 | + return info; |
521 | + } |
522 | + |
523 | + private void sync_model (Dee.SharedModel model) |
524 | + { |
525 | + while (!model.synchronized) |
526 | + { |
527 | + var ml = new MainLoop (); |
528 | + var sig_id = model.notify["synchronized"].connect ( |
529 | + () => { ml.quit (); } |
530 | + ); |
531 | + ml.run (); |
532 | + SignalHandler.disconnect (model, sig_id); |
533 | + } |
534 | + } |
535 | + |
536 | + private void dump_results_model (Dee.Model model) |
537 | + { |
538 | + var iter = model.get_first_iter (); |
539 | + var last_iter = model.get_last_iter (); |
540 | + |
541 | + while (iter != last_iter) |
542 | + { |
543 | + var row = model.get_row (iter); |
544 | + print ("%s\t%s\t%u\t%s\t%s\t%s\t%s\n", |
545 | + row[0].get_string (), |
546 | + row[1].get_string (), |
547 | + row[2].get_uint32 (), |
548 | + row[3].get_string (), |
549 | + row[4].get_string (), |
550 | + row[5].get_string (), |
551 | + row[6].get_string () |
552 | + ); |
553 | + |
554 | + iter = model.next (iter); |
555 | + } |
556 | + } |
557 | + |
558 | + private void dump_filters_model (Dee.Model model) |
559 | + { |
560 | + var iter = model.get_first_iter (); |
561 | + var last_iter = model.get_last_iter (); |
562 | + |
563 | + while (iter != last_iter) |
564 | + { |
565 | + var row = model.get_row (iter); |
566 | + print ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", |
567 | + row[0].get_string (), |
568 | + row[1].get_string (), |
569 | + row[2].get_string (), |
570 | + row[3].get_string (), |
571 | + row[4].print (true), |
572 | + row[5].get_boolean ().to_string (), |
573 | + row[6].get_boolean ().to_string (), |
574 | + row[7].get_boolean ().to_string () |
575 | + ); |
576 | + |
577 | + iter = model.next (iter); |
578 | + } |
579 | + } |
580 | +} |
Looking really good, and fun to play with :-D
Some remarks:
- I'd like to use this binary as a generic place to shove Unity cli introspection and instrumentation for all future needs we are goona have, hence I'd like to rename it to something more generic like 'unity-tool'. This way it can possibly also satisfy cli junkies' desire to drive unity from the command line
- When running the executable without arguments could you dump the -h info instead? That seems to be the general pattern for cli tools
- the --common-tests suite is just insanely awesome, let's be mindful of adding any general tests we can come up with there
- about --test-server-mode; it's not clear to me what this does? And running the tool with it just reports "No test cases specified"