Merge lp:~stolowski/unity-scope-home/phone-disable-filters into lp:unity-scope-home

Proposed by Paweł Stołowski
Status: Merged
Approved by: Francis Ginther
Approved revision: 183
Merged at revision: 174
Proposed branch: lp:~stolowski/unity-scope-home/phone-disable-filters
Merge into: lp:unity-scope-home
Diff against target: 954 lines (+519/-154)
13 files modified
configure.ac (+1/-1)
src/platform-info.vala (+14/-11)
src/scope-registry.vala (+2/-1)
src/scope.vala (+18/-6)
src/search-util.vala (+0/-11)
tests/fake-server/samples/remote-scopes-minimal.txt (+1/-0)
tests/unit/Makefile.am (+14/-3)
tests/unit/data/unity/scopes/masterscope_a.scope (+2/-2)
tests/unit/data/unity/scopes/masterscope_b.scope (+2/-2)
tests/unit/data/unity/scopes/more_suggestions.scope (+17/-0)
tests/unit/data/unity/scopes/reference.scope (+33/-0)
tests/unit/test-home-scope.vala (+221/-117)
tests/unit/test-utils.vala (+194/-0)
To merge this branch: bzr merge lp:~stolowski/unity-scope-home/phone-disable-filters
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Michal Hruby (community) Approve
Review via email: mp+187021@code.launchpad.net

Commit message

Disable filter updates if phone factor is not 'desktop'.

Description of the change

Disable filter updates if phone factor is not 'desktop' (i.e. currently displayed categores are not reflected in the filters of Home view). This is required because UI in Unity 8 support single selection filters only (any selection made by the user will narrow results to single category in Home).

In addition, sort scope registry by scope id to give more sensible default order on the phone, until real category sorting works there.

To post a comment you must log in.
Revision history for this message
Michal Hruby (mhr3) wrote :

Could we see some tests for this? Not updating the filters seems a bit scary, does changing the query still reset them etc? Those things should be ensured by a test.

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Paweł Stołowski (stolowski) wrote :

> Could we see some tests for this? Not updating the filters seems a bit scary,
> does changing the query still reset them etc? Those things should be ensured
> by a test.

Right, that was a bug; fixed.

As much as I'd love to add a test for it, I don't see a way to do it with a reasonable amount of effort due to the number of prerequisites or mocks needed.

The point of this change is to disable updates of filters in the UI from the backend (which only Home Scope does). The logic that sets scopes to query from SSS recommendations, always-search scopes or default view stays.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

222 + echo $(nodist_test_home_scope_SOURCES)

Would be nice to get rid of it :)

418 + Process.close_pid (server_pid);

I think this frees the handle on some systems, yet it's used later in stop(), fortunately it's a noop on linux, anyway, better remove it (or move to destructor to have super-clean code).

519 + var proxy = acquire_test_proxy (HOME_SCOPE_DBUS_NAME, HOME_SCOPE_DBUS_PATH);
520 + var channel_id = open_channel (proxy, ChannelType.GLOBAL, null);
521 +
522 + assert (channel_id != null);

Looks like something that should go into setup() + close_channel() in teardown().

80 + string? form_factor = scope_search.search_context.search_metadata.form_factor;

Micro-optimisation - turn this into unowned string.

I know this was a hard fight, but it really opens doors to have more thorough testing of the entire home-scope codebase... Well done! :)

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michal Hruby (mhr3) wrote :

+1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

Autolanding failure caused by catching the archive in the middle of an update (hash sum mismatch). Re-approved.

Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'configure.ac'
--- configure.ac 2013-09-27 14:33:11 +0000
+++ configure.ac 2013-10-01 10:06:09 +0000
@@ -104,7 +104,7 @@
104####################################################################104####################################################################
105AC_ARG_ENABLE([headless-tests],105AC_ARG_ENABLE([headless-tests],
106 AS_HELP_STRING([--enable-headless-tests=@<:@no/yes@:>@],[enable headless test suite (requires Xvfb) @<:@default=no@:>@]),,106 AS_HELP_STRING([--enable-headless-tests=@<:@no/yes@:>@],[enable headless test suite (requires Xvfb) @<:@default=no@:>@]),,
107 [enable_headless_tests=no])107 [enable_headless_tests=yes])
108108
109AM_CONDITIONAL([ENABLE_HEADLESS_TESTS],[test "x$enable_headless_tests" != "xno"])109AM_CONDITIONAL([ENABLE_HEADLESS_TESTS],[test "x$enable_headless_tests" != "xno"])
110110
111111
=== modified file 'src/platform-info.vala'
--- src/platform-info.vala 2013-08-28 14:24:07 +0000
+++ src/platform-info.vala 2013-10-01 10:06:09 +0000
@@ -92,17 +92,20 @@
92 try92 try
93 {93 {
94 is_ready = false;94 is_ready = false;
95 var connection = yield Bus.get (BusType.SYSTEM, null);95 if (Environment.get_variable ("HOME_SCOPE_IGNORE_OFONO") == null)
96 var reply = yield connection.call ("org.ofono", "/ril_0",96 {
97 "org.ofono.SimManager",97 var connection = yield Bus.get (BusType.SYSTEM, null);
98 "GetProperties", null,98 var reply = yield connection.call ("org.ofono", "/ril_0",
99 new VariantType ("(a{sv})"),99 "org.ofono.SimManager",
100 DBusCallFlags.NONE, -1, null);100 "GetProperties", null,
101 reply = reply.get_child_value (0);101 new VariantType ("(a{sv})"),
102 var mcc_v = reply.lookup_value ("MobileCountryCode", VariantType.STRING);102 DBusCallFlags.NONE, -1, null);
103 var mnc_v = reply.lookup_value ("MobileNetworkCode", VariantType.STRING);103 reply = reply.get_child_value (0);
104 if (mcc_v != null) country_code = mcc_v.get_string ();104 var mcc_v = reply.lookup_value ("MobileCountryCode", VariantType.STRING);
105 if (mnc_v != null) network_code = mnc_v.get_string ();105 var mnc_v = reply.lookup_value ("MobileNetworkCode", VariantType.STRING);
106 if (mcc_v != null) country_code = mcc_v.get_string ();
107 if (mnc_v != null) network_code = mnc_v.get_string ();
108 }
106 }109 }
107 catch (Error err)110 catch (Error err)
108 {111 {
109112
=== modified file 'src/scope-registry.vala'
--- src/scope-registry.vala 2013-09-04 10:28:06 +0000
+++ src/scope-registry.vala 2013-10-01 10:06:09 +0000
@@ -119,7 +119,8 @@
119 // with remote scopes; we would need to wait for remote-scopes query to finish to know if119 // with remote scopes; we would need to wait for remote-scopes query to finish to know if
120 // if this master is needed for remote results.120 // if this master is needed for remote results.
121121
122 this.registry.append (node);122 // sort master scopes by scope_id
123 this.registry.insert_sorted (node, (node_a, node_b) => { return strcmp (node_a.scope_info.id, node_b.scope_info.id); });
123 master_to_node.insert (node.scope_info.id, node);124 master_to_node.insert (node.scope_info.id, node);
124 }125 }
125 else126 else
126127
=== modified file 'src/scope.vala'
--- src/scope.vala 2013-09-20 16:40:39 +0000
+++ src/scope.vala 2013-10-01 10:06:09 +0000
@@ -42,7 +42,7 @@
42 private FilterState filter_state = new FilterState ();42 private FilterState filter_state = new FilterState ();
43 private KeywordSearch keywords_search = new KeywordSearch ();43 private KeywordSearch keywords_search = new KeywordSearch ();
44 private bool smart_scopes_initialized = false;44 private bool smart_scopes_initialized = false;
45 private bool smart_scopes_ready = false;45 public bool smart_scopes_ready { get; internal set; default = false; }
46 private SmartScopes.SmartScopeClientInterface sss_client = null;46 private SmartScopes.SmartScopeClientInterface sss_client = null;
47 private SmartScopes.ChannelIdMap channel_id_map = new SmartScopes.ChannelIdMap ();47 private SmartScopes.ChannelIdMap channel_id_map = new SmartScopes.ChannelIdMap ();
48 private uint metrics_timer;48 private uint metrics_timer;
@@ -616,6 +616,13 @@
616 uint num_scopes = 0;616 uint num_scopes = 0;
617617
618 bool flushing_enabled = false;618 bool flushing_enabled = false;
619 unowned string? form_factor = scope_search.search_context.search_metadata.form_factor;
620 if (form_factor == null)
621 form_factor = "unknown"; // set to 'unknown' as it's sent with smart scopes request
622 bool disable_filter_updates = (form_factor != "desktop");
623
624 if (disable_filter_updates)
625 debug ("Filter updates disabled, form factor is %s", form_factor);
619626
620 // ids of scopes recommended by Smart Scope Service627 // ids of scopes recommended by Smart Scope Service
621 var recommended_search_scopes = new List<SmartScopes.RecommendedScope?> ();628 var recommended_search_scopes = new List<SmartScopes.RecommendedScope?> ();
@@ -711,6 +718,8 @@
711 unowned Unity.OptionsFilter categories_filter = scope_search.get_filter ("categories") as Unity.OptionsFilter;718 unowned Unity.OptionsFilter categories_filter = scope_search.get_filter ("categories") as Unity.OptionsFilter;
712 unowned Unity.OptionsFilter sources_filter = scope_search.get_filter ("sources") as Unity.OptionsFilter;719 unowned Unity.OptionsFilter sources_filter = scope_search.get_filter ("sources") as Unity.OptionsFilter;
713720
721 bool relations_changed = false;
722
714 // if query is empty but it's not just a filter change (i.e. state is REMOVES_FROM_PREVIOUS_QUERY or NEW_QUERY),723 // if query is empty but it's not just a filter change (i.e. state is REMOVES_FROM_PREVIOUS_QUERY or NEW_QUERY),
715 // then apply default user filters.724 // then apply default user filters.
716 if (empty_query && search_query_changed != SearchQueryChange.NOT_CHANGED)725 if (empty_query && search_query_changed != SearchQueryChange.NOT_CHANGED)
@@ -724,8 +733,12 @@
724 default_view = true;733 default_view = true;
725 }734 }
726735
727 debug ("Updating filter interrelationships");736 if (!disable_filter_updates) {
728 bool relations_changed = filter_state.update_filter_relations (scope_search.channel_id, categories_filter, sources_filter);737 debug ("Updating filter interrelationships");
738 relations_changed = filter_state.update_filter_relations (scope_search.channel_id, categories_filter, sources_filter);
739 } else {
740 needs_filter_update = false; //reset filter update flag if on the phone
741 }
729742
730 // caution: push_filter_settings may get cancelled if we ever yield before;743 // caution: push_filter_settings may get cancelled if we ever yield before;
731 // in such case internal filter state must be updated later (at the end of search).744 // in such case internal filter state must be updated later (at the end of search).
@@ -888,7 +901,6 @@
888 }901 }
889902
890 sss_query_started = true;903 sss_query_started = true;
891 var form_factor = SearchUtil.get_form_factor (scope_search);
892 sss_client.search.begin (search_string, form_factor, session_id, remote_scopes_to_query, scope_mgr.disabled_scopes,904 sss_client.search.begin (search_string, form_factor, session_id, remote_scopes_to_query, scope_mgr.disabled_scopes,
893 (scope_id, row) =>905 (scope_id, row) =>
894 {906 {
@@ -1024,7 +1036,7 @@
1024 use_recommended_scopes = true;1036 use_recommended_scopes = true;
10251037
1026 // only update filters with searched scopes when not in the default view, otherwise default view filters may get de-selected1038 // only update filters with searched scopes when not in the default view, otherwise default view filters may get de-selected
1027 if (!default_view)1039 if (!default_view && !disable_filter_updates)
1028 {1040 {
1029 debug ("Updating filter state");1041 debug ("Updating filter state");
1030 needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null,1042 needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null,
@@ -1108,7 +1120,7 @@
1108 }1120 }
11091121
1110 // update filter state again, but this time check result counts and send the update only if any of the highlighted masters has no results1122 // update filter state again, but this time check result counts and send the update only if any of the highlighted masters has no results
1111 if (!default_view)1123 if (!default_view && !disable_filter_updates)
1112 needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null, scope_search, filter_change_only == false);1124 needs_filter_update |= SearchUtil.update_filters (search_scopes, use_recommended_scopes ? recommended_search_scopes : null, scope_search, filter_change_only == false);
11131125
1114 if (needs_filter_update)1126 if (needs_filter_update)
11151127
=== modified file 'src/search-util.vala'
--- src/search-util.vala 2013-06-14 15:49:21 +0000
+++ src/search-util.vala 2013-10-01 10:06:09 +0000
@@ -317,15 +317,4 @@
317 }317 }
318 return found;318 return found;
319 }319 }
320
321 public string get_form_factor (Unity.AggregatedScopeSearch scope_search)
322 {
323 const string FORM_FACTOR_HINT = "form-factor";
324 unowned Variant? hint = scope_search.hints[FORM_FACTOR_HINT];
325 if (hint != null && hint.is_of_type (VariantType.STRING))
326 {
327 return hint.get_string ();
328 }
329 return "unknown";
330 }
331}320}
332321
=== added file 'tests/fake-server/samples/remote-scopes-minimal.txt'
--- tests/fake-server/samples/remote-scopes-minimal.txt 1970-01-01 00:00:00 +0000
+++ tests/fake-server/samples/remote-scopes-minimal.txt 2013-10-01 10:06:09 +0000
@@ -0,0 +1,1 @@
1[{"description": "This is an Ubuntu search plugin that enables information from Ubuntu One Music Store to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/7XpGFTkSugUON0PEsBBYHK", "name": "Ubuntu One Music Search", "keywords": ["u1ms", "u1", "ubuntuone"], "id": "more_suggestions-u1ms.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-u1.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Skimlinks to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/3VvxS1Dri9CKKloEzBs2lT", "name": "Skimlinks", "keywords": ["skimlinks"], "id": "more_suggestions-skimlinks.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/group-treat-yourself.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Wikipedia to be searched and displayed in the Dash underneath the Reference header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/4QiCFcHJS3fmDCMFvgi9lo", "name": "Wikipedia", "keywords": ["wikipedia", "wiki"], "id": "reference-wikipedia.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-wikipedia.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Wordnik to be searched and displayed in the Dash underneath the Reference header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/15gptcYAwD6vk53cUtOrvX", "name": "Dictionary", "keywords": ["define"], "id": "reference-dictionary.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-wordnik.svg"}, {"description": "Find themoviedb.org items", "screenshot": null, "name": "themoviedb.org", "keywords": ["themoviedb", "movie", "db", "actor", "cinema"], "id": "reference-themoviedb.scope", "icon": null}, {"description": "This is an Ubuntu search plugin that enables information from Amazon to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.\n", "screenshot": "http://ubuntuone.com/5apoKe0t8OOj1BQkWKnfWi", "name": "Amazon", "keywords": ["amazon"], "id": "more_suggestions-amazon.scope", "icon": "file:///usr/share/icons/unity-icon-theme/places/svg/service-amazon.svg"}, {"description": "This is an Ubuntu search plugin that enables information from Etsy to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.", "screenshot": null, "name": "Etsy", "keywords": ["etsy"], "id": "more_suggestions-etsy.scope", "icon": null}, {"description": "This is an Ubuntu search plugin that enables information from eBay to be searched and displayed in the Dash underneath the More Suggestions header. If you do not wish to search this content source, you can disable this search plugin.", "screenshot": null, "name": "eBay", "keywords": ["ebay"], "id": "more_suggestions-ebay.scope", "icon": null}, {"description": "Find Stackexchange items", "screenshot": null, "name": "Stackexchange", "keywords": ["stackexchange"], "id": "reference-stackexchange.scope", "icon": null}]
02
=== modified file 'tests/unit/Makefile.am'
--- tests/unit/Makefile.am 2013-06-11 15:36:38 +0000
+++ tests/unit/Makefile.am 2013-10-01 10:06:09 +0000
@@ -19,6 +19,7 @@
19 --pkg glib-2.0 \19 --pkg glib-2.0 \
20 --pkg json-glib-1.0 \20 --pkg json-glib-1.0 \
21 --pkg gee-1.0 \21 --pkg gee-1.0 \
22 --pkg unity-extras \
22 --vapidir $(srcdir) \23 --vapidir $(srcdir) \
23 --vapidir $(top_srcdir)/vapi \24 --vapidir $(top_srcdir)/vapi \
24 --target-glib=2.26 \25 --target-glib=2.26 \
@@ -36,7 +37,6 @@
3637
37AM_CPPFLAGS = \38AM_CPPFLAGS = \
38 -DDATADIR=\"$(DATADIR)\" \39 -DDATADIR=\"$(DATADIR)\" \
39 -DPKGDATADIR=\"$(PKGDATADIR)\" \
40 -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \40 -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
41 -DG_LOG_DOMAIN=\"unity-scope-home\" \41 -DG_LOG_DOMAIN=\"unity-scope-home\" \
42 $(HOME_SCOPE_CFLAGS) \42 $(HOME_SCOPE_CFLAGS) \
@@ -49,7 +49,7 @@
49 AM_CPPFLAGS += -w49 AM_CPPFLAGS += -w
50endif50endif
5151
52test_home_scope_VALASOURCES = \52MAINSOURCES = \
53 ../../src/scope.vala \53 ../../src/scope.vala \
54 ../../src/scope-manager.vala \54 ../../src/scope-manager.vala \
55 ../../src/keyword-search.vala \55 ../../src/keyword-search.vala \
@@ -74,11 +74,21 @@
74 ../../src/markup-cleaner.vala \74 ../../src/markup-cleaner.vala \
75 ../../src/master-scopes.vala \75 ../../src/master-scopes.vala \
76 ../../src/smart-scopes-preview-parser.vala \76 ../../src/smart-scopes-preview-parser.vala \
77 $(NULL)
78
79TEST_SOURCES = \
77 config-tests.vala \80 config-tests.vala \
81 test-utils.vala \
78 test-home-scope.vala \82 test-home-scope.vala \
79 $(NULL)83 $(NULL)
8084
81nodist_test_home_scope_SOURCES = $(test_home_scope_VALASOURCES:.vala=.c)85test_home_scope_VALASOURCES = $(TEST_SOURCES) $(MAINSOURCES)
86
87# the patsubst rule below and objects override are needed to force dependency on *.c files
88# generated in current test dir rather than on those from ../../src
89nodist_test_home_scope_SOURCES = $(TEST_SOURCES:.vala=.c) $(patsubst ../../src/%,%,$(MAINSOURCES:.vala=.c))
90nodist_test_home_scope_OBJECTS = $(nodist_test_home_scope_SOURCES:.c=.o)
91
8292
83CLEANFILES = *.stamp \93CLEANFILES = *.stamp \
84 *.c \94 *.c \
@@ -96,6 +106,7 @@
96 $(AM_V_GEN)$(VALAC) -C $(AM_VALAFLAGS) $(VALAFLAGS) $^106 $(AM_V_GEN)$(VALAC) -C $(AM_VALAFLAGS) $(VALAFLAGS) $^
97 @touch $@107 @touch $@
98108
109
99# START HEADLESS TESTS110# START HEADLESS TESTS
100if ENABLE_HEADLESS_TESTS111if ENABLE_HEADLESS_TESTS
101test-headless:112test-headless:
102113
=== renamed file 'tests/unit/data/client-scopes.json' => 'tests/unit/data/unity/client-scopes.json'
=== modified file 'tests/unit/data/unity/scopes/masterscope_a.scope'
--- tests/unit/data/unity/scopes/masterscope_a.scope 2013-01-23 10:48:55 +0000
+++ tests/unit/data/unity/scopes/masterscope_a.scope 2013-10-01 10:06:09 +0000
@@ -1,6 +1,6 @@
1[Scope]1[Scope]
2DBusName=com.canonical.Unity.Scope.MasterA2DBusName=com.canonical.Unity.Scope.HomeTest
3DBusPath=/com/canonical/unity/scope/mastera3DBusPath=/com/canonical/unity/masterscopes/mastera
4Icon=/usr/share/unity/6/icon1.svg4Icon=/usr/share/unity/6/icon1.svg
5IsMaster=true5IsMaster=true
6RequiredMetadata=some_id[s];foo[s];bar[y];6RequiredMetadata=some_id[s];foo[s];bar[y];
77
=== modified file 'tests/unit/data/unity/scopes/masterscope_b.scope'
--- tests/unit/data/unity/scopes/masterscope_b.scope 2013-01-23 10:48:55 +0000
+++ tests/unit/data/unity/scopes/masterscope_b.scope 2013-10-01 10:06:09 +0000
@@ -1,6 +1,6 @@
1[Scope]1[Scope]
2DBusName=com.canonical.Unity.Scope.MasterB2DBusName=com.canonical.Unity.Scope.HomeTest
3DBusPath=/com/canonical/unity/scope/masterb3DBusPath=/com/canonical/unity/masterscopes/masterb
4Icon=/usr/share/unity/6/icon2.svg4Icon=/usr/share/unity/6/icon2.svg
5IsMaster=true5IsMaster=true
6RequiredMetadata=bid[s];a[s];b[y];6RequiredMetadata=bid[s];a[s];b[y];
77
=== added file 'tests/unit/data/unity/scopes/more_suggestions.scope'
--- tests/unit/data/unity/scopes/more_suggestions.scope 1970-01-01 00:00:00 +0000
+++ tests/unit/data/unity/scopes/more_suggestions.scope 2013-10-01 10:06:09 +0000
@@ -0,0 +1,17 @@
1[Scope]
2DBusName=com.canonical.Unity.Scope.HomeTest
3DBusPath=/com/canonical/unity/masterscope/moresuggestions
4Icon=
5CategoryIcon=/usr/share/icons/unity-icon-theme/places/svg/group-treat-yourself.svg
6Name=More suggestions
7Type=moresug
8IsMaster=true
9
10[Desktop Entry]
11X-Ubuntu-Gettext-Domain=unity-scope-home
12
13[Category more_suggestions]
14Name=More suggestions
15Icon=
16SortField=uri
17
018
=== added file 'tests/unit/data/unity/scopes/reference.scope'
--- tests/unit/data/unity/scopes/reference.scope 1970-01-01 00:00:00 +0000
+++ tests/unit/data/unity/scopes/reference.scope 2013-10-01 10:06:09 +0000
@@ -0,0 +1,33 @@
1[Scope]
2DBusName=com.canonical.Unity.Scope.HomeTest
3DBusPath=/com/canonical/unity/masterscope/reference
4Icon=
5CategoryIcon=/usr/share/icons/unity-icon-theme/places/svg/group-reference.svg
6Name=Reference
7Type=reference
8IsMaster=true
9Keywords=reference;
10
11[Desktop Entry]
12X-Ubuntu-Gettext-Domain=unity-scope-home
13
14[Category encyclopedia]
15Name=Encyclopedia
16Icon=
17DedupField=uri
18
19[Category vocabulary]
20Name=Vocabulary
21Icon=
22DedupField=uri
23
24[Category scholar]
25Name=Scholar
26Icon=
27DedupField=uri
28
29[Category sources]
30Name=Sources
31Icon=
32DedupField=uri
33
034
=== modified file 'tests/unit/test-home-scope.vala'
--- tests/unit/test-home-scope.vala 2013-09-19 15:22:33 +0000
+++ tests/unit/test-home-scope.vala 2013-10-01 10:06:09 +0000
@@ -17,55 +17,77 @@
17 */17 */
1818
19using Unity.HomeScope.SmartScopes;19using Unity.HomeScope.SmartScopes;
20using Unity.Protocol;
2021
21namespace Unity.HomeScope22namespace Unity.HomeScope
22{23{
2324
25 static const string HOME_SCOPE_DBUS_NAME = "com.canonical.Unity.Scope.HomeTest";
26 static const string HOME_SCOPE_DBUS_PATH = "/com/canonical/unity/home";
27
24 bool verbose_debug = false;28 bool verbose_debug = false;
29
30 HomeScope? scope = null;
31 Application? app = null;
25 32
26 /* A bit of magic to get proper-ish fixture support */
27 public interface Fixture : Object
28 {
29 class DelegateWrapper
30 {
31 TestDataFunc func;
32 public DelegateWrapper (owned TestDataFunc f) { func = (owned) f; }
33 }
34
35 public virtual void setup () {}
36 public virtual void teardown () {}
37
38 [CCode (has_target = false)]
39 public delegate void Callback<T> (T ptr);
40
41 private static List<DelegateWrapper> _tests;
42
43 public static unowned TestDataFunc create<F> (Callback<void*> cb)
44 requires (typeof (F).is_a (typeof (Fixture)))
45 {
46 TestDataFunc functor = () =>
47 {
48 var type = typeof (F);
49 var instance = Object.new (type) as Fixture;
50 instance.setup ();
51 cb (instance);
52 instance.teardown ();
53 };
54 unowned TestDataFunc copy = functor;
55 _tests.append (new DelegateWrapper ((owned) functor));
56 return copy;
57 }
58 public static unowned TestDataFunc create_static<F> (Callback<F> cb)
59 {
60 return create<F> ((Callback<void*>) cb);
61 }
62 }
63
64 private KeywordSearch kw;33 private KeywordSearch kw;
65 const string[] RESULTS_SCHEMA = {"s", "s", "u", "u", "s", "s", "s", "s", "a{sv}"}; //TODO use schema def from libunity when it's public34 const string[] RESULTS_SCHEMA = {"s", "s", "u", "u", "s", "s", "s", "s", "a{sv}"}; //TODO use schema def from libunity when it's public
6635
36 public class FakeSmartScopesServer
37 {
38 private Rand rand = new Rand ();
39 private Pid server_pid;
40 public int server_port { get; internal set; }
41
42 public void start () throws SpawnError
43 {
44 server_port = rand.int_range (1024, 9000);
45
46 Process.spawn_async (null, {Config.TOPSRCDIR + "/tests/fake-server/fake-sss-server.py",
47 "--scopes", Config.TOPSRCDIR + "/tests/fake-server/samples/remote-scopes-minimal.txt",
48 "--search", Config.TESTRUNDATADIR + "/search.dump",
49 "--feedback", Config.TESTRUNDATADIR + "/feedback.dump",
50 "--requests", "6",
51 "--timeout", "15",
52 "--port", server_port.to_string (),
53 Config.TOPSRCDIR + "/tests/unit/data/search_results1.txt"},
54 null, 0, null, out server_pid);
55
56 Socket socket = new Socket (SocketFamily.IPV4, SocketType.STREAM, SocketProtocol.TCP);
57 assert (socket != null);
58
59 InetAddress addr = new InetAddress.from_bytes ({127, 0, 0, 1}, SocketFamily.IPV4);
60 InetSocketAddress server_addr = new InetSocketAddress (addr, (uint16)server_port);
61
62 bool conn = false;
63 int retry = 5;
64 while (!conn && retry > 0)
65 {
66 try
67 {
68 conn = socket.connect (server_addr);
69 }
70 catch (Error e) {}
71 if (!conn)
72 Thread.usleep (1*1000000); // sleep for 1 second
73 --retry;
74 }
75 }
76
77 public void stop ()
78 {
79 Posix.kill (server_pid, Posix.SIGTERM);
80 Process.close_pid (server_pid);
81 }
82 }
83
84 FakeSmartScopesServer fake_server;
85
67 public static int main (string[] args)86 public static int main (string[] args)
68 {87 {
88 Environment.set_variable ("GSETTINGS_BACKEND", "memory", true);
89 Environment.set_variable ("HOME_SCOPE_IGNORE_OFONO", "1", true);
90
69 var xdg_data_dirs = Environment.get_variable ("XDG_DATA_DIRS");91 var xdg_data_dirs = Environment.get_variable ("XDG_DATA_DIRS");
70 if (xdg_data_dirs == null) xdg_data_dirs = "/usr/share";92 if (xdg_data_dirs == null) xdg_data_dirs = "/usr/share";
71 Environment.set_variable ("XDG_DATA_DIRS",93 Environment.set_variable ("XDG_DATA_DIRS",
@@ -74,10 +96,14 @@
74 Environment.set_variable ("LIBUNITY_SCOPE_DIRECTORIES",96 Environment.set_variable ("LIBUNITY_SCOPE_DIRECTORIES",
75 "%s/unity/scopes".printf (Config.TESTDATADIR),97 "%s/unity/scopes".printf (Config.TESTDATADIR),
76 true);98 true);
99
100 fake_server = new FakeSmartScopesServer ();
101 fake_server.start ();
102
77 kw = new KeywordSearch ();103 kw = new KeywordSearch ();
78104
79 Test.init (ref args); 105 Test.init (ref args);
80106
81 Test.add_data_func ("/Unit/Search/ScopeRegistry", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_registry));107 Test.add_data_func ("/Unit/Search/ScopeRegistry", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_registry));
82 Test.add_data_func ("/Unit/Search/KeywordSearch", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_keyword_search));108 Test.add_data_func ("/Unit/Search/KeywordSearch", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_keyword_search));
83 Test.add_data_func ("/Unit/Search/SearchQueryState", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_search_query_state));109 Test.add_data_func ("/Unit/Search/SearchQueryState", Fixture.create<HomeScopeSearchTester> (HomeScopeSearchTester.test_search_query_state));
@@ -131,37 +157,153 @@
131 Test.add_data_func ("/Unit/MarkupCleaner/UnsupportedEntitiesAreRaw", Fixture.create<MarkupCleanerTester> (MarkupCleanerTester.test_unsupported_entities_are_raw));157 Test.add_data_func ("/Unit/MarkupCleaner/UnsupportedEntitiesAreRaw", Fixture.create<MarkupCleanerTester> (MarkupCleanerTester.test_unsupported_entities_are_raw));
132 Test.add_data_func ("/Unit/MarkupCleaner/NumericEntitiesArePreserved", Fixture.create<MarkupCleanerTester> (MarkupCleanerTester.test_num_entities_are_preserved));158 Test.add_data_func ("/Unit/MarkupCleaner/NumericEntitiesArePreserved", Fixture.create<MarkupCleanerTester> (MarkupCleanerTester.test_num_entities_are_preserved));
133159
134 var ml = new MainLoop ();160 Test.add_data_func ("/Unit/HomeScopeInstance/PhoneFilters", Fixture.create<HomeScopeInstanceTester> (HomeScopeInstanceTester.test_phone_filters));
135 ScopeRegistry.instance ().find_scopes.begin ((obj, res) =>161 Test.add_data_func ("/Unit/HomeScopeInstance/DesktopFilters", Fixture.create<HomeScopeInstanceTester> (HomeScopeInstanceTester.test_desktop_filters));
162
163 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (fake_server.server_port), true);
164
165 HomeScope.discover_scopes_sync ();
166
167 app = Extras.dbus_own_name (HOME_SCOPE_DBUS_NAME, () =>
136 {168 {
137 ScopeRegistry.instance ().find_scopes.end (res);169 scope = new HomeScope ();
138 kw.rebuild ();
139 ml.quit ();
140 });170 });
141 ml.run ();171 kw.rebuild ();
142 MetaScopeRegistry.instance ().update (ScopeRegistry.instance (), null);
143172
144 Test.run ();173 Test.run ();
145174
175 fake_server.stop ();
176
146 return 0;177 return 0;
147 }178 }
148 179
149 public static bool run_with_timeout (MainLoop ml, uint timeout_ms = 5000)180 class HomeScopeInstanceTester: Object, Fixture
150 {181 {
151 bool timeout_reached = false;182 ScopeProxy? proxy = null;
152 var t_id = Timeout.add (timeout_ms, () =>183 string channel_id;
153 {184
154 timeout_reached = true;185 private void setup ()
155 debug ("Timeout reached");186 {
156 ml.quit ();187 if (!scope.smart_scopes_ready) {
157 return false;188 var ml = new MainLoop ();
158 });189 scope.notify["smart_scopes_ready"].connect(() => { ml.quit (); });
159190 run_with_timeout (ml, 8);
160 ml.run ();191 }
161192
162 if (!timeout_reached) Source.remove (t_id);193 proxy = acquire_test_proxy (HOME_SCOPE_DBUS_NAME, HOME_SCOPE_DBUS_PATH);
163194 channel_id = open_channel (proxy, ChannelType.GLOBAL, null);
164 return !timeout_reached;195 assert (channel_id != null);
196 }
197
198 private void teardown ()
199 {
200 proxy.close_channel (channel_id, null);
201 proxy = null;
202 }
203
204 internal void test_phone_filters ()
205 {
206 // ignore warnings
207 Test.log_set_fatal_handler (() => { return false; });
208
209 bool got_filters_update = false;
210
211 proxy.filter_settings_changed.connect ((chid, filter_rows) => {
212 got_filters_update = true;
213 });
214
215 var hints = new HashTable<string, Variant> (str_hash, str_equal);
216 hints["form-factor"] = "phone";
217 perform_search (proxy, channel_id, "metallica", hints, null);
218
219 assert (got_filters_update == false); // we expect no filter updates on the phone
220 }
221
222 internal void test_desktop_filters ()
223 {
224 // ignore warnings
225 Test.log_set_fatal_handler (() => { return false; });
226
227 int got_filters_update = 0;
228
229 Variant? filters = null;
230 proxy.filter_settings_changed.connect ((chid, filter_rows) => {
231 got_filters_update += 1;
232 // note: there are 2 filter updates during search, but we care about the final value of filters
233 filters = filter_rows;
234 });
235
236 assert (channel_id != null);
237 assert (got_filters_update == 0);
238
239 wait_for_synchronization (proxy.filters_model);
240 assert (proxy.filters_model.get_n_rows () == 2);
241
242 // verify all filter options are initially inactive
243 int option_count = 0;
244 for (var iter = proxy.filters_model.get_first_iter (); iter != proxy.filters_model.get_last_iter (); iter = proxy.filters_model.next (iter))
245 {
246 var opts = proxy.filters_model.get_row (iter)[4].lookup_value ("options", null);
247 for (int i = 0; i<opts.n_children (); i++)
248 {
249 option_count += 1;
250 var opt = opts.get_child_value(i);
251 assert (opt.get_child_value (3).get_boolean () == false);
252 }
253 }
254
255 assert (option_count == 17);
256
257 var hints = new HashTable<string, Variant> (str_hash, str_equal);
258 hints["form-factor"] = "desktop";
259 perform_search (proxy, channel_id, "iron maiden", hints, null);
260
261 assert (got_filters_update == 2);
262 assert (filters.n_children() == 2); // two filters ('sources' and 'categories')
263 var src_filter = filters.get_child_value(0);
264 var cat_filter = filters.get_child_value(1);
265
266 // verify 'sources' filter
267 var opts = src_filter.get_child_value (4).lookup_value ("options", null);
268 var option_flags = new HashTable<string, bool>(str_hash, str_equal);
269
270 for (int i = 0; i<opts.n_children (); i++) // create scopeid -> enabled flag lookup for sources filter
271 {
272 var opt = opts.get_child_value(i);
273 option_flags[opt.get_child_value (0).get_string ()] = opt.get_child_value (3).get_boolean ();
274 }
275
276 assert (option_flags["reference-stackexchange.scope"] == false);
277 assert (option_flags["reference-dictionary.scope"] == false);
278 assert (option_flags["reference-themoviedb.scope"] == false);
279 assert (option_flags["masterscope_b-subscope1.scope"] == false);
280 assert (option_flags["masterscope_b-subscope2.scope"] == false);
281 assert (option_flags["masterscope_a-subscope1.scope"] == false);
282 assert (option_flags["masterscope_a-subscope2.scope"] == false);
283 assert (option_flags["more_suggestions-amazon.scope"] == false);
284 assert (option_flags["more_suggestions-etsy.scope"] == false);
285 assert (option_flags["more_suggestions-ebay.scope"] == false);
286 assert (option_flags["more_suggestions-skimlinks.scope"] == false);
287
288 assert (option_flags["more_suggestions-u1ms.scope"] == true);
289 assert (option_flags["reference-wikipedia.scope"] == true);
290
291 // verify 'categories' filter
292 opts = cat_filter.get_child_value (4).lookup_value ("options", null);
293 option_flags = new HashTable<string, bool>(str_hash, str_equal);
294
295 for (int i = 0; i<opts.n_children (); i++) // create scopeid -> enabled flag lookup for categories filter
296 {
297 var opt = opts.get_child_value(i);
298 option_flags[opt.get_child_value (0).get_string ()] = opt.get_child_value (3).get_boolean ();
299 }
300
301 assert (option_flags["masterscope_a.scope"] == false);
302 assert (option_flags["masterscope_b.scope"] == false);
303
304 assert (option_flags["more_suggestions.scope"] == true);
305 assert (option_flags["reference.scope"] == true);
306 }
165 }307 }
166308
167 class HomeScopeSearchTester: Object, Fixture309 class HomeScopeSearchTester: Object, Fixture
@@ -178,7 +320,7 @@
178 // scope registry is a singleton and is initialized in main on start320 // scope registry is a singleton and is initialized in main on start
179 var registry = ScopeRegistry.instance ();321 var registry = ScopeRegistry.instance ();
180 var scopes = registry.flatten ();322 var scopes = registry.flatten ();
181 assert (scopes.size == 6);323 assert (scopes.size == 8);
182 assert (scopes.contains ("masterscope_a.scope"));324 assert (scopes.contains ("masterscope_a.scope"));
183 assert (scopes.contains ("masterscope_b.scope"));325 assert (scopes.contains ("masterscope_b.scope"));
184 assert (scopes.contains ("masterscope_a-subscope1.scope"));326 assert (scopes.contains ("masterscope_a-subscope1.scope"));
@@ -189,7 +331,7 @@
189331
190 internal void test_keyword_search ()332 internal void test_keyword_search ()
191 {333 {
192 assert (kw.num_of_mappings == 8);334 assert (kw.num_of_mappings == 9);
193 string new_search_string;335 string new_search_string;
194336
195 assert (kw.process_query ("abcd: foobar", out new_search_string) == null); //unknown keyword, leave query as is337 assert (kw.process_query ("abcd: foobar", out new_search_string) == null); //unknown keyword, leave query as is
@@ -652,6 +794,7 @@
652 internal void test_smart_scopes_parse ()794 internal void test_smart_scopes_parse ()
653 {795 {
654 CategoryManager.instance ().register ("more_suggestions.scope");796 CategoryManager.instance ().register ("more_suggestions.scope");
797 CategoryManager.instance ().register ("reference.scope");
655798
656 int row_count = 0;799 int row_count = 0;
657 int recommend_count = 0;800 int recommend_count = 0;
@@ -783,6 +926,8 @@
783 internal void test_smart_scopes_on_chunk_data ()926 internal void test_smart_scopes_on_chunk_data ()
784 {927 {
785 CategoryManager.instance ().register ("more_suggestions.scope");928 CategoryManager.instance ().register ("more_suggestions.scope");
929 CategoryManager.instance ().register ("reference.scope");
930
786 int recommend_count = 0;931 int recommend_count = 0;
787 int result_count = 0;932 int result_count = 0;
788933
@@ -1003,7 +1148,7 @@
1003 installed.add ("scope2.scope");1148 installed.add ("scope2.scope");
1004 installed.add ("scope4.scope");1149 installed.add ("scope4.scope");
10051150
1006 var clinfo = ClientScopesInfo.from_file (Config.TOPSRCDIR + "/tests/unit/data/client-scopes.json", installed);1151 var clinfo = ClientScopesInfo.from_file (Config.TOPSRCDIR + "/tests/unit/data/unity/client-scopes.json", installed);
1007 var added = clinfo.get_added_scopes ();1152 var added = clinfo.get_added_scopes ();
1008 var removed = clinfo.get_removed_scopes ();1153 var removed = clinfo.get_removed_scopes ();
10091154
@@ -1062,59 +1207,12 @@
10621207
1063 class SmartScopesInterfaceTester: Object, Fixture1208 class SmartScopesInterfaceTester: Object, Fixture
1064 {1209 {
1065 private Rand rand = new Rand ();
1066 private Pid server_pid;
1067 private int server_port;
1068
1069 private void start_fake_server () throws SpawnError
1070 {
1071 server_port = rand.int_range (1024, 9000);
1072
1073 Process.spawn_async (null, {Config.TOPSRCDIR + "/tests/fake-server/fake-sss-server.py",
1074 "--scopes", Config.TOPSRCDIR + "/tests/fake-server/samples/remote-scopes.txt",
1075 "--search", Config.TESTRUNDATADIR + "/search.dump",
1076 "--feedback", Config.TESTRUNDATADIR + "/feedback.dump",
1077 "--requests", "2",
1078 "--timeout", "5",
1079 "--port", server_port.to_string (),
1080 Config.TOPSRCDIR + "/tests/unit/data/search_results1.txt"},
1081 null, 0, null, out server_pid);
1082
1083 Socket socket = new Socket (SocketFamily.IPV4, SocketType.STREAM, SocketProtocol.TCP);
1084 assert (socket != null);
1085
1086 InetAddress addr = new InetAddress.from_bytes ({127, 0, 0, 1}, SocketFamily.IPV4);
1087 InetSocketAddress server_addr = new InetSocketAddress (addr, (uint16)server_port);
1088
1089 bool conn = false;
1090 int retry = 5;
1091 while (!conn && retry > 0)
1092 {
1093 try
1094 {
1095 conn = socket.connect (server_addr);
1096 }
1097 catch (Error e) {}
1098 if (!conn)
1099 Thread.usleep (1*1000000); // sleep for 1 second
1100 --retry;
1101 }
1102 Process.close_pid (server_pid);
1103 }
1104
1105 private void setup ()
1106 {
1107 start_fake_server ();
1108 }
1109
1110 private void teardown ()
1111 {
1112 Posix.kill (server_pid, Posix.SIGTERM);
1113 }
1114
1115 internal void test_smart_scopes_client_iface_search ()1210 internal void test_smart_scopes_client_iface_search ()
1116 {1211 {
1117 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (server_port), true);1212 // ignore warnings
1213 Test.log_set_fatal_handler (() => { return false; });
1214
1215 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (fake_server.server_port), true);
1118 var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"});1216 var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"});
1119 var client = new SmartScopes.SmartScopesClient (pinfo);1217 var client = new SmartScopes.SmartScopesClient (pinfo);
1120 var session_id = "5d06cc10-751b-11e2-87e0-fb468b0a185a";1218 var session_id = "5d06cc10-751b-11e2-87e0-fb468b0a185a";
@@ -1159,7 +1257,10 @@
11591257
1160 internal void test_smart_scopes_client_iface_metrics ()1258 internal void test_smart_scopes_client_iface_metrics ()
1161 {1259 {
1162 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (server_port), true);1260 // ignore warnings
1261 Test.log_set_fatal_handler (() => { return false; });
1262
1263 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:%d".printf (fake_server.server_port), true);
1163 var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"});1264 var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"});
1164 var client = new SmartScopes.SmartScopesClient (pinfo);1265 var client = new SmartScopes.SmartScopesClient (pinfo);
1165 var session_id = "5d06cc10-751b-11e2-87e0-fb468b0a185a";1266 var session_id = "5d06cc10-751b-11e2-87e0-fb468b0a185a";
@@ -1245,6 +1346,9 @@
12451346
1246 internal void test_smart_scopes_client_iface_error ()1347 internal void test_smart_scopes_client_iface_error ()
1247 {1348 {
1349 // ignore warnings
1350 Test.log_set_fatal_handler (() => { return false; });
1351
1248 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:9999", true); // non-existing server (connection failure)1352 Environment.set_variable ("SMART_SCOPES_SERVER", "http://127.0.0.1:9999", true); // non-existing server (connection failure)
1249 var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"});1353 var pinfo = new SmartScopes.PlatformInfo.with_data ("1304", "EN", {"scope1"}, {"scope3"});
1250 var client = new SmartScopes.SmartScopesClient (pinfo);1354 var client = new SmartScopes.SmartScopesClient (pinfo);
12511355
=== added file 'tests/unit/test-utils.vala'
--- tests/unit/test-utils.vala 1970-01-01 00:00:00 +0000
+++ tests/unit/test-utils.vala 2013-10-01 10:06:09 +0000
@@ -0,0 +1,194 @@
1/*
2 * Copyright (C) 2011-2013 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by Michal Hruby <michal.hruby@canonical.com>
17 *
18 */
19
20using Unity.Protocol;
21
22public static bool run_with_timeout (MainLoop ml, uint timeout_ms = 5000)
23{
24 bool timeout_reached = false;
25 var t_id = Timeout.add (timeout_ms, () =>
26 {
27 timeout_reached = true;
28 debug ("Timeout reached");
29 ml.quit ();
30 return false;
31 });
32
33 ml.run ();
34
35 if (!timeout_reached) Source.remove (t_id);
36
37 return !timeout_reached;
38}
39
40/* A bit of magic to get proper-ish fixture support */
41public interface Fixture : Object
42{
43 class DelegateWrapper
44 {
45 TestDataFunc func;
46 public DelegateWrapper (owned TestDataFunc f) { func = (owned) f; }
47 }
48
49 public virtual void setup () {}
50 public virtual void teardown () {}
51
52 [CCode (has_target = false)]
53 public delegate void Callback<T> (T ptr);
54
55 private static List<DelegateWrapper> _tests;
56
57 public static unowned TestDataFunc create<F> (Callback<void*> cb)
58 requires (typeof (F).is_a (typeof (Fixture)))
59 {
60 TestDataFunc functor = () =>
61 {
62 var type = typeof (F);
63 var instance = Object.new (type) as Fixture;
64 instance.setup ();
65 cb (instance);
66 instance.teardown ();
67 };
68 unowned TestDataFunc copy = functor;
69 _tests.append (new DelegateWrapper ((owned) functor));
70 return copy;
71 }
72 public static unowned TestDataFunc create_static<F> (Callback<F> cb)
73 {
74 return create<F> ((Callback<void*>) cb);
75 }
76}
77
78// this will auto-disconnect signals when it goes out of scope
79public class SignalWrapper
80{
81 unowned Object obj;
82 ulong sig_id;
83
84 public SignalWrapper (Object o, ulong signal_id)
85 {
86 obj = o;
87 sig_id = signal_id;
88 }
89
90 ~SignalWrapper ()
91 {
92 SignalHandler.disconnect (obj, sig_id);
93 }
94}
95
96public static ScopeProxy? acquire_test_proxy (string name, string path)
97{
98 var ml = new MainLoop ();
99 ScopeProxy? proxy = null;
100 ScopeProxy.new_from_dbus.begin (name, path, null, (obj, res) =>
101 {
102 try
103 {
104 proxy = ScopeProxy.new_from_dbus.end (res);
105 }
106 catch (Error e) {}
107 ml.quit ();
108 });
109 assert (run_with_timeout (ml));
110 return proxy;
111}
112
113public static void wait_for_synchronization (Dee.Model model)
114{
115 var shared_model = model as Dee.SharedModel;
116 if (shared_model == null) return;
117
118 if (shared_model.is_synchronized ()) return;
119 SignalWrapper[] signals = {};
120 var ml = new MainLoop ();
121
122 signals += new SignalWrapper (shared_model,
123 shared_model.notify["synchronized"].connect (() =>
124 {
125 ml.quit ();
126 }));
127
128 run_with_timeout (ml);
129}
130
131public static string open_channel (ScopeProxy proxy,
132 ChannelType channel_type,
133 out Dee.SerializableModel model,
134 bool wait_for_sync = false,
135 ChannelFlags flags = 0)
136{
137 string? channel_id = null;
138 Dee.Model? real_model = null;
139 var ml = new MainLoop ();
140 /* Need to use PRIVATE channel, cause standard SharedModel won't
141 * synchronize properly when trying to connect to the model
142 * from the same process (/bus address) */
143 proxy.open_channel.begin (channel_type,
144 flags | ChannelFlags.PRIVATE,
145 null,
146 (obj, res) =>
147 {
148 try
149 {
150 channel_id = proxy.open_channel.end (res, out real_model);
151 if (wait_for_sync)
152 {
153 wait_for_synchronization (real_model);
154 }
155 ml.quit ();
156 }
157 catch (Error err)
158 {
159 ml.quit ();
160 }
161 });
162
163 assert (run_with_timeout (ml));
164 assert (channel_id != null);
165 model = real_model as Dee.SerializableModel;
166 return channel_id;
167}
168
169public static HashTable<string, Variant> perform_search (
170 ScopeProxy proxy, string channel_id, string query,
171 HashTable<string, Variant>? hints = null,
172 Dee.SerializableModel? model = null)
173{
174 var ml = new MainLoop ();
175 HashTable<string, Variant>? reply_dict = null;
176 proxy.search.begin (channel_id, query,
177 hints ?? new HashTable<string, Variant> (null, null),
178 null,
179 (obj, res) =>
180 {
181 try
182 {
183 reply_dict = proxy.search.end (res);
184 }
185 catch (Error err) {}
186 ml.quit ();
187 });
188
189 bool got_search_signal = false;
190
191 assert (run_with_timeout (ml, 10000));
192 assert (reply_dict != null);
193 return reply_dict;
194}

Subscribers

People subscribed via source and target branches

to all changes: