Merge lp:~michihenning/unity-scopes-api/push-errors into lp:unity-scopes-api
- push-errors
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michal Hruby |
Approved revision: | 101 |
Merged at revision: | 118 |
Proposed branch: | lp:~michihenning/unity-scopes-api/push-errors |
Merge into: | lp:unity-scopes-api |
Diff against target: |
574 lines (+130/-45) 21 files modified
CMakeLists.txt (+1/-1) debian/changelog (+8/-0) demo/client.cpp (+20/-6) demo/scopes/scope-B/scope-B.cpp (+7/-2) include/scopes/ReceiverBase.h (+5/-3) include/scopes/Reply.h (+16/-5) include/scopes/internal/MWReply.h (+1/-1) include/scopes/internal/ReplyImpl.h (+1/-0) include/scopes/internal/ReplyObject.h (+1/-1) include/scopes/internal/zmq_middleware/ZmqReply.h (+1/-1) src/Reply.cpp (+4/-0) src/internal/QueryCtrlImpl.cpp (+4/-2) src/internal/QueryObject.cpp (+3/-3) src/internal/ReplyImpl.cpp (+36/-3) src/internal/ReplyObject.cpp (+11/-11) src/internal/ScopeImpl.cpp (+1/-1) src/internal/ScopeObject.cpp (+2/-2) src/internal/zmq_middleware/ReplyI.cpp (+3/-1) src/internal/zmq_middleware/ZmqReply.cpp (+2/-1) src/internal/zmq_middleware/capnproto/Reply.capnp (+1/-0) test/gtest/scopes/Runtime/Runtime_test.cpp (+2/-1) |
To merge this branch: | bzr merge lp:~michihenning/unity-scopes-api/push-errors |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+199601@code.launchpad.net |
Commit message
Added ability for scope to push an exception (as an exception_ptr). On the client side,
the exception is delivered as the what() string (if the exception is a std::exception) and
as "unknown exception", otherwise.
Description of the change
Added ability for scope to push an exception (as an exception_ptr). On the client side,
the exception is delivered as the what() string (if the exception is a std::exception) and
as "unknown exception", otherwise.
PS Jenkins bot (ps-jenkins) wrote : | # |
Michal Hruby (mhr3) wrote : | # |
Hm, thinking more about this, there is pretty much nothing a client can do with the message in the finished() method, so I'm wondering whether it should really be there.
A much nicer API would be if create_query() returned a future and you could get() the operation result from there - and it could even throw an error at that point.
Michal Hruby (mhr3) wrote : | # |
Of course that doesn't change the fact the error should be tranferred on the protocol level.
Michi Henning (michihenning) wrote : | # |
I could remove the message in the finished() method on the server side, but I think James wanted to have this for the Go binding (which is why I added it in the first place).
I agree, the client can't do all that much with it. But, in James's case, he needs the error for testing, to see whether Go errors are correctly propagated across to C++. (James, correct me please if I got that wrong.)
Michal, if you recall, when you first pushed for this, it was *me* who argued that an error flag is good enough for the Dash because the Dash can't do much useful with the error message either :-)
It looks like we can't have our cake and eat it too. And I'd rather not pollute the public API with methods that are there purely for testing.
We could make a derived version of the interface for testing that provides access to the extra parameter, but it adds yet complexity.
Does anyone else have a bright idea?
I think I could return a future in addition to the CtrlProxy. But I'm not sure that this would necessarily work better. Results can arrive at any time (push, cancel, finished, or error), and there can be multiple pushes. A future is a one-shot API, effectively saying "wait for finish or exception".
Hmmm... Michal, you are sitting at the receiving end of the API. Would providing a future make more sense than the current finished() and error() callbacks? If an error is recorded, the future would return something like a ScopeException with an error string, regardless of the actual exception that was caught on the scope side. That's because I can't marshal arbitrary exceptions back over the wire.
I can add a future, but I'd like to do this only if there is a compelling reason. Doing so will make create_query() more complicated because it then would have two return values. (Or I overload create_query() to make the return of the future optional, but that's also more complex.)
The current callback API has the advantage that it is very simple and that C++ programmers of moderate skill level will have no problem understanding it. On the other hand, there are many C++ programmers whose eyes glaze over as soon as you mention std::future...
Michal Hruby (mhr3) wrote : | # |
Well, for UI-programming futures suck, cause they block the thread :) Plus having a dedicated thread just to allow it to run each future's get sounds expensive. Moreover we do want to get the partial resultsets as soon as possible - so the virtual push() is nice. That being said, with all the threading in place, you could actually end up processing finished() before processing last push(), and that'd be bad. But I'm getting sidetracked.
I can see that futures would simplify aggregating scopes, and being able to start the query and wait for it to finish + get potential exception in the same place is really nice, and ultimately will be what you end up doing "manually" if there's no future.
So bottomline, I don't see a silver bullet, both approaches have their pros and cons.
Michi Henning (michihenning) wrote : | # |
I think it's probably better, on balance, to leave it as is. It's easy enough for the scope author to use a promise/future or a condvar if they want to wait for completion.
Michal, if you can live with that, can you approve please?
- 99. By Michi Henning
-
Merged trunk and resolved conflict.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:99
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michal Hruby (mhr3) wrote : | # |
18 +unity-scopes-api (0.1.7+
No need to change the -0ubuntuX suffix.
20 + [ michi ]
25 + -- michi <michi@djembefola> Thu, 02 Jan 2014 16:10:06 +1000
Could you please create ~/.devscripts with the content:
<email address hidden>
DEBFULLNAME=Your name
With that dch will produce a proper changelog entry. Also there's no need for the [Name] line, dch will do that automatically when there are multiple authors.
537 +#include <iostream> // TODO: remove this
555 +cerr << "sending error reply: " << error_message << endl;
Forgotten debug?
- 100. By Michi Henning
-
Removed left-over debug trace.
Michi Henning (michihenning) wrote : | # |
> 18 +unity-scopes-api (0.1.7+
> urgency=low
>
> No need to change the -0ubuntuX suffix.
OK, thanks for that. So, what should I do when I commit something? (Sorry, but the whole debian thing is still a bit of mystery to me.)
> 20 + [ michi ]
> 25 + -- michi <michi@djembefola> Thu, 02 Jan 2014 16:10:06 +1000
>
> Could you please create ~/.devscripts with the content:
> <email address hidden>
> DEBFULLNAME=Your name
>
> With that dch will produce a proper changelog entry. Also there's no need for
> the [Name] line, dch will do that automatically when there are multiple
> authors.
OK, I just did that, thanks!
> 537 +#include <iostream> // TODO: remove this
> 555 +cerr << "sending error reply: " << error_message << endl;
>
> Forgotten debug?
Yes, thanks for spotting this! I've just committed with this removed. Hopefully, that'll be OK this time.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:100
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michal Hruby (mhr3) wrote : | # |
> OK, thanks for that. So, what should I do when I commit something? (Sorry, but
> the whole debian thing is still a bit of mystery to me.)
So, when changing API, you bump the version number as you did:
8 -set(UNITY_
9 +set(UNITY_
Then you run `dch -v "[new-version]
That will create a new changelog entry where you just add the message, nothing else. Plus with the correct DEB* variables as mentioned above, it'll use your real name and email, not just username@hostname as is visible here (michi@djembefola, is that a real DJ btw? :))
So can you please revert the changelog change and do it again to fix it?
Michal Hruby (mhr3) wrote : | # |
> So can you please revert the changelog change and do it again to fix it?
Just to clarify, no need for VCS revert, just delete the new entry and run "dch ..." again.
- 101. By Michi Henning
-
Fixed changelog yet again.
Michi Henning (michihenning) wrote : | # |
> Then you run `dch -v "[new-version]
> in this case.
>
> That will create a new changelog entry where you just add the message, nothing
> else. Plus with the correct DEB* variables as mentioned above, it'll use your
> real name and email, not just username@hostname as is visible here
Thanks for that! I've just pushed this. It looks like dch is ignoring what's in my .devscripts file. Here are the contents:
<email address hidden>
DEBFULLNAME="Michi Henning"
When I run
dch -v "0.1.7-0ubuntu1"
I get the following at the bottom:
-- Michi Henning <michi@djembefola> Fri, 03 Jan 2014 07:35:43 +1000
DEBEMAIL is being ignored, it seems. I've verified that .devscripts is being read by adding a syntax error. When I do that, I get an error message. So it's not that the file has the wrong name or is in the wrong place.
When I set this as an environment variable instead, it works, so I've set it up in my .bashrc now.
> (michi@djembefola, is that a real DJ btw? :))
:-)
"Djembefola" is a Malinke word. "Fola" means to "play an instrument". So a djembefola literally means "one who plays the djembe". It's the name of my desktop machine :-)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:101
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michal Hruby (mhr3) wrote : | # |
> -- Michi Henning <michi@djembefola> Fri, 03 Jan 2014 07:35:43 +1000
>
> DEBEMAIL is being ignored, it seems. I've verified that .devscripts is being
> read by adding a syntax error. When I do that, I get an error message. So it's
> not that the file has the wrong name or is in the wrong place.
>
> When I set this as an environment variable instead, it works, so I've set it
> up in my .bashrc now.
Ah, you're right indeed, I have it also both in my ~/.devscripts and ~/.bashrc
> > (michi@djembefola, is that a real DJ btw? :))
>
> :-)
>
> "Djembefola" is a Malinke word. "Fola" means to "play an instrument". So a
> djembefola literally means "one who plays the djembe". It's the name of my
> desktop machine :-)
I see, so not exactly a DJ, but close :)
Michi Henning (michihenning) wrote : | # |
Aargh... :-(
I think the version should now be 8 because that was an incompatible ABI change. That's a problem when there is more than one branch outstanding that touches the API.
Michal, could you check please and perform whatever requisite magic we need?
Michal Hruby (mhr3) wrote : | # |
> Aargh... :-(
>
> I think the version should now be 8 because that was an incompatible ABI
> change. That's a problem when there is more than one branch outstanding that
> touches the API.
>
> Michal, could you check please and perform whatever requisite magic we need?
Right, but there are no other approved branches which would bump the version number, so it's fine (we don't care about strict ABI compatibility just yet). But of course other branches which again change the API will need to be bumped to 8.
Michi Henning (michihenning) wrote : | # |
> Right, but there are no other approved branches which would bump the version
> number, so it's fine (we don't care about strict ABI compatibility just yet).
Phew! :-)
> But of course other branches which again change the API will need to be bumped
> to 8.
We have a more general problem here: suppose we are at version 7. I make an incompatible change in an MR and dutifully bump the version to 8. The MR hangs around for a few days (like some just did because of the Christmas break.) Then I fix something else that's incompatible and also dutifully bump the version to 8. (Or, more likely, someone else does.) Now we have two incompatible changes, but only one version increment :-(
Depending when the branches get merged, there is a window where someone will get bitten :-(
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2013-12-27 02:52:30 +0000 |
3 | +++ CMakeLists.txt 2014-01-02 21:33:37 +0000 |
4 | @@ -150,7 +150,7 @@ |
5 | # API version |
6 | set(UNITY_SCOPES_MAJOR 0) |
7 | set(UNITY_SCOPES_MINOR 1) |
8 | -set(UNITY_SCOPES_MICRO 6) |
9 | +set(UNITY_SCOPES_MICRO 7) |
10 | |
11 | # Scopes library |
12 | set(UNITY_SCOPES_LIB unity-scopes) |
13 | |
14 | === modified file 'debian/changelog' |
15 | --- debian/changelog 2013-12-19 21:08:02 +0000 |
16 | +++ debian/changelog 2014-01-02 21:33:37 +0000 |
17 | @@ -1,3 +1,11 @@ |
18 | +unity-scopes-api (0.1.7-0ubuntu1) UNRELEASED; urgency=low |
19 | + |
20 | + * Added ability for scope to push an exception (as an exception_ptr). On the client side, |
21 | + the exception is delivered as the what() string (if the exception is a std::exception) and |
22 | + as "unknown exception", otherwise. |
23 | + |
24 | + -- Michi Henning <michi.henning@canonical.com> Fri, 03 Jan 2014 07:31:02 +1000 |
25 | + |
26 | unity-scopes-api (0.1.6+14.04.20131219.1-0ubuntu1) trusty; urgency=low |
27 | |
28 | [ Pawel Stolowski ] |
29 | |
30 | === modified file 'demo/client.cpp' |
31 | --- demo/client.cpp 2013-12-16 07:05:08 +0000 |
32 | +++ demo/client.cpp 2014-01-02 21:33:37 +0000 |
33 | @@ -40,28 +40,42 @@ |
34 | |
35 | virtual void push(Category::SCPtr category) override |
36 | { |
37 | - cout << "received category: id=" << category->id() << " title=" << category->title() << " icon=" << category->icon() << " template=" << |
38 | - category->renderer_template().data() << endl; |
39 | + cout << "received category: id=" << category->id() |
40 | + << " title=" << category->title() |
41 | + << " icon=" << category->icon() |
42 | + << " template=" << category->renderer_template().data() |
43 | + << endl; |
44 | } |
45 | |
46 | virtual void push(CategorisedResult result) override |
47 | { |
48 | - cout << "received result: uri=" << result.uri() << " title=" << result.title() << " category id: " << result.category()->id() << endl; |
49 | + cout << "received result: uri=" << result.uri() |
50 | + << " title=" << result.title() |
51 | + << " category id: " |
52 | + << result.category()->id() |
53 | + << endl; |
54 | } |
55 | |
56 | virtual void push(Annotation annotation) override |
57 | { |
58 | auto links = annotation.links(); |
59 | - cout << "received annotation of type " << annotation.annotation_type() << " with " << links.size() << " link(s):" << endl; |
60 | + cout << "received annotation of type " << annotation.annotation_type() |
61 | + << " with " << links.size() << " link(s):" |
62 | + << endl; |
63 | for (auto link: links) |
64 | { |
65 | cout << " " << link->query().to_string() << endl; |
66 | } |
67 | } |
68 | |
69 | - virtual void finished(ReceiverBase::Reason reason) override |
70 | + virtual void finished(ReceiverBase::Reason reason, string const& error_message) override |
71 | { |
72 | - cout << "query complete, status: " << to_string(reason) << endl; |
73 | + cout << "query complete, status: " << to_string(reason); |
74 | + if (reason == ReceiverBase::Error) |
75 | + { |
76 | + cout << ": " << error_message; |
77 | + } |
78 | + cout << endl; |
79 | { |
80 | unique_lock<decltype(mutex_)> lock(mutex_); |
81 | query_complete_ = true; |
82 | |
83 | === modified file 'demo/scopes/scope-B/scope-B.cpp' |
84 | --- demo/scopes/scope-B/scope-B.cpp 2013-12-04 12:00:33 +0000 |
85 | +++ demo/scopes/scope-B/scope-B.cpp 2014-01-02 21:33:37 +0000 |
86 | @@ -57,9 +57,14 @@ |
87 | } |
88 | } |
89 | |
90 | - virtual void finished(Reason reason) override |
91 | + virtual void finished(Reason reason, string const& error_message) override |
92 | { |
93 | - cout << "query to " << scope_name_ << " complete, status: " << to_string(reason) << endl; |
94 | + cout << "query to " << scope_name_ << " complete, status: " << to_string(reason); |
95 | + if (reason == ReceiverBase::Error) |
96 | + { |
97 | + cout << ": " << error_message; |
98 | + } |
99 | + cout << endl; |
100 | } |
101 | |
102 | Receiver(string const& scope_name, ReplyProxy const& upstream) : |
103 | |
104 | === modified file 'include/scopes/ReceiverBase.h' |
105 | --- include/scopes/ReceiverBase.h 2013-12-27 03:32:57 +0000 |
106 | +++ include/scopes/ReceiverBase.h 2014-01-02 21:33:37 +0000 |
107 | @@ -84,8 +84,8 @@ |
108 | /** |
109 | \brief Indicates the cause of a call to finished(). |
110 | The Error enumerator indicates that a query terminated abnormally, for example, |
111 | - because a scope could not be reached over the network or terminated an query |
112 | - abnormally. |
113 | + because a scope could not be reached over the network, a query terminated |
114 | + abnormally, or explicitly reported an error. |
115 | */ |
116 | enum Reason { Finished, Cancelled, Error }; |
117 | |
118 | @@ -93,8 +93,10 @@ |
119 | \brief Called once by the scopes run time after the final result for a query() was sent. |
120 | Exceptions thrown from finished() are ignored. |
121 | \param r Indicates the cause for the call to finished(). |
122 | + \param error_message If r is set to Reason::Error, error_message contains further details. |
123 | + Otherwise, error_message is the empty string. |
124 | */ |
125 | - virtual void finished(Reason r) = 0; |
126 | + virtual void finished(Reason r, std::string const& error_message) = 0; |
127 | |
128 | protected: |
129 | /// @cond |
130 | |
131 | === modified file 'include/scopes/Reply.h' |
132 | --- include/scopes/Reply.h 2013-12-05 12:20:08 +0000 |
133 | +++ include/scopes/Reply.h 2014-01-02 21:33:37 +0000 |
134 | @@ -55,13 +55,15 @@ |
135 | \brief Create and register a new Category. The category is automatically sent to the source of the query. |
136 | \return Category instance |
137 | */ |
138 | - Category::SCPtr register_category(std::string const& id, std::string const& title, std::string const &icon, CategoryRenderer const& renderer_template = |
139 | - CategoryRenderer()); |
140 | + Category::SCPtr register_category(std::string const& id, |
141 | + std::string const& title, |
142 | + std::string const &icon, |
143 | + CategoryRenderer const& renderer_template = CategoryRenderer()); |
144 | |
145 | /** |
146 | \brief Register an existing category instance and send it to the source of the query. |
147 | - The purpose of this call is to register a category obtained via ReplyBase::push(Category::SCPtr) when aggregating results and categories from |
148 | - other scope(s). |
149 | + The purpose of this call is to register a category obtained via ReplyBase::push(Category::SCPtr) when aggregating |
150 | + results and categories from other scope(s). |
151 | */ |
152 | void register_category(Category::SCPtr category); |
153 | |
154 | @@ -89,13 +91,22 @@ |
155 | was sent, that is, that the query is complete. |
156 | The scope application code is responsible for calling finished() once it has sent the |
157 | final result for a query. |
158 | - Multiple calls to finished() are ignored. |
159 | + Multiple calls to finished() and calls to error() after finished() was called are ignored. |
160 | The destructor implicitly calls finished() if a Reply goes out of scope without |
161 | a prior call to finished(). |
162 | */ |
163 | void finished() const; |
164 | |
165 | /** |
166 | + \brief Informs the source of a query that the query was terminated due to an error. |
167 | + Multiple calls to error() and calls to finished() after error() was called are ignored. |
168 | + \param ex An exception_ptr indicating the cause of the error. If ex is a `std::exception`, |
169 | + the return value of `what()` is made available to the query source. Otherwise, |
170 | + the query source receives `"unknown exception"`. |
171 | + */ |
172 | + void error(std::exception_ptr ex) const; |
173 | + |
174 | + /** |
175 | \brief Destroys a Reply. |
176 | If a Reply goes out of scope without a prior call to finished(), the destructor implicitly calls finished(). |
177 | */ |
178 | |
179 | === modified file 'include/scopes/internal/MWReply.h' |
180 | --- include/scopes/internal/MWReply.h 2013-11-25 19:05:41 +0000 |
181 | +++ include/scopes/internal/MWReply.h 2014-01-02 21:33:37 +0000 |
182 | @@ -44,7 +44,7 @@ |
183 | virtual ~MWReply() noexcept; |
184 | |
185 | virtual void push(VariantMap const& result) = 0; |
186 | - virtual void finished(ReceiverBase::Reason reason) = 0; |
187 | + virtual void finished(ReceiverBase::Reason reason, std::string const& error_message) = 0; |
188 | |
189 | protected: |
190 | MWReply(MiddlewareBase* mw_base); |
191 | |
192 | === modified file 'include/scopes/internal/ReplyImpl.h' |
193 | --- include/scopes/internal/ReplyImpl.h 2013-12-05 12:20:08 +0000 |
194 | +++ include/scopes/internal/ReplyImpl.h 2014-01-02 21:33:37 +0000 |
195 | @@ -66,6 +66,7 @@ |
196 | bool push(unity::api::scopes::Annotation const& annotation); |
197 | void finished(); |
198 | void finished(unity::api::scopes::ReceiverBase::Reason reason); |
199 | + void error(std::exception_ptr ex); |
200 | |
201 | static ReplyProxy create(MWReplyProxy const& mw_proxy, std::shared_ptr<QueryObject> const& qo); |
202 | |
203 | |
204 | === modified file 'include/scopes/internal/ReplyObject.h' |
205 | --- include/scopes/internal/ReplyObject.h 2013-11-25 19:05:41 +0000 |
206 | +++ include/scopes/internal/ReplyObject.h 2014-01-02 21:33:37 +0000 |
207 | @@ -56,7 +56,7 @@ |
208 | |
209 | // Remote operation implementations |
210 | void push(VariantMap const& result) noexcept; |
211 | - void finished(ReceiverBase::Reason reason) noexcept; |
212 | + void finished(ReceiverBase::Reason reason, std::string const& error_message) noexcept; |
213 | |
214 | private: |
215 | ReceiverBase::SPtr const receiver_base_; |
216 | |
217 | === modified file 'include/scopes/internal/zmq_middleware/ZmqReply.h' |
218 | --- include/scopes/internal/zmq_middleware/ZmqReply.h 2013-11-25 19:05:41 +0000 |
219 | +++ include/scopes/internal/zmq_middleware/ZmqReply.h 2014-01-02 21:33:37 +0000 |
220 | @@ -45,7 +45,7 @@ |
221 | virtual ~ZmqReply() noexcept; |
222 | |
223 | virtual void push(VariantMap const& result) override; |
224 | - virtual void finished(ReceiverBase::Reason reason) override; |
225 | + virtual void finished(ReceiverBase::Reason reason, std::string const& error_message) override; |
226 | }; |
227 | |
228 | } // namespace zmq_middleware |
229 | |
230 | === modified file 'src/Reply.cpp' |
231 | --- src/Reply.cpp 2013-12-05 12:20:08 +0000 |
232 | +++ src/Reply.cpp 2014-01-02 21:33:37 +0000 |
233 | @@ -73,6 +73,10 @@ |
234 | return fwd()->finished(); |
235 | } |
236 | |
237 | +void Reply::error(std::exception_ptr ex) const |
238 | +{ |
239 | + return fwd()->error(ex); |
240 | +} |
241 | internal::ReplyImpl* Reply::fwd() const |
242 | { |
243 | return dynamic_cast<internal::ReplyImpl*>(pimpl()); |
244 | |
245 | === modified file 'src/internal/QueryCtrlImpl.cpp' |
246 | --- src/internal/QueryCtrlImpl.cpp 2013-11-25 19:05:41 +0000 |
247 | +++ src/internal/QueryCtrlImpl.cpp 2014-01-02 21:33:37 +0000 |
248 | @@ -26,6 +26,7 @@ |
249 | #include <scopes/ScopeExceptions.h> |
250 | |
251 | #include <cassert> |
252 | +#include <iostream> // TODO: remove this once logging is added |
253 | |
254 | using namespace std; |
255 | |
256 | @@ -65,10 +66,11 @@ |
257 | // Indicate (to ourselves) that this query is complete. Calling via the MWReplyProxy ensures |
258 | // the finished() call will be processed by a seperate server-side thread, |
259 | // so we cannot block here. |
260 | - reply_proxy_->finished(ReceiverBase::Cancelled); |
261 | + reply_proxy_->finished(ReceiverBase::Cancelled, ""); |
262 | } |
263 | - catch (MiddlewareException const& e) |
264 | + catch (std::exception const& e) |
265 | { |
266 | + cerr << e.what() << endl; |
267 | // TODO: log error |
268 | } |
269 | } |
270 | |
271 | === modified file 'src/internal/QueryObject.cpp' |
272 | --- src/internal/QueryObject.cpp 2013-12-13 04:48:38 +0000 |
273 | +++ src/internal/QueryObject.cpp 2014-01-02 21:33:37 +0000 |
274 | @@ -94,15 +94,15 @@ |
275 | catch (std::exception const& e) |
276 | { |
277 | pushable_ = false; |
278 | - reply_->finished(ReceiverBase::Error); // Oneway, can't block |
279 | // TODO: log error |
280 | + reply_->finished(ReceiverBase::Error, e.what()); // Oneway, can't block |
281 | cerr << "ScopeBase::run(): " << e.what() << endl; |
282 | } |
283 | catch (...) |
284 | { |
285 | pushable_ = false; |
286 | - reply_->finished(ReceiverBase::Error); // Oneway, can't block |
287 | // TODO: log error |
288 | + reply_->finished(ReceiverBase::Error, "unknown exception"); // Oneway, can't block |
289 | cerr << "ScopeBase::run(): unknown exception" << endl; |
290 | } |
291 | } |
292 | @@ -116,7 +116,7 @@ |
293 | // Send finished() to up-stream client to tell him the query is done. |
294 | // We send via the MWReplyProxy here because that allows passing |
295 | // a ReceiverBase::Reason (whereas the public ReplyProxy does not). |
296 | - reply_->finished(ReceiverBase::Cancelled); // Oneway, can't block |
297 | + reply_->finished(ReceiverBase::Cancelled, ""); // Oneway, can't block |
298 | } |
299 | |
300 | // Forward the cancellation to the query base (which in turn will forward it to any subqueries). |
301 | |
302 | === modified file 'src/internal/ReplyImpl.cpp' |
303 | --- src/internal/ReplyImpl.cpp 2013-12-06 11:22:12 +0000 |
304 | +++ src/internal/ReplyImpl.cpp 2014-01-02 21:33:37 +0000 |
305 | @@ -30,6 +30,7 @@ |
306 | |
307 | #include <sstream> |
308 | #include <cassert> |
309 | +#include <iostream> // TODO: remove this once logging is added |
310 | |
311 | using namespace std; |
312 | |
313 | @@ -73,7 +74,10 @@ |
314 | push(category); |
315 | } |
316 | |
317 | -Category::SCPtr ReplyImpl::register_category(std::string const& id, std::string const& title, std::string const &icon, CategoryRenderer const& renderer_template) |
318 | +Category::SCPtr ReplyImpl::register_category(std::string const& id, |
319 | + std::string const& title, |
320 | + std::string const &icon, |
321 | + CategoryRenderer const& renderer_template) |
322 | { |
323 | auto cat = cat_registry_->register_category(id, title, icon, renderer_template); // will throw if adding same category again |
324 | |
325 | @@ -139,7 +143,7 @@ |
326 | catch (MiddlewareException const& e) |
327 | { |
328 | // TODO: log error |
329 | - finished(ReceiverBase::Error); |
330 | + error(current_exception()); |
331 | return false; |
332 | } |
333 | } |
334 | @@ -157,15 +161,44 @@ |
335 | { |
336 | try |
337 | { |
338 | - fwd()->finished(reason); |
339 | + fwd()->finished(reason, ""); |
340 | } |
341 | catch (MiddlewareException const& e) |
342 | { |
343 | // TODO: log error |
344 | + cerr << e.what() << endl; |
345 | } |
346 | } |
347 | } |
348 | |
349 | +void ReplyImpl::error(exception_ptr ex) |
350 | +{ |
351 | + string error_message; |
352 | + try |
353 | + { |
354 | + rethrow_exception(ex); |
355 | + } |
356 | + catch (std::exception const& e) |
357 | + { |
358 | + error_message = e.what(); |
359 | + } |
360 | + catch (...) |
361 | + { |
362 | + error_message = "unknown exception"; |
363 | + } |
364 | + |
365 | + try |
366 | + { |
367 | + fwd()->finished(ReceiverBase::Error, error_message); |
368 | + } |
369 | + catch (MiddlewareException const& e) |
370 | + { |
371 | + // TODO: log error |
372 | + cerr << e.what() << endl; |
373 | + } |
374 | +} |
375 | + |
376 | + |
377 | ReplyProxy ReplyImpl::create(MWReplyProxy const& mw_proxy, std::shared_ptr<QueryObject> const& qo) |
378 | { |
379 | return ReplyProxy(new Reply((new ReplyImpl(mw_proxy, qo)))); |
380 | |
381 | === modified file 'src/internal/ReplyObject.cpp' |
382 | --- src/internal/ReplyObject.cpp 2013-12-17 01:39:35 +0000 |
383 | +++ src/internal/ReplyObject.cpp 2014-01-02 21:33:37 +0000 |
384 | @@ -22,7 +22,6 @@ |
385 | #include <scopes/ReceiverBase.h> |
386 | #include <scopes/Category.h> |
387 | #include <scopes/CategorisedResult.h> |
388 | -#include <unity/Exception.h> |
389 | |
390 | #include <cassert> |
391 | #include <iostream> // TODO: remove this once logging is added |
392 | @@ -57,7 +56,7 @@ |
393 | { |
394 | try |
395 | { |
396 | - finished(ReceiverBase::Finished); |
397 | + finished(ReceiverBase::Finished, ""); |
398 | } |
399 | catch (...) |
400 | { |
401 | @@ -110,10 +109,11 @@ |
402 | Annotation annotation(new internal::AnnotationImpl(*cat_registry_, result_var)); |
403 | receiver_base_->push(std::move(annotation)); |
404 | } |
405 | - catch (unity::Exception const& e) |
406 | + catch (std::exception const& e) |
407 | { |
408 | - // TODO: this is an internal error; log error |
409 | - finished(ReceiverBase::Error); |
410 | + // TODO: log this |
411 | + cerr << "ReplyObject::receiver_base_->push(): " << e.what() << endl; |
412 | + finished(ReceiverBase::Error, e.what()); |
413 | } |
414 | } |
415 | |
416 | @@ -128,9 +128,9 @@ |
417 | } |
418 | catch (std::exception const& e) |
419 | { |
420 | - // TODO: this is an internal error; log error |
421 | + // TODO: log this |
422 | cerr << "ReplyObject::receiver_base_->push(): " << e.what() << endl; |
423 | - finished(ReceiverBase::Error); |
424 | + finished(ReceiverBase::Error, e.what()); |
425 | } |
426 | } |
427 | } |
428 | @@ -140,7 +140,7 @@ |
429 | cerr << "ReplyObject::push(VariantMap): " << e.what() << endl; |
430 | try |
431 | { |
432 | - finished(ReceiverBase::Error); |
433 | + finished(ReceiverBase::Error, e.what()); |
434 | } |
435 | catch (...) |
436 | { |
437 | @@ -152,7 +152,7 @@ |
438 | cerr << "ReplyObject::push(VariantMap): unknown exception" << endl; |
439 | try |
440 | { |
441 | - finished(ReceiverBase::Error); |
442 | + finished(ReceiverBase::Error, "unknown exception"); |
443 | } |
444 | catch (...) |
445 | { |
446 | @@ -165,7 +165,7 @@ |
447 | } |
448 | } |
449 | |
450 | -void ReplyObject::finished(ReceiverBase::Reason r) noexcept |
451 | +void ReplyObject::finished(ReceiverBase::Reason r, string const& error_message) noexcept |
452 | { |
453 | // We permit exactly one finished() call for a query. This avoids |
454 | // a race condition where the executing down-stream query invokes |
455 | @@ -188,7 +188,7 @@ |
456 | lock.unlock(); // Inform the application code that the query is complete outside synchronization. |
457 | try |
458 | { |
459 | - receiver_base_->finished(r); |
460 | + receiver_base_->finished(r, error_message); |
461 | } |
462 | catch (std::exception const& e) |
463 | { |
464 | |
465 | === modified file 'src/internal/ScopeImpl.cpp' |
466 | --- src/internal/ScopeImpl.cpp 2013-12-13 04:48:38 +0000 |
467 | +++ src/internal/ScopeImpl.cpp 2014-01-02 21:33:37 +0000 |
468 | @@ -79,7 +79,7 @@ |
469 | { |
470 | // TODO: if things go wrong, we need to make sure that the reply object |
471 | // is disconnected from the middleware, so it gets deallocated. |
472 | - reply->finished(ReceiverBase::Error); |
473 | + reply->finished(ReceiverBase::Error, e.what()); |
474 | throw; |
475 | } |
476 | catch (...) |
477 | |
478 | === modified file 'src/internal/ScopeObject.cpp' |
479 | --- src/internal/ScopeObject.cpp 2013-12-13 04:48:38 +0000 |
480 | +++ src/internal/ScopeObject.cpp 2014-01-02 21:33:37 +0000 |
481 | @@ -123,7 +123,7 @@ |
482 | { |
483 | try |
484 | { |
485 | - reply->finished(ReceiverBase::Error); |
486 | + reply->finished(ReceiverBase::Error, e.what()); |
487 | } |
488 | catch (...) |
489 | { |
490 | @@ -136,7 +136,7 @@ |
491 | { |
492 | try |
493 | { |
494 | - reply->finished(ReceiverBase::Error); |
495 | + reply->finished(ReceiverBase::Error, "unknown exception"); |
496 | } |
497 | catch (...) |
498 | { |
499 | |
500 | === modified file 'src/internal/zmq_middleware/ReplyI.cpp' |
501 | --- src/internal/zmq_middleware/ReplyI.cpp 2013-12-12 16:02:06 +0000 |
502 | +++ src/internal/zmq_middleware/ReplyI.cpp 2014-01-02 21:33:37 +0000 |
503 | @@ -81,6 +81,7 @@ |
504 | auto req = in_params.getAs<capnproto::Reply::FinishedRequest>(); |
505 | auto r = req.getReason(); |
506 | ReceiverBase::Reason reason; |
507 | + string err; |
508 | switch (r) |
509 | { |
510 | case capnproto::Reply::FinishedReason::FINISHED: |
511 | @@ -96,6 +97,7 @@ |
512 | case capnproto::Reply::FinishedReason::ERROR: |
513 | { |
514 | reason = ReceiverBase::Error; |
515 | + err = req.getError(); |
516 | break; |
517 | } |
518 | default: |
519 | @@ -104,7 +106,7 @@ |
520 | reason = ReceiverBase::Error; // LCOV_EXCL_LINE |
521 | } |
522 | } |
523 | - delegate->finished(reason); |
524 | + delegate->finished(reason, err); |
525 | } |
526 | |
527 | } // namespace zmq_middleware |
528 | |
529 | === modified file 'src/internal/zmq_middleware/ZmqReply.cpp' |
530 | --- src/internal/zmq_middleware/ZmqReply.cpp 2013-12-02 18:10:46 +0000 |
531 | +++ src/internal/zmq_middleware/ZmqReply.cpp 2014-01-02 21:33:37 +0000 |
532 | @@ -71,7 +71,7 @@ |
533 | future.wait(); |
534 | } |
535 | |
536 | -void ZmqReply::finished(ReceiverBase::Reason reason) |
537 | +void ZmqReply::finished(ReceiverBase::Reason reason, string const& error_message) |
538 | { |
539 | capnp::MallocMessageBuilder request_builder; |
540 | auto request = make_request_(request_builder, "finished"); |
541 | @@ -92,6 +92,7 @@ |
542 | case ReceiverBase::Error: |
543 | { |
544 | r = capnproto::Reply::FinishedReason::ERROR; |
545 | + in_params.setError(error_message); |
546 | break; |
547 | } |
548 | default: |
549 | |
550 | === modified file 'src/internal/zmq_middleware/capnproto/Reply.capnp' |
551 | --- src/internal/zmq_middleware/capnproto/Reply.capnp 2013-11-22 04:00:45 +0000 |
552 | +++ src/internal/zmq_middleware/capnproto/Reply.capnp 2014-01-02 21:33:37 +0000 |
553 | @@ -54,4 +54,5 @@ |
554 | struct FinishedRequest |
555 | { |
556 | reason @0 : FinishedReason; |
557 | + error @1 : Text; # Present only if reason is error |
558 | } |
559 | |
560 | === modified file 'test/gtest/scopes/Runtime/Runtime_test.cpp' |
561 | --- test/gtest/scopes/Runtime/Runtime_test.cpp 2013-12-06 10:42:26 +0000 |
562 | +++ test/gtest/scopes/Runtime/Runtime_test.cpp 2014-01-02 21:33:37 +0000 |
563 | @@ -53,9 +53,10 @@ |
564 | EXPECT_EQ("dnd_uri", result.dnd_uri()); |
565 | count_++; |
566 | } |
567 | - virtual void finished(ReceiverBase::Reason reason) override |
568 | + virtual void finished(ReceiverBase::Reason reason, string const& error_message) override |
569 | { |
570 | EXPECT_EQ(Finished, reason); |
571 | + EXPECT_EQ("", error_message); |
572 | EXPECT_EQ(1, count_); |
573 | // Signal that the query has completed. |
574 | unique_lock<mutex> lock(mutex_); |
PASSED: Continuous integration, rev:98 jenkins. qa.ubuntu. com/job/ unity-scopes- api-ci/ 152/ jenkins. qa.ubuntu. com/job/ unity-scopes- api-trusty- amd64-ci/ 152 jenkins. qa.ubuntu. com/job/ unity-scopes- api-trusty- armhf-ci/ 152 jenkins. qa.ubuntu. com/job/ unity-scopes- api-trusty- armhf-ci/ 152/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ unity-scopes- api-trusty- i386-ci/ 152
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- scopes- api-ci/ 152/rebuild
http://