Merge lp:~marcustomlinson/unity-scopes-api/metadata_isaggregator_attr into lp:unity-scopes-api/devel

Proposed by Marcus Tomlinson
Status: Merged
Approved by: Michi Henning
Approved revision: 568
Merged at revision: 555
Proposed branch: lp:~marcustomlinson/unity-scopes-api/metadata_isaggregator_attr
Merge into: lp:unity-scopes-api/devel
Prerequisite: lp:~marcustomlinson/unity-scopes-api/rename_tags_to_keywords
Diff against target: 565 lines (+114/-6)
20 files modified
CONFIGFILES (+4/-0)
RELEASE_NOTES.md (+2/-1)
STRUCTS (+1/-0)
debian/changelog (+3/-2)
debian/libunity-scopes3.symbols (+5/-0)
include/unity/scopes/ScopeMetadata.h (+6/-0)
include/unity/scopes/internal/ScopeConfig.h (+2/-0)
include/unity/scopes/internal/ScopeMetadataImpl.h (+3/-0)
include/unity/scopes/testing/ScopeMetadataBuilder.h (+1/-0)
scoperegistry/scoperegistry.cpp (+1/-0)
src/scopes/ScopeMetadata.cpp (+5/-0)
src/scopes/internal/ScopeConfig.cpp (+17/-1)
src/scopes/internal/ScopeMetadataImpl.cpp (+29/-0)
src/scopes/testing/ScopeMetadataBuilder.cpp (+9/-0)
test/gtest/scopes/Registry/Registry_test.cpp (+2/-0)
test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in (+1/-0)
test/gtest/scopes/internal/ScopeConfig/ScopeConfig_test.cpp (+3/-0)
test/gtest/scopes/internal/ScopeConfig/complete_config.ini.in (+1/-0)
test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp (+16/-1)
test/gtest/scopes/testing/IsolatedScope/IsolatedScope_test.cpp (+3/-1)
To merge this branch: bzr merge lp:~marcustomlinson/unity-scopes-api/metadata_isaggregator_attr
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Michi Henning (community) Approve
Review via email: mp+243518@code.launchpad.net

Commit message

Added support for IsAggregator scope .ini option.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michi Henning (michihenning) wrote :

Looks fine, but don't we need to distinguish SAs from GAs in the shell? In particular, how do we prevent the creation of loops with GAs? My suggestion was to never allow a GA to aggregate another GA. That way, loops are not possible, assuming that SAs won't ever aggregate from a GA. I suspect we may need to put some special magic in place to guarantee this can't happen.

But, to me, it looks like we really need and enum for this attribute, not a boolean?

review: Needs Information
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

> Looks fine, but don't we need to distinguish SAs from GAs in the shell? In
> particular, how do we prevent the creation of loops with GAs? My suggestion
> was to never allow a GA to aggregate another GA. That way, loops are not
> possible, assuming that SAs won't ever aggregate from a GA. I suspect we may
> need to put some special magic in place to guarantee this can't happen.
>
> But, to me, it looks like we really need and enum for this attribute, not a
> boolean?

Had a chat with the others in the standup this morning and there is a majority vote not to differentiate between GAs and SAs (at least not via this attribute). The general consensus is that we should keep the interface as generic as possible without introducing a concept of different kinds of aggregators. I think if there is any way to avoid this, we should. Our current design allows for the aggregator type to be transparent.

About the infinite loop thing. I don't see a way we can entirely avoid this as an SA may aggregate another SA that aggregates its parent again. Now that we're intruding aggregation via tags, this becomes quite possible unfortunately. I think this problem really doesn't have anything to do with what type of aggregator is involved. Its really a separate issue we need to address. The consensus of the team is to implement a simple hop count with a limit. I do believe we still have the problem whereby too many layers of aggregation will cause a deadlock from thread starvation, so we should probably implement this anyway (https://bugs.launchpad.net/ubuntu/+source/unity-scopes-api/+bug/1360281)

Revision history for this message
Michi Henning (michihenning) wrote :

For SA's, we are probably a lot safer, because these aren't constructed willy-nilly on the fly.

For GA's, I think that's a real problem. What is this going to look like to the user? They make an aggregator that introduces a loop, and the queries will time out, without producing results, most likely. The user gets to see something that simply doesn't work, with no real idea of how to diagnose or remedy the problem.

Too many layers cannot cause deadlock. Rather, they'll cause queries to time out.

Even if we have loop detection of some kind, how should it behave? Detecting the loop doesn't solve the problem because, when we detect a loop, the user is still presented with a query that doesn't work. What we would need isn't loop detection, but "loop repair". The only way to fix this that I can see would be to track all scopes that are currently involved in a query and, if a subquery() goes to a scope that is already in the loop, not forward that subquery.

Doing this will be somewhat intrusive. At the very least, we would need a change at the protocol level that adds the IDs of all scopes involved so far to the search request on the wire.

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

> For SA's, we are probably a lot safer, because these aren't constructed willy-
> nilly on the fly.
>
> For GA's, I think that's a real problem. What is this going to look like to
> the user? They make an aggregator that introduces a loop, and the queries will
> time out, without producing results, most likely. The user gets to see
> something that simply doesn't work, with no real idea of how to diagnose or
> remedy the problem.
>
> Too many layers cannot cause deadlock. Rather, they'll cause queries to time
> out.
>
> Even if we have loop detection of some kind, how should it behave? Detecting
> the loop doesn't solve the problem because, when we detect a loop, the user is
> still presented with a query that doesn't work. What we would need isn't loop
> detection, but "loop repair". The only way to fix this that I can see would be
> to track all scopes that are currently involved in a query and, if a
> subquery() goes to a scope that is already in the loop, not forward that
> subquery.
>
> Doing this will be somewhat intrusive. At the very least, we would need a
> change at the protocol level that adds the IDs of all scopes involved so far
> to the search request on the wire.

So the issue here is that aggregators can cause loops. I don't see that its really a problem specific to GAs or SAs. Now that we're introducing the concept of aggregation by keywords, SAs too become vulnerable to loops created on the fly.

Consider a News SA that aggregates all scopes with the keyword "news". Then we create a Ubuntu News SA (tagged "news") that also aggregates all scope with the keyword "news" but forwards the query "Ubuntu" to each. Perhaps the Ubuntu News scope also pushes some of its own unique results.

With the "loop repair" approach we will end up with the News scope showing only the unique results from Ubuntu News, and we won't see the Ubuntu News scope appearing under the Ubuntu News itself. That sounds like a pretty cool result.

So yeah, I'm leaning towards us implementing loop repair.

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Actually, its only the aggregators (identified by this config key) that we need to keep in the list of visited scopes. Looking back at my previous example, I think its totally valid that the Ubuntu News scope shows its "Ubuntu" specific results of the same leaf scopes its parent (News) has.

So the second-to-last paragraph of my last comment will change to:

With the "loop repair" approach we will end up with the News scope showing all of its regular child scopes' results, along with an "Ubuntu News" category under which all the "Ubuntu" specific results for the same children are shown. We also won't see the Ubuntu News scope appearing under Ubuntu News itself, nor the News scope showing under News either.

Revision history for this message
Michi Henning (michihenning) wrote :

OK, sounds like a boolean will do in conjunction with detecting and axing off cycles.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
568. By Marcus Tomlinson

Merged devel and resolved conflicts

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michi Henning (michihenning) wrote :

OK, tests pass, so I assume the conflict resolution didn't break anything :-)

review: Approve
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
1=== modified file 'CONFIGFILES'
2--- CONFIGFILES 2014-12-03 07:31:22 +0000
3+++ CONFIGFILES 2014-12-08 08:09:05 +0000
4@@ -411,6 +411,10 @@
5
6 Note: make sure there are no trailing spaces following the keywords, as they will be preserved.
7
8+- IsAggregator
9+
10+ Whether the scope is an aggregator. The default value is false.
11+
12
13 The following keys are recognized in the Appearance group:
14
15
16=== modified file 'RELEASE_NOTES.md'
17--- RELEASE_NOTES.md 2014-12-03 06:53:40 +0000
18+++ RELEASE_NOTES.md 2014-12-08 08:09:05 +0000
19@@ -3,7 +3,8 @@
20
21 Changes in version 0.6.10
22 =========================
23- - Renamed "Tags" scope .ini option to "Keywords"
24+ - Renamed "Tags" scope .ini option to "Keywords".
25+ - Added support for IsAggregator scope .ini option.
26
27 Changes in version 0.6.9
28 ========================
29
30=== modified file 'STRUCTS'
31--- STRUCTS 2014-12-03 07:31:22 +0000
32+++ STRUCTS 2014-12-08 08:09:05 +0000
33@@ -80,6 +80,7 @@
34 'child_scopes' : array of strings, optional
35 'version' : int, optional
36 'keywords' : array of strings, optional
37+ 'is_aggregator' : bool, optional
38
39 Query (returned by serialize())
40 ===============================
41
42=== modified file 'debian/changelog'
43--- debian/changelog 2014-12-03 06:53:40 +0000
44+++ debian/changelog 2014-12-08 08:09:05 +0000
45@@ -1,8 +1,9 @@
46 unity-scopes-api (0.6.10-0ubuntu1) UNRELEASED; urgency=medium
47
48- * Renamed "Tags" scope .ini option to "Keywords"
49+ * Renamed "Tags" scope .ini option to "Keywords".
50+ * Added support for IsAggregator scope .ini option.
51
52- -- Marcus Tomlinson <marcus.tomlinson@canonical.com> Wed, 03 Dec 2014 08:32:29 +0200
53+ -- Marcus Tomlinson <marcus.tomlinson@canonical.com> Wed, 03 Dec 2014 09:47:07 +0200
54
55 unity-scopes-api (0.6.9+15.04.20141129-0ubuntu1) vivid; urgency=medium
56
57
58=== modified file 'debian/libunity-scopes3.symbols'
59--- debian/libunity-scopes3.symbols 2014-12-05 08:11:13 +0000
60+++ debian/libunity-scopes3.symbols 2014-12-08 08:09:05 +0000
61@@ -450,6 +450,7 @@
62 (c++)"unity::scopes::internal::ScopeConfig::icon() const@Base" 0.4.0+14.04.20140312.1
63 (c++)"unity::scopes::internal::ScopeConfig::idle_timeout() const@Base" 0.4.5+14.10.20140513
64 (c++)"unity::scopes::internal::ScopeConfig::invisible() const@Base" 0.4.0+14.04.20140312.1
65+ (c++)"unity::scopes::internal::ScopeConfig::is_aggregator() const@Base" 0replaceme
66 (c++)"unity::scopes::internal::ScopeConfig::keywords() const@Base" 0.6.9+15.04.20141129
67 (c++)"unity::scopes::internal::ScopeConfig::location_data_needed() const@Base" 0.5.2+14.10.20140709.2
68 (c++)"unity::scopes::internal::ScopeConfig::overrideable() const@Base" 0.4.0+14.04.20140312.1
69@@ -491,6 +492,7 @@
70 (c++)"unity::scopes::internal::ScopeMetadataImpl::hot_key() const@Base" 0.4.0+14.04.20140312.1
71 (c++)"unity::scopes::internal::ScopeMetadataImpl::icon() const@Base" 0.4.0+14.04.20140312.1
72 (c++)"unity::scopes::internal::ScopeMetadataImpl::invisible() const@Base" 0.4.0+14.04.20140312.1
73+ (c++)"unity::scopes::internal::ScopeMetadataImpl::is_aggregator() const@Base" 0replaceme
74 (c++)"unity::scopes::internal::ScopeMetadataImpl::keywords() const@Base" 0.6.9+15.04.20141129
75 (c++)"unity::scopes::internal::ScopeMetadataImpl::location_data_needed() const@Base" 0.5.2+14.10.20140709.2
76 (c++)"unity::scopes::internal::ScopeMetadataImpl::operator=(unity::scopes::internal::ScopeMetadataImpl const&)@Base" 0.4.0+14.04.20140312.1
77@@ -512,6 +514,7 @@
78 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_hot_key(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
79 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_icon(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
80 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_invisible(bool)@Base" 0.4.0+14.04.20140312.1
81+ (c++)"unity::scopes::internal::ScopeMetadataImpl::set_is_aggregator(bool)@Base" 0replaceme
82 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_keywords(std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)@Base" 0.6.9+15.04.20141129
83 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_location_data_needed(bool)@Base" 0.5.2+14.10.20140709.2
84 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_proxy(std::shared_ptr<unity::scopes::Scope> const&)@Base" 0.4.0+14.04.20140312.1
85@@ -777,6 +780,7 @@
86 (c++)"unity::scopes::ScopeMetadata::hot_key() const@Base" 0.4.0+14.04.20140312.1
87 (c++)"unity::scopes::ScopeMetadata::icon() const@Base" 0.4.0+14.04.20140312.1
88 (c++)"unity::scopes::ScopeMetadata::invisible() const@Base" 0.4.0+14.04.20140312.1
89+ (c++)"unity::scopes::ScopeMetadata::is_aggregator() const@Base" 0replaceme
90 (c++)"unity::scopes::ScopeMetadata::keywords() const@Base" 0.6.9+15.04.20141129
91 (c++)"unity::scopes::ScopeMetadata::location_data_needed() const@Base" 0.5.2+14.10.20140709.2
92 (c++)"unity::scopes::ScopeMetadata::operator=(unity::scopes::ScopeMetadata&&)@Base" 0.4.0+14.04.20140312.1
93@@ -870,6 +874,7 @@
94 (c++)"unity::scopes::testing::ScopeMetadataBuilder::hot_key(unity::scopes::testing::ScopeMetadataBuilder::Optional<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)@Base" 0.4.0+14.04.20140312.1
95 (c++)"unity::scopes::testing::ScopeMetadataBuilder::icon(unity::scopes::testing::ScopeMetadataBuilder::Optional<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)@Base" 0.4.0+14.04.20140312.1
96 (c++)"unity::scopes::testing::ScopeMetadataBuilder::invisible(unity::scopes::testing::ScopeMetadataBuilder::Optional<bool> const&)@Base" 0.5.0+14.10.20140619
97+ (c++)"unity::scopes::testing::ScopeMetadataBuilder::is_aggregator(unity::scopes::testing::ScopeMetadataBuilder::Optional<bool> const&)@Base" 0replaceme
98 (c++)"unity::scopes::testing::ScopeMetadataBuilder::keywords(unity::scopes::testing::ScopeMetadataBuilder::Optional<std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&)@Base" 0.6.9+15.04.20141129
99 (c++)"unity::scopes::testing::ScopeMetadataBuilder::location_data_needed(unity::scopes::testing::ScopeMetadataBuilder::Optional<bool> const&)@Base" 0.6.9+15.04.20141129
100 (c++)"unity::scopes::testing::ScopeMetadataBuilder::operator()() const@Base" 0.4.0+14.04.20140312.1
101
102=== modified file 'include/unity/scopes/ScopeMetadata.h'
103--- include/unity/scopes/ScopeMetadata.h 2014-12-03 06:53:40 +0000
104+++ include/unity/scopes/ScopeMetadata.h 2014-12-08 08:09:05 +0000
105@@ -213,6 +213,12 @@
106 */
107 std::vector<std::string> keywords() const;
108
109+ /**
110+ \brief Check if this scope is an aggregator.
111+ \return True if this scope is an aggregator.
112+ */
113+ bool is_aggregator() const; // optional (default = false)
114+
115 private:
116 ScopeMetadata(std::unique_ptr<internal::ScopeMetadataImpl>); // Instantiable only by ScopeMetadataImpl
117 std::unique_ptr<internal::ScopeMetadataImpl> p;
118
119=== modified file 'include/unity/scopes/internal/ScopeConfig.h'
120--- include/unity/scopes/internal/ScopeConfig.h 2014-12-03 06:53:40 +0000
121+++ include/unity/scopes/internal/ScopeConfig.h 2014-12-08 08:09:05 +0000
122@@ -55,6 +55,7 @@
123 std::vector<std::string> child_scope_ids() const; // Optional, returns an empty vector if no ids are present
124 int version() const; // Optional, returns 0 if not present
125 std::vector<std::string> keywords() const; // Optional, returns an empty vector if no keywords are present
126+ bool is_aggregator() const; // Optional, returns false if not present
127
128 VariantMap appearance_attributes() const; // Optional, returns empty map if no attributes are present
129
130@@ -78,6 +79,7 @@
131 std::vector<std::string> child_scope_ids_;
132 int version_;
133 std::vector<std::string> keywords_;
134+ bool is_aggregator_;
135
136 VariantMap appearance_attributes_;
137 };
138
139=== modified file 'include/unity/scopes/internal/ScopeMetadataImpl.h'
140--- include/unity/scopes/internal/ScopeMetadataImpl.h 2014-12-03 06:53:40 +0000
141+++ include/unity/scopes/internal/ScopeMetadataImpl.h 2014-12-08 08:09:05 +0000
142@@ -60,6 +60,7 @@
143 std::vector<std::string> child_scope_ids() const; // optional (default: empty array)
144 int version() const; // optional (default: 0)
145 std::vector<std::string> keywords() const; // optional (default: empty array)
146+ bool is_aggregator() const; // optional (default: false)
147
148 void set_scope_id(std::string const& scope_id);
149 void set_proxy(ScopeProxy const& proxy);
150@@ -79,6 +80,7 @@
151 void set_child_scope_ids(std::vector<std::string> const& ids);
152 void set_version(int v);
153 void set_keywords(std::vector<std::string> const& keywords);
154+ void set_is_aggregator(bool is_aggregator);
155
156 VariantMap serialize() const;
157 void deserialize(VariantMap const& var);
158@@ -106,6 +108,7 @@
159 std::vector<std::string> child_scope_ids_;
160 int version_;
161 std::vector<std::string> keywords_;
162+ std::unique_ptr<bool> is_aggregator_; // Optional, hence a pointer
163 };
164
165 } // namespace internal
166
167=== modified file 'include/unity/scopes/testing/ScopeMetadataBuilder.h'
168--- include/unity/scopes/testing/ScopeMetadataBuilder.h 2014-12-03 06:53:40 +0000
169+++ include/unity/scopes/testing/ScopeMetadataBuilder.h 2014-12-08 08:09:05 +0000
170@@ -98,6 +98,7 @@
171 ScopeMetadataBuilder& child_scope_ids(Optional<std::vector<std::string>> const& value);
172 ScopeMetadataBuilder& version(Optional<int> const& value);
173 ScopeMetadataBuilder& keywords(Optional<std::vector<std::string>> const& value);
174+ ScopeMetadataBuilder& is_aggregator(Optional<bool> const& value);
175
176 ScopeMetadata operator()() const;
177
178
179=== modified file 'scoperegistry/scoperegistry.cpp'
180--- scoperegistry/scoperegistry.cpp 2014-12-03 06:53:40 +0000
181+++ scoperegistry/scoperegistry.cpp 2014-12-08 08:09:05 +0000
182@@ -320,6 +320,7 @@
183 mi->set_child_scope_ids(sc.child_scope_ids());
184 mi->set_version(sc.version());
185 mi->set_keywords(sc.keywords());
186+ mi->set_is_aggregator(sc.is_aggregator());
187
188 // Prepend scope_dir to pageheader logo path if logo path is relative.
189 // TODO: Once we have type-safe parsing in the config files, remove
190
191=== modified file 'src/scopes/ScopeMetadata.cpp'
192--- src/scopes/ScopeMetadata.cpp 2014-12-03 06:53:40 +0000
193+++ src/scopes/ScopeMetadata.cpp 2014-12-08 08:09:05 +0000
194@@ -162,6 +162,11 @@
195 return p->keywords();
196 }
197
198+bool ScopeMetadata::is_aggregator() const
199+{
200+ return p->is_aggregator();
201+}
202+
203 //! @endcond
204
205 } // namespace scopes
206
207=== modified file 'src/scopes/internal/ScopeConfig.cpp'
208--- src/scopes/internal/ScopeConfig.cpp 2014-12-03 06:53:40 +0000
209+++ src/scopes/internal/ScopeConfig.cpp 2014-12-08 08:09:05 +0000
210@@ -58,6 +58,7 @@
211 const string child_scope_ids_key = "ChildScopes";
212 const string version_key = "Version";
213 const string keywords_key = "Keywords";
214+ const string is_aggregator_key = "IsAggregator";
215
216 const string scope_appearance_group = "Appearance";
217 const string fg_color_key = "ForegroundColor";
218@@ -239,6 +240,15 @@
219
220 try
221 {
222+ is_aggregator_ = parser()->get_boolean(scope_config_group, is_aggregator_key);
223+ }
224+ catch (LogicException const&)
225+ {
226+ is_aggregator_ = false;
227+ }
228+
229+ try
230+ {
231 debug_mode_ = parser()->get_boolean(scope_config_group, debug_mode_key);
232 }
233 catch (LogicException const&)
234@@ -277,7 +287,8 @@
235 debug_mode_key,
236 child_scope_ids_key,
237 version_key,
238- keywords_key
239+ keywords_key,
240+ is_aggregator_key
241 }
242 },
243 { scope_appearance_group,
244@@ -466,6 +477,11 @@
245 return keywords_;
246 }
247
248+bool ScopeConfig::is_aggregator() const
249+{
250+ return is_aggregator_;
251+}
252+
253 } // namespace internal
254
255 } // namespace scopes
256
257=== modified file 'src/scopes/internal/ScopeMetadataImpl.cpp'
258--- src/scopes/internal/ScopeMetadataImpl.cpp 2014-12-03 06:53:40 +0000
259+++ src/scopes/internal/ScopeMetadataImpl.cpp 2014-12-08 08:09:05 +0000
260@@ -95,6 +95,10 @@
261 {
262 location_data_needed_.reset(new bool(*other.location_data_needed_));
263 }
264+ if (other.is_aggregator_)
265+ {
266+ is_aggregator_.reset(new bool(*other.is_aggregator_));
267+ }
268 }
269
270 ScopeMetadataImpl& ScopeMetadataImpl::operator=(ScopeMetadataImpl const& rhs)
271@@ -120,6 +124,7 @@
272 child_scope_ids_ = rhs.child_scope_ids_;
273 version_ = rhs.version_;
274 keywords_ = rhs.keywords_;
275+ is_aggregator_.reset(rhs.is_aggregator_ ? new bool(*rhs.is_aggregator_) : nullptr);
276 }
277 return *this;
278 }
279@@ -246,6 +251,15 @@
280 return keywords_;
281 }
282
283+bool ScopeMetadataImpl::is_aggregator() const
284+{
285+ if (is_aggregator_)
286+ {
287+ return *is_aggregator_;
288+ }
289+ return false;
290+}
291+
292 void ScopeMetadataImpl::set_scope_id(std::string const& scope_id)
293 {
294 scope_id_ = scope_id;
295@@ -321,6 +335,11 @@
296 location_data_needed_.reset(new bool(location_data_needed));
297 }
298
299+void ScopeMetadataImpl::set_is_aggregator(bool is_aggregator)
300+{
301+ is_aggregator_.reset(new bool(is_aggregator));
302+}
303+
304 void ScopeMetadataImpl::set_child_scope_ids(std::vector<std::string> const& ids)
305 {
306 child_scope_ids_ = ids;
307@@ -434,6 +453,10 @@
308 }
309 var["keywords"] = Variant(va);
310 }
311+ if (is_aggregator_)
312+ {
313+ var["is_aggregator"] = *is_aggregator_;
314+ }
315
316 return var;
317 }
318@@ -588,6 +611,12 @@
319 keywords_.push_back(v.get_string());
320 }
321 }
322+
323+ it = var.find("is_aggregator");
324+ if (it != var.end())
325+ {
326+ is_aggregator_.reset(new bool(it->second.get_bool()));
327+ }
328 }
329
330 ScopeMetadata ScopeMetadataImpl::create(unique_ptr<ScopeMetadataImpl> impl)
331
332=== modified file 'src/scopes/testing/ScopeMetadataBuilder.cpp'
333--- src/scopes/testing/ScopeMetadataBuilder.cpp 2014-12-03 06:53:40 +0000
334+++ src/scopes/testing/ScopeMetadataBuilder.cpp 2014-12-08 08:09:05 +0000
335@@ -49,6 +49,7 @@
336 Optional<std::vector<std::string>> child_scope_ids;
337 Optional<int> version;
338 Optional<std::vector<std::string>> keywords;
339+ Optional<bool> is_aggregator;
340 };
341
342 testing::ScopeMetadataBuilder::ScopeMetadataBuilder() : p(new Private())
343@@ -167,6 +168,12 @@
344 return *this;
345 }
346
347+testing::ScopeMetadataBuilder& testing::ScopeMetadataBuilder::is_aggregator(Optional<bool> const& value)
348+{
349+ p->is_aggregator = value;
350+ return *this;
351+}
352+
353 unity::scopes::ScopeMetadata testing::ScopeMetadataBuilder::operator()() const
354 {
355 auto impl = new unity::scopes::internal::ScopeMetadataImpl(Private::invalid_middleware);
356@@ -202,6 +209,8 @@
357 impl->set_version(*p->version);
358 if (p->keywords)
359 impl->set_keywords(*p->keywords);
360+ if (p->is_aggregator)
361+ impl->set_is_aggregator(*p->is_aggregator);
362
363 return unity::scopes::internal::ScopeMetadataImpl::create(
364 std::move(
365
366=== modified file 'test/gtest/scopes/Registry/Registry_test.cpp'
367--- test/gtest/scopes/Registry/Registry_test.cpp 2014-12-03 06:53:40 +0000
368+++ test/gtest/scopes/Registry/Registry_test.cpp 2014-12-08 08:09:05 +0000
369@@ -116,6 +116,7 @@
370 EXPECT_EQ("music", keywords[0]);
371 EXPECT_EQ("news", keywords[1]);
372 EXPECT_EQ("foo", keywords[2]);
373+ EXPECT_FALSE(meta.is_aggregator());
374
375 auto attrs = meta.appearance_attributes();
376 EXPECT_EQ("fg_color", attrs["foreground-color"].get_string());
377@@ -149,6 +150,7 @@
378 EXPECT_EQ(0, meta.child_scope_ids().size());
379 EXPECT_EQ(0, meta.keywords().size());
380 EXPECT_EQ(0, meta.version());
381+ EXPECT_FALSE(meta.is_aggregator());
382 }
383
384 auto const wait_for_update_time = std::chrono::milliseconds(5000);
385
386=== modified file 'test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in'
387--- test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in 2014-12-03 06:53:40 +0000
388+++ test/gtest/scopes/Registry/scopes/testscopeA/testscopeA.ini.in 2014-12-08 08:09:05 +0000
389@@ -10,6 +10,7 @@
390 ChildScopes = com.foo.bar;com.foo.baz
391 Version = 1
392 Keywords = music;news;foo
393+IsAggregator = false
394
395 [Appearance]
396 ForegroundColor = fg_color
397
398=== modified file 'test/gtest/scopes/internal/ScopeConfig/ScopeConfig_test.cpp'
399--- test/gtest/scopes/internal/ScopeConfig/ScopeConfig_test.cpp 2014-12-03 06:53:40 +0000
400+++ test/gtest/scopes/internal/ScopeConfig/ScopeConfig_test.cpp 2014-12-08 08:09:05 +0000
401@@ -62,6 +62,8 @@
402 EXPECT_EQ("foo", keywords[0]);
403 EXPECT_EQ("bar", keywords[1]);
404
405+ EXPECT_TRUE(cfg.is_aggregator());
406+
407 auto attrs = cfg.appearance_attributes();
408 EXPECT_EQ(5, attrs.size());
409 EXPECT_TRUE(attrs["arbitrary_key"].get_bool());
410@@ -93,6 +95,7 @@
411 EXPECT_FALSE(cfg.location_data_needed());
412 EXPECT_FALSE(cfg.debug_mode());
413 EXPECT_EQ(0, cfg.version());
414+ EXPECT_FALSE(cfg.is_aggregator());
415
416 EXPECT_EQ(0, cfg.appearance_attributes().size());
417
418
419=== modified file 'test/gtest/scopes/internal/ScopeConfig/complete_config.ini.in'
420--- test/gtest/scopes/internal/ScopeConfig/complete_config.ini.in 2014-12-03 06:53:40 +0000
421+++ test/gtest/scopes/internal/ScopeConfig/complete_config.ini.in 2014-12-08 08:09:05 +0000
422@@ -20,6 +20,7 @@
423 Version = 1
424 ChildScopes = com.foo.bar;com.foo.bar2;com.foo.boo
425 Keywords = foo;bar
426+IsAggregator = true
427
428 [Appearance]
429 arbitrary_key = true
430
431=== modified file 'test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp'
432--- test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp 2014-12-03 06:53:40 +0000
433+++ test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp 2014-12-08 08:09:05 +0000
434@@ -134,6 +134,9 @@
435 // when "version" is not set, 0 is returned
436 EXPECT_EQ(0, m.version());
437
438+ // when "is_aggregator" is not set, false is returned
439+ EXPECT_FALSE(m.is_aggregator());
440+
441 // Check that the copy has the same values as the original
442 EXPECT_EQ("scope_id", mi2->scope_id());
443 EXPECT_EQ("identity", mi2->proxy()->identity());
444@@ -163,6 +166,7 @@
445 mi2->set_location_data_needed(true);
446 mi2->set_child_scope_ids(vector<string>{"abc", "def"});
447 mi2->set_keywords(vector<string>{"music", "video", "news"});
448+ mi2->set_is_aggregator(true);
449
450 // Make another copy, so we get coverage on the entire copy constructor
451 unique_ptr<ScopeMetadataImpl> mi3(new ScopeMetadataImpl(*mi2));
452@@ -177,6 +181,7 @@
453 EXPECT_TRUE(m.location_data_needed());
454 EXPECT_EQ((vector<string>{"abc", "def"}), m.child_scope_ids());
455 EXPECT_EQ((vector<string>{"music", "video", "news"}), m.keywords());
456+ EXPECT_TRUE(m.is_aggregator());
457
458 // Make another value
459 unique_ptr<ScopeMetadataImpl> ti(new ScopeMetadataImpl(&mw));
460@@ -201,6 +206,7 @@
461 ti->set_location_data_needed(true);
462 ti->set_child_scope_ids(vector<string>{"tmp abc", "tmp def"});
463 ti->set_keywords(vector<string>{"music", "video"});
464+ ti->set_is_aggregator(true);
465
466 // Check impl assignment operator
467 ScopeMetadataImpl ci(&mw);
468@@ -224,6 +230,7 @@
469 EXPECT_EQ((vector<string>{"tmp abc", "tmp def"}), ci.child_scope_ids());
470 EXPECT_EQ(99, ci.version());
471 EXPECT_EQ((vector<string>{"music", "video"}), ci.keywords());
472+ EXPECT_TRUE(ci.is_aggregator());
473
474 // Check public assignment operator
475 auto tmp = ScopeMetadataImpl::create(move(ti));
476@@ -247,6 +254,7 @@
477 EXPECT_TRUE(m.location_data_needed());
478 EXPECT_EQ((vector<string>{"tmp abc", "tmp def"}), m.child_scope_ids());
479 EXPECT_EQ((vector<string>{"music", "video"}), m.keywords());
480+ EXPECT_TRUE(m.is_aggregator());
481
482 // Self-assignment
483 tmp = tmp;
484@@ -269,6 +277,7 @@
485 EXPECT_TRUE(tmp.location_data_needed());
486 EXPECT_EQ((vector<string>{"tmp abc", "tmp def"}), tmp.child_scope_ids());
487 EXPECT_EQ((vector<string>{"music", "video"}), tmp.keywords());
488+ EXPECT_TRUE(tmp.is_aggregator());
489
490 // Copy constructor
491 ScopeMetadata tmp2(tmp);
492@@ -291,6 +300,7 @@
493 EXPECT_TRUE(tmp2.location_data_needed());
494 EXPECT_EQ((vector<string>{"tmp abc", "tmp def"}), tmp2.child_scope_ids());
495 EXPECT_EQ((vector<string>{"music", "video"}), tmp2.keywords());
496+ EXPECT_TRUE(tmp2.is_aggregator());
497 }
498
499 TEST(ScopeMetadataImpl, serialize)
500@@ -323,11 +333,12 @@
501 mi->set_location_data_needed(false);
502 mi->set_child_scope_ids({"com.foo.bar", "com.foo.baz"});
503 mi->set_keywords({"news", "games"});
504+ mi->set_is_aggregator(false);
505
506 // Check that serialize() sets the map values correctly
507 auto m = ScopeMetadataImpl::create(move(mi));
508 auto var = m.serialize();
509- EXPECT_EQ(18u, var.size());
510+ EXPECT_EQ(19u, var.size());
511 EXPECT_EQ("scope_id", var["scope_id"].get_string());
512 EXPECT_EQ("display_name", var["display_name"].get_string());
513 EXPECT_EQ("description", var["description"].get_string());
514@@ -351,6 +362,7 @@
515 EXPECT_EQ(2u, var["keywords"].get_array().size());
516 EXPECT_EQ("news", var["keywords"].get_array()[0].get_string());
517 EXPECT_EQ("games", var["keywords"].get_array()[1].get_string());
518+ EXPECT_FALSE(var["is_aggregator"].get_bool());
519
520 // Make another instance from the VariantMap and check its fields
521 ScopeMetadataImpl c(var, &mw);
522@@ -378,6 +390,7 @@
523 EXPECT_EQ(2u, c.keywords().size());
524 EXPECT_EQ("news", c.keywords()[0]);
525 EXPECT_EQ("games", c.keywords()[1]);
526+ EXPECT_FALSE(c.is_aggregator());
527 }
528
529 TEST(ScopeMetadataImpl, serialize_exceptions)
530@@ -594,6 +607,7 @@
531 m["appearance_attributes"] = appearance;
532 m["results_ttl_type"] = 0;
533 m["location_data_needed"] = true;
534+ m["is_aggregator"] = true;
535
536 ScopeMetadataImpl mi(m, &mw);
537 mi.deserialize(m);
538@@ -612,4 +626,5 @@
539 EXPECT_EQ(appearance, mi.appearance_attributes());
540 EXPECT_EQ(ScopeMetadata::ResultsTtlType::None, mi.results_ttl_type());
541 EXPECT_TRUE(mi.location_data_needed());
542+ EXPECT_TRUE(mi.is_aggregator());
543 }
544
545=== modified file 'test/gtest/scopes/testing/IsolatedScope/IsolatedScope_test.cpp'
546--- test/gtest/scopes/testing/IsolatedScope/IsolatedScope_test.cpp 2014-12-03 06:53:40 +0000
547+++ test/gtest/scopes/testing/IsolatedScope/IsolatedScope_test.cpp 2014-12-08 08:09:05 +0000
548@@ -114,7 +114,8 @@
549 .location_data_needed(true)
550 .child_scope_ids(child_scope_ids)
551 .version(42)
552- .keywords(keywords);
553+ .keywords(keywords)
554+ .is_aggregator(true);
555 unity::scopes::ScopeMetadata metadata = builder();
556 EXPECT_EQ(scope_id, metadata.scope_id());
557 EXPECT_EQ("display_name", metadata.display_name());
558@@ -133,6 +134,7 @@
559 EXPECT_EQ(child_scope_ids, metadata.child_scope_ids());
560 EXPECT_EQ(42, metadata.version());
561 EXPECT_EQ(keywords, metadata.keywords());
562+ EXPECT_TRUE(metadata.is_aggregator());
563 }
564
565 TEST(ScopeMetadataBuilder, construction_in_case_of_missing_mandatory_arguments_aborts)

Subscribers

People subscribed via source and target branches

to all changes: